5e8e0ed53c05f2ef9b51ce897440bae308367f47 chmalee Wed Feb 9 14:45:54 2022 -0800 Add csv output option to table browser to support opening files in Excel, refs #27623. Also change the output filename message to hint that Excel can auto-recognize .csv extensions and behave appropriately. Lastly, fix output dropdown selection to properly warn on update when using GTF output option or a snp table. diff --git src/hg/hgTables/custom.c src/hg/hgTables/custom.c index 4a48f98..1b85598 100644 --- src/hg/hgTables/custom.c +++ src/hg/hgTables/custom.c @@ -256,42 +256,44 @@ hPrintf("%u,", bed->expIds[i]); } else if (sameString(type, "expScores")) { unsigned i; for (i=0; i<bed->expCount; ++i) hPrintf("%f,", bed->expScores[i]); } else errAbort("Unrecognized bed field %s", type); } hPrintf("\n"); } #endif /* UNUSED */ -static void tabBedRowFile(struct bed *bed, struct slName *fieldList, FILE *f) +static void tabBedRowFile(struct bed *bed, struct slName *fieldList, FILE *f, char outSep) /* Print out to a file named fields from bed. */ { struct slName *field; boolean needTab = FALSE; for (field = fieldList; field != NULL; field = field->next) { char *type = field->name; if (needTab) - fprintf(f, "\t"); + fprintf(f, "%c", outSep); else needTab = TRUE; + if (outSep == ',') + fputc('"', f); if (sameString(type, "chrom")) fprintf(f, "%s", bed->chrom); else if (sameString(type, "chromStart")) fprintf(f, "%u", bed->chromStart); else if (sameString(type, "chromEnd")) fprintf(f, "%u", bed->chromEnd); else if (sameString(type, "name")) fprintf(f, "%s", bed->name); else if (sameString(type, "score")) fprintf(f, "%d", bed->score); else if (sameString(type, "strand")) fprintf(f, "%s", bed->strand); else if (sameString(type, "thickStart")) fprintf(f, "%u", bed->thickStart); else if (sameString(type, "thickEnd")) @@ -320,30 +322,32 @@ fprintf(f, "%u", bed->expCount); else if (sameString(type, "expIds")) { unsigned i; for (i=0; i<bed->expCount; ++i) fprintf(f, "%u,", bed->expIds[i]); } else if (sameString(type, "expScores")) { unsigned i; for (i=0; i<bed->expCount; ++i) fprintf(f, "%f,", bed->expScores[i]); } else errAbort("Unrecognized bed field %s", type); + if (outSep == ',') + fputc('"', f); } fprintf(f, "\n"); } struct bedFilter *bedFilterForCustomTrack(char *ctName) /* If the user specified constraints, then translate them to a bedFilter. */ { struct hashEl *var, *varList = cartFindPrefix(cart, hgtaFilterVarPrefix); int prefixSize = strlen(hgtaFilterVarPrefix); struct bedFilter *bf = NULL; int *trash; for (var = varList; var != NULL; var = var->next) { char *dbTrackFieldType = cloneString(var->name + prefixSize); @@ -538,88 +542,90 @@ /* Grab filtered beds for each region. */ for (region = regionList; region != NULL; region = region->next) customTrackFilteredBedOnRegion(region, ct, idHash, bf, lm, &bedList); /* clean up. */ hashFree(&idHash); slReverse(&bedList); } if (retFieldCount != NULL) *retFieldCount = fieldCount; return bedList; } static void doTabOutBedLike(struct customTrack *ct, char *table, - struct sqlConnection *conn, char *fields, FILE *f) + struct sqlConnection *conn, char *fields, FILE *f, char outSep) /* Print out selected fields from a bed-like custom track. If fields * is NULL, then print out all fields. */ { struct region *regionList = getRegions(), *region; struct slName *chosenFields, *field; int count = 0; if (fields == NULL) chosenFields = getBedFields(ct->fieldCount); else chosenFields = commaSepToSlNames(fields); if (f == NULL) f = stdout; fprintf(f, "#"); for (field = chosenFields; field != NULL; field = field->next) { if (field != chosenFields) - fprintf(f, "\t"); + fprintf(f, "%c", outSep); + if (outSep == ',') fputc('"', f); fprintf(f, "%s", field->name); + if (outSep == ',') fputc('"', f); } fprintf(f, "\n"); for (region = regionList; region != NULL; region = region->next) { struct lm *lm = lmInit(64*1024); struct bed *bed, *bedList = cookedBedList(conn, table, region, lm, NULL); for (bed = bedList; bed != NULL; bed = bed->next) { - tabBedRowFile(bed, chosenFields, f); + tabBedRowFile(bed, chosenFields, f, outSep); ++count; } lmCleanup(&lm); } if (count == 0) explainWhyNoResults(f); } void doTabOutCustomTracks(char *db, char *table, struct sqlConnection *conn, - char *fields, FILE *f) + char *fields, FILE *f, char outSep) /* Print out selected fields from custom track. If fields * is NULL, then print out all fields. */ { struct customTrack *ct = ctLookupName(table); char *type = ct->tdb->type; if (startsWithWord("makeItems", type) || sameWord("bedDetail", type) || sameWord("barChart", type) || sameWord("interact", type) || sameWord("pgSnp", type)) { struct sqlConnection *conn = hAllocConn(CUSTOM_TRASH); - doTabOutDb(CUSTOM_TRASH, db, ct->dbTableName, table, f, conn, fields); + doTabOutDb(CUSTOM_TRASH, db, ct->dbTableName, table, f, conn, fields, outSep); hFreeConn(&conn); } else - doTabOutBedLike(ct, table, conn, fields, f); + doTabOutBedLike(ct, table, conn, fields, f, outSep); } void removeNamedCustom(struct customTrack **pList, char *name) /* Remove named custom track from list if it's on there. */ { struct customTrack *newList = NULL, *ct, *next; for (ct = *pList; ct != NULL; ct = next) { next = ct->next; if (!sameString(ct->tdb->table, name)) { slAddHead(&newList, ct); } }