comparison sidinfo.c @ 191:d26bc1adfd14

Add internal directory reading and filename matching, plus optional subdirectory recursion via '-R' option.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 09 Jul 2018 16:46:08 +0300
parents 77eb019b7386
children c0849f47e10f
comparison
equal deleted inserted replaced
190:72c415154700 191:d26bc1adfd14
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 "th_file.h"
9 #include "th_datastruct.h" 9 #include "th_datastruct.h"
10 #include "sidlib.h" 10 #include "sidlib.h"
11 #include <sys/types.h>
12 #include <dirent.h>
11 #ifdef HAVE_ICONV 13 #ifdef HAVE_ICONV
12 # include <iconv.h> 14 # include <iconv.h>
13 #endif 15 #endif
14 16
15 17
97 *setSLDBPath = NULL; 99 *setSLDBPath = NULL;
98 BOOL setSLDBNewFormat = FALSE, 100 BOOL setSLDBNewFormat = FALSE,
99 optParsable = FALSE, 101 optParsable = FALSE,
100 optNoNamePrefix = FALSE, 102 optNoNamePrefix = FALSE,
101 optHexadecimal = FALSE, 103 optHexadecimal = FALSE,
102 optFieldOutput = TRUE; 104 optFieldOutput = TRUE,
105 optRecurseDirs = FALSE;
103 char *optOneLineFieldSep = NULL, 106 char *optOneLineFieldSep = NULL,
104 *optEscapeChars = NULL; 107 *optEscapeChars = NULL;
105 int optNFiles = 0; 108 int optNFiles = 0;
106 109
107 PSFStack optFormat; 110 PSFStack optFormat;
128 { 3, 'f', "fields", "Show only specified field(s)", OPT_ARGREQ }, 131 { 3, 'f', "fields", "Show only specified field(s)", OPT_ARGREQ },
129 { 4, 'x', "hex", "Use hexadecimal values", OPT_NONE }, 132 { 4, 'x', "hex", "Use hexadecimal values", OPT_NONE },
130 { 7, 'F', "format", "Use given format string (see below)", OPT_ARGREQ }, 133 { 7, 'F', "format", "Use given format string (see below)", OPT_ARGREQ },
131 { 8, 'H', "hvsc", "Specify path to HVSC documents directory", OPT_ARGREQ }, 134 { 8, 'H', "hvsc", "Specify path to HVSC documents directory", OPT_ARGREQ },
132 { 9, 'S', "sldb", "Specify Songlengths.txt file (use -H if possible)", OPT_ARGREQ }, 135 { 9, 'S', "sldb", "Specify Songlengths.txt file (use -H if possible)", OPT_ARGREQ },
136 {12, 'R', "recurse", "Recurse into sub-directories", OPT_NONE },
133 }; 137 };
134 138
135 static const int optListN = sizeof(optList) / sizeof(optList[0]); 139 static const int optListN = sizeof(optList) / sizeof(optList[0]);
136 140
137 141
724 728
725 case 11: 729 case 11:
726 optEscapeChars = optArg; 730 optEscapeChars = optArg;
727 break; 731 break;
728 732
733 case 12:
734 optRecurseDirs = TRUE;
735 break;
736
729 default: 737 default:
730 THERR("Unknown option '%s'.\n", currArg); 738 THERR("Unknown option '%s'.\n", currArg);
731 return FALSE; 739 return FALSE;
732 } 740 }
733 741
968 (void) err; 976 (void) err;
969 fprintf(stderr, "%s", msg); 977 fprintf(stderr, "%s", msg);
970 } 978 }
971 979
972 980
973 BOOL argHandleFile(char *filename) 981 BOOL siHandleSIDFile(const char *filename)
974 { 982 {
975 PSIDHeader *psid = NULL; 983 PSIDHeader *psid = NULL;
976 th_ioctx *inFile = NULL; 984 th_ioctx *inFile = NULL;
977 FILE *outFile; 985 FILE *outFile;
978 BOOL shown = FALSE; 986 BOOL shown = FALSE;
979 int res; 987 int res;
980 988
981 optNFiles++;
982 outFile = stdout; 989 outFile = stdout;
983 990
984 if ((res = th_io_fopen(&inFile, &th_stdio_io_ops, filename, "rb")) != THERR_OK) 991 if ((res = th_io_fopen(&inFile, &th_stdio_io_ops, filename, "rb")) != THERR_OK)
985 { 992 {
986 THERR("Could not open file '%s': %s\n", 993 THERR("Could not open file '%s': %s\n",
1030 1037
1031 return TRUE; 1038 return TRUE;
1032 } 1039 }
1033 1040
1034 1041
1042 BOOL argHandleFileDir(const char *path, const char *filename, const char *pattern)
1043 {
1044 th_stat_data sdata;
1045 char *npath;
1046 BOOL ret = TRUE;
1047
1048 if (filename != NULL)
1049 npath = th_strdup_printf("%s%c%s", path, TH_DIR_SEPARATOR, filename);
1050 else
1051 npath = th_strdup(path);
1052
1053 if (!th_stat_path(npath, &sdata))
1054 {
1055 THERR("File or path '%s' does not exist.\n", npath);
1056 ret = FALSE;
1057 goto out;
1058 }
1059
1060 optNFiles++;
1061
1062 if (sdata.flags & TH_IS_DIR)
1063 {
1064 DIR *dirh;
1065 struct dirent *entry;
1066
1067 // Check if recursion is disabled
1068 if (!optRecurseDirs && optNFiles > 1)
1069 goto out;
1070
1071 if ((dirh = opendir(npath)) == NULL)
1072 {
1073 int err = th_get_error();
1074 THERR("Could not open directory '%s': %s\n",
1075 path, th_error_str(err));
1076 ret = FALSE;
1077 goto out;
1078 }
1079
1080 while ((entry = readdir(dirh)) != NULL)
1081 if (entry->d_name[0] != '.')
1082 {
1083 if (!argHandleFileDir(npath, entry->d_name, pattern))
1084 {
1085 ret = FALSE;
1086 goto out;
1087 }
1088 }
1089
1090 closedir(dirh);
1091 }
1092 else
1093 if (pattern == NULL || th_strmatch(filename, pattern))
1094 {
1095 siHandleSIDFile(npath);
1096 }
1097
1098 out:
1099 th_free(npath);
1100 return ret;
1101 }
1102
1103
1104 BOOL argHandleFile(char *path)
1105 {
1106 char *pattern = NULL, *filename = NULL, *pt, *npath = th_strdup(path);
1107 BOOL ret;
1108
1109 if (npath == NULL)
1110 return FALSE;
1111
1112 // Check if we have path separators
1113 if ((pt = strrchr(npath, '/')) != NULL ||
1114 (pt = strrchr(npath, '\\')) != NULL)
1115 {
1116 *pt++ = 0;
1117 }
1118 else
1119 {
1120 th_free(npath);
1121 npath = th_strdup(".");
1122 pt = strcmp(path, npath) != 0 ? path : NULL;
1123 }
1124
1125 // Check if we have glob pattern chars
1126 if (pt != NULL && *pt != 0)
1127 {
1128 if (strchr(pt, '*') || strchr(pt, '?'))
1129 pattern = th_strdup(pt);
1130 else
1131 filename = th_strdup(pt);
1132 }
1133
1134 ret = argHandleFileDir(npath, filename, pattern);
1135
1136 th_free(pattern);
1137 th_free(npath);
1138 th_free(filename);
1139 return ret;
1140 }
1141
1142
1035 int main(int argc, char *argv[]) 1143 int main(int argc, char *argv[])
1036 { 1144 {
1037 // Initialize 1145 // Initialize
1038 th_init("SIDInfo", "PSID/RSID information displayer", "0.7.5", 1146 th_init("SIDInfo", "PSID/RSID information displayer", "0.7.5",
1039 "By Matti 'ccr' Hamalainen (C) Copyright 2014-2018 TNSP", 1147 "By Matti 'ccr' Hamalainen (C) Copyright 2014-2018 TNSP",
1057 th_free(setLang); 1165 th_free(setLang);
1058 #endif 1166 #endif
1059 1167
1060 // Parse command line arguments 1168 // Parse command line arguments
1061 if (!th_args_process(argc, argv, optList, optListN, 1169 if (!th_args_process(argc, argv, optList, optListN,
1062 argHandleOpt, argHandleFile, OPTH_ONLY_OPTS)) 1170 argHandleOpt, NULL, OPTH_ONLY_OPTS))
1063 return -1; 1171 return -1;
1064 1172
1065 if (optOneLineFieldSep != NULL) 1173 if (optOneLineFieldSep != NULL)
1066 { 1174 {
1067 // For one-line format, disable parsing and prefixes 1175 // For one-line format, disable parsing and prefixes
1135 th_io_close(inFile); 1243 th_io_close(inFile);
1136 } 1244 }
1137 1245
1138 // Process files 1246 // Process files
1139 if (!th_args_process(argc, argv, optList, optListN, 1247 if (!th_args_process(argc, argv, optList, optListN,
1140 argHandleOpt, argHandleFile, OPTH_ONLY_OTHER)) 1248 NULL, argHandleFile, OPTH_ONLY_OTHER))
1141 goto out; 1249 goto out;
1142 1250
1143 if (optNFiles == 0) 1251 if (optNFiles == 0)
1144 { 1252 {
1145 THERR("No filename(s) specified. Try --help.\n"); 1253 THERR("No filename(s) specified. Try --help.\n");