8fdc86ea29f656cf7efee9954fdae6b573190fb3
tdreszer
Fri May 6 17:23:22 2011 -0700
Standardized replacement for
with cgiDown and worked out more spacing issues in hgFileUi and hgTrackUi.
diff --git src/lib/cheapcgi.c src/lib/cheapcgi.c
index ff099e9..8397f34 100644
--- src/lib/cheapcgi.c
+++ src/lib/cheapcgi.c
@@ -1,2116 +1,2122 @@
/* 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
static char const rcsid[] = "$Id: cheapcgi.c,v 1.137 2010/06/11 22:34:53 tdreszer Exp $";
/* 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 */
{
return getenv("SERVER_NAME");
}
char *cgiServerPort()
/* Return port number of server */
{
char *port = getenv("SERVER_PORT");
if (port)
return port;
else
return "80";
}
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)
/* 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 input variable %s\n"
"Probably the web page didn't mean to call this program.",
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("
%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.";
}
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)
/* 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);
cgiMakeHiddenVar(buf, ( enabled ? "0" : (checked ? "-1" : "-2")));
}
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)
{
cgiMakeCheckBox2Bool(name, checked, TRUE, NULL, msg);
}
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)
/* 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], extra[256];
printf("");
// The hidden var needs to hold the 4way state
safef(shadName, sizeof(shadName), "%s%s", cgiBooleanShadowPrefix(), name);
safef(extra, sizeof(extra), "id='%s_4way'",name);
cgiMakeHiddenVarWithExtra(shadName, ( enabled ? "0" : (checked ? "-1" : "-2")),extra); // Doesn't need enabled/checked!
}
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);
cgiMakeHiddenVar(buf, "1");
}
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)
/* 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)
{
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)
/* 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)
{
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");
}
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);
}
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("
");
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("