# HG changeset patch # User Matti Hamalainen # Date 1455542657 -7200 # Node ID 36552c7d71711c47d23be9783842fc31c84f7036 # Parent 9a0aeb9ce9bafea23c2669613c32597366bd8708# Parent d062312ea8505634a420222a0a8b43b3885ebfbe Merged. diff -r 9a0aeb9ce9ba -r 36552c7d7171 sidinfo.c --- a/sidinfo.c Mon Feb 15 07:00:22 2016 +0200 +++ b/sidinfo.c Mon Feb 15 15:24:17 2016 +0200 @@ -1,6 +1,6 @@ /* * SIDInfo - PSID/RSID information displayer - * Written by Matti 'ccr' Hämäläinen + * Written by Matti 'ccr' Hämäläinen * (C) Copyright 2014-2016 Tecnic Software productions (TNSP) */ #include "th_args.h" @@ -12,35 +12,11 @@ // Some constants #define SET_SLDB_FILENAME "Songlengths.txt" - -// Flags for various information fields enum { - SIF_NONE = 0, - - SIF_TYPE = 0x00000001, - SIF_VERSION = 0x00000002, - SIF_DATA_OFFS = 0x00000004, - SIF_LOAD_ADDR = 0x00000008, - SIF_INIT_ADDR = 0x00000010, - SIF_PLAY_ADDR = 0x00000020, - SIF_SONGS = 0x00000040, - SIF_START_SONG = 0x00000080, - SIF_SPEEDS = 0x00000100, - SIF_SID_NAME = 0x00000200, - SIF_SID_AUTHOR = 0x00000400, - SIF_SID_COPYRIGHT = 0x00000800, - SIF_PLAYER_TYPE = 0x00001000, - SIF_PLAYSID_TUNE = 0x00002000, - SIF_VIDEO_CLOCK = 0x00004000, - SIF_SID_MODEL = 0x00008000, - SIF_SONGLENGTHS = 0x00010000, - - SIF_DATA_SIZE = 0x00100000, - SIF_HASH = 0x00200000, - SIF_FILENAME = 0x01000000, - - SIF_ALL = 0x0fffffff, + OTYPE_OTHER = 0, + OTYPE_STR = 1, + OTYPE_INT = 2, }; @@ -49,6 +25,7 @@ int cmd; char *str; char chr; + int flags; } PSFStackItem; @@ -61,40 +38,39 @@ typedef struct { - uint32_t flag; char *name; char *lname; + int type; } PSFOption; -static const PSFOption optPSFlags[] = +static const PSFOption optPSOptions[] = { - { SIF_FILENAME , "Filename" , NULL }, - { SIF_TYPE , "Type" , NULL }, - { SIF_VERSION , "Version" , NULL }, - { SIF_PLAYER_TYPE , "PlayerType" , "Player type" }, - { SIF_PLAYSID_TUNE , "PlayerCompat", "Player compatibility" }, - { SIF_VIDEO_CLOCK , "VideoClock" , "Video clock speed" }, - { SIF_SID_MODEL , "SIDModel" , "SID model" }, + { "Filename" , NULL , OTYPE_STR }, + { "Type" , NULL , OTYPE_STR }, + { "Version" , NULL , OTYPE_STR }, + { "PlayerType" , "Player type" , OTYPE_STR }, + { "PlayerCompat" , "Player compatibility" , OTYPE_STR }, + { "VideoClock" , "Video clock speed" , OTYPE_STR }, + { "SIDModel" , "SID model" , OTYPE_STR }, - { SIF_DATA_OFFS , "DataOffs" , "Data offset" }, - { SIF_DATA_SIZE , "DataSize" , "Data size" }, - { SIF_LOAD_ADDR , "LoadAddr" , "Load address" }, - { SIF_INIT_ADDR , "InitAddr" , "Init address" }, - { SIF_PLAY_ADDR , "PlayAddr" , "Play address" }, - { SIF_SONGS , "Songs" , "Songs" }, - { SIF_START_SONG , "StartSong" , "Start song" }, - { SIF_SID_NAME , "Name" , NULL }, - { SIF_SID_AUTHOR , "Author" , NULL }, - { SIF_SID_COPYRIGHT , "Copyright" , NULL }, - { SIF_HASH , "Hash" , NULL }, + { "DataOffs" , "Data offset" , OTYPE_INT }, + { "DataSize" , "Data size" , OTYPE_INT }, + { "LoadAddr" , "Load address" , OTYPE_INT }, + { "InitAddr" , "Init address" , OTYPE_INT }, + { "PlayAddr" , "Play address" , OTYPE_INT }, + { "Songs" , "Songs" , OTYPE_INT }, + { "StartSong" , "Start song" , OTYPE_INT }, - { SIF_SONGLENGTHS , "Songlengths", "Song lengths" }, + { "Name" , NULL , OTYPE_STR }, + { "Author" , NULL , OTYPE_STR }, + { "Copyright" , NULL , OTYPE_STR }, + { "Hash" , NULL , OTYPE_OTHER }, - { SIF_ALL , "All" , NULL }, + { "Songlengths" , "Song lengths" , OTYPE_OTHER }, }; -static const int noptPSFlags = sizeof(optPSFlags) / sizeof(optPSFlags[0]); +static const int noptPSOptions = sizeof(optPSOptions) / sizeof(optPSOptions[0]); // Option variables @@ -103,9 +79,9 @@ BOOL optParsable = FALSE, optNoNamePrefix = FALSE, optHexadecimal = FALSE, - optOneLine = FALSE; + optOneLine = FALSE, + optFieldOutput = TRUE; char *optFieldSep = NULL; -uint32_t optFields = SIF_ALL; int optNFiles = 0; PSFStack optFormat; @@ -141,16 +117,16 @@ "\n" "Available fields:\n"); - for (len = index = 0; index < noptPSFlags; index++) + for (len = index = 0; index < noptPSOptions; index++) { - const PSFOption *opt = &optPSFlags[index]; + const PSFOption *opt = &optPSOptions[index]; len += strlen(opt->name) + 3; if (len >= 72) { printf("\n"); len = 0; } - printf("%s%s", opt->name, (index < noptPSFlags - 1) ? ", " : "\n\n"); + printf("%s%s", opt->name, (index < noptPSOptions - 1) ? ", " : "\n\n"); } printf( @@ -169,9 +145,9 @@ int argMatchPSField(const char *field) { int index, found = -1; - for (index = 0; index < noptPSFlags; index++) + for (index = 0; index < noptPSOptions; index++) { - const PSFOption *opt = &optPSFlags[index]; + const PSFOption *opt = &optPSOptions[index]; if (th_strcasecmp(opt->name, field) == 0) { if (found >= 0) @@ -201,25 +177,6 @@ } -BOOL argParsePSField(char *opt, char *end, uint32_t *fields) -{ - // Trim whitespace - if (end != NULL) - while (end > opt && *end && th_isspace(*end)) end--; - - while (*opt && th_isspace(*opt)) opt++; - - // Match field name - char *field = (end != NULL) ? th_strndup(opt, end - opt) : th_strdup(opt); - int found = argMatchPSFieldError(field); - if (found >= 0) - *fields |= optPSFlags[found].flag; - - th_free(field); - return FALSE; -} - - BOOL siStackAddItem(PSFStack *stack, const PSFStackItem *item) { if (stack->items == NULL || stack->nitems + 1 >= stack->nallocated) @@ -257,6 +214,40 @@ } +BOOL argParsePSFields(PSFStack *stack, const char *fmt) +{ + const char *start = fmt; + siClearStack(stack); + + while (*start) + { + PSFStackItem item; + const char *end = strchr(start, ','); + char *field = (end != NULL) ? + th_strndup_trim(start, end - start, TH_TRIM_BOTH) : + th_strdup_trim(start, TH_TRIM_BOTH); + + int found = argMatchPSFieldError(field); + th_free(field); + + if (found < 0) + return FALSE; + + item.cmd = found; + item.str = NULL; + if (!siStackAddItem(stack, &item)) + return FALSE; + + if (!end) + break; + + start = end + 1; + } + + return TRUE; +} + + // // Parse a format string into a PSFStack structure // @@ -265,6 +256,7 @@ PSFStackItem item; const char *start = NULL; int mode = 0; + BOOL rval = TRUE; siClearStack(stack); @@ -298,19 +290,18 @@ } else { - char *field = th_strndup(start, fmt - start); + char *field = th_strndup_trim(start, fmt - start, TH_TRIM_BOTH); int ret = argMatchPSFieldError(field); + th_free(field); if (ret >= 0) { item.cmd = ret; item.str = NULL; if (!siStackAddItem(stack, &item)) - { - th_free(field); return FALSE; - } } - th_free(field); + else + rval = FALSE; } mode = 0; } @@ -335,7 +326,7 @@ break; } - return TRUE; + return rval; } @@ -357,23 +348,8 @@ break; case 3: - { - char *start = optArg; - optFields = SIF_NONE; - - while (*start) - { - char *end = strchr(start, ','); - - if (!argParsePSField(start, end, &optFields)) - return FALSE; - - if (!end) - break; - - start = end + 1; - } - } + if (!argParsePSFields(&optFormat, optArg)) + return FALSE; break; case 4: @@ -390,6 +366,7 @@ break; case 7: + optFieldOutput = FALSE; if (!argParsePSFormatStr(&optFormat, optArg)) return FALSE; break; @@ -435,44 +412,42 @@ static void siPrintFieldPrefix(FILE *outFile, const PSFOption *opt) { const char *name = (optParsable || opt->lname == NULL) ? opt->name : opt->lname; - if (!optNoNamePrefix && !optFormat.nitems) + if (!optNoNamePrefix && optFieldOutput) fprintf(outFile, optParsable ? "%s=" : "%-20s : ", name); } static void siPrintFieldSeparator(FILE *outFile) { - if (!optFormat.nitems) + if (optFieldOutput) fputs(optOneLine ? optFieldSep : "\n", outFile); } static void siPrintPSIDInfoLine(FILE *outFile, BOOL *shown, const int xindex, const char *xfmt, const char *xaltfmt, ...) { - const PSFOption *opt = &optPSFlags[xindex]; - if (optFormat.nitems || (optFields & opt->flag)) - { - va_list ap; - const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; + const PSFOption *opt = &optPSOptions[xindex]; + va_list ap; + const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; - siPrintFieldPrefix(outFile, opt); + siPrintFieldPrefix(outFile, opt); - va_start(ap, xaltfmt); - vfprintf(outFile, fmt, ap); - va_end(ap); + va_start(ap, xaltfmt); + vfprintf(outFile, fmt, ap); + va_end(ap); - siPrintFieldSeparator(outFile); - *shown = TRUE; - } + siPrintFieldSeparator(outFile); + *shown = TRUE; } #define PR(xfmt, xaltfmt, ...) siPrintPSIDInfoLine(outFile, shown, xindex, xfmt, xaltfmt, __VA_ARGS__ ) -static void siPrintPSIDInformationField(FILE *outFile, const char *filename, const PSIDHeader *psid, BOOL *shown, const int xindex) +static void siPrintPSIDInformationField(FILE *outFile, const char *filename, const PSIDHeader *psid, BOOL *shown, const PSFStackItem *item) { - switch (xindex) + const PSFOption *opt = &optPSOptions[item->cmd]; + switch (item->cmd) { case 0: PR("%s", NULL, filename); break; case 1: PR("%s", NULL, psid->magic); break; @@ -503,38 +478,25 @@ case 16: PR("%s", NULL, psid->sidCopyright); break; case 17: - { - const PSFOption *opt = &optPSFlags[xindex]; - if (optFormat.nitems || (optFields & opt->flag)) - { - siPrintFieldPrefix(outFile, opt); - th_md5_print(outFile, psid->hash); - siPrintFieldSeparator(outFile); - } - } + siPrintFieldPrefix(outFile, opt); + th_md5_print(outFile, psid->hash); + siPrintFieldSeparator(outFile); break; case 18: + siPrintFieldPrefix(outFile, opt); + if (psid->lengths != NULL) { - const PSFOption *opt = &optPSFlags[xindex]; - if (optFormat.nitems || (optFields & opt->flag)) + int i; + for (i = 0; i < psid->lengths->nlengths; i++) { - siPrintFieldPrefix(outFile, opt); - if (psid->lengths != NULL) - { - int i; - for (i = 0; i < psid->lengths->nlengths; i++) - { - int len = psid->lengths->lengths[i]; - fprintf(outFile, "%d:%d%s", len / 60, len % 60, - (i < psid->lengths->nlengths - 1) ? " " : ""); - } - } - siPrintFieldSeparator(outFile); + int len = psid->lengths->lengths[i]; + fprintf(outFile, "%d:%d%s", len / 60, len % 60, + (i < psid->lengths->nlengths - 1) ? " " : ""); } } + siPrintFieldSeparator(outFile); break; - } } @@ -568,32 +530,27 @@ psid.lengths = si_sldb_get_by_hash(sidSLDB, psid.hash); // Output - if (optFormat.nitems) + for (index = 0; index < optFormat.nitems; index++) { - for (index = 0; index < optFormat.nitems; index++) + PSFStackItem *item = &optFormat.items[index]; + switch (item->cmd) { - PSFStackItem *item = &optFormat.items[index]; - switch (item->cmd) - { - case -1: - siPrintStrEscapes(outFile, item->str); - break; + case -1: + siPrintStrEscapes(outFile, item->str); + break; - case -2: - fputc(item->chr, outFile); - break; + case -2: + fputc(item->chr, outFile); + break; - default: - siPrintPSIDInformationField(outFile, filename, &psid, &shown, item->cmd); - break; - } + default: + siPrintPSIDInformationField(outFile, filename, &psid, &shown, item); + break; } } - else + + if (optFieldOutput) { - for (index = 0; index < noptPSFlags - 1; index++) - siPrintPSIDInformationField(outFile, filename, &psid, &shown, index); - if (shown && optOneLine) fprintf(outFile, "\n"); } @@ -624,6 +581,19 @@ optParsable = FALSE; optNoNamePrefix = TRUE; } + + if (optFieldOutput && !optFormat.nitems) + { + PSFStackItem item; + int i; + memset(&item, 0, sizeof(item)); + siClearStack(&optFormat); + for (i = 0; i < noptPSOptions; i++) + { + item.cmd = i; + siStackAddItem(&optFormat, &item); + } + } // Check paths if (setHVSCPath != NULL) @@ -635,29 +605,39 @@ if (setSLDBPath != NULL) { // Initialize SLDB - int ret; - th_ioctx *ctx; + int ret = THERR_OK; + th_ioctx *ctx = NULL; if ((ctx = th_io_fopen(&th_stdio_io_ops, setSLDBPath, "r")) == NULL) { - THERR("Could not open SLDB '%s'.\n", setSLDBPath); - goto out; + THERR("Could not open SLDB '%s'.\n", + setSLDBPath); + goto err; } - if ((sidSLDB = si_sldb_new()) == NULL || - si_sldb_read(ctx, sidSLDB) != THERR_OK) + THMSG(1, "Reading SLDB.\n"); + if ((sidSLDB = si_sldb_new()) == NULL) { - THERR("Error parsing SLDB.\n"); - th_io_close(ctx); - goto out; + THERR("Could not allocate SLDB structure!\n"); + goto err; + } + + if ((ret = si_sldb_read(ctx, sidSLDB)) != THERR_OK) + { + THERR("Error parsing SLDB: %d, %s\n", + ret, th_error_str(ret)); + goto err; } th_io_close(ctx); if ((ret = si_sldb_build_index(sidSLDB)) != THERR_OK) { - THERR("Error building SLDB index: %s.\n", - th_error_str(ret)); - goto out; + THERR("Error building SLDB index: %d, %s.\n", + ret, th_error_str(ret)); + goto err; } + +err: + th_io_close(ctx); } // Process files