80c13ab201d59baa021d5c1a2222872ecbdf196f hiram Fri Feb 8 16:17:16 2019 -0800 now using functions in src/lib/jsonWrite.c refs #18869 #22859 diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c index 8b6078c..1639d99 100644 --- src/hg/hubApi/hubApi.c +++ src/hg/hubApi/hubApi.c @@ -12,30 +12,31 @@ #include "udc.h" #include "knetUdc.h" #include "genbank.h" #include "trackHub.h" #include "hgConfig.h" #include "hCommon.h" #include "hPrint.h" #include "bigWig.h" #include "hubConnect.h" #include "obscure.h" #include "errCatch.h" #include "vcf.h" #include "bedTabix.h" #include "bamFile.h" #include "jsonParse.h" +#include "jsonWrite.h" #include "chromInfo.h" #ifdef USE_HAL #include "halBlockViz.h" #endif /* +------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------------+------------------+------+-----+---------+-------+ | hubUrl | longblob | NO | PRI | NULL | | | shortLabel | varchar(255) | NO | | NULL | | | longLabel | varchar(255) | NO | | NULL | | | registrationTime | varchar(255) | NO | | NULL | | | dbCount | int(10) unsigned | NO | | NULL | | @@ -64,96 +65,93 @@ static long totalTracks = 0; static boolean measureTiming = FALSE; /* set by CGI parameters */ static boolean allTrackSettings = FALSE; /* checkbox setting */ static char **shortLabels = NULL; /* public hub short labels in array */ struct hubPublic *publicHubList = NULL; static int publicHubCount = 0; static char *defaultHub = "Plants"; static char *defaultDb = "ce11"; static long enteredMainTime = 0; /* will become = clock1000() on entry */ /* to allow calculation of when to bail out, taking too long */ static long timeOutSeconds = 100; static boolean timedOut = FALSE; /* ######################################################################### */ +#ifdef NOT static void jsonInteger(FILE *f, char *tag, long long value) /* output one json interger: "tag":value appropriately quoted and encoded */ { fprintf(f,"\"%s\":%lld",tag, value); } +#endif static void jsonStringPrint(FILE *f, char *value) /* escape string for output */ { char *a = jsonStringEscape(value); if (isEmpty(a)) fprintf(f, "%s", "null"); else fprintf(f, "\"%s\"", a); freeMem(a); } static void jsonTagValue(FILE *f, char *tag, char *value) /* output one json string: "tag":"value" appropriately quoted and encoded */ { fprintf(f,"\"%s\":",tag); jsonStringPrint(f, value); } -static void jsonStartOutput(FILE *f) +static struct jsonWrite *jsonStartOutput() /* begin json output */ { -fputc('{',f); -jsonTagValue(f, "source", "UCSantaCruz"); -fputc(',',f); +struct jsonWrite *jw = jsonWriteNew(); +jsonWriteObjectStart(jw, NULL); +jsonWriteString(jw, "source", "UCSantaCurz"); +return jw; } static void jsonErrAbort(char *format, ...) /* Issue an error message in json format. */ { char errMsg[2048]; va_list args; va_start(args, format); vsnprintf(errMsg, sizeof(errMsg), format, args); fputc('{',stdout); jsonTagValue(stdout, "error", errMsg); fputc('}',stdout); } -static void hubPublicJsonData(FILE *f, struct hubPublic *el) +static void hubPublicJsonData(struct jsonWrite *jw, struct hubPublic *el) /* Print array data for one row from hubPublic table, order here * must be same as was stated in the columnName header element * TODO: need to figure out how to use the order of the columns as * they are in the 'desc' request */ { -fputc('[',f); -jsonStringPrint(f, el->hubUrl); -fputc(',',f); -jsonStringPrint(f, el->shortLabel); -fputc(',',f); -jsonStringPrint(f, el->longLabel); -fputc(',',f); -jsonStringPrint(f, el->registrationTime); -fputc(',',f); -fprintf(f, "%lld", (long long)el->dbCount); -fputc(',',f); -jsonStringPrint(f, el->dbList); -fputc(',',f); -jsonStringPrint(f, el->descriptionUrl); -fputc(']',f); +jsonWriteListStart(jw, NULL); +jsonWriteString(jw, NULL, el->hubUrl); +jsonWriteString(jw, NULL, el->shortLabel); +jsonWriteString(jw, NULL, el->longLabel); +jsonWriteString(jw, NULL, el->registrationTime); +jsonWriteNumber(jw, NULL, (long long)el->dbCount); +jsonWriteString(jw, NULL, el->dbList); +jsonWriteString(jw, NULL, el->descriptionUrl); +jsonWriteListEnd(jw); } #ifdef NOT /* This function should be in hg/lib/hubPublic.c */ static void hubPublicJsonOutput(FILE *f, struct hubPublic *el) /* Print out hubPublic element in JSON format. */ { fputc('{',f); jsonTagValue(f, "hubUrl", el->hubUrl); fputc(',',f); jsonTagValue(f, "shortLabel", el->shortLabel); fputc(',',f); jsonTagValue(f, "longLabel", el->longLabel); fputc(',',f); jsonTagValue(f, "registrationTime", el->registrationTime); @@ -535,66 +533,53 @@ static char *urlFromShortLabel(char *shortLabel) { char hubUrl[1024]; char query[1024]; struct sqlConnection *conn = hConnectCentral(); // Build a query to select the hubUrl for the given shortLabel sqlSafef(query, sizeof(query), "select hubUrl from %s where shortLabel='%s'", hubPublicTableName(), shortLabel); if (! sqlQuickQuery(conn, query, hubUrl, sizeof(hubUrl))) hubUrl[0] = 0; hDisconnectCentral(&conn); return cloneString(hubUrl); } -static void dbDbJsonData(FILE *f, struct dbDb *el) +static void dbDbJsonData(struct jsonWrite *jw, struct dbDb *el) /* Print out dbDb table element in JSON format. * must be same as was stated in the columnName header element * TODO: need to figure out how to use the order of the columns as * they are in the 'desc' request */ { -fputc('[',f); -jsonStringPrint(f, el->name); -fputc(',',f); -jsonStringPrint(f, el->description); -fputc(',',f); -jsonStringPrint(f, el->nibPath); -fputc(',',f); -jsonStringPrint(f, el->organism); -fputc(',',f); -jsonStringPrint(f, el->defaultPos); -fputc(',',f); -fprintf(f, "%lld", (long long)el->active); -fputc(',',f); -fprintf(f, "%lld", (long long)el->orderKey); -fputc(',',f); -jsonStringPrint(f, el->genome); -fputc(',',f); -jsonStringPrint(f, el->scientificName); -fputc(',',f); -jsonStringPrint(f, el->htmlPath); -fputc(',',f); -fprintf(f, "%lld", (long long)el->hgNearOk); -fputc(',',f); -fprintf(f, "%lld", (long long)el->hgPbOk); -fputc(',',f); -jsonStringPrint(f, el->sourceName); -fputc(',',f); -fprintf(f, "%lld", (long long)el->taxId); -fputc(']',f); +jsonWriteListStart(jw, NULL); +jsonWriteString(jw, NULL, el->name); +jsonWriteString(jw, NULL, el->description); +jsonWriteString(jw, NULL, el->nibPath); +jsonWriteString(jw, NULL, el->organism); +jsonWriteString(jw, NULL, el->defaultPos); +jsonWriteNumber(jw, NULL, (long long)el->active); +jsonWriteNumber(jw, NULL, (long long)el->orderKey); +jsonWriteString(jw, NULL, el->genome); +jsonWriteString(jw, NULL, el->scientificName); +jsonWriteString(jw, NULL, el->htmlPath); +jsonWriteNumber(jw, NULL, (long long)el->hgNearOk); +jsonWriteNumber(jw, NULL, (long long)el->hgPbOk); +jsonWriteString(jw, NULL, el->sourceName); +jsonWriteNumber(jw, NULL, (long long)el->taxId); +jsonWriteListEnd(jw); } #ifdef NOT /* this code should be in hg/lib/dbDb.c */ static void dbDbJsonOutput(FILE *f, struct dbDb *el) /* Print out hubPublic element in JSON format. */ { fputc('{',f); jsonTagValue(f, "name", el->name); fputc(',',f); jsonTagValue(f, "description", el->description); fputc(',',f); jsonTagValue(f, "nibPath", el->nibPath); fputc(',',f); jsonTagValue(f, "organism", el->organism); @@ -610,74 +595,69 @@ jsonTagValue(f, "scientificName", el->scientificName); fputc(',',f); jsonTagValue(f, "htmlPath", el->htmlPath); fputc(',',f); jsonInteger(f, "hgNearOk", el->hgNearOk); fputc(',',f); jsonInteger(f, "hgPbOk", el->hgPbOk); fputc(',',f); jsonTagValue(f, "sourceName", el->sourceName); fputc(',',f); jsonInteger(f, "taxId", el->taxId); fputc('}',f); } #endif -static boolean tableColumns(FILE *f, char *table) +static boolean tableColumns(struct jsonWrite *jw, char *table) /* output the column names for the given table * return: TRUE on error, FALSE on success */ { -fprintf(f, "\"columnNames\":["); +jsonWriteListStart(jw, "columnNames"); char query[1024]; struct sqlConnection *conn = hConnectCentral(); sqlSafef(query, sizeof(query), "desc %s", table); struct sqlResult *sr = sqlGetResult(conn, query); char **row; row = sqlNextRow(sr); if (NULL == row) { jsonErrAbort("ERROR: can not 'desc' table '%s'\n", table); return TRUE; } -fprintf(f, "\"%s\"",row[0]); -while (row != NULL) - { - row = sqlNextRow(sr); - if (row) - fprintf(f, ",\"%s\"",row[0]); - } +while ((row = sqlNextRow(sr)) != NULL) + jsonWriteString(jw, NULL, row[0]); sqlFreeResult(&sr); hDisconnectCentral(&conn); -fprintf(f, "],"); +jsonWriteListEnd(jw); return FALSE; } static void jsonPublicHubs() /* output the hubPublic SQL table */ { struct hubPublic *el = publicHubList; -jsonStartOutput(stdout); -tableColumns(stdout, hubPublicTableName()); -printf("\"publicHubData\":["); +struct jsonWrite *jw = jsonStartOutput(); +tableColumns(jw, hubPublicTableName()); +jsonWriteListStart(jw, "publicHubData"); for ( ; el != NULL; el = el->next ) { - hubPublicJsonData(stdout, el); - if (el->next) - printf(","); + hubPublicJsonData(jw, el); } -printf("]}\n"); +jsonWriteListEnd(jw); +jsonWriteObjectEnd(jw); +fputs(jw->dy->string,stdout); } static int dbDbCmpName(const void *va, const void *vb) /* Compare two dbDb elements: name, ignore case. */ { const struct dbDb *a = *((struct dbDb **)va); const struct dbDb *b = *((struct dbDb **)vb); return strcasecmp(a->name, b->name); } static struct dbDb *ucscDbDb() /* return the dbDb table as an slList */ { char query[1024]; struct sqlConnection *conn = hConnectCentral(); @@ -689,198 +669,183 @@ { el = dbDbLoad(row); slAddHead(&dbList, el); } sqlFreeResult(&sr); hDisconnectCentral(&conn); slSort(&dbList, dbDbCmpName); return dbList; } static void jsonDbDb() /* output the dbDb SQL table */ { struct dbDb *dbList = ucscDbDb(); struct dbDb *el; -jsonStartOutput(stdout); -tableColumns(stdout, "dbDb"); -printf("\"ucscGenomes\":["); +struct jsonWrite *jw = jsonStartOutput(); +tableColumns(jw, "dbDb"); +jsonWriteListStart(jw, "ucscGenomes"); for ( el=dbList; el != NULL; el = el->next ) { - dbDbJsonData(stdout, el); - if (el->next) - printf(","); + dbDbJsonData(jw, el); } -printf("]}\n"); +jsonWriteListEnd(jw); +jsonWriteObjectEnd(jw); +fputs(jw->dy->string,stdout); } static void chromInfoJsonOutput(FILE *f, char *db) /* for given db, if there is a track, list the chromosomes in that track, * for no track, simply list the chromosomes in the sequence */ { char *track = cgiOptionalString("track"); if (track) { struct sqlConnection *conn = hAllocConn(db); if (! sqlTableExists(conn, track)) jsonErrAbort("ERROR: endpoint: /list/chromosomes?db=%&table=%s ERROR table does not exist", db, track); if (sqlColumnExists(conn, track, "chrom")) { - jsonStartOutput(f); - jsonTagValue(f, "genome", db); - fputc(',',f); - jsonTagValue(f, "track", track); - fputc(',',f); + struct jsonWrite *jw = jsonStartOutput(); + jsonWriteString(jw, "genome", db); + jsonWriteString(jw, "track", track); struct slPair *list = NULL; char query[2048]; sqlSafef(query, sizeof(query), "select distinct chrom from %s", track); struct sqlResult *sr = sqlGetResult(conn, query); char **row; while ((row = sqlNextRow(sr)) != NULL) { int size = hChromSize(db, row[0]); slAddHead(&list, slPairNew(row[0], intToPt(size))); } sqlFreeResult(&sr); slPairIntSort(&list); slReverse(&list); - jsonInteger(f, "chromCount", slCount(list)); - fputc(',',f); + jsonWriteNumber(jw, "chromCount", (long long)slCount(list)); struct slPair *el = list; for ( ; el != NULL; el = el->next ) - { - jsonInteger(f, el->name, ptToInt(el->val)); - if (el->next) - fputc(',',f); - } - fputc('}',f); + jsonWriteNumber(jw, el->name, (long long)ptToInt(el->val)); + jsonWriteObjectEnd(jw); + fputs(jw->dy->string,stdout); } else { jsonErrAbort("ERROR: table '%s' is not a position table, no chromosomes for genome: '%s'", track, db); } hFreeConn(&conn); } else { struct chromInfo *ciList = createChromInfoList(NULL, db); struct chromInfo *el = ciList; - jsonStartOutput(f); - jsonTagValue(f, "genome", db); - fputc(',',f); - jsonInteger(f, "chromCount", slCount(ciList)); - fputc(',',f); + struct jsonWrite *jw = jsonStartOutput(); + jsonWriteString(jw, "genome", db); + jsonWriteNumber(jw, "chromCount", (long long)slCount(ciList)); for ( ; el != NULL; el = el->next ) { - jsonInteger(f, el->chrom, el->size); - if (el->next) - fputc(',',f); + jsonWriteNumber(jw, el->chrom, (long long)el->size); } - fputc('}',f); + jsonWriteObjectEnd(jw); + fputs(jw->dy->string,stdout); } } static void trackDbJsonOutput(char *db, FILE *f) /* return track list from specified UCSC database name */ { struct trackDb *tdbList = hTrackDb(db); struct trackDb *el; -jsonStartOutput(f); -jsonTagValue(f, "db", db); -fputc(',',f); -fprintf(f, "\"tracks\":["); +struct jsonWrite *jw = jsonStartOutput(); +jsonWriteString(jw, "db", db); +jsonWriteListStart(jw, "tracks"); for (el = tdbList; el != NULL; el = el->next ) - { - jsonStringPrint(f, el->track); - if (el->next) - fputc(',',f); - } -fprintf(f, "]}\n"); + jsonWriteString(jw, NULL, el->track); +jsonWriteListEnd(jw); +jsonWriteObjectEnd(jw); +fputs(jw->dy->string,stdout); } /* static void trackDbJsonOutput(char *db, FILE *f) */ #define MAX_PATH_INFO 32 static void apiList(char *words[MAX_PATH_INFO]) /* 'list' function words[1] is the subCommand */ { if (sameWord("publicHubs", words[1])) jsonPublicHubs(); else if (sameWord("ucscGenomes", words[1])) jsonDbDb(); else if (sameWord("hubGenomes", words[1])) { char *hubUrl = cgiOptionalString("hubUrl"); if (isEmpty(hubUrl)) jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes\n"); struct trackHub *hub = trackHubOpen(hubUrl, ""); if (hub->genomeList) { - jsonStartOutput(stdout); - jsonTagValue(stdout, "hubUrl", hubUrl); - fputc(',',stdout); - printf("\"genomes\":["); + struct jsonWrite *jw = jsonStartOutput(); + jsonWriteString(jw, "hubUrl", hubUrl); + jsonWriteListStart(jw, "genomes"); struct slName *theList = genomeList(hub, NULL, NULL); slNameSort(&theList); struct slName *el = theList; for ( ; el ; el = el->next ) { - jsonStringPrint(stdout, el->name); - if (el->next) - fputc(',',stdout); + jsonWriteString(jw, NULL, el->name); } - printf("]}\n"); + jsonWriteListEnd(jw); + jsonWriteObjectEnd(jw); + fputs(jw->dy->string,stdout); } } else if (sameWord("tracks", words[1])) { char *hubUrl = cgiOptionalString("hubUrl"); char *genome = cgiOptionalString("genome"); char *db = cgiOptionalString("db"); if (isEmpty(hubUrl) && isEmpty(db)) jsonErrAbort("ERROR: must supply hubUrl or db name to return track list"); if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database { trackDbJsonOutput(db, stdout); // only need db for this function return; } if (isEmpty(genome) || isEmpty(hubUrl)) { if (isEmpty(genome)) warn("# must supply genome='someName' the name of a genome in a hub for /list/tracks\n"); if (isEmpty(hubUrl)) jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes\n"); } struct trackHub *hub = trackHubOpen(hubUrl, ""); if (hub->genomeList) { struct slName *dbTrackList = NULL; (void) genomeList(hub, &dbTrackList, genome); - jsonStartOutput(stdout); - jsonTagValue(stdout, "hubUrl", hubUrl); - fputc(',',stdout); - jsonTagValue(stdout, "genome", genome); - fputc(',',stdout); + struct jsonWrite *jw = jsonStartOutput(); + jsonWriteString(jw, "hubUrl", hubUrl); + jsonWriteListStart(jw, "genome"); slNameSort(&dbTrackList); struct slName *el = dbTrackList; for ( ; el != NULL; el = el->next ) { - jsonStringPrint(stdout, el->name); - if (el->next) - fputc(',',stdout); + jsonWriteString(jw, NULL, el->name); } - printf("]}\n"); + jsonWriteListEnd(jw); + jsonWriteObjectEnd(jw); + fputs(jw->dy->string,stdout); } } else if (sameWord("chromosomes", words[1])) { char *hubUrl = cgiOptionalString("hubUrl"); // char *genome = cgiOptionalString("genome"); char *db = cgiOptionalString("db"); if (isEmpty(hubUrl) && isEmpty(db)) jsonErrAbort("ERROR: must supply hubUrl or db name to return chromosome list"); if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database { chromInfoJsonOutput(stdout, db); return; }