diff --git a/src/python/pyrte.c b/src/python/pyrte.c old mode 100755 new mode 100644 index 4faf67d9e880b4660203a492fd8d833d016ec074_c3JjL3B5dGhvbi9weXJ0ZS5j..bdd8cb18f7176c99a537d760568ae9717df424b3_c3JjL3B5dGhvbi9weXJ0ZS5j --- a/src/python/pyrte.c +++ b/src/python/pyrte.c @@ -95,6 +95,13 @@ Python functions provided by this module: + wasd.cgi_callout() + + Initiate a CGI callout to the server. + The required parameter provides the callout request string. + If the request string begins with '!' or '#' the callout will return + Py_None, otherwise the response string. + wasd.cgiplus_begin() This function is used to synchronise an explicitly CGIplus script @@ -111,6 +118,10 @@ function can be used to obtain the same data (and some variables that don't make it into os.environ (e.g. FORM_..). + wasd.read_cgiplusin() + + Read a record from the CGIPLUSIN stream (caution!) + wasd.reuse_interpreter() See discussion of 'latencies' above. Takes one arugment; True to reuse @@ -146,6 +157,10 @@ Returns an integer representing the number of times this RTE has been used. + wasd.write() + + Writes directly to <stdout> with a following fflush(). + WSGI INTERFACE -------------- @@ -183,7 +198,8 @@ Python/C API Reference Manual, Release 2.4.3 Extending and Embedding the Python Interpreter, Release 2.4.3 Lots of Googling with many and varied query strings. +http://python3porting.com/cextensions.html PYRTE COPYRIGHT --------------- @@ -186,8 +202,8 @@ PYRTE COPYRIGHT --------------- -Copyright (C) 2007-2013 Mark G.Daniel +Copyright (C) 2007-2020 Mark G.Daniel This package comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version. @@ -272,7 +288,7 @@ LOGICAL NAMES ------------- -PYRTE$DBUG enables all if(Debug) output statements; +PYRTE$DBUG enables all if(dbug) output statements; if some unique part of the script debugs just that script if defined to something like 'c' or '/' or '-' debugs all (this script-name check is CASE-SENSITIVE) @@ -283,8 +299,10 @@ PYRTE_CACHE_MAX integer size of code cache (zero to compare uncached) PYRTE_METRICS enable metric collection and report via "?$metrics$" query PYRTE_NOREUSE_INTERPRETER do not reuse interpreter for each script instance -PYRTE_USAGE_LIMIT integer number of requests before voluntary exit -PYRTE_WSGI_FORCE_BUFFERING enable buffering with WASD, this break the WSGI +PYRTE_ONESHOT voluntary exit after a single use (see PYRTE_USAGE_LIMIT) +PYRTE_STAT_TIMER incorporate basic stats in HTML comment +PYRTE_USAGE_LIMIT integer number of requests before voluntary exit +PYRTE_WSGI_FORCE_BUFFERING enable buffering with WASD, this breaks the WSGI specification but may give a performance boost. BUILD DETAILS @@ -296,6 +314,13 @@ VERSION HISTORY (update SOFTWAREVN as well!) --------------- +20-AUG-2020 MGD v3.0.0, Python 3 (via JFP Python 3.10.0a0) + v2.0.0, Python 2 equivalent + Python 2.7.18 build kludge for + VSI C V7.4-001 on OpenVMS IA64 V8.4-2L1 +22-JUL-2017 MGD v1.1.12, wasd.cgi_callout and RtePyMethCgiCallout() + provides callout environment regardless of WSGI + bugfix; stderr = freopen(stderr); 20-JUN-2013 MGD v1.1.11, bugfix; ProcessCachingRte() it appears to be necessary to destroy *EnvironDict along with using Py_EndInterpreter() @@ -323,8 +348,9 @@ */ /*****************************************************************************/ -#define SOFTWARECR "Copyright (C) 2007-2013 Mark G.Daniel" -#define SOFTWAREVN "1.1.11" +#define SOFTWARECR "Copyright (C) 2007-2020 Mark G.Daniel" +#define SOFTWAREVN "x.0.0" /* just the minor and tweak versions here! */ +/** ----------------^^^^^ and IDENTIFICATION=x.n.n in BUILD_PYRTE[n].COM **/ #define SOFTWARENM "PYRTE" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN @@ -366,5 +392,16 @@ */ #include <unistd.h> +/* 2.7.18 build kludge */ +#ifdef __ia64 +/** VSI C V7.4-001 on OpenVMS IA64 V8.4-2L1 **/ +#ifndef intmax_t +typedef signed long long int intmax_t; +typedef unsigned long long int uintmax_t; +typedef signed long long int intptr_t; +typedef unsigned long long int uintptr_t; +#endif +#endif + /* Python-specific includes (must come first!) */ @@ -369,5 +406,8 @@ /* Python-specific includes (must come first!) */ +/** INTERIM **/ +#define PY_SSIZE_T_CLEAN + #include <python.h> /* standard C header files */ @@ -382,8 +422,9 @@ #include <time.h> #include <unixlib.h> #include <unixio.h> +#include <wchar.h> /* VMS-specific header files */ #include <cvt$routines.h> #include <cvtdef.h> @@ -385,8 +426,9 @@ /* VMS-specific header files */ #include <cvt$routines.h> #include <cvtdef.h> +#include <fabdef.h> #include <jpidef.h> #include <lib$routines.h> #include <libdef.h> @@ -399,6 +441,13 @@ /* macros */ /**********/ +/** INTERIM **/ +#if PY_MAJOR_VERSION >= 3 +#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT +#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT +#define Py_BuildValue _Py_BuildValue_SizeT +#endif + #ifndef BUILD_DATETIME # define BUILD_DATETIME "(undefined)" #endif @@ -406,7 +455,7 @@ #define OBJREFCNT(pobj) ((pobj)->ob_refcnt) #define DEBUGPYOBJ(sobj,pobj) \ - if (Debug) \ + if (dbug) \ { \ fprintf (stdout, "\n***** %s ***** ", sobj); \ PyObject_Print (pobj, stdout, 0); \ @@ -414,9 +463,9 @@ } #define DEBUGREFCNT(sobj,pobj) \ - if (Debug) \ + if (dbug) \ fprintf (stdout, "%s%s->ob_refcnt: %d\n", \ sobj, (pobj) ? "" : "(null)", (pobj) ? pobj->ob_refcnt : 0); #define FI_LI __FILE__, __LINE__ @@ -418,9 +467,14 @@ fprintf (stdout, "%s%s->ob_refcnt: %d\n", \ sobj, (pobj) ? "" : "(null)", (pobj) ? pobj->ob_refcnt : 0); #define FI_LI __FILE__, __LINE__ +/* mainly to allow easy use of the __unaligned directive */ +#define ULONGPTR __unaligned unsigned long* +#define USHORTPTR __unaligned unsigned short* +#define INT64PTR __unaligned __int64* + /******************/ /* global storage */ /******************/ @@ -423,7 +477,8 @@ /******************/ /* global storage */ /******************/ -int AppOutputCount, +int dbug, + AppOutputCount, CgiPlusPythonEnd, CodeMetricEnabled, @@ -428,6 +483,5 @@ CgiPlusPythonEnd, CodeMetricEnabled, - Debug, GlobalDebug, HeadCvtGet, IsCgiPlusMode, @@ -466,6 +520,10 @@ ErrorPython [] = "Error initialising Python environment.", ErrorWsgiEnv [] = "Error initialising WSGI environment."; +char SoftwareId [] = SOFTWAREID; + +FILE *CgiPlusInFp; + PyObject *pBuiltins, *pError, *pEnvironDict, @@ -527,4 +585,7 @@ char *FileNamePtr, *FileNameByteCodePtr; PyThreadState *pInterpState; +#if PY_MAJOR_VERSION >= 3 + PyObject *pByteCode; +#else PyCodeObject *pByteCode; @@ -530,4 +591,5 @@ PyCodeObject *pByteCode; +#endif struct CodeMetricStruct *CodeMetricPtr; } CodeCache [CACHE_MAX]; @@ -538,6 +600,14 @@ /* python extension methods */ /****************************/ +static PyObject* RtePyMethCgiCallout (); + +PyDoc_STRVAR (rte_cgi_callout__doc__, +"Initiate a CGI callout to the server. \ +The required parameter provides the callout request string. \ +If the request string begins with '!' or '#' the callout will return \ +NULL otherwise the callout response string."); + static PyObject* RtePyMethCgiPlusBegin (PyObject*, PyObject*); PyDoc_STRVAR (rte_cgiplus_begin__doc__, @@ -560,6 +630,11 @@ in the function argument. Generally CGI variables are accessed from \ os.environ in the same manner as other environment variables."); +static PyObject* RtePyMethReadCgiPlusIn (); + +PyDoc_STRVAR (rte_read_cgiplusin__doc__, +"Retuns a string containing a record read from the CGIPLUSIN stream."); + static PyObject* RtePyMethReuseInterpreter (); PyDoc_STRVAR (rte_reuse_interpreter__doc__, @@ -619,7 +694,7 @@ PyDoc_STRVAR (wsgi_write__doc__, "Write direct to <stdout>."); -/* Jean-Fran�ois Pi�ronne's original '_wasd' module functions */ +/* Jean-Francois Pieronne's original '_wasd' module functions */ static PyObject* wasd_cgi_init (); static PyObject* wasd_isCgiPlus (); @@ -630,10 +705,11 @@ static struct PyMethodDef RtePyMethods [] = { /* WASD PyRTE methods */ - + { "cgi_callout", (PyCFunction)RtePyMethCgiCallout, METH_VARARGS, + rte_cgi_callout__doc__ }, { "cgiplus_begin", (PyCFunction)RtePyMethCgiPlusBegin, METH_VARARGS, rte_cgiplus_begin__doc__ }, { "cgiplus_end", (PyCFunction)RtePyMethCgiPlusEnd, METH_VARARGS, rte_cgiplus_end__doc__ }, { "getvar", (PyCFunction)RtePyMethGetVar, METH_VARARGS, rte_getvar__doc__ }, @@ -634,9 +710,11 @@ { "cgiplus_begin", (PyCFunction)RtePyMethCgiPlusBegin, METH_VARARGS, rte_cgiplus_begin__doc__ }, { "cgiplus_end", (PyCFunction)RtePyMethCgiPlusEnd, METH_VARARGS, rte_cgiplus_end__doc__ }, { "getvar", (PyCFunction)RtePyMethGetVar, METH_VARARGS, rte_getvar__doc__ }, + { "read_cgiplusin", (PyCFunction)RtePyMethReadCgiPlusIn, METH_VARARGS, + rte_read_cgiplusin__doc__ }, { "reuse_interpreter", (PyCFunction)RtePyMethReuseInterpreter, METH_VARARGS, rte_reuse_interpreter__doc__ }, { "rte_cache_entry", (PyCFunction)RtePyMethRteCacheEntry, METH_VARARGS, @@ -663,5 +741,5 @@ /* JFP's original '_wasd' module functions */ - { "cgi_init", (PyCFunction)wasd_cgi_init, 0, + { "cgi_init", (PyCFunction)wasd_cgi_init, METH_NOARGS, "initialise CGIplus environment" }, @@ -667,3 +745,3 @@ "initialise CGIplus environment" }, - { "isCgiPlus", (PyCFunction)wasd_isCgiPlus, 0, + { "isCgiPlus", (PyCFunction)wasd_isCgiPlus, METH_NOARGS, "is it activated in CGIplus mode?" }, @@ -669,5 +747,5 @@ "is it activated in CGIplus mode?" }, - { "cgi_eof", (PyCFunction)wasd_cgi_eof, 0, + { "cgi_eof", (PyCFunction)wasd_cgi_eof, METH_NOARGS, "concludes the current CGIplus request" }, { "cgi_info", (PyCFunction)wasd_cgi_info, METH_VARARGS, "return a CGI variable" }, @@ -677,6 +755,20 @@ { NULL, NULL, 0, NULL } }; +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef RtePyModuleDef = { + PyModuleDef_HEAD_INIT, + "wasd", /* m_name */ + "WASD pyRTE module\n", /* m_doc */ + -1, /* m_size */ + RtePyMethods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif + /**************/ /* prototypes */ /**************/ @@ -687,6 +779,7 @@ char* CgiVar (char*); char* CgiVarDclSymbol (char*); void CollectMetrics (struct CodeCacheStruct*, int); +void DbugCheck (); int EmptyScriptName (char*, char*); void EnsureExit (unsigned long*); void FlushCacheEntry (struct CodeCacheStruct*); @@ -701,5 +794,6 @@ void ProcessBasicRte (); void ProcessCachingRte (); int ProctorDetect (); +int ReadFileIntoMemory (char*, char**, int*); void ReportError (int, int, int, char*, ...); void RteScriptParam (); @@ -704,5 +798,6 @@ void ReportError (int, int, int, char*, ...); void RteScriptParam (); +void SetProgramName (char*); int SetupOsEnvCgiVar (int); char* StatTimer (int); char* TrnLnm (char*, char*); @@ -706,6 +801,7 @@ int SetupOsEnvCgiVar (int); char* StatTimer (int); char* TrnLnm (char*, char*); +int WasdModuleInit (void); int WsgiSendHeaders (); int WsgiSendResponse (PyObject*); int WsgiOsEnvVar (); @@ -709,6 +805,14 @@ int WsgiSendHeaders (); int WsgiSendResponse (PyObject*); int WsgiOsEnvVar (); - +#if PY_MAJOR_VERSION >= 3 +wchar_t** MungeArgv (int, char*[]); +#else +char** MungeArgv (int, char*[]); +#endif + +#if PY_MAJOR_VERSION >= 3 +PyAPI_FUNC(void) PyNode_Free (struct _mod*); +#else /* not in an include file for some reason (adapted from node.h)*/ PyAPI_FUNC(void) PyNode_Free (struct _node*); @@ -713,5 +817,6 @@ /* not in an include file for some reason (adapted from node.h)*/ PyAPI_FUNC(void) PyNode_Free (struct _node*); +#endif PyAPI_FUNC(PyObject*) PyMarshal_ReadObjectFromFile(FILE*); unsigned long PyMarshal_ReadLongFromFile(FILE*); @@ -741,7 +846,16 @@ /* begin */ /*********/ +#if PY_MAJOR_VERSION >= 3 + *strchr(SoftwareId,'x') = '3'; +#else + *strchr(SoftwareId,'x') = '2'; +#endif + + /* set the global pointer used by some functions */ + CodeCachePtr = &CodeCache[0]; + if (argc == 2) { if (!strncasecmp(argv[1], "/cli=", 5)) { @@ -744,10 +858,11 @@ if (argc == 2) { if (!strncasecmp(argv[1], "/cli=", 5)) { + DbugCheck(); ProcessCLI (argv[1]+5); exit (SS$_NORMAL); } if (!strcasecmp(argv[1], "/version")) { fprintf (stdout, "%%PYRTE-I-VERSION, %s (%s)\n%s\n%s", @@ -748,10 +863,10 @@ ProcessCLI (argv[1]+5); exit (SS$_NORMAL); } if (!strcasecmp(argv[1], "/version")) { fprintf (stdout, "%%PYRTE-I-VERSION, %s (%s)\n%s\n%s", - SOFTWAREID, BUILD_DATETIME, SOFTWARECR, SOFTWAREGPL); + SoftwareId, BUILD_DATETIME, SOFTWARECR, SOFTWAREGPL); exit (SS$_NORMAL); } } @@ -759,14 +874,7 @@ status = sys$getjpiw (0, 0, 0, &JpiItems, 0, 0, 0); if (!(status & 1)) exit (status); - /* this is almost a 'bit too clever' :-) */ - if ((cptr = TrnLnm ("PYRTE$DBUG", NULL)) != NULL) - if (strchr (cptr, '*')) - if (GlobalDebug = Debug = 1) - { - fputs ("Content-Type: text/plain\n\n", stdout); - fflush (stdout); - } + DbugCheck(); WsgiForceBuffering = (TrnLnm ("PYRTE_WSGI_FORCE_BUFFERING", NULL) != NULL); @@ -774,7 +882,7 @@ /* if it doesn't look like CGI environment then forget it */ if (!TrnLnm ("HTTP$INPUT", NULL)) exit (SS$_ABORT); - if (!Debug) + if (!dbug) { /* binary mode to eliminate carriage-control */ if (!(stdin = freopen ("HTTP$INPUT:", "r", stdin, @@ -783,7 +891,7 @@ if (!(stdout = freopen ("SYS$OUTPUT:", "w", stdout, "ctx=bin", "ctx=xplct"))) exit (vaxc$errno); - if (!(stdout = freopen ("SYS$ERROR:", "w", stderr, + if (!(stderr = freopen ("SYS$ERROR:", "w", stderr, "ctx=bin", "ctx=xplct"))) exit (vaxc$errno); } @@ -791,6 +899,8 @@ cptr = TrnLnm ("PYRTE_USAGE_LIMIT", NULL); if (cptr && isdigit(*cptr)) UsageLimit = atoi(cptr); + if (TrnLnm ("PYRTE_ONESHOT", NULL)) UsageLimit = 1; + /* need differentiate between RTE/CGIplus and CGIplus script */ IsCgiPlusMode = (TrnLnm ("CGIPLUSEOF", NULL) != NULL); CgiPlusEofPtr = TrnLnm ("CGIPLUSEOF", CgiPlusEof); @@ -854,7 +964,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "EnsureExit() %%X%08.08X\n", ExitStatus); + if (dbug) fprintf (stdout, "EnsureExit() %%X%08.08X\n", ExitStatus); if (ExitStatus & 0x00000001) exit (ExitStatus); @@ -878,6 +988,8 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProcessCLI()\n"); - + if (dbug) fprintf (stdout, "ProcessCLI()\n"); + + SetProgramName (ScriptName); + WasdModuleInit (); Py_Initialize(); @@ -883,8 +995,5 @@ Py_Initialize(); - pWasdModule = Py_InitModule ("wasd", RtePyMethods); - - Py_SetProgramName (ScriptName); fp = fopen (ScriptName, "r"); if (fp) { @@ -887,7 +996,8 @@ fp = fopen (ScriptName, "r"); if (fp) { + if (dbug) fprintf (stdout, "fp:%u\n", fp); PyRun_AnyFileExFlags (fp, ScriptName, 0, NULL); fclose (fp); } @@ -897,7 +1007,10 @@ ReportError (__LINE__, status, 0, "Error opening !AZ", ScriptName); } - Py_Finalize(); + Py_Finalize (); + + if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL)) + fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE)); } /*****************************************************************************/ @@ -920,16 +1033,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProcessCGI()\n"); - - Py_Initialize(); - pWasdModule = Py_InitModule ("wasd", RtePyMethods); - - sptr = CgiVar ("SCRIPT_NAME"); - Py_SetProgramName (sptr); - - /* NEEDS WORK!! */ - PySys_SetArgv (argc, argv); - - cptr = CgiVar ("SCRIPT_FILENAME"); + if (dbug) fprintf (stdout, "ProcessCGI()\n"); + + cptr = sptr = CgiVar ("PATH_INFO"); fp = fopen (cptr, "r"); @@ -935,3 +1039,8 @@ fp = fopen (cptr, "r"); + if (!fp) + { + sptr = CgiVar ("PATH_TRANSLATED"); + fp = fopen (sptr, "r"); + } if (fp) { @@ -936,3 +1045,11 @@ if (fp) { + StatTimer(FALSE); + + SetProgramName (cptr); + WasdModuleInit (); + Py_Initialize(); + + PySys_SetArgv (argc, MungeArgv(argc,argv)); + PyRun_AnyFileExFlags (fp, cptr, 0, NULL); @@ -938,4 +1055,10 @@ PyRun_AnyFileExFlags (fp, cptr, 0, NULL); + + if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL)) + fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE)); + + Py_Finalize(); + fclose (fp); } else @@ -943,8 +1066,6 @@ status = vaxc$errno; ReportError (__LINE__, status, 0, "Error opening !AZ", sptr); } - - Py_Finalize(); } /*****************************************************************************/ @@ -967,8 +1088,8 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProcessCGIplus() %d\n", argc); + if (dbug) fprintf (stdout, "ProcessCGIplus() %d\n", argc); /* code behaviours are different for an explicitly CGIplus script */ IsCgiPlusScript = 1; @@ -971,9 +1092,10 @@ /* code behaviours are different for an explicitly CGIplus script */ IsCgiPlusScript = 1; + SetProgramName (argv[1]); Py_Initialize(); /* just use the first element of the code cache */ ccptr = &CodeCache[0]; @@ -975,11 +1097,8 @@ Py_Initialize(); /* just use the first element of the code cache */ ccptr = &CodeCache[0]; - /* set the global pointer used by some functions */ - CodeCachePtr = ccptr; - /* it will have been used the once! */ ccptr->InterpreterUsageCount++; @@ -983,6 +1102,4 @@ /* it will have been used the once! */ ccptr->InterpreterUsageCount++; - Py_SetProgramName (argv[1]); - /* first is RTE image, second CGIplus script, then optional parameters */ @@ -988,5 +1105,5 @@ /* first is RTE image, second CGIplus script, then optional parameters */ - PySys_SetArgv (argc-1, &argv[1]); + PySys_SetArgv (argc-1, MungeArgv(argc,&argv[1])); LoadByteCode (argv[1], argv[1], ccptr); if (!ccptr->pByteCode) return; @@ -1019,13 +1136,8 @@ } DEBUGPYOBJ("pOsDict",pOsDict) - pWasdModule = Py_InitModule ("wasd", RtePyMethods); - if (!pWasdModule) - { - ReportError (__LINE__, 0, 1, ErrorPython); - return; - } + if (!WasdModuleInit ()) return; /* get the first request (which is already available and won't block) */ CgiVar (""); @@ -1028,17 +1140,8 @@ /* get the first request (which is already available and won't block) */ CgiVar (""); - if (!(Debug = GlobalDebug)) - if (cptr = TrnLnm ("PYRTE$DBUG", NULL)) - if (sptr = CgiVar ("SCRIPT_NAME")) - if (strstr (sptr, cptr)) - Debug = 1; - if (Debug) - { - fputs ("Content-Type: text/plain\n\n", stdout); - fflush (stdout); - } + DbugCheck(); RteScriptParam (); @@ -1061,6 +1164,6 @@ fputs (CgiPlusEofPtr, stdout); fflush (stdout); - if (!GlobalDebug) Debug = 0; + if (!GlobalDebug) dbug = 0; Py_Finalize(); @@ -1065,5 +1168,8 @@ Py_Finalize(); + + if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL)) + fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE)); } /*****************************************************************************/ @@ -1085,7 +1191,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProcessBasicRte()\n"); + if (dbug) fprintf (stdout, "ProcessBasicRte()\n"); for (;;) { @@ -1094,5 +1200,6 @@ /* initialise this for special CGI-and-CGIplus script cases */ RtePyMethCgiPlusBegin (NULL, NULL); - /* try to get some of the work out of the way before next request */ + SetProgramName ("ProcessBasicRte()"); + if (!WasdModuleInit()) break; Py_Initialize(); @@ -1098,12 +1205,6 @@ Py_Initialize(); - pWasdModule = Py_InitModule ("wasd", RtePyMethods); - if (!pWasdModule) - { - ReportError (__LINE__, 0, 1, ErrorPython); - return; - } /* block waiting for the first/next request */ CgiVar (""); UsageCount++; @@ -1105,20 +1206,18 @@ /* block waiting for the first/next request */ CgiVar (""); UsageCount++; - if (!(Debug = GlobalDebug)) - if (cptr = TrnLnm ("PYRTE$DBUG", NULL)) - if (sptr = CgiVar ("SCRIPT_NAME")) - if (strstr (sptr, cptr)) - Debug = 1; - if (Debug) - { - fputs ("Content-Type: text/plain\n\n", stdout); - fflush (stdout); - } + DbugCheck(); + + cptr = sptr = CgiVar ("SCRIPT_FILENAME"); + SetProgramName (cptr); + + /* fudge these */ + argv[0] = cptr; + PySys_SetArgv (1, MungeArgv(1,argv)); RteScriptParam (); if (!NoStreamMode) fprintf (stdout, "Script-Control: X-stream-mode\n"); @@ -1120,16 +1219,8 @@ RteScriptParam (); if (!NoStreamMode) fprintf (stdout, "Script-Control: X-stream-mode\n"); - cptr = CgiVar ("SCRIPT_FILENAME"); - - Py_SetProgramName (cptr); - - /* fudge these */ - argv[0] = cptr; - PySys_SetArgv (1, argv); - - fp = fopen (cptr, "r", "shr=get"); + fp = fopen (sptr, "r", "shr=get"); if (fp) { @@ -1134,6 +1225,6 @@ if (fp) { - PyRun_AnyFileExFlags (fp, cptr, 0, NULL); + PyRun_AnyFileExFlags (fp, sptr, 0, NULL); fclose (fp); } else @@ -1145,7 +1236,10 @@ Py_Finalize(); + if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL)) + fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE)); + fflush (stdout); fputs (CgiPlusEofPtr, stdout); fflush (stdout); @@ -1148,8 +1242,8 @@ fflush (stdout); fputs (CgiPlusEofPtr, stdout); fflush (stdout); - if (!GlobalDebug) Debug = 0; + if (!GlobalDebug) dbug = 0; if (UsageLimit && UsageCount >= UsageLimit) break; } @@ -1161,9 +1255,7 @@ (compiled) byte-code for a number of scripts (determined by compilation constant and logical name value). The byte-code used is either loaded from pre-compiled file content (.PYO or .PYC) or compiled dynamically (and then -cached) from a source file (.PY). Also, and based on RTE or script -configuration, maintain a cache of pre-initialized (and previously used) Python -subinterpreters. +cached) from a source file (.PY). */ void ProcessCachingRte () @@ -1172,8 +1264,8 @@ int idx, tidx, retval, status; unsigned long mtime, CurrentTimeSecs; - char *cptr, *sptr; + char *cptr, *fnptr, *sptr, *snptr; char *argv [2] = { NULL, NULL }; struct CodeCacheStruct *ccptr; PyObject *pObject, *pResult; @@ -1176,11 +1268,9 @@ char *argv [2] = { NULL, NULL }; struct CodeCacheStruct *ccptr; PyObject *pObject, *pResult; - PyThreadState *pStateBuffer, - *pNewInterpState = NULL; /*********/ /* begin */ /*********/ @@ -1182,11 +1272,11 @@ /*********/ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProcessCachingRte()\n"); + if (dbug) fprintf (stdout, "ProcessCachingRte()\n"); cptr = TrnLnm ("PYRTE_CACHE_MAX", NULL); if (cptr && isdigit(*cptr)) CodeCacheMax = atoi(cptr); if (CodeCacheMax > CACHE_MAX) CodeCacheMax = CACHE_MAX; @@ -1188,14 +1278,11 @@ cptr = TrnLnm ("PYRTE_CACHE_MAX", NULL); if (cptr && isdigit(*cptr)) CodeCacheMax = atoi(cptr); if (CodeCacheMax > CACHE_MAX) CodeCacheMax = CACHE_MAX; - Py_Initialize(); - PyEval_InitThreads (); - for (;;) { /********/ /* wait */ /********/ @@ -1196,25 +1283,9 @@ for (;;) { /********/ /* wait */ /********/ - if (!pNewInterpState) - { - /* - Create a new interpreter *before* checking for the next request. - This reduces response latency where requests are not back-to-back. - */ - pStateBuffer = PyEval_SaveThread (); - pNewInterpState = Py_NewInterpreter (); - if (!pNewInterpState) - { - ReportError (__LINE__, 0, 0, "Error initialising interpreter."); - break; - } - PyThreadState_Swap (pStateBuffer); - } - /* initialise this for special CGI-and-CGIplus script cases */ RtePyMethCgiPlusBegin (NULL, NULL); @@ -1218,5 +1289,9 @@ /* initialise this for special CGI-and-CGIplus script cases */ RtePyMethCgiPlusBegin (NULL, NULL); + SetProgramName ("ProcessBasicRte()"); + if (!WasdModuleInit()) break; + Py_Initialize(); + /* block waiting for the first/next request */ CgiVar (""); @@ -1221,4 +1296,5 @@ /* block waiting for the first/next request */ CgiVar (""); + sys$gettim (&CurrentBinTime); CurrentTimeSecs = decc$fix_time (&CurrentBinTime); @@ -1223,16 +1299,6 @@ sys$gettim (&CurrentBinTime); CurrentTimeSecs = decc$fix_time (&CurrentBinTime); - - if (!(Debug = GlobalDebug)) - if (cptr = TrnLnm ("PYRTE$DBUG", NULL)) - if (sptr = CgiVar ("SCRIPT_NAME")) - if (strstr (sptr, cptr)) - Debug = 1; - if (Debug) - { - fputs ("Content-Type: text/plain\n\n", stdout); - fflush (stdout); - } + DbugCheck(); if (TrnLnm ("PYRTE_METRICS", NULL)) CodeMetricEnabled = 1; @@ -1254,8 +1320,8 @@ /* request */ /***********/ - cptr = CgiVar ("SCRIPT_FILENAME"); - if (!cptr) + fnptr = CgiVar ("SCRIPT_FILENAME"); + if (!fnptr) { ReportError (__LINE__, 0, 0, "Error getting SCRIPT_FILENAME."); break; @@ -1273,8 +1339,10 @@ /* byte-code cache */ /*******************/ + if (dbug) fprintf (stdout, "CodeCacheCount:%d\n", CodeCacheCount); + /* look to see if we have the script byte-code cached */ for (idx = 0; idx < CodeCacheCount; idx++) { ccptr = &CodeCache[idx]; if (!ccptr->FileNamePtr) continue; @@ -1276,8 +1344,8 @@ /* look to see if we have the script byte-code cached */ for (idx = 0; idx < CodeCacheCount; idx++) { ccptr = &CodeCache[idx]; if (!ccptr->FileNamePtr) continue; - if (Debug) fprintf (stdout, "%d %d |%s|%s|\n", + if (dbug) fprintf (stdout, "%d %d |%s|%s|\n", idx, ccptr->InterpreterUsageCount, cptr, ccptr->FileNamePtr); @@ -1282,7 +1350,7 @@ idx, ccptr->InterpreterUsageCount, cptr, ccptr->FileNamePtr); - if (!strcasecmp (cptr, ccptr->FileNamePtr)) break; - ccptr++; + if (!strcasecmp (fnptr, ccptr->FileNamePtr)) break; + ccptr = NULL; } if (idx < CodeCacheCount) @@ -1291,6 +1359,7 @@ /* found cache */ /***************/ + if (dbug) fprintf (stdout, "hit:%d\n", idx); if (!ByteCodeUpToDate (ccptr)) { /* apparently not */ @@ -1310,7 +1379,7 @@ if (tidx < CodeCacheCount) ccptr = &CodeCache[tidx]; else - if (idx < CodeCacheMax) + if (tidx < CodeCacheMax) { /* didn't find an unused entry */ CodeCacheCount++; @@ -1314,7 +1383,7 @@ { /* didn't find an unused entry */ CodeCacheCount++; - ccptr = &CodeCache[idx]; + ccptr = &CodeCache[tidx]; } else { @@ -1325,6 +1394,7 @@ ccptr = &CodeCache[tidx]; FlushCacheEntry (ccptr); } + idx = tidx; } else { @@ -1332,6 +1402,8 @@ ccptr = &CodeCache[0]; if (ccptr->FileNamePtr) FlushCacheEntry (ccptr); } + if (dbug) fprintf (stdout, "CodeCacheCount:%d idx:%d usage:%d\n", + CodeCacheCount, idx, ccptr->CodeUsageCount); /* set the global pointer used by some functions */ CodeCachePtr = ccptr; @@ -1342,20 +1414,10 @@ /* load script */ /***************/ - if (ccptr->pInterpState) - { - /* also lose any previously associated interpreter */ - pStateBuffer = PyThreadState_Swap (ccptr->pInterpState); - Py_EndInterpreter (ccptr->pInterpState); - PyThreadState_Swap (pStateBuffer); - ccptr->pInterpState = NULL; - ccptr->InterpreterUsageCount = 0; - } - - sptr = CgiVar ("SCRIPT_NAME"); - if (!sptr) + snptr = CgiVar ("SCRIPT_NAME"); + if (!snptr) { ReportError (__LINE__, 0, 0, "Error getting SCRIPT_NAME."); break; } @@ -1357,9 +1419,9 @@ { ReportError (__LINE__, 0, 0, "Error getting SCRIPT_NAME."); break; } - LoadByteCode (cptr, sptr, ccptr); + LoadByteCode (fnptr, snptr, ccptr); AddMetrics (ccptr); } @@ -1375,23 +1437,6 @@ ccptr->CodeUsageCount++; ccptr->LastUsedSecs = CurrentTimeSecs; - if (!ccptr->pInterpState) - { - /* associate an interpreter with the byte-code */ - ccptr->pInterpState = pNewInterpState; - pNewInterpState = NULL; - - /* fudge the arguments */ - pStateBuffer = PyThreadState_Swap (ccptr->pInterpState); - Py_SetProgramName (cptr); - argv[0] = cptr; - PySys_SetArgv (1, argv); - PyThreadState_Swap (pStateBuffer); - } - ccptr->InterpreterUsageCount++; - - pStateBuffer = PyThreadState_Swap (ccptr->pInterpState); - /* borrowed reference */ pMainModule = PyImport_AddModule ("__main__"); if (!pMainModule) @@ -1424,13 +1469,5 @@ } DEBUGPYOBJ("pOsDict",pOsDict) - /* borrowed reference */ - pWasdModule = Py_InitModule ("wasd", RtePyMethods); - if (!pWasdModule) - { - ReportError (__LINE__, 0, 1, ErrorPython); - return; - } - if (!SetupOsEnvCgiVar (1)) return; @@ -1435,4 +1472,6 @@ if (!SetupOsEnvCgiVar (1)) return; + SetProgramName (snptr); + PyErr_Clear (); @@ -1437,6 +1476,5 @@ PyErr_Clear (); - /* new reference */ pResult = PyEval_EvalCode (ccptr->pByteCode, pMainDict, pMainDict); /* new reference */ if (pError = PyErr_Occurred()) @@ -1450,10 +1488,6 @@ /* new reference, can be NULL */ Py_XDECREF (pResult); - - DEBUGPYOBJ("pMainDict",pMainDict) - - PyThreadState_Swap (pStateBuffer); } else { @@ -1461,7 +1495,9 @@ FlushCacheEntry (ccptr); } + Py_Finalize(); + /******************/ /* end of request */ /******************/ @@ -1464,9 +1500,7 @@ /******************/ /* end of request */ /******************/ - fflush (stdout); - /* after the flush to accumulate any outstanding BIO */ CollectMetrics (ccptr, 1); @@ -1470,6 +1504,10 @@ /* after the flush to accumulate any outstanding BIO */ CollectMetrics (ccptr, 1); + if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL)) + fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE)); + + fflush (stdout); fputs (CgiPlusEofPtr, stdout); fflush (stdout); @@ -1473,23 +1511,7 @@ fputs (CgiPlusEofPtr, stdout); fflush (stdout); - if (ccptr->pInterpState) - { - if (!ReuseInterpreter || !ccptr->FileNamePtr) - { - pStateBuffer = PyThreadState_Swap (ccptr->pInterpState); - Py_EndInterpreter (ccptr->pInterpState); - PyThreadState_Swap (pStateBuffer); - ccptr->pInterpState = NULL; - ccptr->InterpreterUsageCount = 0; - /* these seem to need to go after the interpreter */ - Py_DECREF (pEnvironDict); - Py_DECREF (pOsEnvironDict); - pEnvironDict = pOsEnvironDict = NULL; - } - } - - if (!GlobalDebug) Debug = 0; + if (!GlobalDebug) dbug = 0; if (UsageLimit && UsageCount >= UsageLimit) break; } @@ -1493,8 +1515,6 @@ if (UsageLimit && UsageCount >= UsageLimit) break; } - - Py_Finalize(); } /*****************************************************************************/ @@ -1510,7 +1530,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "FlushCacheEntry()\n"); + if (dbug) fprintf (stdout, "FlushCacheEntry()\n"); if (ccptr->FileNamePtr) { @@ -1531,6 +1551,156 @@ /*****************************************************************************/ /* +Initialise the internal WASD module. +Declared before WasdModuleInit() to avoid protyping. +*/ + +#if PY_MAJOR_VERSION >= 3 + +PyObject* WasdModuleInit2 (void) + +{ + PyObject* modptr; + + /*********/ + /* begin */ + /*********/ + + modptr = PyModule_Create (&RtePyModuleDef); + if (!modptr) return (modptr); + PyModule_AddObject (modptr, "__path__", Py_BuildValue("()")); + return (modptr); +} + +#else /* PY_MAJOR_VERSION < 3 */ + +void WasdModuleInit2 (void) + +{ + PyObject* modptr; + + /*********/ + /* begin */ + /*********/ + + modptr = Py_InitModule ("wasd", RtePyMethods); + if (!modptr) return; + PyModule_AddObject (modptr, "__path__", Py_BuildValue("()")); +} + +#endif /* PY_MAJOR_VERSION >= 3 */ + +/*****************************************************************************/ +/* +Initialise the internal WASD module. +*/ + +int WasdModuleInit (void) + +{ + /*********/ + /* begin */ + /*********/ + + if (dbug) fprintf (stdout, "WasdModuleInit()\n"); + + if (PyImport_AppendInittab ("wasd", &WasdModuleInit2) >= 0) return (1); + ReportError (__LINE__, 0, 1, ErrorPython); + return (0); +} + +/*****************************************************************************/ +/* +Set the programme name (doh). +*/ + +void SetProgramName (char* name) + +{ + wchar_t *wcptr; + + /*********/ + /* begin */ + /*********/ + + if (dbug) fprintf (stdout, "SetProgramName() |%s|\n", name); + + if (!name) return; +#if PY_MAJOR_VERSION >= 3 + wcptr = Py_DecodeLocale (name, NULL); + Py_SetProgramName (wcptr); + PyMem_RawFree (wcptr); +#else + Py_SetProgramName (name); +#endif +} + +/*****************************************************************************/ +/* +For Python 3 covert an array of pointers to char to an array of pointers to +wide char. For Python 2 just return the original array of pointers to char. +*/ + +#if PY_MAJOR_VERSION >= 3 + +wchar_t** MungeArgv (int argc, char *argv[]) + +{ + static wchar_t* wargv [32]; + + int idx; + + /*********/ + /* begin */ + /*********/ + + if (dbug) fprintf (stdout, "MungeArgv()\n"); + + /* completely arbitrary */ + if (argc >= 32) exit (SS$_BUGCHECK); + + /* free any existing array of wide strings */ + for (idx = 0; idx < 32; idx++) + { + if (!wargv[idx]) continue; + if (wargv[idx]) PyMem_RawFree (wargv[idx]); + wargv[idx] = NULL; + } + + for (idx = 0; idx < argc; idx++) + { + if (dbug) fprintf (stdout, "%d |%s|\n", idx, argv[idx]); + if (!argv[idx]) return (NULL); + wargv[idx] = Py_DecodeLocale (argv[idx], NULL); + } + + return (wargv); +} + +#else /* PY_MAJOR_VERSION < 3 */ + +char** MungeArgv (int argc, char *argv[]) + +{ + int idx; + + /*********/ + /* begin */ + /*********/ + + if (dbug) fprintf (stdout, "MungeArgv()\n"); + + if (dbug) + for (idx = 0; idx < argc; idx++) + fprintf (stdout, "%d |%s|\n", idx, argv[idx]); + + return (argv); +} + +#endif /* PY_MAJOR_VERSION >= 3 */ + +/*****************************************************************************/ +/* Create the script byte-code by either loading the source code (.PY) and compiling, or loading the pre-compiled byte code (.PYC) or optimised, pre-compiled byte-code (.PYO). Reports it's own errors. Success is indicated @@ -1545,6 +1715,6 @@ struct CodeCacheStruct *ccptr ) { - int status, + int flen, status, FileNameLength; unsigned long magic, mtime; @@ -1549,7 +1719,7 @@ FileNameLength; unsigned long magic, mtime; - char *cptr, *sptr, *zptr, + char *cptr, *fptr, *sptr, *zptr, *CharPtr; char FileNameByteCode [256]; FILE *fp; stat_t FstatBuffer; @@ -1552,5 +1722,8 @@ *CharPtr; char FileNameByteCode [256]; FILE *fp; stat_t FstatBuffer; +#if PY_MAJOR_VERSION >= 3 + struct _mod *pNode; +#else struct _node *pNode; @@ -1556,7 +1729,8 @@ struct _node *pNode; +#endif struct CodeMetricStruct *cmptr; /*********/ /* begin */ /*********/ @@ -1557,10 +1731,10 @@ struct CodeMetricStruct *cmptr; /*********/ /* begin */ /*********/ - if (Debug) fprintf (stdout, "LoadByteCode() |%s|\n", FileName); + if (dbug) fprintf (stdout, "LoadByteCode() |%s|\n", FileName); ccptr->LastUsedSecs = ccptr->ScriptMtimeSecs = ccptr->CodeUsageCount = 0; @@ -1589,7 +1763,7 @@ fp = NULL; for (;;) { - if (Debug) fprintf (stdout, "|%s|\n", FileNameByteCode); + if (dbug) fprintf (stdout, "|%s|\n", FileNameByteCode); /* note; opened in 'binary' mode */ fp = fopen (FileNameByteCode, "rb", "shr=get"); if (fp) break; @@ -1602,7 +1776,7 @@ { /* well, it's certainly not pre-compiled! */ FileNameByteCode[0] = '\0'; - if (Debug) fprintf (stdout, "|%s|\n", FileName); + if (dbug) fprintf (stdout, "|%s|\n", FileName); /* note; opened in 'record' mode */ fp = fopen (FileName, "r", "ctx=rec", "shr=get"); if (!fp) @@ -1627,4 +1801,7 @@ magic = PyMarshal_ReadLongFromFile (fp); mtime = PyMarshal_ReadLongFromFile (fp); /* what's left is the byte-code */ +#if PY_MAJOR_VERSION >= 3 + ccptr->pByteCode = PyMarshal_ReadObjectFromFile (fp); +#else ccptr->pByteCode = (PyCodeObject*)PyMarshal_ReadObjectFromFile (fp); @@ -1630,4 +1807,5 @@ ccptr->pByteCode = (PyCodeObject*)PyMarshal_ReadObjectFromFile (fp); +#endif fclose (fp); if (!ccptr->pByteCode) { @@ -1638,10 +1816,9 @@ else { /* source code file */ - pNode = PyParser_SimpleParseFile (fp, ScriptName, Py_file_input); - fclose (fp); - if (!pNode) + status = ReadFileIntoMemory (FileName, &fptr, &flen); + if (!(status & 1)) { ReportError (__LINE__, 0, 1, NULL); return; } @@ -1644,9 +1821,15 @@ { ReportError (__LINE__, 0, 1, NULL); return; } - ccptr->pByteCode = (PyCodeObject*) PyNode_Compile (pNode, ScriptName); - PyNode_Free (pNode); +#if PY_MAJOR_VERSION >= 3 + ccptr->pByteCode = Py_CompileString (fptr, ScriptName, Py_file_input); +#else + ccptr->pByteCode = (PyCodeObject*)Py_CompileString (fptr, ScriptName, + Py_file_input); +#endif + free (fptr); + fclose (fp); if (!ccptr->pByteCode) { ReportError (__LINE__, 0, 1, NULL); @@ -1665,8 +1848,16 @@ if (!ccptr->FileNameByteCodePtr) exit (vaxc$errno); strcpy (ccptr->FileNameByteCodePtr, FileNameByteCode); } - if (Debug) fprintf (stdout, "|%s|%s|\n", ccptr->FileNamePtr, - ccptr->FileNameByteCodePtr); + if (dbug) + { + fprintf (stdout, "|%s|%s| %u", ccptr->FileNamePtr, + ccptr->FileNameByteCodePtr, ccptr->pByteCode); +#if PY_MAJOR_VERSION >= 3 + DEBUGPYOBJ("->pByteCode", ccptr->pByteCode) +#else + DEBUGPYOBJ("->pByteCode", (struct _object*)ccptr->pByteCode) +#endif + } } /*****************************************************************************/ @@ -1684,7 +1875,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ByteCodeUpToDate()\n"); + if (dbug) fprintf (stdout, "ByteCodeUpToDate()\n"); if (ccptr->FileNameByteCodePtr) retval = stat (ccptr->FileNameByteCodePtr, &StatBuffer); @@ -1692,8 +1883,9 @@ retval = stat (ccptr->FileNamePtr, &StatBuffer); if (retval) return (0); /* if the script file is more recent than the cached byte-code */ - if (Debug) fprintf (stdout, "|%d|%d|\n", - StatBuffer.st_mtime, ccptr->ScriptMtimeSecs); + if (dbug) fprintf (stdout, "|%d|%d|%s\n", + StatBuffer.st_mtime, ccptr->ScriptMtimeSecs, + StatBuffer.st_mtime == ccptr->ScriptMtimeSecs ? "YES" : "NO"); if (StatBuffer.st_mtime != ccptr->ScriptMtimeSecs) return (0); return (1); } @@ -1719,7 +1911,7 @@ /*********/ /** - if (Debug) fprintf (stdout, "RteStdoutWrite()\n"); + if (dbug) fprintf (stdout, "RteStdoutWrite()\n"); DEBUGPYOBJ("self",self) DEBUGPYOBJ("args",args) **/ @@ -1734,4 +1926,7 @@ return (Py_None); } +#if PY_MAJOR_VERSION >= 3 + if (PyBytes_Check (pValue)) +#else if (PyString_Check (pValue)) @@ -1737,2 +1932,3 @@ if (PyString_Check (pValue)) +#endif { @@ -1738,4 +1934,11 @@ { +#if PY_MAJOR_VERSION >= 3 + PyBytes_AsStringAndSize (pValue, &DataPtr, &DataLength); +#else + PyString_AsStringAndSize (pValue, &DataPtr, &DataLength); +#endif + if (dbug) fprintf (stdout, "%d |%s|\n", DataLength, DataPtr); + /* if the deprecated WSGI write() method is being used */ if (WsgiRunApp && !WsgiHeadersSent) WsgiSendHeaders (); @@ -1739,8 +1942,6 @@ /* if the deprecated WSGI write() method is being used */ if (WsgiRunApp && !WsgiHeadersSent) WsgiSendHeaders (); - PyString_AsStringAndSize (pValue, &DataPtr, &DataLength); - AppOutputCount += DataLength; fwrite (DataPtr, DataLength, 1, stdout); @@ -1776,10 +1977,10 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "SetupOsEnvCgiVar() %d\n", InitEnv); + if (dbug) fprintf (stdout, "SetupOsEnvCgiVar() %d\n", InitEnv); if (!HeadCvtGet) HeadCvtGet = (TrnLnm ("PYRTE_HEAD_CVT_GET", NULL) != NULL); if (InitEnv) { @@ -1780,8 +1981,10 @@ if (!HeadCvtGet) HeadCvtGet = (TrnLnm ("PYRTE_HEAD_CVT_GET", NULL) != NULL); if (InitEnv) { + /* borrowed reference */ + pOsEnvironDict = PyDict_GetItemString (pOsDict, "environ"); if (!pOsEnvironDict) { @@ -1786,18 +1989,5 @@ if (!pOsEnvironDict) { - /* borrowed reference */ - pOsEnvironDict = PyDict_GetItemString (pOsDict, "environ"); - if (!pOsEnvironDict) - { - ReportError (__LINE__, 0, 1, ErrorCgiVarEnv); - return (0); - } - Py_INCREF (pOsEnvironDict); - DEBUGPYOBJ("pOsEnvironDict",pOsEnvironDict) - } - - if (!pEnvironDict) - { - /* new reference */ - pEnvironDict = PyObject_CallMethod(pOsEnvironDict, "copy", "()"); + ReportError (__LINE__, 0, 1, ErrorCgiVarEnv); + return (0); } @@ -1803,29 +1993,9 @@ } - else - { - /* Restore missing environ variables */ - pKeys = PyMapping_Keys(pOsEnvironDict); - pKenLen = PyList_Size(pKeys); - for (int i = 0; i < pKenLen; ++i) - { - pKey = PyList_GetItem(pKeys, i); - if (! PyMapping_HasKey(pEnvironDict, pKey)) - { - char *key; - key = PyString_AsString(pKey); - pValue = PyMapping_GetItemString(pOsEnvironDict, key); - retval = PyMapping_SetItemString(pEnvironDict, key, pValue); - if (retval == -1) - { - ReportError (__LINE__, 0, 1, ErrorCgiVarEnv); - return (0); - } - Py_DECREF(pValue); - } - } - Py_DECREF(pKeys); - } + DEBUGPYOBJ("pOsEnvironDict",pOsEnvironDict) + + /* new reference */ + pEnvironDict = PyObject_CallMethod(pOsEnvironDict, "copy", "()"); DEBUGPYOBJ("pEnvironDict",pEnvironDict) while (cptr = CgiVar ("*")) { @@ -1828,8 +1998,8 @@ DEBUGPYOBJ("pEnvironDict",pEnvironDict) while (cptr = CgiVar ("*")) { - /** if (Debug) fprintf (stdout, "|%s|\n", cptr); **/ + /** if (dbug) fprintf (stdout, "|%s|\n", cptr); **/ if ((toupper(*cptr) == 'F' && !strncmp (cptr, "FORM_", 5)) || @@ -1852,4 +2022,7 @@ for (sptr = cptr; *sptr && *sptr != '='; sptr++); if (!*sptr) continue; *sptr = '\0'; +#if PY_MAJOR_VERSION >= 3 + pValue = PyUnicode_FromString (sptr+1); +#else pValue = PyString_FromString (sptr+1); @@ -1855,4 +2028,5 @@ pValue = PyString_FromString (sptr+1); +#endif retval = PyMapping_SetItemString (pEnvironDict, cptr, pValue); if (retval == -1) { @@ -1870,6 +2044,6 @@ ReportError (__LINE__, 0, 1, ErrorCgiVarEnv); return (0); } - if (Debug) fprintf (stdout, "PyMapping_SetItemString() %d\n", retval); + if (dbug) fprintf (stdout, "PyMapping_SetItemString() %d\n", retval); } else @@ -1874,11 +2048,6 @@ } else - { - DEBUGPYOBJ("1pEnvironDict",pEnvironDict) - pValue = PyObject_CallMethod(pEnvironDict, "clear", "()"); - Py_DECREF (pValue); - DEBUGPYOBJ("2pEnvironDict",pEnvironDict) - } + Py_DECREF (pEnvironDict); return (1); } @@ -1904,7 +2073,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethGetVar()\n"); + if (dbug) fprintf (stdout, "RtePyMethGetVar()\n"); if (!PyArg_ParseTuple (args, "S|O", &pVarName, &pVarDefault)) return (NULL); @@ -1908,4 +2077,7 @@ if (!PyArg_ParseTuple (args, "S|O", &pVarName, &pVarDefault)) return (NULL); +#if PY_MAJOR_VERSION >= 3 + if (!(cptr = PyBytes_AsString (pVarName))) return (NULL); +#else if (!(cptr = PyString_AsString (pVarName))) return (NULL); @@ -1911,4 +2083,5 @@ if (!(cptr = PyString_AsString (pVarName))) return (NULL); +#endif if (!(sptr = CgiVar (cptr))) { if (pVarDefault) return (pVarDefault); @@ -1931,7 +2104,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethUsageCode()\n"); + if (dbug) fprintf (stdout, "RtePyMethUsageCode()\n"); return (Py_BuildValue ("i", CodeCachePtr->CodeUsageCount)); } @@ -1948,7 +2121,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethUsageInterpreter()\n"); + if (dbug) fprintf (stdout, "RtePyMethUsageInterpreter()\n"); return (Py_BuildValue ("i", CodeCachePtr->InterpreterUsageCount)); } @@ -1965,7 +2138,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethUsageRte()\n"); + if (dbug) fprintf (stdout, "RtePyMethUsageRte()\n"); return (Py_BuildValue ("i", UsageCount)); } @@ -1982,7 +2155,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethStatTimer()\n"); + if (dbug) fprintf (stdout, "RtePyMethStatTimer()\n"); return (Py_BuildValue ("s", StatTimer (TRUE))); } @@ -2025,7 +2198,7 @@ return (NULL); } - if (Debug) fprintf (stdout, "RtePyMethCgiPlusBegin()\n"); + if (dbug) fprintf (stdout, "RtePyMethCgiPlusBegin()\n"); if (WsgiRunApp) { @@ -2087,16 +2260,7 @@ CgiPlusPythonEnd = 1; AppOutputCount = 0; - if (!(Debug = GlobalDebug)) - if (cptr = TrnLnm ("PYRTE$DBUG", NULL)) - if (sptr = CgiVar ("SCRIPT_NAME")) - if (strstr (sptr, cptr)) - Debug = 1; - if (Debug) - { - fputs ("Content-Type: text/plain\n\n", stdout); - fflush (stdout); - } + DbugCheck(); RteScriptParam (); @@ -2135,7 +2299,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethCgiPlusEnd()\n"); + if (dbug) fprintf (stdout, "RtePyMethCgiPlusEnd()\n"); if (!IsCgiPlusScript) { @@ -2167,6 +2331,111 @@ /*****************************************************************************/ /* +Full CGI callout including response as available. +*/ + +static PyObject* RtePyMethCgiCallout +( +PyObject *self, +PyObject *args +) +{ + int retval; + char *sptr; + char buf [1024]; + PyObject* pReturn; + + if (!PyArg_ParseTuple (args, "s", &sptr)) return (NULL); + + fflush(stdout); + fputs (CgiPlusEscPtr, stdout); + fflush(stdout); + fputs (sptr, stdout); + fflush(stdout); + + if (*sptr == '!' || *sptr == '#') + { + Py_INCREF (Py_None); + pReturn = Py_None; + } + else + { + /* with plain old CGI might not already be open */ + if (!CgiPlusInFp) + if (!(CgiPlusInFp = fopen (TrnLnm("CGIPLUSIN", NULL), "r"))) + exit (vaxc$errno); + + rewind (CgiPlusInFp); + retval = read (fileno(CgiPlusInFp), buf, sizeof(buf)); + if (retval < 0) + { + Py_INCREF (Py_None); + pReturn = Py_None; + } + else + { + /* excise the (CRTL) trailing newline */ + if (retval) retval--; +#if PY_MAJOR_VERSION >= 3 + pReturn = PyUnicode_FromStringAndSize (buf, retval); +#else + pReturn = PyString_FromStringAndSize (buf, retval); +#endif + } + } + + fputs (CgiPlusEotPtr, stdout); + fflush(stdout); + + return (pReturn); +} + +/*****************************************************************************/ +/* +Read a record directly from CGIPLUSIN. +Optional parameter specifies non-default (255 bytes) size of buffer. +*/ + +static PyObject* RtePyMethReadCgiPlusIn +( +PyObject *self, +PyObject *args +) +{ + int bsize, retval; + char *bptr; + PyObject* pReturn; + + bsize = 255; + if (!PyArg_ParseTuple(args, "|i", &bsize)) return (NULL); + bptr = calloc (1, bsize+32); + + rewind (CgiPlusInFp); + retval = read (fileno(CgiPlusInFp), bptr, bsize); + + if (retval < 0) + { + Py_INCREF (Py_None); + pReturn = Py_None; + } + else + { + /* excise the (CRTL) trailing newline */ + if (retval) retval--; +#if PY_MAJOR_VERSION >= 3 + pReturn = PyUnicode_FromStringAndSize (bptr, retval); +#else + pReturn = PyString_FromStringAndSize (bptr, retval); +#endif + } + + free (bptr); + + return (pReturn); +} + +/*****************************************************************************/ +/* Set whether the Python interpreter being used is disposed of at the end of the current request (0 or False) or resued for the next request (1 or True). */ @@ -2181,7 +2450,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethReuseInterpreter()\n"); + if (dbug) fprintf (stdout, "RtePyMethReuseInterpreter()\n"); if (!PyArg_ParseTuple (args, "i", &ReuseInterpreter)) return (NULL); Py_INCREF(Py_None); @@ -2202,9 +2471,9 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethRteId()\n"); - - sprintf (RteIdBuf, "%s, %s", SOFTWAREID, BUILD_DATETIME); + if (dbug) fprintf (stdout, "RtePyMethRteId()\n"); + + sprintf (RteIdBuf, "%s, %s", SoftwareId, BUILD_DATETIME); return (Py_BuildValue ("s", RteIdBuf)); } @@ -2230,7 +2499,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RtePyMethRteCacheEntry()\n"); + if (dbug) fprintf (stdout, "RtePyMethRteCacheEntry()\n"); if (!TrnLnm ("PYRTE_CACHE_ENTRY", NULL)) { @@ -2288,7 +2557,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "WsgiRun()\n"); + if (dbug) fprintf (stdout, "WsgiRun()\n"); WsgiRunApp = 1; @@ -2351,7 +2620,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "WsgiStartResponse()\n"); + if (dbug) fprintf (stdout, "WsgiStartResponse()\n"); if (!WsgiRunApp) { @@ -2431,9 +2700,9 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "WsgiSendResponse() 0x%08.08x\n", pResponse); + if (dbug) fprintf (stdout, "WsgiSendResponse() 0x%08.08x\n", pResponse); if (!WsgiRunApp || !pResponse) return (1); DEBUGPYOBJ("pResponse",pResponse) @@ -2435,6 +2704,9 @@ if (!WsgiRunApp || !pResponse) return (1); DEBUGPYOBJ("pResponse",pResponse) +#if PY_MAJOR_VERSION >= 3 + if (PyBytes_Check (pResponse)) +#else if (PyString_Check (pResponse)) @@ -2440,2 +2712,3 @@ if (PyString_Check (pResponse)) +#endif { @@ -2441,2 +2714,5 @@ { +#if PY_MAJOR_VERSION >= 3 + PyBytes_AsStringAndSize (pResponse, &DataPtr, &DataLength); +#else PyString_AsStringAndSize (pResponse, &DataPtr, &DataLength); @@ -2442,4 +2718,6 @@ PyString_AsStringAndSize (pResponse, &DataPtr, &DataLength); +#endif + if (dbug) fprintf (stdout, "%d |%s|\n", DataLength, DataPtr); AppOutputCount += DataLength; fwrite (DataPtr, DataLength, 1, stdout); return (1); @@ -2451,4 +2729,7 @@ while (pItem = PyIter_Next(pIter)) { if (!WsgiHeadersSent) WsgiSendHeaders (); +#if PY_MAJOR_VERSION >= 3 + if (PyBytes_Check (pItem)) +#else if (PyString_Check (pItem)) @@ -2454,2 +2735,6 @@ if (PyString_Check (pItem)) +#endif +#if PY_MAJOR_VERSION >= 3 + if (!PyBytes_AsStringAndSize (pItem, &DataPtr, &DataLength)) +#else if (!PyString_AsStringAndSize (pItem, &DataPtr, &DataLength)) @@ -2455,3 +2740,4 @@ if (!PyString_AsStringAndSize (pItem, &DataPtr, &DataLength)) +#endif if (DataPtr && DataLength) { @@ -2456,6 +2742,6 @@ if (DataPtr && DataLength) { - /** if (Debug) fprintf (stdout, "pIter()\n"); **/ + /** if (dbug) fprintf (stdout, "pIter()\n"); **/ AppOutputCount += DataLength; fwrite (DataPtr, DataLength, 1, stdout); if (!WsgiForceBuffering) fflush (stdout); @@ -2490,9 +2776,9 @@ /* begin */ /*********/ - if (Debug) + if (dbug) fprintf (stdout, "WsgiSendHeaders() 0x%08.08x 0x%08.08x\n", pWsgiStatus, pWsgiHeaders); if (!pWsgiHeaders || !pWsgiStatus) return (0); @@ -2494,6 +2780,9 @@ fprintf (stdout, "WsgiSendHeaders() 0x%08.08x 0x%08.08x\n", pWsgiStatus, pWsgiHeaders); if (!pWsgiHeaders || !pWsgiStatus) return (0); +#if PY_MAJOR_VERSION >= 3 + if (!PyBytes_Check (pWsgiStatus)) +#else if (!PyString_Check (pWsgiStatus)) @@ -2499,7 +2788,8 @@ if (!PyString_Check (pWsgiStatus)) +#endif { ReportError (__LINE__, 0, 1, NULL); return (0); } WsgiHeadersSent = 1; @@ -2500,7 +2790,10 @@ { ReportError (__LINE__, 0, 1, NULL); return (0); } WsgiHeadersSent = 1; +#if PY_MAJOR_VERSION >= 3 + StatusPtr = PyBytes_AsString (pWsgiStatus); +#else StatusPtr = PyString_AsString (pWsgiStatus); @@ -2506,4 +2799,5 @@ StatusPtr = PyString_AsString (pWsgiStatus); +#endif StatusCode = atoi(StatusPtr); if (!StatusCode || strlen(StatusPtr) < 5) return (0); StatusPtr += 4; @@ -2549,7 +2843,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "WsgiOsEnvVar()\n"); + if (dbug) fprintf (stdout, "WsgiOsEnvVar()\n"); pValue = Py_BuildValue ("(ii)", 1, 0); retval = PyMapping_SetItemString (pEnvironDict, "wsgi.version", pValue); @@ -2553,8 +2847,8 @@ pValue = Py_BuildValue ("(ii)", 1, 0); retval = PyMapping_SetItemString (pEnvironDict, "wsgi.version", pValue); - if (Debug) fprintf (stdout, "retval: %d\n", retval); + if (dbug) fprintf (stdout, "retval: %d\n", retval); Py_DECREF(pValue); cptr = CgiVar ("REQUEST_SCHEME"); if (!*cptr || !strcmp (cptr, "http:")) @@ -2557,5 +2851,8 @@ Py_DECREF(pValue); cptr = CgiVar ("REQUEST_SCHEME"); if (!*cptr || !strcmp (cptr, "http:")) +#if PY_MAJOR_VERSION >= 3 + pValue = PyUnicode_FromString ("http"); +#else pValue = PyString_FromString ("http"); @@ -2561,2 +2858,3 @@ pValue = PyString_FromString ("http"); +#endif else @@ -2562,2 +2860,5 @@ else +#if PY_MAJOR_VERSION >= 3 + pValue = PyUnicode_FromString ("https"); +#else pValue = PyString_FromString ("https"); @@ -2563,4 +2864,5 @@ pValue = PyString_FromString ("https"); +#endif PyMapping_SetItemString (pEnvironDict, "wsgi.url_scheme", pValue); Py_DECREF(pValue); @@ -2602,7 +2904,7 @@ /*****************************************************************************/ /* -Jean-Fran�ois Pi�ronne's original '_wasd' module functions (massaged just a +Jean-Francois Pieronne's original '_wasd' module functions (massaged just a little :-) */ @@ -2618,4 +2920,7 @@ PyObject *args ) { +#if PY_MAJOR_VERSION >= 3 + if (!PyArg_ParseTuple (args, "")) return (NULL); +#else if (!PyArg_NoArgs(args)) return (NULL); @@ -2621,3 +2926,4 @@ if (!PyArg_NoArgs(args)) return (NULL); +#endif if (IsCgiPlusScript) @@ -2622,3 +2928,6 @@ if (IsCgiPlusScript) +#if PY_MAJOR_VERSION >= 3 + return (PyObject *)PyLong_FromLong(1L); +#else return (PyObject *)PyInt_FromLong(1L); @@ -2624,4 +2933,5 @@ return (PyObject *)PyInt_FromLong(1L); +#endif else { Py_INCREF(Py_None); @@ -2635,4 +2945,7 @@ PyObject *args ) { +#if PY_MAJOR_VERSION >= 3 + if (!PyArg_ParseTuple (args, "")) return (NULL); +#else if (!PyArg_NoArgs(args)) return (NULL); @@ -2638,4 +2951,5 @@ if (!PyArg_NoArgs(args)) return (NULL); +#endif if (IsCgiPlusScript) { @@ -2669,4 +2983,7 @@ res = Py_None; } else +#if PY_MAJOR_VERSION >= 3 + res = PyBytes_FromString (buffer); +#else res = PyString_FromString(buffer); @@ -2672,4 +2989,5 @@ res = PyString_FromString(buffer); +#endif return (res); } @@ -2704,4 +3022,7 @@ BodyLength = cptr - BodyPtr; if (BodyLength == 0) +#if PY_MAJOR_VERSION >= 3 + pBody = PyUnicode_FromString(""); +#else pBody = PyString_FromString(""); @@ -2707,3 +3028,4 @@ pBody = PyString_FromString(""); +#endif else if (BodyLength == strlen (BodyPtr)) @@ -2708,3 +3030,6 @@ else if (BodyLength == strlen (BodyPtr)) +#if PY_MAJOR_VERSION >= 3 + pBody = PyUnicode_FromString (BodyPtr); +#else pBody = PyString_FromString (BodyPtr); @@ -2710,2 +3035,3 @@ pBody = PyString_FromString (BodyPtr); +#endif else @@ -2711,2 +3037,5 @@ else +#if PY_MAJOR_VERSION >= 3 + pBody = PyUnicode_FromStringAndSize (BodyPtr, BodyLength); +#else pBody = PyString_FromStringAndSize (BodyPtr, BodyLength); @@ -2712,4 +3041,5 @@ pBody = PyString_FromStringAndSize (BodyPtr, BodyLength); +#endif if (BodyPtr) free (BodyPtr); @@ -2729,9 +3059,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "RteScriptParam()\n"); - - NoStreamMode = HeadCvtGet = 0; + if (dbug) fprintf (stdout, "RteScriptParam()\n"); cptr = CgiVar ("PYRTE"); if (!cptr) return; @@ -2735,6 +3063,7 @@ cptr = CgiVar ("PYRTE"); if (!cptr) return; + NoStreamMode = HeadCvtGet = 0; while (*cptr) { while (*cptr && *cptr != '/') cptr++; @@ -2755,10 +3084,10 @@ HeadCvtGet = 1; else if (!strncasecmp (cptr, "/dbug", 5)) - Debug = 1; + dbug = 1; cptr++; } } /*****************************************************************************/ /* @@ -2759,9 +3088,157 @@ cptr++; } } /*****************************************************************************/ /* +*/ + +void DbugCheck () +{ + char *cptr, *sptr; + + /*********/ + /* begin */ + /*********/ + + if (!GlobalDebug) + if (cptr = TrnLnm ("PYRTE$DBUG", NULL)) + if (!strchr (cptr, '*')) + if (sptr = CgiVar ("SCRIPT_NAME")) + if (!strstr (sptr, cptr)) + cptr = NULL; + + if ((dbug = GlobalDebug) || (dbug = (cptr != NULL))) + { + fprintf (stdout, +"Script-Control: X-record-mode\n\ +Content-Type: text/plain\n\ +\n\ +***** %s (%s) Python %s *****\n", + SoftwareId, BUILD_DATETIME, Py_GetVersion()); +fprintf (stdout, "+++++ %d %d\n",cptr,sptr); + fflush (stdout); + NoStreamMode = 1; + } + +} + +/****************************************************************************/ +/* +Read the file contents specified by 'FileName' into memory, set the pointer +at 'FileTextPtr' to the contents and the file size at 'FileSizePtr'. Returns a +VMS status value that should be checked. +*/ + +int ReadFileIntoMemory +( +char *FileName, +char **FileTextPtr, +int *FileSizePtr +) +{ + int status, + Bytes, + BytesRemaining, + BufferCount; + char *cptr, *sptr, + *BufferPtr, + *LinePtr; + FILE *FilePtr; + stat_t StatBuffer; + + /*********/ + /* begin */ + /*********/ + + if (dbug) fprintf (stdout, "ReadFileIntoMemory() |%s|\n", FileName); + + if (FileTextPtr != NULL) *FileTextPtr = NULL; + if (FileSizePtr != NULL) *FileSizePtr = 0; + + if (stat (FileName, &StatBuffer) < 0) + { + status = vaxc$errno; + if (dbug) fprintf (stdout, "stat() %%X%08.08X\n", status); + return (status); + } + + if (StatBuffer.st_fab_rfm == FAB$C_VAR || + StatBuffer.st_fab_rfm == FAB$C_VFC) + FilePtr = fopen (FileName, "r", "shr=put"); + else + FilePtr = fopen (FileName, "r", "shr=put", "ctx=bin"); + if (FilePtr == NULL) + { + status = vaxc$errno; + if (dbug) fprintf (stdout, "fopen() %%X%08.08X\n", status); + return (status); + } + + Bytes = StatBuffer.st_size; + if (dbug) fprintf (stdout, "%d bytes\n", Bytes); + + /* a little margin for error ;^) */ + BufferPtr = calloc (1, Bytes+32); + if (!BufferPtr) return (vaxc$errno); + + BufferCount = 0; + + if (StatBuffer.st_fab_rfm == FAB$C_VAR || + StatBuffer.st_fab_rfm == FAB$C_VFC) + { + BytesRemaining = Bytes; + LinePtr = BufferPtr; + while (fgets (LinePtr, BytesRemaining, FilePtr) != NULL) + { + /** if (dbug) fprintf (stdout, "|%s|\n", LinePtr); **/ + if (!*LinePtr) break; + for (cptr = LinePtr; *cptr; cptr++); + BufferCount += cptr - LinePtr; + BytesRemaining -= cptr - LinePtr; + LinePtr = cptr; + } + } + else + { + status = fread (BufferPtr, Bytes, 1, FilePtr); + if (status == 1) BufferCount = Bytes; + } + + fclose (FilePtr); + + if (StatBuffer.st_fab_rfm == FAB$C_STMLF) + { + /* text file, newlines only (check first 512 characters and quit) */ + for (cptr = BufferPtr; *cptr && cptr < BufferPtr+512; cptr++) + if (*(USHORTPTR)cptr == '\r\n') + { + sptr = cptr; + while (*cptr) + { + if (*(USHORTPTR)cptr == '\r\n') cptr++; + *sptr++ = *cptr++; + } + *sptr = '\0'; + BufferCount = sptr - BufferPtr; + break; + } + } + + if (dbug) + if (BufferCount < 50000) + fprintf (stdout, "%d |%s|\n", BufferCount, BufferPtr); + else + fprintf (stdout, "%d || TOO LARGE!\n", BufferCount); + + if (FileTextPtr != NULL) *FileTextPtr = BufferPtr; + if (FileSizePtr != NULL) *FileSizePtr = BufferCount; + + return (SS$_NORMAL); +} + +/*****************************************************************************/ +/* Self-contained functionality. Designed to be called if the script is not found. If found the script needs to instantiate whatever resources it is proctored for and then return an HTTP 204 to the server. If not found then @@ -2783,7 +3260,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ProctorDetect()\n"); + if (dbug) fprintf (stdout, "ProctorDetect()\n"); if (DetectCount++) return (0); @@ -2832,9 +3309,9 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "ReportError() %d\n", SourceCodeLine); + if (dbug) fprintf (stdout, "ReportError() %d\n", SourceCodeLine); CgiTbLoaded = 0; if (Py_IsInitialized()) { /* assume that if it's loaded it's also enabled */ @@ -2836,12 +3313,12 @@ CgiTbLoaded = 0; if (Py_IsInitialized()) { /* assume that if it's loaded it's also enabled */ - pObject = PyString_FromString ("cgitb"); + pObject = PyUnicode_FromString ("cgitb"); if (pObject) { if (pMainDict && PyDict_Contains (pMainDict, pObject) == 1) CgiTbLoaded = 1; Py_DECREF (pObject); } @@ -2842,9 +3319,21 @@ if (pObject) { if (pMainDict && PyDict_Contains (pMainDict, pObject) == 1) CgiTbLoaded = 1; Py_DECREF (pObject); } + if (dbug) fprintf (stdout, "pObject:%u CgiTbLoaded:%d\n", + pObject, CgiTbLoaded); + if (CgiTbLoaded) + { + if (PythonErrorPrint) + { + PyErr_Print(); + fprintf (stdout, "<!-- PyRTE %s LINE:%d -->\n", + SoftwareId, SourceCodeLine); + return; + } + } } va_count (argcnt); @@ -2860,7 +3349,7 @@ FaoStringDsc.dsc$w_length = strlen(FaoString); status = sys$faol (&FaoStringDsc, &ShortLen, &BufferDsc, (unsigned long*)&FaoVector); - if (Debug) fprintf (stdout, "sys$fao() %%X%08.08X\n", status); + if (dbug) fprintf (stdout, "sys$fao() %%X%08.08X\n", status); if (status & 1) Buffer[ShortLen] = '\0'; else @@ -2871,7 +3360,8 @@ if (AppOutputCount) { - fprintf (stdout, "\n<!-- PyRTE LINE:%d -->\n", SourceCodeLine); + fprintf (stdout, "\n<!-- PyRTE %s LINE:%d -->\n", + SoftwareId, SourceCodeLine); if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus); if (!CgiTbLoaded) fputs ("<pre>\n----------\n", stdout); PyErr_Print(); @@ -2881,14 +3371,4 @@ fputs ("Status: 502\nContent-Type: text/html\n\n", stdout); - if (CgiTbLoaded) - { - fputs ("<html>\n", stdout); - fprintf (stdout, "<!-- PyRTE LINE:%d -->\n", SourceCodeLine); - if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus); - PyErr_Print(); - fputs ("</html>\n", stdout); - return; - } - fprintf (stdout, @@ -2894,15 +3374,16 @@ fprintf (stdout, -"<HTML>\n\ -<HEAD>\n\ -<META NAME=\"generator\" CONTENT=\"%s\">\n\ -<META NAME=\"line\" CONTENT=\"%d\">\n\ -<TITLE>ERROR 502 Bad Gateway</TITLE>\n\ -</HEAD>\n\ -<BODY>\n\ -<FONT SIZE=\"+1\"><B>ERROR 502</B> - \ -External agent did not respond (or not acceptably)</FONT>\n", - SOFTWAREID, +"<!DOCTYPE html>\n\ +<html>\n\ +<head>\n\ +<meta name=\"generator\" content=\"%s\">\n\ +<meta name=\"line\" content=\"%d\">\n\ +<title>ERROR 502 Bad Gateway</title>\n\ +</head>\n\ +<body>\n\ +<font size=\"+1\"><b>ERROR 502</b> - \ +External agent did not respond (or not acceptably)</font>\n", + SoftwareId, SourceCodeLine); if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus); @@ -2905,8 +3386,8 @@ SourceCodeLine); if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus); - if (Buffer[0]) fprintf (stdout, "<P>%s", Buffer); + if (Buffer[0]) fprintf (stdout, "<p>%s", Buffer); if (PythonErrorPrint) { @@ -2910,5 +3391,5 @@ if (PythonErrorPrint) { - fprintf (stdout, "<P><PRE>"); + fprintf (stdout, "<p><pre>"); PyErr_Print(); @@ -2914,7 +3395,7 @@ PyErr_Print(); - fprintf (stdout, "</PRE>\n"); + fprintf (stdout, "</pre>\n"); } cptr = CgiVar ("SERVER_SIGNATURE"); fprintf (stdout, @@ -2916,7 +3397,7 @@ } cptr = CgiVar ("SERVER_SIGNATURE"); fprintf (stdout, -"<P><HR WIDTH=85%% ALIGN=left SIZE=2 NOSHADE>\n\ +"<p><hr width=85%% align=\"left\" size=\"2\" noshade>\n\ %s%s\ @@ -2922,6 +3403,6 @@ %s%s\ -</BODY>\n\ -</HTML>\n", +</body>\n\ +</html>\n", cptr ? cptr : "", cptr ? "\n" : ""); } @@ -2954,7 +3435,6 @@ static char *EmptyScriptNamePtr = NULL, *NextVarNamePtr; static char StructBuffer [CGIVAR_STRUCT_SIZE]; - static FILE *CgiPlusIn; int status; int Length; @@ -2964,7 +3444,7 @@ /* begin */ /*********/ - if (Debug && VarName && VarName[0] && VarName[0] != '*') + if (dbug && VarName && VarName[0] && VarName[0] != '*') fprintf (stdout, "CgiVar() |%s|\n", !VarName ? "NULL" : VarName); if (!VarName || !VarName[0]) @@ -3053,10 +3533,10 @@ } /* the CGIPLUSIN stream can be left open */ - if (!CgiPlusIn) - if (!(CgiPlusIn = fopen (TrnLnm("CGIPLUSIN", NULL), "r"))) + if (!CgiPlusInFp) + if (!(CgiPlusInFp = fopen (TrnLnm("CGIPLUSIN", NULL), "r"))) exit (vaxc$errno); /* get the starting record (the essentially discardable one) */ for (;;) { @@ -3058,9 +3538,9 @@ exit (vaxc$errno); /* get the starting record (the essentially discardable one) */ for (;;) { - cptr = fgets (StructBuffer, sizeof(StructBuffer), CgiPlusIn); + cptr = fgets (StructBuffer, sizeof(StructBuffer), CgiPlusInFp); if (!cptr) exit (vaxc$errno); /* if the starting sentinal is detected then break */ if (*(unsigned short*)cptr == '!\0' || @@ -3082,7 +3562,7 @@ if (StructLength <= 0 || StructLength > sizeof(StructBuffer)) exit (SS$_BUGCHECK); - if (!fread (StructBuffer, 1, StructLength, CgiPlusIn)) + if (!fread (StructBuffer, 1, StructLength, CgiPlusInFp)) exit (vaxc$errno); } else @@ -3093,7 +3573,7 @@ /* reconstructs the original 'struct'ure from the records */ sptr = (bptr = StructBuffer) + sizeof(StructBuffer); - while (fgets (bptr+SOUS, sptr-(bptr+SOUS), CgiPlusIn)) + while (fgets (bptr+SOUS, sptr-(bptr+SOUS), CgiPlusInFp)) { /* first empty record (line) terminates variables */ if (bptr[SOUS] == '\n') break; @@ -3211,7 +3691,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "CgiVarDclSymbol()\n"); + if (dbug) fprintf (stdout, "CgiVarDclSymbol()\n"); if (VarName[0] == '*') cptr = SymbolNames[SymbolIndex++]; @@ -3269,7 +3749,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "EmptyScriptName() %s %s\n", VarName, VarValue); + if (dbug) fprintf (stdout, "EmptyScriptName() %s %s\n", VarName, VarValue); while (*cptr && *sptr && *sptr != '=') { @@ -3324,7 +3804,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "MetricsReport()\n"); + if (dbug) fprintf (stdout, "MetricsReport()\n"); if (!CodeMetricEnabled) return (0); @@ -3336,4 +3816,7 @@ pValue = PyObject_CallFunction (pFunc, NULL); if (!pValue) return (0); +#if PY_MAJOR_VERSION >= 3 + strcpy (pyver, PyBytes_AsString (pValue)); +#else strcpy (pyver, PyString_AsString (pValue)); @@ -3339,4 +3822,5 @@ strcpy (pyver, PyString_AsString (pValue)); +#endif Py_DECREF(pPlatMod); Py_DECREF(pFunc); @@ -3346,12 +3830,19 @@ "Status: 200\n\ Content-Type: text/html\n\ \n\ -<HTML>\n\ -<HEAD>\n\ -<TITLE>Metrics Report - %s (%s)</TITLE>\n\ -</HEAD>\n\ -<STYLE TYPE=\"text/css\">\n\ +<!DOCTYPE html>\n\ +<html>\n\ +<head>\n\ +<title>Metrics Report - %s (%s)</title>\n\ +</head>\n\ +<style type=\"text/css\">\n\ +body {\n\ + font-family:arial,helvetica,sans-serif;\n\ + font-size:11pt;\n\ + background-color:#ffffff; color:#000000;\n\ + margin:1.5em; padding:0;\n\ +}\n\ th { margin:0; padding:0 0 2px 1em; white-space:nowrap; \ text-decoration:underline; }\n\ td { margin:0; padding:0 0 2px 1em; white-space:nowrap; }\n\ pre { font-size:80%%; line-height:90%%; }\n\ @@ -3354,18 +3845,19 @@ th { margin:0; padding:0 0 2px 1em; white-space:nowrap; \ text-decoration:underline; }\n\ td { margin:0; padding:0 0 2px 1em; white-space:nowrap; }\n\ pre { font-size:80%%; line-height:90%%; }\n\ -</STYLE>\n\ -<BODY>\n\ -<FONT SIZE=\"+1\"><B>Metrics Report - %s \ - - Python %s</B></FONT>\n\ -<P>PID <TT>%08.08X</TT> Usage Count: %u\n\ -<P>%d Item(s)\n", - SOFTWAREID, BUILD_DATETIME, - SOFTWAREID, pyver, +</style>\n\ +<body>\n\ +<span style=\"font-size:120%%;font-weight:bold;\">\ +Metrics Report - %s - Python %s\ +</span>\n\ +<p>PID <tt>%08.08X</tt> Usage Count: %u\n\ +<p>%d Item(s)\n", + SoftwareId, BUILD_DATETIME, + SoftwareId, pyver, ProcessPid, UsageCount, CodeCacheCount); if (CodeCacheCount) { fputs ( @@ -3366,26 +3858,26 @@ ProcessPid, UsageCount, CodeCacheCount); if (CodeCacheCount) { fputs ( -"<P><TABLE BORDER=\"0\">\n\ -<TR>\ -<TH></TH>\n\ -<TH ALIGN=\"right\">Usage</TH>\ -<TH ALIGN=\"right\">Size</TH>\ -<TH ALIGN=\"right\">Number</TH>\ -<TH ALIGN=\"left\">Last Used</TH>\ -<TH ALIGN=\"right\">Duration</TH>\ -<TH ALIGN=\"right\">CPU</TH>\ -<TH ALIGN=\"right\">BIO</TH>\ -<TH ALIGN=\"right\">DIO</TH>\ -<TH ALIGN=\"right\">FLT</TH>\ -<TH ALIGN=\"right\">PGS</TH>\ -<TH ALIGN=\"left\">Modified</TH>\ -<TH ALIGN=\"left\">Script File</TH>\ -<TH ALIGN=\"left\">Byte-Code File</TH>\ -</TR>\n", +"<p><table border=\"0\">\n\ +<tr>\ +<th></th>\n\ +<th align=\"right\">Usage</th>\ +<th align=\"right\">Size</th>\ +<th align=\"right\">Number</th>\ +<th align=\"left\">Last Used</th>\ +<th align=\"right\">Duration</th>\ +<th align=\"right\">CPU</th>\ +<th align=\"right\">BIO</th>\ +<th align=\"right\">DIO</th>\ +<th align=\"right\">FLT</th>\ +<th align=\"right\">PGS</th>\ +<th align=\"left\">Modified</th>\ +<th align=\"left\">Script File</th>\ +<th align=\"left\">Byte-Code File</th>\ +</tr>\n", stdout); /* lib$cvts..() is not available before VMS V8.2 so work around */ @@ -3398,14 +3890,14 @@ if (!(status & 1)) exit (status); fprintf (stdout, -"<TR><TD COLSPAN=\"4\"></TD>\ -<TD ALIGN=\"right\"><I>RTE cummulative</I></TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD></TR>\n", +"<tr><td colspan=\"4\"></td>\ +<td align=\"right\"><i>RTE cummulative</i></td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td></tr>\n", tfloat, (float)(RteJpiCpuTim)/100.0, RteJpiBufIO, @@ -3442,21 +3934,21 @@ bcsize = -1; fprintf (stdout, -"<TR><TD ALIGN=\"right\">%d.</TD>\ -<TD ALIGN=\"right\">%d</TD>\ -<TD ALIGN=\"right\">%d</TD>\ -<TD ALIGN=\"right\"></TD>\ -<TD ALIGN=\"right\"><I>cummulative</I></TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD>%s</TD>\ -<TD><TT>%s</TT></TD>\ -<TD><TT>%s</TT></TD>\ -</TR>\n", +"<tr><td align=\"right\">%d.</td>\ +<td align=\"right\">%d</td>\ +<td align=\"right\">%d</td>\ +<td align=\"right\"></td>\ +<td align=\"right\"><i>cummulative</i></td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td>%s</td>\ +<td><tt>%s</tt></td>\ +<td><tt>%s</tt></td>\ +</tr>\n", idx + 1, ccptr->CodeUsageCount, bcsize, @@ -3488,16 +3980,16 @@ tsecs = decc$fix_time(&cmptr->StartBinTime[midx]); fprintf (stdout, -"<TR><TD COLSPAN=\"3\"></TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD>%s</TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%.4f</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD ALIGN=\"right\">%u</TD>\ -<TD COLSPAN=\"3\"><TT>%s</TT>%s</TD></TR>\n", +"<tr><td colspan=\"3\"></td>\ +<td align=\"right\">%u</td>\ +<td>%s</td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%.4f</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td align=\"right\">%u</td>\ +<td colspan=\"3\"><tt>%s</tt>%s</td></tr>\n", cmptr->UsageNumber[midx], my_ctime_r(&tsecs,lubuf), tfloat, @@ -3520,5 +4012,5 @@ /*** if (pValue) { - fputs("<TR><TD COLSPAN=\"3\"></TD><TD COLSPAN=\"5\"><TT>", stdout); + fputs("<tr><td colspan=\"3\"></td><td colspan=\"5\"><tt>", stdout); PyObject_Print ((PyObject*)CodeCache[idx].pByteCode, stdout, 0); @@ -3524,5 +4016,5 @@ PyObject_Print ((PyObject*)CodeCache[idx].pByteCode, stdout, 0); - fputs("</TT></TD></TR>\n", stdout); - - fputs("<TR><TD COLSPAN=\"3\"></TD><TD COLSPAN=\"5\"><TT>", stdout); + fputs("</tt></td></tr>\n", stdout); + + fputs("<tr><td colspan=\"3\"></td><td colspan=\"5\"><tt>", stdout); PyObject_Print (pValue, stdout, 0); @@ -3528,5 +4020,5 @@ PyObject_Print (pValue, stdout, 0); - fputs("</TT></TD></TR>\n", stdout); + fputs("</tt></td></tr>\n", stdout); Py_DECREF(pValue); } @@ -3536,9 +4028,9 @@ ***/ } - fputs ("</TABLE>\n<PRE>", stdout); + fputs ("</table>\n<pre>", stdout); /*** LibVmReport (NULL); ***/ @@ -3540,12 +4032,12 @@ /*** LibVmReport (NULL); ***/ - fputs ("</PRE>\n\ -<P><HR WIDTH=85%% ALIGN=left SIZE=2 NOSHADE>\n\ -</BODY>\n\ -</HTML>\n", stdout); + fputs ("</pre>\n\ +<p><hr width=\"85%%\" align=\"left\" size=\"2\" noshade>\n\ +</body>\n\ +</html>\n", stdout); fflush (stdout); fputs (CgiPlusEofPtr, stdout); @@ -3569,7 +4061,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "AddMetrics()\n"); + if (dbug) fprintf (stdout, "AddMetrics()\n"); if (!CodeMetricEnabled) return; if (ccptr->CodeMetricPtr) return; @@ -3622,7 +4114,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "CollectMetrics()\n"); + if (dbug) fprintf (stdout, "CollectMetrics()\n"); if (!CodeMetricEnabled) return; /* possible if metric reporting is enabled on an existing RTE */ @@ -3720,7 +4212,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "LibVmReport()\n"); + if (dbug) fprintf (stdout, "LibVmReport()\n"); if (StrDscPtr) { @@ -3840,7 +4332,7 @@ /* begin */ /*********/ - if (Debug) fprintf (stdout, "TrnLnm() |%s|\n", LogName); + if (dbug) fprintf (stdout, "TrnLnm() |%s|\n", LogName); LogNameDsc.dsc$a_pointer = LogName; LogNameDsc.dsc$w_length = strlen(LogName); @@ -3850,6 +4342,6 @@ cptr = LnmItems[0].buf_addr = StaticLogValue; status = sys$trnlnm (0, &LnmFileDevDsc, &LogNameDsc, 0, &LnmItems); - if (Debug) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status); + if (dbug) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status); if (!(status & 1)) { @@ -3854,7 +4346,7 @@ if (!(status & 1)) { - if (Debug) fprintf (stdout, "|(null)|\n"); + if (dbug) fprintf (stdout, "|(null)|\n"); return (NULL); } cptr[ShortLength] = '\0'; @@ -3857,8 +4349,8 @@ return (NULL); } cptr[ShortLength] = '\0'; - if (Debug) fprintf (stdout, "|%s|\n", cptr); + if (dbug) fprintf (stdout, "|%s|\n", cptr); return (cptr); }