/*****************************************************************************/ /* 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 Mark G.Daniel (mark.daniel@wasd.vsm.com.au) This software 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 2. 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 } /*****************************************************************************/