/*****************************************************************************/ /* CGIplus_cgivar.c Generic, SELF-CONTAINED FUNCTION to return the values of a CGI variable regardless of whether it is used in a standard CGI environment or a WASD CGIplus environment. Also automatically switches WASD V7.2 and later servers into 'struct' mode for significantly improved performance. To "force" the use of 'record' mode (perhaps for performance comparison purposes) assign a non-empty environment variable (symbol or logical) named CGIPLUS_VAR_RECORD. Call with 'VarName' empty ("") to synchronize CGIplus requests. This waits for a CGIplus variable stream, checks if it's in 'record' or 'struct' mode, reads the stream appropriately before returning ready to provide variables. DO NOT modify the character string returned by this function. Copy to other storage if this is necessary. The behaviour is indeterminate if the returned values are modified in any way! All CGIplus variables may be returned by making successive calls using a 'VarName' of "*" (often useful when debugging). CGIVAR_NONE is returned when variables exhausted. Also see the more extensive set of functions offered by [SRC.MISC]CGILIB.C Required standard library header files: stdlib.h, stdio.h, string.h Required function prototype: char* CgiVar (char*); COPYRIGHT --------- Copyright (C) 2001-2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY --------------- 01-APR-2001 MGD initial */ /*****************************************************************************/ char* CgiVar (char *VarName) { # ifndef CGIVAR_STRUCT_SIZE # define CGIVAR_STRUCT_SIZE 8192 # endif # ifndef CGIVAR_NONE # define CGIVAR_NONE NULL # endif # define SOUS sizeof(unsigned short) static int CalloutDone, StructLength; static char *CgiPlusVarRecordPtr, *IsCgiPlusPtr, *NextVarNamePtr; static char StructBuffer [CGIVAR_STRUCT_SIZE]; static FILE *CgiPlusIn; int Length; char *bptr, *cptr, *sptr; /*********/ /* begin */ /*********/ #ifdef DEBUGIT if (DEBUGIT) if (VarName != NULL && VarName[0]) fprintf (stdout, "CgiVar() |%s|\n", VarName == NULL ? "NULL" : VarName); #endif if (VarName == NULL || !VarName[0]) { /* initialize */ StructLength = 0; NextVarNamePtr = StructBuffer; if (VarName == NULL) return (CGIVAR_NONE); } /* detect the CGIplus environment (once) */ if (IsCgiPlusPtr == NULL) if ((IsCgiPlusPtr = getenv ("CGIPLUSEOF")) == NULL) IsCgiPlusPtr = ""; if (VarName[0]) { /***************************/ /* return a variable value */ /***************************/ if (!IsCgiPlusPtr[0]) { /* standard CGI environment */ if ((cptr = getenv (VarName)) == NULL) cptr = CGIVAR_NONE; #ifdef DEBUGIT if (DEBUGIT) fprintf (stdout, "CGI |%s|\n", cptr == NULL ? "NULL" : cptr); #endif return (cptr); } /* hmmm, not initialized */ if (!StructLength) return (CGIVAR_NONE); if (VarName[0] == '*') { /* return each CGIplus variable in successive calls */ if (!(Length = *(unsigned short*)NextVarNamePtr)) { NextVarNamePtr = StructBuffer; return (CGIVAR_NONE); } sptr = (NextVarNamePtr += SOUS); NextVarNamePtr += Length; return (sptr); } /* return a pointer to this CGIplus variable's value */ for (bptr = StructBuffer; Length = *(unsigned short*)bptr; bptr += Length) { sptr = (bptr += SOUS); for (cptr = VarName; *cptr && *sptr && *sptr != '='; cptr++, sptr++) if (toupper(*cptr) != toupper(*sptr)) break; /* if found return a pointer to the value */ if (!*cptr && *sptr == '=') { #ifdef DEBUGIT if (DEBUGIT) fprintf (stdout, "CGIplus |%s|\n", sptr+1); #endif return (sptr+1); } } /* not found */ #ifdef DEBUGIT if (DEBUGIT) fprintf (stdout, "CGIplus |%s|\n", CGIVAR_NONE == NULL ? "NULL" : CGIVAR_NONE); #endif return (CGIVAR_NONE); } /*****************************/ /* get the CGIplus variables */ /*****************************/ /* cannot "sync" in a non-CGIplus environment */ if (!VarName[0] && !IsCgiPlusPtr[0]) return (CGIVAR_NONE); /* the CGIPLUSIN stream can be left open */ if (CgiPlusIn == NULL) if ((CgiPlusIn = fopen (getenv("CGIPLUSIN"), "r")) == NULL) exit (vaxc$errno); /* get the starting record (the essentially discardable one) */ for (;;) { cptr = fgets (StructBuffer, sizeof(StructBuffer), CgiPlusIn); if (cptr == NULL) exit (vaxc$errno); /* if the starting sentinal is detected then break */ if (*(unsigned short*)cptr == '!\0' || *(unsigned short*)cptr == '!\n' || (*(unsigned short*)cptr == '!!' && isdigit(*(cptr+2)))) break; } #ifdef DEBUGIT /* MUST be done after reading the synchronizing starting record */ if (DEBUGIT) fprintf (stdout, "Content-Type: text/plain\n\n%s", StructBuffer); #endif /* detect the CGIplus "force" record-mode environment variable (once) */ if (CgiPlusVarRecordPtr == NULL) if ((CgiPlusVarRecordPtr = getenv ("CGIPLUS_VAR_RECORD")) == NULL) CgiPlusVarRecordPtr = ""; if (*(unsigned short*)cptr == '!!' && !CgiPlusVarRecordPtr[0]) { /********************/ /* CGIplus 'struct' */ /********************/ /* get the size of the binary structure */ StructLength = atoi(cptr+2); if (StructLength <= 0 || StructLength > sizeof(StructBuffer)) exit (SS$_BUGCHECK); if (!fread (StructBuffer, 1, StructLength, CgiPlusIn)) exit (vaxc$errno); } else { /*********************/ /* CGIplus 'records' */ /*********************/ /* reconstructs the original 'struct'ure from the records */ sptr = (bptr = StructBuffer) + sizeof(StructBuffer); while (fgets (bptr+SOUS, sptr-(bptr+SOUS), CgiPlusIn) != NULL) { /* first empty record (line) terminates variables */ if (bptr[SOUS] == '\n') break; /* note the location of the length word */ cptr = bptr; for (bptr += SOUS; *bptr && *bptr != '\n'; bptr++); if (*bptr != '\n') exit (SS$_BUGCHECK); *bptr++ = '\0'; if (bptr >= sptr) exit (SS$_BUGCHECK); /* update the length word */ *(unsigned short*)cptr = bptr - (cptr + SOUS); } if (bptr >= sptr) exit (SS$_BUGCHECK); /* terminate with a zero-length entry */ *(unsigned short*)bptr = 0; StructLength = (bptr + SOUS) - StructBuffer; } #ifdef DEBUGIT if (DEBUGIT) { fprintf (stdout, "%d\n", StructLength); for (bptr = StructBuffer; Length = *(unsigned short*)bptr; bptr += Length) fprintf (stdout, "|%s|\n", bptr += SOUS); } #endif if (!CalloutDone && !CgiPlusVarRecordPtr[0]) { /* provide the CGI callout to set CGIplus into 'struct' mode */ fflush (stdout); fputs (CgiPlusEscPtr, stdout); fflush (stdout); /* the leading '!' indicates we're not going to read the response */ fputs ("!CGIPLUS: struct", stdout); fflush (stdout); fputs (CgiPlusEotPtr, stdout); fflush (stdout); /* don't need to do this again (the '!!' tells us what mode) */ CalloutDone = 1; } return (CGIVAR_NONE); # undef SOUS } /*****************************************************************************/