/* hgNear - gene sorter. */
#include "common.h"
#include "linefile.h"
#include "hash.h"
#include "dystring.h"
#include "obscure.h"
#include "portable.h"
#include "cheapcgi.h"
#include "memalloc.h"
#include "jksql.h"
#include "htmshell.h"
#include "hVarSubst.h"
#include "cart.h"
#include "dbDb.h"
#include "hdb.h"
#include "hui.h"
#include "web.h"
#include "ra.h"
#include "hgColors.h"
#include "hgNear.h"
#include "versionInfo.h"
char *excludeVars[] = { "submit", "Submit", idPosVarName, NULL };
/* The excludeVars are not saved to the cart. (We also exclude
* any variables that start "near.do.") */
/* ---- Global variables. ---- */
struct cart *cart; /* This holds cgi and other variables between clicks. */
struct hash *oldVars = NULL; /* The cart vars before new cgi stuff added. */
char *database; /* Name of genome database - hg15, mm3, or the like. */
char *genome; /* Name of genome - mouse, human, etc. */
char *groupOn; /* Current grouping strategy. */
int displayCount; /* Number of items to display. */
char *displayCountString; /* Ascii version of display count, including 'all'. */
struct hash *genomeSettings; /* Genome-specific settings from settings.ra. */
struct hash *columnHash; /* Hash of active columns keyed by name. */
struct genePos *curGeneId; /* Identity of current gene. */
int kgVersion = KG_UNKNOWN; /* KG version */
/* ---- General purpose helper routines. ---- */
int genePosCmpName(const void *va, const void *vb)
/* Sort function to compare two genePos by name. */
{
const struct genePos *a = *((struct genePos **)va);
const struct genePos *b = *((struct genePos **)vb);
return strcmp(a->name, b->name);
}
int genePosCmpPos(const void *va, const void *vb)
/* Sort function to compare two genePos by chrom,start. */
{
const struct genePos *a = *((struct genePos **)va);
const struct genePos *b = *((struct genePos **)vb);
int diff = strcmp(a->chrom, b->chrom);
if (diff == 0)
diff = a->start - b->start;
return diff;
}
void genePosFillFrom5(struct genePos *gp, char **row)
/* Fill in genePos from row containing ascii version of
* name/chrom/start/end/protein. */
{
gp->name = cloneString(row[0]);
gp->chrom = cloneString(row[1]);
gp->start = sqlUnsigned(row[2]);
gp->end = sqlUnsigned(row[3]);
gp->protein = cloneString(row[4]);
gp->distance = genePosTooFar;
}
int genePosCmpDistance(const void *va, const void *vb)
/* Compare to sort based on distance. */
{
const struct genePos *a = *((struct genePos **)va);
const struct genePos *b = *((struct genePos **)vb);
float diff = a->distance - b->distance;
if (diff > 0)
return 1;
else if (diff < 0)
return -1;
else
{
return strcmp(a->protein, b->protein);
}
}
boolean wildMatchAny(char *word, struct slName *wildList)
/* Return TRUE if word matches any thing in wildList. */
{
struct slName *w;
for (w = wildList; w != NULL; w = w->next)
if (wildMatch(w->name, word) )
return TRUE;
return FALSE;
}
boolean wildMatchAll(char *word, struct slName *wildList)
/* Return TRUE if word matches all things in wildList. */
{
struct slName *w;
for (w = wildList; w != NULL; w = w->next)
if (!wildMatch(w->name, word) )
return FALSE;
return TRUE;
}
boolean wildMatchList(char *word, struct slName *wildList, boolean orLogic)
/* Return TRUE if word matches things in wildList. */
{
if (orLogic)
return wildMatchAny(word, wildList);
else
return wildMatchAll(word, wildList);
}
boolean anyRealInCart(struct cart *cart, char *wild)
/* Return TRUE if variables are set matching wildcard. */
{
struct hashEl *varList = NULL, *var;
boolean ret = FALSE;
varList = cartFindLike(cart, wild);
for (var = varList; var != NULL; var = var->next)
{
char *s = var->val;
if (s != NULL)
{
s = trimSpaces(s);
if (s[0] != 0)
{
ret = TRUE;
break;
}
}
}
hashElFreeList(&varList);
return ret;
}
void fixSafariSpaceInQuotes(char *s)
/* Safari on the Mac changes a space (ascii 32) to a
* ascii 160 if it's inside of a single-quote in a
* text input box!? This tuns it back to a 32. */
{
unsigned char c;
while ((c = *s) != 0)
{
if (c == 160)
*s = 32;
++s;
}
}
void makeTitle(char *title, char *helpName)
/* Print main menu and the title bar. */
{
char buf[1024];
if(!helpName)
helpName = "hgNearHelp.html";
safef(buf, sizeof(buf), "../goldenPath/help/%s", helpName);
setContextSpecificHelp(buf, NULL);
cartWebStart(cart, database, "%s", title);
}
/* ---- Some helper routines for order methods. ---- */
char *orderSetting(struct order *ord, char *name, char *defaultVal)
/* Return value of named setting in order, or default if it doesn't exist. */
{
char *result = hashFindVal(ord->settings, name);
if (result == NULL)
result = defaultVal;
return result;
}
char *orderRequiredSetting(struct order *ord, char *name)
/* Return value of named setting. Abort if it doesn't exist. */
{
char *result = hashFindVal(ord->settings, name);
if (result == NULL)
errAbort("Missing required %s field in %s record of orderDb.ra",
name, ord->name);
return result;
}
int orderIntSetting(struct order *ord, char *name, int defaultVal)
/* Return value of named integer setting or default if it doesn't exist. */
{
char *result = hashFindVal(ord->settings, name);
if (result == NULL)
return defaultVal;
return atoi(result);
}
boolean orderSettingExists(struct order *ord, char *name)
/* Return TRUE if setting exists in column. */
{
return hashFindVal(ord->settings, name) != NULL;
}
/* ---- Some helper routines for column methods. ---- */
char *columnSetting(struct column *col, char *name, char *defaultVal)
/* Return value of named setting in column, or default if it doesn't exist. */
{
char *result = hashFindVal(col->settings, name);
if (result == NULL)
result = defaultVal;
return result;
}
char *columnRequiredSetting(struct column *col, char *name)
/* Return value of named setting. Abort if it doesn't exist. */
{
char *result = hashFindVal(col->settings, name);
if (result == NULL)
errAbort("Missing required %s field in %s record of columnDb.ra",
name, col->name);
return result;
}
int columnSettingInt(struct column *col, char *name, int defaultVal)
/* Return value of named integer setting or default if it doesn't exist. */
{
char *result = hashFindVal(col->settings, name);
if (result == NULL)
return defaultVal;
return atoi(result);
}
boolean columnSettingExists(struct column *col, char *name)
/* Return TRUE if setting exists in column. */
{
return hashFindVal(col->settings, name) != NULL;
}
struct sqlConnection *hgFixedConn()
/* Return connection to hgFixed database.
* This is effectively a global, but not
* opened until needed. */
{
static struct sqlConnection *conn = NULL;
if (conn == NULL)
conn = sqlConnect("hgFixed");
return conn;
}
char *colVarName(struct column *col, char *prefix)
/* Return variable name prefix.col->name. This is just a static
* variable, so don't nest these calls*/
{
static char name[64];
safef(name, sizeof(name), "%s%s", prefix, col->name);
return name;
}
void colButton(struct column *col, char *prefix, char *label)
/* Make a button named prefix.col->name with given label. */
{
static char name[64];
safef(name, sizeof(name), "%s%s", prefix, col->name);
cgiMakeButton(name, label);
}
struct column *colButtonPressed(struct column *colList, char *prefix)
/* See if a button named prefix.column is pressed for some
* column, and if so return the column, else NULL. */
{
static char pattern[64];
char colName[64];
char *match;
safef(pattern, sizeof(pattern), "%s*", prefix);
match = cartFindFirstLike(cart, pattern);
if (match == NULL)
return NULL;
/* Construct column name. If variable is from an file upload
* there __filename suffix attached that we need to remove. */
safef(colName, sizeof(colName), "%s", match + strlen(prefix));
if (endsWith(colName, "__filename"))
{
int newLen = strlen(colName) - strlen("__filename");
colName[newLen] = 0;
}
return findNamedColumn(colName);
}
static char *keyFileName(struct column *col)
/* Return key file name for this column. Return
* NULL if no key file. */
{
char *fileName = advFilterVal(col, "keyFile");
if (fileName == NULL)
return NULL;
if (!fileExists(fileName))
{
cartRemove(cart, advFilterName(col, "keyFile"));
return NULL;
}
return fileName;
}
struct slName *keyFileList(struct column *col)
/* Make up list from key file for this column.
* return NULL if no key file. */
{
char *fileName = keyFileName(col);
char *buf;
struct slName *list;
if (fileName == NULL)
return NULL;
readInGulp(fileName, &buf, NULL);
list = stringToSlNames(buf);
freez(&buf);
return list;
}
static struct hash *upcHashWordsInFile(char *fileName, int hashSize)
/* Create a hash of space delimited uppercased words in file. */
{
struct hash *hash = newHash(hashSize);
struct lineFile *lf = lineFileOpen(fileName, TRUE);
char *line, *word;
while (lineFileNext(lf, &line, NULL))
{
while ((word = nextQuotedWord(&line)) != NULL)
{
touppers(word);
hashAdd(hash, word, NULL);
}
}
lineFileClose(&lf);
return hash;
}
struct hash *keyFileHash(struct column *col)
/* Make up a hash from key file for this column.
* Return NULL if no key file. */
{
char *fileName = keyFileName(col);
if (fileName == NULL)
return NULL;
return upcHashWordsInFile(fileName, 16);
}
char *cellLookupVal(struct column *col, struct genePos *gp,
struct sqlConnection *conn)
/* Get a field in a table defined by col->table, col->keyField,
* col->valField. If an xrefLookup is specified in col->settings,
* use that to look up an alternate name for the result. */
{
char *xrefDb = hashFindVal(col->settings, "xrefDb");
char *xrefTable = hashFindVal(col->settings, "xrefTable");
char *xrefNameField = hashFindVal(col->settings, "xrefNameField");
char *xrefAliasField = hashFindVal(col->settings, "xrefAliasField");
char query[1024];
if (xrefDb)
safef(query, sizeof(query),
"select %s.%s.%s "
"from %s.%s, %s "
"where %s.%s = '%s' "
"and %s.%s = %s.%s.%s;",
xrefDb, xrefTable, xrefAliasField,
xrefDb, xrefTable, col->table,
col->table, col->keyField, gp->name,
col->table, col->valField, xrefDb, xrefTable, xrefNameField);
else
safef(query, sizeof(query), "select %s from %s where %s = '%s'",
col->valField, col->table, col->keyField, gp->name);
return sqlQuickString(conn, query);
}
char *lookupItemUrlVal(struct column *col, char *sVal,
struct sqlConnection *conn)
{
char query[512];
safef(query, sizeof(query), col->itemUrlQuery, sVal);
return sqlQuickString(conn, query);
}
void cellSimplePrintExt(struct column *col, struct genePos *gp,
struct sqlConnection *conn, boolean lookupForUrl)
/* This just prints one field from table. */
{
char *s = col->cellVal(col, gp, conn);
hPrintf("
");
}
void cellSimplePrint(struct column *col, struct genePos *gp,
struct sqlConnection *conn)
/* This just prints one field from table. */
{
cellSimplePrintExt(col, gp, conn, TRUE);
}
void cellSimplePrintNoLookupUrl(struct column *col, struct genePos *gp,
struct sqlConnection *conn)
/* This just prints one field from table using gp->name for
* itemUrl. */
{
cellSimplePrintExt(col, gp, conn, FALSE);
}
static void hPrintSpaces(int count)
/* Print count number of spaces. */
{
while (--count >= 0)
hPrintf(" ");
}
char *colInfoUrl(struct column *col)
/* Return URL to get column info. freeMem this when done. */
{
char *labelUrl;
if ((labelUrl = columnSetting(col, "labelUrl", NULL)) != NULL)
return labelUrl;
else
{
char url[512];
char *encoded = cgiEncode(col->name);
safef(url, sizeof(url), "../cgi-bin/hgNear?%s&%s=%s",
cartSidUrlString(cart), colInfoVarName, encoded);
freeMem(encoded);
return cloneString(url);
}
}
void colInfoAnchor(struct column *col)
/* Print anchor tag that leads to column info page. */
{
char *url = colInfoUrl(col);
hPrintf("", url);
freeMem(url);
}
void colInfoLink(struct column *col)
/* Print link to column. */
{
colInfoAnchor(col);
hPrintf("%s", col->shortLabel);
}
void labelSimplePrint(struct column *col)
/* This just prints cell->shortLabel. If colWidth is
* set it will add spaces, center justifying it. */
{
int colWidth = columnSettingInt(col, "colWidth", 0);
hPrintf("
");
/* The
above helps Internet Explorer avoid wrapping
* in the label column, which helps us avoid wrapping in
* the data columns below. Wrapping in the data columns
* makes the expression display less effective so we try
* to minimize it. -jk */
if (colWidth == 0)
{
colInfoLink(col);
}
else
{
int labelLen = strlen(col->shortLabel);
int diff = colWidth - labelLen;
if (diff < 0) diff = 0;
colInfoLink(col);
hPrintSpaces(diff);
}
hPrintf("