Mercurial > hg > sidinfo
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"); |