4e4f5951fed8f4d923dcbbc313b3596c62374091 tdreszer Mon Jun 25 12:13:22 2012 -0700 Next batch of many checkins as dictated by Jim. Formatting space after if and limiting lines to 100 chars. Changes limited to lines last touched by tdreszer (git blame) so as not to ruin history. None of these changes should affect executables in any way. Only affect is to my sanity and Jim's. diff --git src/lib/cheapcgi.c src/lib/cheapcgi.c index dd05761..3b5ccc3 100644 --- src/lib/cheapcgi.c +++ src/lib/cheapcgi.c @@ -1,2142 +1,2110 @@ /* Routines for getting variables passed in from web page * forms via CGI. * * This file is copyright 2002 Jim Kent, but license is hereby * granted for all use - public, private or commercial. */ #include "common.h" #include "hash.h" #include "cheapcgi.h" #include "portable.h" #include "linefile.h" #include "errabort.h" #ifndef GBROWSE #include "mime.h" #endif /* GBROWSE */ #include /* These three variables hold the parsed version of cgi variables. */ static char *inputString = NULL; static unsigned long inputSize; static struct hash *inputHash = NULL; static struct cgiVar *inputList = NULL; static boolean haveCookiesHash = FALSE; static struct hash *cookieHash = NULL; static struct cgiVar *cookieList = NULL; /* should cheapcgi use temp files to store uploaded files */ static boolean doUseTempFile = FALSE; void dumpCookieList() /* Print out the cookie list. */ { struct cgiVar *v; for (v=cookieList; v != NULL; v = v->next) printf("%s=%s (%d)\n", v->name, v->val, v->saved); } void useTempFile() /* tell cheapcgi to use temp files */ { doUseTempFile = TRUE; } boolean cgiIsOnWeb() /* Return TRUE if looks like we're being run as a CGI. */ { return getenv("REQUEST_METHOD") != NULL; } char *cgiRequestMethod() /* Return CGI REQUEST_METHOD (such as 'GET/POST/PUT/DELETE/HEAD') */ { return getenv("REQUEST_METHOD"); } char *cgiRequestUri() /* Return CGI REQUEST_URI */ { return getenv("REQUEST_URI"); } char *cgiRequestContentLength() /* Return HTTP REQUEST CONTENT_LENGTH if available*/ { return getenv("CONTENT_LENGTH"); } char *cgiScriptName() /* Return name of script so libs can do context-sensitive stuff. */ { return getenv("SCRIPT_NAME"); } char *cgiServerName() /* Return name of server, better to use cgiServerNamePort() for actual URL construction */ { return getenv("SERVER_NAME"); } char *cgiServerPort() /* Return port number of server, default 80 if not found */ { char *port = getenv("SERVER_PORT"); if (port) return port; else return "80"; } char *cgiServerNamePort() /* Return name of server with port if different than 80 */ { char *port = cgiServerPort(); char *namePort = cgiServerName(); struct dyString *result = newDyString(256); if (namePort) { dyStringPrintf(result,"%s",namePort); if (differentString(port, "80")) dyStringPrintf(result,":%s",port); return dyStringCannibalize(&result); } else return NULL; } char *cgiRemoteAddr() /* Return IP address of client (or "unknown"). */ { static char *dunno = "unknown"; char *remoteAddr = getenv("REMOTE_ADDR"); if (remoteAddr == NULL) remoteAddr = dunno; return remoteAddr; } char *cgiUserAgent() /* Return remote user agent (HTTP_USER_AGENT) or NULL if remote user agent is not known */ { return getenv("HTTP_USER_AGENT"); } -enum browserType cgiClientBrowser(char **browserQualifier, enum osType *clientOs, char **clientOsQualifier) +enum browserType cgiClientBrowser(char **browserQualifier, enum osType *clientOs, + char **clientOsQualifier) /* Return client browser type determined from (HTTP_USER_AGENT) Optionally requuest the additional info about the client */ { // WARNING: The specifics of the HTTP_USER_AGENT vary widely. // This has only been tested on a few cases. static enum browserType clientBrowser = btUnknown; static enum browserType clientOsType = osUnknown; static char *clientBrowserExtra = NULL; static char *clientOsExtra = NULL; if (clientBrowser == btUnknown) { char *userAgent = cgiUserAgent(); if (userAgent != NULL) { //warn(userAgent); // Use this to investigate other cases char *ptr=NULL; // Determine the browser if ((ptr = stringIn("Opera",userAgent)) != NULL) // Must be before IE { clientBrowser = btOpera; } else if ((ptr = stringIn("MSIE ",userAgent)) != NULL) { clientBrowser = btIE; ptr += strlen("MSIE "); clientBrowserExtra = cloneFirstWordByDelimiter(ptr,';'); } else if ((ptr = stringIn("Firefox",userAgent)) != NULL) { clientBrowser = btFF; ptr += strlen("(Firefox/"); clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' '); } else if ((ptr = stringIn("Chrome",userAgent)) != NULL) // Must be before Safari { clientBrowser = btChrome; ptr += strlen("Chrome/"); clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' '); } else if ((ptr = stringIn("Safari",userAgent)) != NULL) { clientBrowser = btSafari; ptr += strlen("Safari/"); clientBrowserExtra = cloneFirstWordByDelimiter(ptr,' '); } else { clientBrowser = btOther; } // Determine the OS if ((ptr = stringIn("Windows",userAgent)) != NULL) { clientOsType = osWindows; ptr += strlen("Windows "); clientOsExtra = cloneFirstWordByDelimiter(ptr,';'); } else if ((ptr = stringIn("Linux",userAgent)) != NULL) { clientOsType = osLinux; ptr += strlen("Linux "); clientOsExtra = cloneFirstWordByDelimiter(ptr,';'); } else if ((ptr = stringIn("Mac ",userAgent)) != NULL) { clientOsType = osMac; ptr += strlen("Mac "); clientOsExtra = cloneFirstWordByDelimiter(ptr,';'); } else { clientOsType = osOther; } } } if (browserQualifier != NULL) { if (clientBrowserExtra != NULL) *browserQualifier = cloneString(clientBrowserExtra); else *browserQualifier = NULL; } if (clientOs != NULL) *clientOs = clientOsType; if (clientOsQualifier != NULL) { if (clientOsExtra != NULL) *clientOsQualifier = cloneString(clientOsExtra); else *clientOsQualifier = NULL; } return clientBrowser; } char *_cgiRawInput() /* For debugging get the unprocessed input. */ { return inputString; } static void getQueryInputExt(boolean abortOnErr) /* Get query string from environment if they've used GET method. */ { inputString = getenv("QUERY_STRING"); if (inputString == NULL) { if (abortOnErr) errAbort("No QUERY_STRING in environment."); inputString = cloneString(""); return; } inputString = cloneString(inputString); } static void getQueryInput() /* Get query string from environment if they've used GET method. */ { getQueryInputExt(TRUE); } static void getPostInput() /* Get input from file if they've used POST method. * Grab any GET QUERY_STRING input first. */ { char *s; long i; int r; getQueryInputExt(FALSE); int getSize = strlen(inputString); s = getenv("CONTENT_LENGTH"); if (s == NULL) errAbort("No CONTENT_LENGTH in environment."); if (sscanf(s, "%lu", &inputSize) != 1) errAbort("CONTENT_LENGTH isn't a number."); s = getenv("CONTENT_TYPE"); if (s != NULL && startsWith("multipart/form-data", s)) { /* use MIME parse on input stream instead, can handle large uploads */ /* inputString must not be NULL so it knows it was set */ return; } int len = getSize + inputSize; if (getSize > 0) ++len; char *temp = needMem((size_t)len+1); for (i=0; i 0) temp[i++] = '&'; strncpy(temp+i, inputString, getSize); temp[len] = 0; freeMem(inputString); inputString = temp; } #define memmem(hay, haySize, needle, needleSize) \ memMatch(needle, needleSize, hay, haySize) #ifndef GBROWSE static void cgiParseMultipart(struct hash **retHash, struct cgiVar **retList) /* process a multipart form */ { char h[1024]; /* hold mime header line */ char *s = NULL, *ct = NULL; struct dyString *dy = newDyString(256); struct mimeBuf *mb = NULL; struct mimePart *mp = NULL; char **env = NULL; struct hash *hash = newHash(6); struct cgiVar *list = NULL, *el; extern char **environ; //debug //fprintf(stderr,"GALT: top of cgiParseMultipart()\n"); //fflush(stderr); /* find the CONTENT_ environment strings, use to make Alternate Header string for MIME */ for(env=environ; *env; env++) if (startsWith("CONTENT_",*env)) { //debug //fprintf(stderr,"%s\n",*env); //debug safef(h,sizeof(h),"%s",*env); s = strchr(h,'_'); /* change env syntax to MIME style header, from _= to -: */ if (!s) errAbort("expecting '_' parsing env var %s for MIME alt header", *env); *s = '-'; s = strchr(h,'='); if (!s) errAbort("expecting '=' parsing env var %s for MIME alt header", *env); *s = ':'; dyStringPrintf(dy,"%s\r\n",h); } dyStringAppend(dy,"\r\n"); /* blank line at end means end of headers */ //debug //fprintf(stderr,"Alternate Header Text:\n%s",dy->string); //fflush(stderr); mb = initMimeBuf(STDIN_FILENO); //debug //fprintf(stderr,"got past initMimeBuf(STDIN_FILENO)\n"); //fflush(stderr); mp = parseMultiParts(mb, cloneString(dy->string)); /* The Alternate Header will get freed */ freeDyString(&dy); if(!mp->multi) /* expecting multipart child parts */ errAbort("Malformatted multipart-form."); //debug //fprintf(stderr,"GALT: Wow got past parse of MIME!\n"); //fflush(stderr); ct = hashFindVal(mp->hdr,"content-type"); //debug //fprintf(stderr,"GALT: main content-type: %s\n",ct); //fflush(stderr); if (!startsWith("multipart/form-data",ct)) errAbort("main content-type expected starts with [multipart/form-data], found [%s]",ct); for(mp=mp->multi;mp;mp=mp->next) { char *cd = NULL, *cdMain = NULL, *cdName = NULL, *cdFileName = NULL, *ct = NULL; cd = hashFindVal(mp->hdr,"content-disposition"); ct = hashFindVal(mp->hdr,"content-type"); //debug //fprintf(stderr,"GALT: content-disposition: %s\n",cd); //fprintf(stderr,"GALT: content-type: %s\n",ct); //fflush(stderr); cdMain=getMimeHeaderMainVal(cd); cdName=getMimeHeaderFieldVal(cd,"name"); cdFileName=getMimeHeaderFieldVal(cd,"filename"); //debug //fprintf(stderr,"cgiParseMultipart: main:[%s], name:[%s], filename:[%s]\n",cdMain,cdName,cdFileName); //fflush(stderr); if (!sameString(cdMain,"form-data")) errAbort("main content-type expected [form-data], found [%s]",cdMain); //debug //fprintf(stderr,"GALT: mp->size[%llu], mp->binary=[%d], mp->fileName=[%s], mp=>data:[%s]\n", //(unsigned long long) mp->size, mp->binary, mp->fileName, //mp->binary && mp->data ? "" : mp->data); //fflush(stderr); /* filename if there is one */ /* Internet Explorer on Windows is sending full path names, strip * directory name from those. Using \ and / and : as potential * path separator characters, e.g.: * C:\Documents and Settings\tmp\file.txt.gz */ if(cdFileName) { char *lastPathSep = strrchr(cdFileName, (int) '\\'); if (!lastPathSep) lastPathSep = strrchr(cdFileName, (int) '/'); if (!lastPathSep) lastPathSep = strrchr(cdFileName, (int) ':'); char varNameFilename[256]; safef(varNameFilename, sizeof(varNameFilename), "%s__filename", cdName); AllocVar(el); if (lastPathSep) el->val = cloneString(lastPathSep+1); else el->val = cloneString(cdFileName); slAddHead(&list, el); hashAddSaveName(hash, varNameFilename, el, &el->name); } if (mp->data) { if (mp->binary) { char varNameBinary[256]; char addrSizeBuf[40]; safef(varNameBinary,sizeof(varNameBinary),"%s__binary",cdName); safef(addrSizeBuf,sizeof(addrSizeBuf),"%lu %llu", (unsigned long)mp->data, (unsigned long long)mp->size); AllocVar(el); el->val = cloneString(addrSizeBuf); slAddHead(&list, el); hashAddSaveName(hash, varNameBinary, el, &el->name); } else /* normal variable, not too big, does not contain zeros */ { AllocVar(el); el->val = mp->data; slAddHead(&list, el); hashAddSaveName(hash, cdName, el, &el->name); } } else if (mp->fileName) { char varNameData[256]; safef(varNameData, sizeof(varNameData), "%s__data", cdName); AllocVar(el); el->val = mp->fileName; slAddHead(&list, el); hashAddSaveName(hash, varNameData, el, &el->name); //debug //fprintf(stderr,"GALT special: saved varNameData:[%s], mp=>fileName:[%s]\n",el->name,el->val); //fflush(stderr); } else if (mp->multi) { warn("unexpected nested MIME structures"); } else { errAbort("mp-> type not data,fileName, or multi - unexpected MIME structure"); } freez(&cdMain); freez(&cdName); freez(&cdFileName); } slReverse(&list); *retList = list; *retHash = hash; } #endif /* GBROWSE */ static void parseCookies(struct hash **retHash, struct cgiVar **retList) /* parses any cookies and puts them into the given hash and list */ { char* str; char *namePt, *dataPt, *nextNamePt; struct hash *hash; struct cgiVar *list = NULL, *el; /* don't build the hash table again */ if(haveCookiesHash == TRUE) return; str = cloneString(getenv("HTTP_COOKIE")); if(str == NULL) /* don't have a cookie */ return; hash = newHash(6); namePt = str; while (isNotEmpty(namePt)) { dataPt = strchr(namePt, '='); if (dataPt == NULL) errAbort("Mangled Cookie input string: no = in '%s' (offset %d in complete cookie string: '%s')", namePt, (int)(namePt - str), getenv("HTTP_COOKIE")); *dataPt++ = 0; nextNamePt = strchr(dataPt, ';'); if (nextNamePt != NULL) { *nextNamePt++ = 0; if (*nextNamePt == ' ') nextNamePt++; } cgiDecode(dataPt,dataPt,strlen(dataPt)); AllocVar(el); el->val = dataPt; slAddHead(&list, el); hashAddSaveName(hash, namePt, el, &el->name); namePt = nextNamePt; } haveCookiesHash = TRUE; slReverse(&list); *retList = list; *retHash = hash; } char *findCookieData(char *varName) /* Get the string associated with varName from the cookie string. */ { struct hashEl *hel; char *firstResult; /* make sure that the cookie hash table has been created */ parseCookies(&cookieHash, &cookieList); if (cookieHash == NULL) return NULL; /* Watch out for multiple cookies with the same name (hel is a list) -- * warn if we find them. */ hel = hashLookup(cookieHash, varName); if (hel == NULL) return NULL; else firstResult = ((struct cgiVar *)hel->val)->val; hel = hel->next; while (hel != NULL) { char *val = ((struct cgiVar *)(hel->val))->val; if (sameString(varName, hel->name) && !sameString(firstResult, val)) { /* This is too early to call warn -- it will mess up html output. */ fprintf(stderr, "findCookieData: Duplicate cookie value from IP=%s: " "%s has both %s and %s\n", cgiRemoteAddr(), varName, firstResult, val); } hel = hel->next; } return firstResult; } static char *cgiInputSource(char *s) /* For NULL sources make a guess as to real source. */ { char *qs; if (s != NULL) return s; qs = getenv("QUERY_STRING"); if (qs == NULL) return "POST"; char *cl = getenv("CONTENT_LENGTH"); if (cl != NULL && atoi(cl) > 0) return "POST"; return "QUERY"; } static void _cgiFindInput(char *method) /* Get raw CGI input into inputString. Method can be "POST", "QUERY", "GET" or NULL * for unknown. */ { if (inputString == NULL) { method = cgiInputSource(method); if (sameWord(method, "POST")) getPostInput(); else if (sameWord(method, "QUERY") || sameWord(method, "GET")) getQueryInput(); else errAbort("Unknown form method"); } } static void cgiParseInputAbort(char *input, struct hash **retHash, struct cgiVar **retList) /* Parse cgi-style input into a hash table and list. This will alter * the input data. The hash table will contain references back * into input, so please don't free input until you're done with * the hash. Prints message aborts if there's an error.*/ { char *namePt, *dataPt, *nextNamePt; struct hash *hash = *retHash; struct cgiVar *list = *retList, *el; if (!hash) hash = newHash(6); slReverse(&list); namePt = input; while (namePt != NULL && namePt[0] != 0) { dataPt = strchr(namePt, '='); if (dataPt == NULL) { errAbort("Mangled CGI input string %s", namePt); } *dataPt++ = 0; nextNamePt = strchr(dataPt, '&'); if (nextNamePt == NULL) nextNamePt = strchr(dataPt, ';'); /* Accomodate DAS. */ if (nextNamePt != NULL) *nextNamePt++ = 0; cgiDecode(namePt,namePt,strlen(namePt)); /* for unusual ct names */ cgiDecode(dataPt,dataPt,strlen(dataPt)); AllocVar(el); el->val = dataPt; slAddHead(&list, el); hashAddSaveName(hash, namePt, el, &el->name); namePt = nextNamePt; } slReverse(&list); *retList = list; *retHash = hash; } static jmp_buf cgiParseRecover; static void cgiParseAbort() /* Abort cgi parsing. */ { longjmp(cgiParseRecover, -1); } boolean cgiParseInput(char *input, struct hash **retHash, struct cgiVar **retList) /* Parse cgi-style input into a hash table and list. This will alter * the input data. The hash table will contain references back * into input, so please don't free input until you're done with * the hash. Prints message and returns FALSE if there's an error.*/ { boolean ok = TRUE; int status = setjmp(cgiParseRecover); if (status == 0) /* Always true except after long jump. */ { pushAbortHandler(cgiParseAbort); cgiParseInputAbort(input, retHash, retList); } else /* They long jumped here because of an error. */ { ok = FALSE; } popAbortHandler(); return ok; } static boolean dumpStackOnSignal = FALSE; // should a stack dump be generated? static void catchSignal(int sigNum) /* handler for various terminal signals for logging purposes */ { char *sig = NULL; switch (sigNum) { case SIGABRT: sig = "SIGABRT"; break; case SIGSEGV: sig = "SIGSEGV"; break; case SIGFPE: sig = "SIGFPE"; break; case SIGBUS: sig = "SIGBUS"; break; } logCgiToStderr(); fprintf(stderr, "Received signal %s\n", sig); if (dumpStackOnSignal) dumpStack("Stack for signal %s\n", sig); raise(SIGKILL); } void initSigHandlers(boolean dumpStack) /* set handler for various terminal signals for logging purposes. * if dumpStack is TRUE, attempt to dump the stack. */ { if (cgiIsOnWeb()) { signal(SIGABRT, catchSignal); signal(SIGSEGV, catchSignal); signal(SIGFPE, catchSignal); signal(SIGBUS, catchSignal); dumpStackOnSignal = dumpStack; } } static void initCgiInput() /* Initialize CGI input stuff. After this CGI vars are * stored in an internal hash/list regardless of how they * were passed to the program. */ { char* s; if (inputString != NULL) return; _cgiFindInput(NULL); #ifndef GBROWSE /* check to see if the input is a multipart form */ s = getenv("CONTENT_TYPE"); if (s != NULL && startsWith("multipart/form-data", s)) { cgiParseMultipart(&inputHash, &inputList); } #endif /* GBROWSE */ cgiParseInputAbort(inputString, &inputHash, &inputList); /* now parse the cookies */ parseCookies(&cookieHash, &cookieList); /* Set enviroment variables CGIs to enable sql tracing and/or profiling */ s = cgiOptionalString("JKSQL_TRACE"); if (s != NULL) envUpdate("JKSQL_TRACE", s); s = cgiOptionalString("JKSQL_PROF"); if (s != NULL) envUpdate("JKSQL_PROF", s); } struct cgiVar *cgiVarList() /* return the list of cgiVar's */ { initCgiInput(); return inputList; } static char *findVarData(char *varName) /* Get the string associated with varName from the query string. */ { struct cgiVar *var; initCgiInput(); if ((var = hashFindVal(inputHash, varName)) == NULL) return NULL; return var->val; } void cgiBadVar(char *varName) /* Complain about a variable that's not there. */ { if (varName == NULL) varName = ""; errAbort("Sorry, didn't find CGI input variable '%s'", varName); } static char *mustFindVarData(char *varName) /* Find variable and associated data or die trying. */ { char *res = findVarData(varName); if (res == NULL) cgiBadVar(varName); return res; } char *javaScriptLiteralEncode(char *inString) /* Use backslash escaping on newline * and quote chars, backslash and others. * Intended that the encoded string will be * put between quotes at a higher level and * then interpreted by Javascript. */ { char c; int outSize = 0; char *outString, *out, *in; if (inString == NULL) return(cloneString("")); /* Count up how long it will be */ in = inString; while ((c = *in++) != 0) { if (c == '\'' || c == '\"' || c == '&' || c == '\\' || c == '\n' || c == '\r' || c == '\t' || c == '\b' || c == '\f' ) outSize += 2; else outSize += 1; } outString = needMem(outSize+1); /* Encode string */ in = inString; out = outString; while ((c = *in++) != 0) { if (c == '\'' || c == '\"' || c == '&' || c == '\\' || c == '\n' || c == '\r' || c == '\t' || c == '\b' || c == '\f' ) *out++ = '\\'; *out++ = c; } *out++ = 0; return outString; } void cgiDecode(char *in, char *out, int inLength) /* Decode from cgi pluses-for-spaces format to normal. * Out will be a little shorter than in typically, and * can be the same buffer. */ { char c; int i; for (i=0; inext) { if (sameString(hel->name, varName)) { struct cgiVar *var = hel->val; string = newSlName(var->val); slAddHead(&stringList, string); } } return stringList; } int cgiInt(char *varName) /* Return int value of cgi variable. */ { char *data; char c; data = mustFindVarData(varName); data = skipLeadingSpaces(data); c = data[0]; if (!(isdigit(c) || (c == '-' && isdigit(data[1])))) errAbort("Expecting number in %s, got \"%s\"\n", varName, data); return atoi(data); } int cgiIntExp(char *varName) /* Evaluate an integer expression in varName and * return value. */ { return intExp(cgiString(varName)); } int cgiOptionalInt(char *varName, int defaultVal) /* This returns integer value of varName if it exists in cgi environment * and it's not just the empty string otherwise it returns defaultVal. */ { char *s = cgiOptionalString(varName); s = skipLeadingSpaces(s); if (isEmpty(s)) return defaultVal; return cgiInt(varName); } double cgiDouble(char *varName) /* Returns double value. */ { char *data; double x; data = mustFindVarData(varName); if (sscanf(data, "%lf", &x)<1) errAbort("Expecting real number in %s, got \"%s\"\n", varName, data); return x; } double cgiOptionalDouble(char *varName, double defaultVal) /* Returns double value. */ { if (!cgiVarExists(varName)) return defaultVal; return cgiDouble(varName); } boolean cgiVarExists(char *varName) /* Returns TRUE if the variable was passed in. */ { initCgiInput(); return hashLookup(inputHash, varName) != NULL; } boolean cgiBoolean(char *varName) { return cgiVarExists(varName); } int cgiOneChoice(char *varName, struct cgiChoice *choices, int choiceSize) /* Returns value associated with string variable in choice table. */ { char *key = cgiString(varName); int i; int val = -1; for (i=0; i"); } void cgiMakeClearButton(char *form, char *field) /* Make button to clear a text field. */ { char javascript[1024]; safef(javascript, sizeof(javascript), "document.%s.%s.value = ''; document.%s.submit();", form, field, form); cgiMakeOnClickButton(javascript, " Clear "); } void cgiMakeButtonWithMsg(char *name, char *value, char *msg) /* Make 'submit' type button. Display msg on mouseover, if present*/ { printf("", name, value, (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" )); } void cgiMakeButtonWithOnClick(char *name, char *value, char *msg, char *onClick) /* Make 'submit' type button, with onclick javascript */ { printf("", name, value, onClick, (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" )); } void cgiMakeButton(char *name, char *value) /* Make 'submit' type button */ { cgiMakeButtonWithMsg(name, value, NULL); } void cgiMakeOnClickButton(char *command, char *value) /* Make 'push' type button with client side onClick (java)script. */ { printf("", value, command); } void cgiMakeOnClickSubmitButton(char *command, char *name, char *value) /* Make submit button with both variable name and value with client side * onClick (java)script. */ { printf("", name, value, command); } void cgiMakeOptionalButton(char *name, char *value, boolean disabled) /* Make 'submit' type button that can be disabled. */ { printf(""); } void cgiMakeFileEntry(char *name) /* Make file entry box/browser */ { printf("", name); } void cgiSimpleTableStart() /* start HTML table -- no customization. Leaves room * for a fancier implementation */ { printf("\n"); } void cgiTableEnd() /* end HTML table */ { printf("
\n"); } void cgiSimpleTableRowStart() /* Start table row */ { printf("\n"); } void cgiTableRowEnd() /* End table row */ { printf("\n"); } void cgiSimpleTableFieldStart() /* Start table field */ { printf(""); } void cgiTableFieldStartAlignRight() /* Start table field and align right*/ { printf(""); } void cgiTableFieldEnd() /* End table field */ { printf("\n"); } void cgiTableField(char *text) /* Make table field entry */ { printf(" %s \n", text); } void cgiTableFieldWithMsg(char *text, char *msg) /* Make table field entry with mouseover */ { printf(" %s \n", (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ), text); } void cgiParagraph(char *text) /* Make text paragraph */ { printf("

%s\n", text); } void cgiMakeRadioButton(char *name, char *value, boolean checked) /* Make radio type button. A group of radio buttons should have the * same name but different values. The default selection should be * sent with checked on. */ { printf("", name, value, (checked ? "CHECKED" : "")); } void cgiMakeOnClickRadioButton(char *name, char *value, boolean checked, char *command) /* Make radio type button with onClick command. * A group of radio buttons should have the * same name but different values. The default selection should be * sent with checked on. */ { printf("", name, value, command, (checked ? "CHECKED" : "")); } char *cgiBooleanShadowPrefix() /* Prefix for shadow variable set with boolean variables. */ { return "boolshad."; } #define BOOLSHAD_EXTRA "class='cbShadow'" boolean cgiBooleanDefined(char *name) /* Return TRUE if boolean variable is defined (by * checking for shadow. */ { char buf[256]; safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name); return cgiVarExists(buf); } -static void cgiMakeCheckBox2Bool(char *name, boolean checked, boolean enabled, char *id, char *moreHtml) +static void cgiMakeCheckBox2Bool(char *name, boolean checked, boolean enabled, + char *id, char *moreHtml) /* Make check box - designed to be called by the variously overloaded * cgiMakeCheckBox functions, and should NOT be called directly. * moreHtml: optional additional html like javascript call or mouseover msg (may be NULL) * id: button id (may be NULL) * Also make a shadow hidden variable and support 2 boolean states: * checked/unchecked and enabled/disabled. */ { char buf[256], idBuf[256]; if(id) safef(idBuf, sizeof(idBuf), " id=\"%s\"", id); else idBuf[0] = 0; printf("", name, idBuf, (moreHtml ? moreHtml : ""), (checked ? " CHECKED" : ""), (enabled ? "" : " DISABLED")); safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name); cgiMakeHiddenVarWithExtra(buf, ( enabled ? "0" : (checked ? "-1" : "-2")),BOOLSHAD_EXTRA); } void cgiMakeCheckBoxUtil(char *name, boolean checked, char *msg, char *id) /* Make check box - can be called directly, though it was originally meant * as the common code for all lower level checkbox routines. * However, it's util functionality has been taken over by * cgiMakeCheckBoxWithIdAndOptionalHtml() */ { char buf[256]; if(msg) safef(buf, sizeof(buf), "TITLE=\"%s\"", msg); else buf[0] = 0; cgiMakeCheckBox2Bool(name, checked, TRUE, id, buf); } void cgiMakeCheckBoxWithMsg(char *name, boolean checked, char *msg) { char buf[512]; safef(buf, sizeof(buf), "title='%s'", msg); cgiMakeCheckBox2Bool(name, checked, TRUE, NULL, buf); } void cgiMakeCheckBoxWithId(char *name, boolean checked, char *id) /* Make check box, which includes an ID. */ { cgiMakeCheckBox2Bool(name, checked, TRUE, id, NULL); } void cgiMakeCheckBox(char *name, boolean checked) /* Make check box. */ { cgiMakeCheckBox2Bool(name, checked, TRUE, NULL, NULL); } void cgiMakeCheckBoxJS(char *name, boolean checked, char *javascript) /* Make check box with javascript. */ { cgiMakeCheckBox2Bool(name,checked,TRUE,NULL,javascript); } void cgiMakeCheckBoxIdAndJS(char *name, boolean checked, char *id, char *javascript) /* Make check box with ID and javascript. */ { cgiMakeCheckBox2Bool(name,checked,TRUE,id,javascript); } -void cgiMakeCheckBoxFourWay(char *name, boolean checked, boolean enabled, char *id, char *classes, char *moreHtml) +void cgiMakeCheckBoxFourWay(char *name, boolean checked, boolean enabled, char *id, + char *classes, char *moreHtml) /* Make check box - with fourWay functionality (checked/unchecked by enabled/disabled) * Also makes a shadow hidden variable that supports the 2 boolean states. */ { char shadName[256]; printf(""); // The hidden var needs to hold the 4way state safef(shadName, sizeof(shadName), "%s%s", cgiBooleanShadowPrefix(), name); -cgiMakeHiddenVarWithExtra(shadName, ( enabled ? "0" : (checked ? "-1" : "-2")),BOOLSHAD_EXTRA); // Doesn't need enabled/checked! +cgiMakeHiddenVarWithExtra(shadName, ( enabled ? "0" : (checked ? "-1" : "-2")),BOOLSHAD_EXTRA); } void cgiMakeHiddenBoolean(char *name, boolean on) /* Make hidden boolean variable. Also make a shadow hidden variable so we * can distinguish between variable not present and * variable set to false. */ { char buf[256]; cgiMakeHiddenVar(name, on ? "on" : "off"); safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name); -cgiMakeHiddenVarWithExtra(buf, "1",BOOLSHAD_EXTRA); // shouldn't this be "0" or "off" ? Probably any non-"on" will work. +cgiMakeHiddenVarWithExtra(buf, "1",BOOLSHAD_EXTRA); } void cgiMakeTextArea(char *varName, char *initialVal, int rowCount, int columnCount) /* Make a text area with area rowCount X columnCount and with text: intialVal */ { cgiMakeTextAreaDisableable(varName, initialVal, rowCount, columnCount, FALSE); } void cgiMakeTextAreaDisableable(char *varName, char *initialVal, int rowCount, int columnCount, boolean disabled) /* Make a text area that can be disabled. The rea has rowCount X * columnCount and with text: intialVal */ { printf("", varName, rowCount, columnCount, disabled ? "DISABLED" : "", (initialVal != NULL ? initialVal : "")); } void cgiMakeOnKeypressTextVar(char *varName, char *initialVal, int charSize, char *script) /* Make a text control filled with initial value, with a (java)script * to execute every time a key is pressed. If charSize is zero it's * calculated from initialVal size. */ { if (initialVal == NULL) initialVal = ""; if (charSize == 0) charSize = strlen(initialVal); if (charSize == 0) charSize = 8; printf("\n"); } void cgiMakeTextVar(char *varName, char *initialVal, int charSize) /* Make a text control filled with initial value. If charSize * is zero it's calculated from initialVal size. */ { cgiMakeOnKeypressTextVar(varName, initialVal, charSize, NULL); } void cgiMakeTextVarWithExtraHtml(char *varName, char *initialVal, int width, char *extra) /* Make a text control filled with initial value. */ { if (initialVal == NULL) initialVal = ""; if(width==0) width=strlen(initialVal)*10; if(width==0) width = 100; -printf("\n"); } - void cgiMakeIntVar(char *varName, int initialVal, int maxDigits) /* Make a text control filled with initial value. */ { if (maxDigits == 0) maxDigits = 4; printf("", varName, maxDigits, initialVal); } -void cgiMakeIntVarInRange(char *varName, int initialVal, char *title, int width, char *min, char *max) +void cgiMakeIntVarInRange(char *varName, int initialVal, char *title, int width, + char *min, char *max) /* Make a integer control filled with initial value. If min and/or max are non-NULL will enforce range Requires utils.js jQuery.js and inputBox class */ { if(width==0) { if(max) width=strlen(max)*10; else { int sz=initialVal+1000; if(min) sz=atoi(min) + 1000; width = 10; while(sz/=10) width+=10; } } if (width < 65) width = 65; -printf("\n"); } -void cgiMakeIntVarWithLimits(char *varName, int initialVal, char *title, int width, int min, int max) + +void cgiMakeIntVarWithLimits(char *varName, int initialVal, char *title, int width, + int min, int max) { char minLimit[20]; char maxLimit[20]; char *minStr=NULL; char *maxStr=NULL; if(min != NO_VALUE) { safef(minLimit,sizeof(minLimit),"%d",min); minStr = minLimit; } if(max != NO_VALUE) { safef(maxLimit,sizeof(maxLimit),"%d",max); maxStr = maxLimit; } cgiMakeIntVarInRange(varName,initialVal,title,width,minStr,maxStr); } + void cgiMakeIntVarWithMin(char *varName, int initialVal, char *title, int width, int min) { char minLimit[20]; char *minStr=NULL; if(min != NO_VALUE) { safef(minLimit,sizeof(minLimit),"%d",min); minStr = minLimit; } cgiMakeIntVarInRange(varName,initialVal,title,width,minStr,NULL); } + void cgiMakeIntVarWithMax(char *varName, int initialVal, char *title, int width, int max) { char maxLimit[20]; char *maxStr=NULL; if(max != NO_VALUE) { safef(maxLimit,sizeof(maxLimit),"%d",max); maxStr = maxLimit; } cgiMakeIntVarInRange(varName,initialVal,title,width,NULL,maxStr); } void cgiMakeDoubleVar(char *varName, double initialVal, int maxDigits) /* Make a text control filled with initial floating-point value. */ { if (maxDigits == 0) maxDigits = 4; printf("", varName, maxDigits, initialVal); } -void cgiMakeDoubleVarInRange(char *varName, double initialVal, char *title, int width, char *min, char *max) +void cgiMakeDoubleVarInRange(char *varName, double initialVal, char *title, int width, + char *min, char *max) /* Make a floating point control filled with initial value. If min and/or max are non-NULL will enforce range Requires utils.js jQuery.js and inputBox class */ { if(width==0) { if(max) width=strlen(max)*10; } if (width < 65) width = 65; -printf("\n"); } -void cgiMakeDoubleVarWithLimits(char *varName, double initialVal, char *title, int width, double min, double max) +void cgiMakeDoubleVarWithLimits(char *varName, double initialVal, char *title, int width, + double min, double max) { char minLimit[20]; char maxLimit[20]; char *minStr=NULL; char *maxStr=NULL; if((int)min != NO_VALUE) { safef(minLimit,sizeof(minLimit),"%g",min); minStr = minLimit; } if((int)max != NO_VALUE) { safef(maxLimit,sizeof(maxLimit),"%g",max); maxStr = maxLimit; } cgiMakeDoubleVarInRange(varName,initialVal,title,width,minStr,maxStr); } void cgiMakeDoubleVarWithMin(char *varName, double initialVal, char *title, int width, double min) { char minLimit[20]; char *minStr=NULL; if((int)min != NO_VALUE) { safef(minLimit,sizeof(minLimit),"%g",min); minStr = minLimit; } cgiMakeDoubleVarInRange(varName,initialVal,title,width,minStr,NULL); } + void cgiMakeDoubleVarWithMax(char *varName, double initialVal, char *title, int width, double max) { char maxLimit[20]; char *maxStr=NULL; if((int)max != NO_VALUE) { safef(maxLimit,sizeof(maxLimit),"%g",max); maxStr = maxLimit; } cgiMakeDoubleVarInRange(varName,initialVal,title,width,NULL,maxStr); } void cgiMakeDropListClassWithStyleAndJavascript(char *name, char *menu[], int menuSize, char *checked, char *class, char *style,char *javascript) /* Make a drop-down list with names, text class, style and javascript. */ { int i; char *selString; if (checked == NULL) checked = menu[0]; printf("\n"); for (i=0; i%s\n", selString, menu[i]); } printf("\n"); } void cgiMakeDropListClassWithStyle(char *name, char *menu[], int menuSize, char *checked, char *class, char *style) /* Make a drop-down list with names, text class and style. */ { cgiMakeDropListClassWithStyleAndJavascript(name,menu,menuSize,checked,class,style,""); } void cgiMakeDropListClass(char *name, char *menu[], int menuSize, char *checked, char *class) /* Make a drop-down list with names. */ { - cgiMakeDropListClassWithStyle(name, menu, menuSize, checked, - class, NULL); +cgiMakeDropListClassWithStyle(name, menu, menuSize, checked, class, NULL); } void cgiMakeDropList(char *name, char *menu[], int menuSize, char *checked) /* Make a drop-down list with names. * uses style "normalText" */ { cgiMakeDropListClass(name, menu, menuSize, checked, "normalText"); } char *cgiMultListShadowPrefix() /* Prefix for shadow variable set with multi-select inputs. */ { return "multishad."; } void cgiMakeMultList(char *name, char *menu[], int menuSize, struct slName *checked, int length) /* Make a list of names with window height equalt to length, * which can have multiple selections. Same as drop-down list * except "multiple" is added to select tag. */ { int i; char *selString; if (checked == NULL) checked = slNameNew(menu[0]); printf("\n"); char buf[512]; safef(buf, sizeof(buf), "%s%s", cgiMultListShadowPrefix(), name); cgiMakeHiddenVar(buf, "1"); } void cgiMakeCheckboxGroupWithVals(char *name, char *menu[], char *values[], int menuSize, struct slName *checked, int tableColumns) /* Make a table of checkboxes that have the same variable name but different * values (same behavior as a multi-select input), with nice labels in menu[]. */ { int i; if (values == NULL) values = menu; if (menu == NULL) menu = values; puts(""); for (i = 0; i < menuSize; i++) { if (i > 0 && (i % tableColumns) == 0) printf(""); printf("\n", name, values[i], (slNameInList(checked, values[i]) ? "CHECKED" : ""), menu[i]); } if ((i % tableColumns) != 0) while ((i++ % tableColumns) != 0) printf(""); puts("
%s
"); char buf[512]; safef(buf, sizeof(buf), "%s%s", cgiMultListShadowPrefix(), name); cgiMakeHiddenVar(buf, "0"); } void cgiMakeCheckboxGroup(char *name, char *menu[], int menuSize, struct slName *checked, int tableColumns) /* Make a table of checkboxes that have the same variable name but different * values (same behavior as a multi-select input). */ { cgiMakeCheckboxGroupWithVals(name, menu, NULL, menuSize, checked, tableColumns); } void cgiMakeDropListFull(char *name, char *menu[], char *values[], int menuSize, char *checked, char *extraAttribs) /* Make a drop-down list with names and values. */ { int i; char *selString; if (checked == NULL) checked = menu[0]; if (NULL != extraAttribs) { printf("\n", name); } for (i=0; i%s\n", selString, values[i], menu[i]); } printf("\n"); } -char *cgiMakeSelectDropList(boolean multiple, char *name, struct slPair *valsAndLabels,char *selected, char *anyAll,char *extraClasses, char *extraHtml) -// Returns allocated string of HTML defining a drop-down select (if multiple, REQUIRES ui-dropdownchecklist.js) -// In valsAndLabels, val (pair->name) must be filled in but label (pair->val) may be NULL. -// selected, if not NULL is a val found in the valsAndLabels (multiple then comma delimited list). If null and anyAll not NULL, that will be selected -// anyAll, if not NULL is the string for an initial option. It can contain val and label, delimited by a comma -// extraHtml, if not NULL contains id, javascript calls and style. It does NOT contain class definitions +char *cgiMakeSelectDropList(boolean multiple, char *name, struct slPair *valsAndLabels, + char *selected, char *anyAll,char *extraClasses, char *extraHtml) +// Returns allocated string of HTML defining a drop-down select +// (if multiple, REQUIRES ui-dropdownchecklist.js) +// valsAndLabels: val (pair->name) must be filled in but label (pair->val) may be NULL. +// selected: if not NULL is a val found in the valsAndLabels (multiple then comma delimited list). +// If null and anyAll not NULL, that will be selected +// anyAll: if not NULL is the string for an initial option. It can contain val and label, +// delimited by a comma +// extraHtml: if not NULL contains id, javascript calls and style. +// It does NOT contain class definitions { struct dyString *output = dyStringNew(1024); boolean checked = FALSE; dyStringPrintf(output,"\n"); return dyStringCannibalize(&output); } void cgiMakeDropListWithVals(char *name, char *menu[], char *values[], int menuSize, char *checked) /* Make a drop-down list with names and values. In this case checked * corresponds to a value, not a menu. */ { int i; char *selString; if (checked == NULL) checked = values[0]; printf("\n"); } void cgiDropDownWithTextValsAndExtra(char *name, char *text[], char *values[], int count, char *selected, char *extra) /* Make a drop-down list with both text and values. */ { int i; char *selString; assert(values != NULL && text != NULL); if (selected == NULL) selected = values[0]; printf("\n"); for (i=0; i%s\n", selString, values[i], text[i]); } printf("\n"); } - void cgiMakeHiddenVarWithExtra(char *varName, char *string,char *extra) /* Store string in hidden input for next time around. */ { printf("\n",extra); else puts(">"); } void cgiContinueHiddenVar(char *varName) /* Write CGI var back to hidden input for next time around. */ { if (cgiVarExists(varName)) cgiMakeHiddenVar(varName, cgiString(varName)); } void cgiVarExclude(char *varName) /* If varName exists, remove it. */ { if (cgiVarExists(varName)) { struct cgiVar *cv = hashRemove(inputHash, varName); slRemoveEl(&inputList, cv); } } void cgiVarExcludeExcept(char **varNames) /* Exclude all variables except for those in NULL * terminated array varNames. varNames may be NULL * in which case nothing is excluded. */ { struct hashEl *list, *el; struct hash *exclude = newHash(8); char *s; /* Build up hash of things to exclude */ if (varNames != NULL) { while ((s = *varNames++) != NULL) hashAdd(exclude, s, NULL); } /* Step through variable list and remove them if not * excluded. */ initCgiInput(); list = hashElListHash(inputHash); for (el = list; el != NULL; el = el->next) { if (!hashLookup(exclude, el->name)) cgiVarExclude(el->name); } hashElFreeList(&list); freeHash(&exclude); } void cgiVarSet(char *varName, char *val) /* Set a cgi variable to a particular value. */ { struct cgiVar *var; initCgiInput(); AllocVar(var); var->val = cloneString(val); hashAddSaveName(inputHash, varName, var, &var->name); } struct dyString *cgiUrlString() /* Get URL-formatted that expresses current CGI variable state. */ { struct dyString *dy = newDyString(0); struct cgiVar *cv; char *e; for (cv = inputList; cv != NULL; cv = cv->next) { if (cv != inputList) dyStringAppend(dy, "&"); e = cgiEncode(cv->val); dyStringPrintf(dy, "%s=", cv->name); dyStringAppend(dy, e); freez(&e); } return dy; } void cgiContinueAllVars() /* Write back all CGI vars as hidden input for next time around. */ { struct cgiVar *cv; for (cv = inputList; cv != NULL; cv = cv->next) cgiMakeHiddenVar(cv->name, cv->val); } boolean cgiFromCommandLine(int *pArgc, char *argv[], boolean preferWeb) /* Use the command line to set up things as if we were a CGI program. * User types in command line (assuming your program called cgiScript) * like: * cgiScript nonCgiArg1 var1=value1 var2=value2 var3=value3 nonCgiArg2 * or like * cgiScript nonCgiArg1 var1=value1&var2=value2&var3=value3 nonCgiArg2 * or even like * cgiScript nonCgiArg1 -x -y=bogus z=really * (The non-cgi arguments can occur anywhere. The cgi arguments (all containing * the character '=' or starting with '-') are erased from argc/argv. Normally * you call this cgiSpoof(&argc, argv); */ { int argc = *pArgc; int i; int argcLeft = argc; char *name; static char queryString[16384]; char *q = queryString; boolean needAnd = TRUE; boolean gotAny = FALSE; boolean startDash; boolean gotEq; static char hostLine[512]; if (preferWeb && cgiIsOnWeb()) return TRUE; /* No spoofing required! */ q += safef(q, queryString + sizeof(queryString) - q, "%s", "QUERY_STRING=cgiSpoof=on"); for (i=0; i= maxArgc) { ExpandArray(argv, maxArgc, 2*maxArgc); maxArgc *= 2; } /* Fill in another argument to our psuedo arguments. */ argv[argc++] = cloneString(line); } spoof = cgiSpoof(&argc, argv); /* Cleanup. */ lineFileClose(&lf); for(i=0; i 3) ascTime[len-2] = '\0'; if (!ip) ip = "unknown"; if (!hgsid) hgsid = "unknown"; if (!requestUri) requestUri = "unknown"; fprintf(stderr, "[%s] [%s] [client %s] [hgsid=%.24s] [%.1024s] ", ascTime, cgiFileName, ip, hgsid, requestUri); } void cgiResetState() /* This is for reloading CGI settings multiple times in the same program * execution. No effect if state has not yet been initialized. */ { freez(&inputString); inputString = NULL; if (inputHash != NULL) hashFree(&inputHash); inputHash = NULL; inputList = NULL; haveCookiesHash = FALSE; if (cookieHash != NULL) hashFree(&cookieHash); cookieHash = NULL; cookieList = NULL; } void cgiDown(float lines) // Drop down a certain number of lines (may be fractional) { printf("

\n",lines); } char *commonCssStyles() /* Returns a string of common CSS styles */ { // Contents currently is OBSOLETE as these have been moved to HGStyle.css -// However, don't loose this function call yet, as it may have future uses. -return ""; -#ifdef OMIT -static boolean commonStylesWritten = FALSE; -if(commonStylesWritten) +// TODO: remove all traces (from web.c, hgTracks, hgTables) as this funtion does nothing. return ""; -commonStylesWritten = TRUE; - -struct dyString *style = newDyString(256); - -dyStringPrintf(style,"\n\n"); -return dyStringCannibalize(&style); -#endif///def OMIT }