Mercurial > hg > sidinfo
comparison sidinfo.c @ 89:d9cb7c635e7b
Implement initial SLDB support.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 12 Feb 2016 01:17:52 +0200 |
parents | 1e89b757f8a1 |
children | 2ab9ab4b59eb |
comparison
equal
deleted
inserted
replaced
88:c5ff71d64e53 | 89:d9cb7c635e7b |
---|---|
3 * Written by Matti 'ccr' Hämäläinen <ccr@tnsp.org> | 3 * Written by Matti 'ccr' Hämäläinen <ccr@tnsp.org> |
4 * (C) Copyright 2014-2016 Tecnic Software productions (TNSP) | 4 * (C) Copyright 2014-2016 Tecnic Software productions (TNSP) |
5 */ | 5 */ |
6 #include "th_args.h" | 6 #include "th_args.h" |
7 #include "th_string.h" | 7 #include "th_string.h" |
8 #include "th_file.h" | |
8 #include "sidlib.h" | 9 #include "sidlib.h" |
9 | 10 |
10 | 11 |
11 // Some constants | 12 // Some constants |
13 #define SET_SLDB_FILENAME "Songlengths.txt" | |
12 | 14 |
13 | 15 |
14 // Flags for various information fields | 16 // Flags for various information fields |
15 enum | 17 enum |
16 { | 18 { |
30 SIF_SID_COPYRIGHT = 0x00000800, | 32 SIF_SID_COPYRIGHT = 0x00000800, |
31 SIF_PLAYER_TYPE = 0x00001000, | 33 SIF_PLAYER_TYPE = 0x00001000, |
32 SIF_PLAYSID_TUNE = 0x00002000, | 34 SIF_PLAYSID_TUNE = 0x00002000, |
33 SIF_VIDEO_CLOCK = 0x00004000, | 35 SIF_VIDEO_CLOCK = 0x00004000, |
34 SIF_SID_MODEL = 0x00008000, | 36 SIF_SID_MODEL = 0x00008000, |
37 SIF_SONGLENGTHS = 0x00010000, | |
35 | 38 |
36 SIF_DATA_SIZE = 0x00100000, | 39 SIF_DATA_SIZE = 0x00100000, |
37 SIF_HASH = 0x00200000, | 40 SIF_HASH = 0x00200000, |
38 SIF_FILENAME = 0x01000000, | 41 SIF_FILENAME = 0x01000000, |
39 | 42 |
84 { SIF_SID_NAME , "Name" , NULL }, | 87 { SIF_SID_NAME , "Name" , NULL }, |
85 { SIF_SID_AUTHOR , "Author" , NULL }, | 88 { SIF_SID_AUTHOR , "Author" , NULL }, |
86 { SIF_SID_COPYRIGHT , "Copyright" , NULL }, | 89 { SIF_SID_COPYRIGHT , "Copyright" , NULL }, |
87 { SIF_HASH , "Hash" , NULL }, | 90 { SIF_HASH , "Hash" , NULL }, |
88 | 91 |
92 { SIF_SONGLENGTHS , "Songlengths", "Song lengths" }, | |
93 | |
89 { SIF_ALL , "All" , NULL }, | 94 { SIF_ALL , "All" , NULL }, |
90 }; | 95 }; |
91 | 96 |
92 static const int noptPSFlags = sizeof(optPSFlags) / sizeof(optPSFlags[0]); | 97 static const int noptPSFlags = sizeof(optPSFlags) / sizeof(optPSFlags[0]); |
93 | 98 |
94 | 99 |
95 // Option variables | 100 // Option variables |
101 char *setHVSCPath = NULL, | |
102 *setSLDBPath = NULL; | |
96 BOOL optParsable = FALSE, | 103 BOOL optParsable = FALSE, |
97 optNoNamePrefix = FALSE, | 104 optNoNamePrefix = FALSE, |
98 optHexadecimal = FALSE, | 105 optHexadecimal = FALSE, |
99 optOneLine = FALSE; | 106 optOneLine = FALSE; |
100 char *optFieldSep = NULL; | 107 char *optFieldSep = NULL; |
101 uint32_t optFields = SIF_ALL; | 108 uint32_t optFields = SIF_ALL; |
102 int optNFiles = 0; | 109 int optNFiles = 0; |
103 | 110 |
104 PSFStack optFormat; | 111 PSFStack optFormat; |
112 | |
113 SIDLibSLDB *sidSLDB = NULL; | |
105 | 114 |
106 | 115 |
107 // Define option arguments | 116 // Define option arguments |
108 static const th_optarg_t optList[] = | 117 static const th_optarg_t optList[] = |
109 { | 118 { |
113 { 5, 'n', "noprefix", "Output without field name prefix", OPT_NONE }, | 122 { 5, 'n', "noprefix", "Output without field name prefix", OPT_NONE }, |
114 { 6, 'l', "line", "Output in one line format, -l <field separator>", OPT_ARGREQ }, | 123 { 6, 'l', "line", "Output in one line format, -l <field separator>", OPT_ARGREQ }, |
115 { 3, 'f', "fields", "Show only specified field(s)", OPT_ARGREQ }, | 124 { 3, 'f', "fields", "Show only specified field(s)", OPT_ARGREQ }, |
116 { 4, 'x', "hex", "Use hexadecimal values", OPT_NONE }, | 125 { 4, 'x', "hex", "Use hexadecimal values", OPT_NONE }, |
117 { 7, 'F', "format", "Use given format string (see below)", OPT_ARGREQ }, | 126 { 7, 'F', "format", "Use given format string (see below)", OPT_ARGREQ }, |
127 { 8, 'H', "hvsc", "Specify path to HVSC documents directory", OPT_ARGREQ }, | |
128 { 9, 'S', "sldb", "Specify Songlengths.txt file (use -H if possible)", OPT_ARGREQ }, | |
118 }; | 129 }; |
119 | 130 |
120 static const int optListN = sizeof(optList) / sizeof(optList[0]); | 131 static const int optListN = sizeof(optList) / sizeof(optList[0]); |
121 | 132 |
122 | 133 |
146 "Example: %s -x -p -f hash,copyright somesidfile.sid\n" | 157 "Example: %s -x -p -f hash,copyright somesidfile.sid\n" |
147 "\n" | 158 "\n" |
148 "Format strings for '-F' option are composed of @fields@ that\n" | 159 "Format strings for '-F' option are composed of @fields@ that\n" |
149 "are expanded to their value. Also, escape sequences \\r, \\n and \\t\n" | 160 "are expanded to their value. Also, escape sequences \\r, \\n and \\t\n" |
150 "can be used: -F \"hash=@hash@\\ncopy=@copyright@\\n\"\n" | 161 "can be used: -F \"hash=@hash@\\ncopy=@copyright@\\n\"\n" |
162 "\n" | |
163 "When specifying HVSC path, it is preferable to use -H/--hvsc option,\n" | |
164 "as STIL.txt and Songlengths.txt will be automatically used from there.\n" | |
151 , th_prog_name); | 165 , th_prog_name); |
152 } | 166 } |
153 | 167 |
154 | 168 |
155 int argMatchPSField(const char *field) | 169 int argMatchPSField(const char *field) |
378 case 7: | 392 case 7: |
379 if (!argParsePSFormatStr(&optFormat, optArg)) | 393 if (!argParsePSFormatStr(&optFormat, optArg)) |
380 return FALSE; | 394 return FALSE; |
381 break; | 395 break; |
382 | 396 |
397 case 8: | |
398 setHVSCPath = th_strdup(optArg); | |
399 break; | |
400 | |
401 case 9: | |
402 setSLDBPath = th_strdup(optArg); | |
403 break; | |
404 | |
383 default: | 405 default: |
384 THERR("Unknown option '%s'.\n", currArg); | 406 THERR("Unknown option '%s'.\n", currArg); |
385 return FALSE; | 407 return FALSE; |
386 } | 408 } |
387 | 409 |
408 str++; | 430 str++; |
409 } | 431 } |
410 } | 432 } |
411 | 433 |
412 | 434 |
413 static void siPrintFieldPrefix(FILE *outFile, const char *name) | 435 static void siPrintFieldPrefix(FILE *outFile, const PSFOption *opt) |
414 { | 436 { |
437 const char *name = (optParsable || opt->lname == NULL) ? opt->name : opt->lname; | |
415 if (!optNoNamePrefix && !optFormat.nitems) | 438 if (!optNoNamePrefix && !optFormat.nitems) |
416 fprintf(outFile, optParsable ? "%s=" : "%-20s : ", name); | 439 fprintf(outFile, optParsable ? "%s=" : "%-20s : ", name); |
417 } | 440 } |
418 | 441 |
419 | 442 |
430 if (optFormat.nitems || (optFields & opt->flag)) | 453 if (optFormat.nitems || (optFields & opt->flag)) |
431 { | 454 { |
432 va_list ap; | 455 va_list ap; |
433 const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; | 456 const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; |
434 | 457 |
435 siPrintFieldPrefix(outFile, (optParsable || opt->lname == NULL) ? opt->name : opt->lname); | 458 siPrintFieldPrefix(outFile, opt); |
436 | 459 |
437 va_start(ap, xaltfmt); | 460 va_start(ap, xaltfmt); |
438 vfprintf(outFile, fmt, ap); | 461 vfprintf(outFile, fmt, ap); |
439 va_end(ap); | 462 va_end(ap); |
440 | 463 |
441 siPrintFieldSeparator(outFile); | 464 siPrintFieldSeparator(outFile); |
442 *shown = TRUE; | 465 *shown = TRUE; |
443 } | 466 } |
444 } | 467 } |
468 | |
445 | 469 |
446 #define PR(xfmt, xaltfmt, ...) siPrintPSIDInfoLine(outFile, shown, xindex, xfmt, xaltfmt, __VA_ARGS__ ) | 470 #define PR(xfmt, xaltfmt, ...) siPrintPSIDInfoLine(outFile, shown, xindex, xfmt, xaltfmt, __VA_ARGS__ ) |
447 | 471 |
448 | 472 |
449 static void siPrintPSIDInformationField(FILE *outFile, const char *filename, const PSIDHeader *psid, BOOL *shown, const int xindex) | 473 static void siPrintPSIDInformationField(FILE *outFile, const char *filename, const PSIDHeader *psid, BOOL *shown, const int xindex) |
481 case 17: | 505 case 17: |
482 { | 506 { |
483 const PSFOption *opt = &optPSFlags[xindex]; | 507 const PSFOption *opt = &optPSFlags[xindex]; |
484 if (optFormat.nitems || (optFields & opt->flag)) | 508 if (optFormat.nitems || (optFields & opt->flag)) |
485 { | 509 { |
486 siPrintFieldPrefix(outFile, "Hash"); | 510 siPrintFieldPrefix(outFile, opt); |
487 th_md5_print(outFile, psid->hash); | 511 th_md5_print(outFile, psid->hash); |
488 siPrintFieldSeparator(outFile); | 512 siPrintFieldSeparator(outFile); |
489 } | 513 } |
490 } | 514 } |
491 break; | 515 break; |
516 | |
517 case 18: | |
518 { | |
519 const PSFOption *opt = &optPSFlags[xindex]; | |
520 if (optFormat.nitems || (optFields & opt->flag)) | |
521 { | |
522 siPrintFieldPrefix(outFile, opt); | |
523 if (psid->lengths != NULL) | |
524 { | |
525 int i; | |
526 for (i = 0; i < psid->lengths->nlengths; i++) | |
527 { | |
528 int len = psid->lengths->lengths[i]; | |
529 fprintf(outFile, "%d:%d%s", len / 60, len % 60, | |
530 (i < psid->lengths->nlengths - 1) ? " " : ""); | |
531 } | |
532 } | |
533 siPrintFieldSeparator(outFile); | |
534 } | |
535 } | |
536 break; | |
537 | |
492 } | 538 } |
493 } | 539 } |
494 | 540 |
495 | 541 |
496 BOOL argHandleFile(char *filename) | 542 BOOL argHandleFile(char *filename) |
515 { | 561 { |
516 THERR("Error reading %s\n", filename); | 562 THERR("Error reading %s\n", filename); |
517 goto error; | 563 goto error; |
518 } | 564 } |
519 | 565 |
566 // Get songlength information, if any | |
567 if (sidSLDB != NULL) | |
568 psid.lengths = si_sldb_get_by_hash(sidSLDB, psid.hash); | |
569 | |
520 // Output | 570 // Output |
521 if (optFormat.nitems) | 571 if (optFormat.nitems) |
522 { | 572 { |
523 for (index = 0; index < optFormat.nitems; index++) | 573 for (index = 0; index < optFormat.nitems; index++) |
524 { | 574 { |
573 { | 623 { |
574 optParsable = FALSE; | 624 optParsable = FALSE; |
575 optNoNamePrefix = TRUE; | 625 optNoNamePrefix = TRUE; |
576 } | 626 } |
577 | 627 |
628 if (setHVSCPath != NULL) | |
629 { | |
630 if (setSLDBPath == NULL) | |
631 setSLDBPath = th_strdup_printf("%s%c%s", setHVSCPath, TH_DIR_SEPARATOR, SET_SLDB_FILENAME); | |
632 } | |
633 | |
634 if (setSLDBPath != NULL) | |
635 { | |
636 // Initialize SLDB | |
637 int ret; | |
638 th_ioctx *ctx = th_io_new(&th_stdio_io_ops); | |
639 if (ctx == NULL || th_io_open(ctx, setSLDBPath, "r") != THERR_OK) | |
640 { | |
641 THERR("Ululu!\n"); | |
642 goto out; | |
643 } | |
644 | |
645 if ((sidSLDB = si_sldb_new()) == NULL || | |
646 si_sldb_read(ctx, sidSLDB) != THERR_OK) | |
647 { | |
648 THERR("Error parsing SLDB.\n"); | |
649 goto out; | |
650 } | |
651 | |
652 if ((ret = si_sldb_build_index(sidSLDB)) != THERR_OK) | |
653 { | |
654 THERR("Error building SLDB index: %s.\n", | |
655 th_error_str(ret)); | |
656 goto out; | |
657 } | |
658 } | |
659 | |
578 // Process files | 660 // Process files |
579 if (!th_args_process(argc, argv, optList, optListN, | 661 if (!th_args_process(argc, argv, optList, optListN, |
580 argHandleOpt, argHandleFile, OPTH_ONLY_OTHER)) | 662 argHandleOpt, argHandleFile, OPTH_ONLY_OTHER)) |
581 return -2; | 663 goto out; |
582 | 664 |
583 if (optNFiles == 0) | 665 if (optNFiles == 0) |
584 { | 666 { |
585 argShowHelp(); | 667 argShowHelp(); |
586 THERR("No filename(s) specified.\n"); | 668 THERR("No filename(s) specified.\n"); |
587 } | 669 } |
588 | 670 |
671 out: | |
672 | |
673 th_free(setHVSCPath); | |
674 th_free(setSLDBPath); | |
675 th_free(setSTILPath); | |
676 si_sldb_free(sidSLDB); | |
589 return 0; | 677 return 0; |
590 } | 678 } |