HuntnGather – Diff between revs 10 and 11

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 10 Rev 11
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2021 Wizardry and Steamworks - License: MIT // 2 // Copyright (C) 2021 Wizardry and Steamworks - License: MIT //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4   4  
5 #include <stdio.h> 5 #include <stdio.h>
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <string.h> 7 #include <string.h>
8 #include <dirent.h> 8 #include <dirent.h>
9 #include <signal.h> 9 #include <signal.h>
10   10  
11 #include <sys/types.h> 11 #include <sys/types.h>
12 #include <sys/stat.h> 12 #include <sys/stat.h>
13   13  
14 #include <proto/dos.h> 14 #include <proto/dos.h>
15 #include <proto/exec.h> 15 #include <proto/exec.h>
16   16  
17 #include "StringStack.h" 17 #include "StringStack.h"
18   18  
19 #if !defined ___HAVE_GETOPT___ 19 #if !defined ___HAVE_GETOPT___
20 #include "getopt.h" 20 #include "getopt.h"
21 #endif 21 #endif
22   22  
23 #if defined ___AmigaOS___ 23 #if defined ___AmigaOS___
24 /*************************************************************************/ 24 /*************************************************************************/
25 /* Version string used for querrying the program version. */ 25 /* Version string used for querrying the program version. */
26 /*************************************************************************/ 26 /*************************************************************************/
27 TEXT version_string[] = 27 TEXT version_string[] =
28 "\0$VER: Gather 1.5 "__DATE__" by Wizardry and Steamworks"; 28 "\0$VER: Gather 1.7 "__DATE__" by Wizardry and Steamworks";
29 #endif 29 #endif
30   30  
31 #if !defined TRUE 31 #if !defined TRUE
32 #define TRUE 1; 32 #define TRUE 1;
33 #endif 33 #endif
34   34  
35 #if !defined FALSE 35 #if !defined FALSE
36 #define FALSE 0; 36 #define FALSE 0;
37 #endif 37 #endif
38   38  
39 #define MAX_MEM 262144 39 #define MAX_MEM 262144
-   40 #define NAME_BUF 32
-   41 #define PATH_BUF 128
-   42 #define LINE_BUF 256
40 #define DEFAULT_DATABASE_FILE "S:gather.db" 43 #define DEFAULT_DATABASE_FILE "S:gather.db"
41   44  
42 typedef struct { 45 typedef struct {
43 unsigned int dirs; 46 unsigned int dirs;
44 unsigned int files; 47 unsigned int files;
45 } stats; 48 } stats;
46   49  
47 int run = TRUE; 50 int run = TRUE;
48 int verbose = TRUE; 51 int verbose = TRUE;
49   52  
50 void SignalHandler(int sig) { 53 void SignalHandler(int sig) {
51 // Toggle the run flag to stop execution. 54 // Toggle the run flag to stop execution.
52 run = FALSE; 55 run = FALSE;
53 } 56 }
54   57  
55 int compare(const void *a, const void *b) { 58 int compare(const void *a, const void *b) {
56 const char **p = (const char **)a; 59 const char **p = (const char **)a;
57 const char **q = (const char **)b; 60 const char **q = (const char **)b;
58 return strcmp(*p, *q); 61 return strcmp(*p, *q);
59 } 62 }
60   63  
61 /* 64 /*
62 * 65 *
63 * Sorts a database file lexicographically. 66 * Sorts a database file lexicographically.
64 */ 67 */
65 void SortDatabase(char *dbFile) { 68 void SortDatabase(char *dbFile) {
66 FILE *fp; 69 FILE *fp;
67 char *name = NULL; 70 char *name = NULL;
68 char *path = NULL; 71 char *path = NULL;
69 char **database; 72 char **database;
70 char c; 73 char c;
71 int i; 74 int i;
72 int side; 75 int side;
73 unsigned int line; 76 unsigned int line;
-   77 int name_size;
-   78 int path_size;
74   79  
75 // Open database file for reading. 80 // Open database file for reading.
76 if((fp = fopen(dbFile, "r")) == NULL) { 81 if((fp = fopen(dbFile, "r")) == NULL) {
77 fprintf(stderr, "Unable to open gather database for reading.\n"); 82 fprintf(stderr, "Unable to open gather database for reading.\n");
78 return; 83 return;
79 } 84 }
80   85  
-   86 database = malloc(sizeof(char *));
81 database = (char **) malloc(sizeof(char *)); 87 name_size = NAME_BUF;
-   88 name = malloc(name_size * sizeof(char));
82 name = (char *) malloc(sizeof(char)); 89 path_size = PATH_BUF;
83 path = (char *) malloc(sizeof(char)); 90 path = malloc(path_size * sizeof(char));
84 line = 0; 91 line = 0;
85 side = 0; 92 side = 0;
86 i = 0; 93 i = 0;
87   94  
88 if(verbose) { 95 if(verbose) {
89 fprintf(stdout, "Sorting database: '%s'\n", dbFile); 96 fprintf(stdout, "Sorting database: '%s'\n", dbFile);
90 } 97 }
91   98  
92 while(run && fscanf(fp, "%c", &c) == 1) { 99 while(run && fscanf(fp, "%c", &c) == 1) {
93 #if defined ___AmigaOS___ 100 #if defined ___AmigaOS___
94 // Check if CTRL+C was pressed and abort the program. 101 // Check if CTRL+C was pressed and abort the program.
95 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 102 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
96 run = FALSE; 103 run = FALSE;
97 continue; 104 continue;
98 } 105 }
99 #endif 106 #endif
100 switch(c) { 107 switch(c) {
101 case '\n': 108 case '\n':
102 // Load up the name and path into the database variable. 109 // Load up the name and path into the database variable.
103 database = (char **) realloc(database, (line + 1) * sizeof(char *)); 110 database = realloc(database, (line + 1) * sizeof(char *));
104 database[line] = (char *) malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(char)); 111 database[line] = malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(char));
105 sprintf(database[line], "%s\t%s", name, path); 112 sprintf(database[line], "%s\t%s", name, path);
106 ++line; 113 ++line;
107   114  
108 free(name); 115 free(name);
-   116 name_size = NAME_BUF;
109 name = (char *) malloc(sizeof(char)); 117 name = malloc(name_size * sizeof(char));
110 --side; 118 --side;
111 i = 0; 119 i = 0;
112   120  
113 break; 121 break;
114 case '\t': 122 case '\t':
115 free(path); 123 free(path);
-   124 path_size = PATH_BUF;
116 path = (char *) malloc(sizeof(char)); 125 path = malloc(path_size * sizeof(char));
117 ++side; 126 ++side;
118 i = 0; 127 i = 0;
119 break; 128 break;
120 default: 129 default:
121 switch(side) { 130 switch(side) {
122 case 0: 131 case 0:
-   132 if(strlen(name) == name_size) {
-   133 name_size = name_size * 1.5;
-   134 name = realloc(name, name_size * sizeof(char));
-   135 }
123 name = (char *) realloc(name, (i + 1 + 1) * sizeof(char)); 136 //name = realloc(name, (i + 1 + 1) * sizeof(char));
124 name[i] = c; 137 name[i] = c;
125 name[i + 1] = '\0'; 138 name[i + 1] = '\0';
126 break; 139 break;
127 case 1: 140 case 1:
-   141 if(strlen(path) == path_size) {
-   142 path_size = path_size * 1.5;
-   143 path = realloc(path, path_size * sizeof(char));
-   144 }
128 path = (char *) realloc(path, (i + 1 + 1) * sizeof(char)); 145 //path = realloc(path, (i + 1 + 1) * sizeof(char));
129 path[i] = c; 146 path[i] = c;
130 path[i + 1] = '\0'; 147 path[i + 1] = '\0';
131 break; 148 break;
132 default: 149 default:
133 fprintf(stderr, "Database corrupted.\n"); 150 fprintf(stderr, "Database corrupted.\n");
134 break; 151 break;
135 } 152 }
136 ++i; 153 ++i;
137 break; 154 break;
138 } 155 }
139 } 156 }
140   157  
141 fclose(fp); 158 fclose(fp);
142   159  
143 // Sort the database. 160 // Sort the database.
144 qsort(database, line, sizeof(char *), compare); 161 qsort(database, line, sizeof(char *), compare);
145   162  
146 // Write the database lines back to the database. 163 // Write the database lines back to the database.
147 if((fp = fopen(dbFile, "w+")) == NULL) { 164 if((fp = fopen(dbFile, "w+")) == NULL) {
148 fprintf(stderr, "Unable to open gather database for writing.\n"); 165 fprintf(stderr, "Unable to open gather database for writing.\n");
149 return; 166 return;
150 } 167 }
151   168  
152 for(i = 0; i < line; ++i) { 169 for(i = 0; i < line; ++i) {
153 fprintf(fp, "%s\n", database[i]); 170 fprintf(fp, "%s\n", database[i]);
154 } 171 }
155   172  
156 free(database); 173 free(database);
157 fclose(fp); 174 fclose(fp);
158 } 175 }
159   176  
160 /* 177 /*
161 * 178 *
162 * Updates a database file "dbFile". 179 * Updates a database file "dbFile".
163 */ 180 */
164 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) { 181 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) {
165 FILE *fp; 182 FILE *fp;
166 DIR *dir; 183 DIR *dir;
167 struct dirent *dirEntry; 184 struct dirent *dirEntry;
168 struct stat dirStat; 185 struct stat dirStat;
169 unsigned int size; 186 unsigned int size;
170 char *path; 187 char *path;
171 char *subPath; 188 char *subPath;
172   189  
173 if((fp = fopen(dbFile, "w+")) == NULL) { 190 if((fp = fopen(dbFile, "w+")) == NULL) {
174 fprintf(stderr, "Unable to open gather database for writing.\n"); 191 fprintf(stderr, "Unable to open gather database for writing.\n");
175 return; 192 return;
176 } 193 }
177   194  
178 while(run && !stringStackIsEmpty(dirStack)) { 195 while(run && !stringStackIsEmpty(dirStack)) {
179 #if defined ___AmigaOS___ 196 #if defined ___AmigaOS___
180 // Check if CTRL+C was pressed and abort the program. 197 // Check if CTRL+C was pressed and abort the program.
181 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 198 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
182 run = FALSE; 199 run = FALSE;
183 } 200 }
184 #endif 201 #endif
185 if((path = stringStackPop(dirStack)) == NULL) { 202 if((path = stringStackPop(dirStack)) == NULL) {
186 return; 203 return;
187 } 204 }
188   205  
189 if((dir = opendir(path)) == NULL) { 206 if((dir = opendir(path)) == NULL) {
190 return; 207 return;
191 } 208 }
192   209  
193 while(run && (dirEntry = readdir(dir)) != NULL) { 210 while(run && (dirEntry = readdir(dir)) != NULL) {
194 #if defined ___AmigaOS___ 211 #if defined ___AmigaOS___
195 // Check if CTRL+C was pressed and abort the program. 212 // Check if CTRL+C was pressed and abort the program.
196 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 213 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
197 run = FALSE; 214 run = FALSE;
198 } 215 }
199 #endif 216 #endif
200 size = sizeof(path) + sizeof(dirEntry->d_name) + 1; 217 size = sizeof(path) + sizeof(dirEntry->d_name) + 1;
201 switch(path[strlen(path) - 1]) { 218 switch(path[strlen(path) - 1]) {
202 case '/': 219 case '/':
203 case ':': // This is a drive path. 220 case ':': // This is a drive path.
204 subPath = (char *) malloc(size); 221 subPath = malloc(size);
205 sprintf(subPath, "%s%s", path, dirEntry->d_name); 222 sprintf(subPath, "%s%s", path, dirEntry->d_name);
206 break; 223 break;
207 default: 224 default:
208 subPath = (char *) malloc(size + 1); 225 subPath = malloc(size + 1);
209 sprintf(subPath, "%s/%s", path, dirEntry->d_name); 226 sprintf(subPath, "%s/%s", path, dirEntry->d_name);
210 break; 227 break;
211 } 228 }
212 stat(subPath, &dirStat); 229 stat(subPath, &dirStat);
213 if(S_ISDIR(dirStat.st_mode)) { 230 if(S_ISDIR(dirStat.st_mode)) {
214 stringStackPush(dirStack, subPath); 231 stringStackPush(dirStack, subPath);
215   232  
216 ++stats->dirs; 233 ++stats->dirs;
217   234  
218 if(verbose) { 235 if(verbose) {
219 fprintf(stdout, 236 fprintf(stdout,
220 "Gathered %d directories and %d files.\r", 237 "Gathered %d directories and %d files.\r",
221 stats->dirs, 238 stats->dirs,
222 stats->files); 239 stats->files);
223 } 240 }
224   241  
225 free(subPath); 242 free(subPath);
226 continue; 243 continue;
227 } 244 }
228   245  
229 // Write to database file. 246 // Write to database file.
230 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath); 247 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath);
231   248  
232 ++stats->files; 249 ++stats->files;
233   250  
234 if(verbose) { 251 if(verbose) {
235 fprintf(stdout, 252 fprintf(stdout,
236 "Gathered %d directories and %d files.\r", 253 "Gathered %d directories and %d files.\r",
237 stats->dirs, 254 stats->dirs,
238 stats->files); 255 stats->files);
239 } 256 }
240   257  
241 free(subPath); 258 free(subPath);
242 } 259 }
243   260  
244 closedir(dir); 261 closedir(dir);
245 free(path); 262 free(path);
246 } 263 }
247   264  
248 if(verbose) { 265 if(verbose) {
249 fprintf(stdout, "\n"); 266 fprintf(stdout, "\n");
250 } 267 }
251   268  
252 fclose(fp); 269 fclose(fp);
253   270  
254 } 271 }
255   272  
256 /* 273 /*
257 * 274 *
258 * Gets the size of a database "dbFle". 275 * Gets the size of a database "dbFle".
259 */ 276 */
260 int GetDatabaseSize(char *dbFile) { 277 int GetDatabaseSize(char *dbFile) {
261 FILE *fp; 278 FILE *fp;
262 int size; 279 int size;
263   280  
264 if((fp = fopen(dbFile, "r")) == NULL) { 281 if((fp = fopen(dbFile, "r")) == NULL) {
265 fprintf(stderr, "Unable to open gather database for reading.\n"); 282 fprintf(stderr, "Unable to open gather database for reading.\n");
266 fclose(fp); 283 fclose(fp);
267 return 0; 284 return 0;
268 } 285 }
269   286  
270 fseek(fp, 0L, SEEK_END); 287 fseek(fp, 0L, SEEK_END);
271 size = ftell(fp); 288 size = ftell(fp);
272   289  
273 fclose(fp); 290 fclose(fp);
274 return size; 291 return size;
275 } 292 }
276   293  
277 /* 294 /*
278 * 295 *
279 * Counts the lines in a database file "dbFile". 296 * Counts the lines in a database file "dbFile".
280 */ 297 */
281 int CountDatabaseLines(char *dbFile) { 298 int CountDatabaseLines(char *dbFile) {
282 FILE *fp; 299 FILE *fp;
283 int lines; 300 int lines;
284 char c; 301 char c;
285   302  
286 if((fp = fopen(dbFile, "r")) == NULL) { 303 if((fp = fopen(dbFile, "r")) == NULL) {
287 fprintf(stderr, "Unable to open gather database for reading.\n"); 304 fprintf(stderr, "Unable to open gather database for reading.\n");
288 fclose(fp); 305 fclose(fp);
289 return 0; 306 return 0;
290 } 307 }
291   308  
292 lines = 0; 309 lines = 0;
293 while(fscanf(fp, "%c", &c) == 1) { 310 while(fscanf(fp, "%c", &c) == 1) {
294 switch(c) { 311 switch(c) {
295 case '\n': 312 case '\n':
296 ++lines; 313 ++lines;
297 break; 314 break;
298 } 315 }
299 } 316 }
300   317  
301 fclose(fp); 318 fclose(fp);
302   319  
303 return lines; 320 return lines;
304 } 321 }
305   322  
306 /* 323 /*
307 * 324 *
308 * Creates "files" temporary filenames. 325 * Creates "files" temporary filenames.
309 */ 326 */
310 char **CreateTempFiles(int files) { 327 char **CreateTempFiles(int files) {
311 char **tmpNames; 328 char **tmpNames;
312 int count; 329 int count;
313   330  
314 tmpNames = (char **) malloc(files * sizeof(char *)); 331 tmpNames = malloc(files * sizeof(char *));
315   332  
316 if(verbose) { 333 if(verbose) {
317 fprintf(stdout, "Creating temporary files.\r"); 334 fprintf(stdout, "Creating temporary files.\r");
318 } 335 }
319   336  
320 count = files; 337 count = files;
321 while(--count > -1) { 338 while(--count > -1) {
322 #if defined ___AmigaOS___ 339 #if defined ___AmigaOS___
323 // Check if CTRL+C was pressed and abort the program. 340 // Check if CTRL+C was pressed and abort the program.
324 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 341 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
325 run = FALSE; 342 run = FALSE;
326 } 343 }
327 #endif 344 #endif
328 tmpNames[count] = tmpnam(NULL); 345 tmpNames[count] = tmpnam(NULL);
329   346  
330 if(verbose) { 347 if(verbose) {
331 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0)); 348 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0));
332 } 349 }
333 } 350 }
334   351  
335 if(verbose) { 352 if(verbose) {
336 fprintf(stdout, "\n"); 353 fprintf(stdout, "\n");
337 } 354 }
338   355  
339 return tmpNames; 356 return tmpNames;
340 } 357 }
341   358  
342 /* 359 /*
343 * 360 *
344 * Writes lines from the database "dbFile" to temporary filenames "tmpNames". 361 * Writes lines from the database "dbFile" to temporary filenames "tmpNames".
345 */ 362 */
346 void WriteTempFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) { 363 void WriteTempFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) {
347 FILE *fp, *tp; 364 FILE *fp, *tp;
348 char c; 365 char c;
349 int lines; 366 int lines;
350 int linesWritten; 367 int linesWritten;
351   368  
352 if((fp = fopen(dbFile, "r")) == NULL) { 369 if((fp = fopen(dbFile, "r")) == NULL) {
353 fprintf(stderr, "Unable to open gather database for reading.\n"); 370 fprintf(stderr, "Unable to open gather database for reading.\n");
354 return; 371 return;
355 } 372 }
356   373  
357 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) { 374 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) {
358 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 375 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]);
359 fclose(fp); 376 fclose(fp);
360 return; 377 return;
361 } 378 }
362   379  
363 if(verbose) { 380 if(verbose) {
364 fprintf(stdout, "Writing to temporary files.\r"); 381 fprintf(stdout, "Writing to temporary files.\r");
365 } 382 }
366   383  
367 linesWritten = 0; 384 linesWritten = 0;
368 lines = 0; 385 lines = 0;
369 while(run && fscanf(fp, "%c", &c) == 1) { 386 while(run && fscanf(fp, "%c", &c) == 1) {
370 #if defined ___AmigaOS___ 387 #if defined ___AmigaOS___
371 // Check if CTRL+C was pressed and abort the program. 388 // Check if CTRL+C was pressed and abort the program.
372 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 389 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
373 run = FALSE; 390 run = FALSE;
374 } 391 }
375 #endif 392 #endif
376 switch(c) { 393 switch(c) {
377 case '\n': 394 case '\n':
378 // Increment the total written lines. 395 // Increment the total written lines.
379 ++linesWritten; 396 ++linesWritten;
380   397  
381 if(verbose) { 398 if(verbose) {
382 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0)); 399 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0));
383 } 400 }
384   401  
385 // Write the newline character back. 402 // Write the newline character back.
386 if(fprintf(tp, "%c", c) != 1) { 403 if(fprintf(tp, "%c", c) != 1) {
387 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 404 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]);
388 fclose(tp); 405 fclose(tp);
389 fclose(fp); 406 fclose(fp);
390 return; 407 return;
391 } 408 }
392 // Switch to the next temporary file. 409 // Switch to the next temporary file.
393 if(++lines >= tmpLines) { 410 if(++lines >= tmpLines) {
394 // If there are no temporary files left then run till the end. 411 // If there are no temporary files left then run till the end.
395 if(tmpFiles - 1 < 0) { 412 if(tmpFiles - 1 < 0) {
396 break; 413 break;
397 } 414 }
398   415  
399 // Close the previous temporary file and write to the next temporary file. 416 // Close the previous temporary file and write to the next temporary file.
400 fclose(tp); 417 fclose(tp);
401 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) { 418 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) {
402 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 419 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]);
403 fclose(tp); 420 fclose(tp);
404 fclose(fp); 421 fclose(fp);
405 } 422 }
406 lines = 0; 423 lines = 0;
407 break; 424 break;
408 } 425 }
409 break; 426 break;
410 default: 427 default:
411 if(fprintf(tp, "%c", c) != 1) { 428 if(fprintf(tp, "%c", c) != 1) {
412 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 429 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]);
413 fclose(tp); 430 fclose(tp);
414 fclose(fp); 431 fclose(fp);
415 return; 432 return;
416 } 433 }
417 break; 434 break;
418 } 435 }
419 } 436 }
420   437  
421 fprintf(stdout, "\n"); 438 fprintf(stdout, "\n");
422   439  
423 fclose(tp); 440 fclose(tp);
424 fclose(fp); 441 fclose(fp);
425 } 442 }
426   443  
427 /* 444 /*
428 * 445 *
429 * Skips a line in a database file "fp". 446 * Skips a line in a database file "fp".
430 */ 447 */
431 void SkipDatabaseLine(FILE *fp) { 448 void SkipDatabaseLine(FILE *fp) {
432 char c; 449 char c;
433   450  
434 while(fscanf(fp, "%c", &c) == 1) { 451 while(fscanf(fp, "%c", &c) == 1) {
435 if(c == '\n') { 452 if(c == '\n') {
436 break; 453 break;
437 } 454 }
438 } 455 }
439   456  
440 return; 457 return;
441 } 458 }
442   459  
443 /* 460 /*
444 * 461 *
445 * Reads a line from the database file "fp". 462 * Reads a line from the database file "fp".
446 */ 463 */
447 char *ReadDatabaseLine(FILE *fp) { 464 char *ReadDatabaseLine(FILE *fp) {
448 char c; 465 char c;
449 char *line; 466 char *line;
-   467 int line_size;
450 int chars; 468 int i;
-   469  
451   470 line_size = LINE_BUF;
452 line = (char *) malloc(sizeof(char)); 471 line = malloc(line_size * sizeof(char));
453   472  
454 chars = 0; 473 i = 0;
455 while(run && fscanf(fp, "%c", &c) == 1) { 474 while(run && fscanf(fp, "%c", &c) == 1) {
456 #if defined ___AmigaOS___ 475 #if defined ___AmigaOS___
457 // Check if CTRL+C was pressed and abort the program. 476 // Check if CTRL+C was pressed and abort the program.
458 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 477 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
459 run = FALSE; 478 run = FALSE;
460 } 479 }
461 #endif 480 #endif
462 switch(c) { 481 switch(c) {
463 case '\n': 482 case '\n':
464 // Rewind the file by the number of read characters. 483 // Rewind the file by the number of read characters.
465 fseek(fp, -(chars + 1), SEEK_CUR); 484 fseek(fp, -(i + 1), SEEK_CUR);
466 return line; 485 return line;
467 default: 486 default:
-   487 if(strlen(line) == line_size) {
-   488 line_size = line_size * 1.5;
-   489 line = realloc(line, line_size * sizeof(char));
-   490 }
468 line = (char *) realloc(line, (chars + 1 + 1) * sizeof(char)); 491 //line = realloc(line, (chars + 1 + 1) * sizeof(char));
469 line[chars] = c; 492 line[i] = c;
470 line[chars + 1] = '\0'; 493 line[i + 1] = '\0';
471 break; 494 break;
472 } 495 }
473 ++chars; 496 ++i;
474 } 497 }
475   498  
476 return NULL; 499 return NULL;
477 } 500 }
478   501  
479 /* 502 /*
480 * 503 *
481 * Merges temporary files "tmpNames" into a database "dbFile". 504 * Merges temporary files "tmpNames" into a database "dbFile".
482 */ 505 */
483 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) { 506 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) {
484 FILE *fp; 507 FILE *fp;
485 FILE **tp; 508 FILE **tp;
486 int i; 509 int i;
487 char *tmp; 510 char *tmp;
488 char *tmpMin; 511 char *tmpMin;
489 int idxMin; 512 int idxMin;
490 int count; 513 int count;
491   514  
492 if((fp = fopen(dbFile, "w+")) == NULL) { 515 if((fp = fopen(dbFile, "w+")) == NULL) {
493 fprintf(stderr, "Unable to open gather database for writing.\n"); 516 fprintf(stderr, "Unable to open gather database for writing.\n");
494 return; 517 return;
495 } 518 }
496   519  
497 // Allocate as many file pointers as temporary files. 520 // Allocate as many file pointers as temporary files.
498 tp = (FILE **) malloc(files * sizeof(FILE *)); 521 tp = malloc(files * sizeof(FILE *));
499   522  
500 // Open all temporary files for reading. 523 // Open all temporary files for reading.
501 for(i = 0; i < files; ++i) { 524 for(i = 0; i < files; ++i) {
502 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) { 525 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) {
503 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]); 526 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]);
504 // Close all temporary files. 527 // Close all temporary files.
505 --i; 528 --i;
506 while(i >= 0) { 529 while(i >= 0) {
507 fclose(tp[i]); 530 fclose(tp[i]);
508 } 531 }
509 return; 532 return;
510 } 533 }
511 } 534 }
512   535  
513 if(verbose) { 536 if(verbose) {
514 fprintf(stdout, "Merging all database lines in temporary files.\r"); 537 fprintf(stdout, "Merging all database lines in temporary files.\r");
515 } 538 }
516   539  
517 count = lines; 540 count = lines;
518 idxMin = 0; 541 idxMin = 0;
519 while(run && --count > -1) { 542 while(run && --count > -1) {
520 #if defined ___AmigaOS___ 543 #if defined ___AmigaOS___
521 // Check if CTRL+C was pressed and abort the program. 544 // Check if CTRL+C was pressed and abort the program.
522 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 545 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
523 run = FALSE; 546 run = FALSE;
524 } 547 }
525 #endif 548 #endif
526 // Find the smallest line in all temporary files. 549 // Find the smallest line in all temporary files.
527 if(verbose) { 550 if(verbose) {
528 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0)); 551 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0));
529 } 552 }
530   553  
531 tmpMin = NULL; 554 tmpMin = NULL;
532 for(i = 0; i < files; ++i) { 555 for(i = 0; i < files; ++i) {
533 tmp = ReadDatabaseLine(tp[i]); 556 tmp = ReadDatabaseLine(tp[i]);
534 if(tmp == NULL) { 557 if(tmp == NULL) {
535 free(tmp); 558 free(tmp);
536 continue; 559 continue;
537 } 560 }
538 if(tmpMin == NULL || strcmp(tmp, tmpMin) < 0) { 561 if(tmpMin == NULL || strcmp(tmp, tmpMin) < 0) {
539 if(tmpMin != NULL) { 562 if(tmpMin != NULL) {
540 // Free previous instance. 563 // Free previous instance.
541 free(tmpMin); 564 free(tmpMin);
542 } 565 }
543 tmpMin = (char *) malloc((strlen(tmp) + 1) * sizeof(char)); 566 tmpMin = malloc((strlen(tmp) + 1) * sizeof(char));
544 sprintf(tmpMin, "%s", tmp); 567 sprintf(tmpMin, "%s", tmp);
545 // Remember the index of the file where the smallest entry has been found. 568 // Remember the index of the file where the smallest entry has been found.
546 idxMin = i; 569 idxMin = i;
547 free(tmp); 570 free(tmp);
548 continue; 571 continue;
549 } 572 }
550 free(tmp); 573 free(tmp);
551 } 574 }
552   575  
553 // Forward the file where the smallest line was found. 576 // Forward the file where the smallest line was found.
554 SkipDatabaseLine(tp[idxMin]); 577 SkipDatabaseLine(tp[idxMin]);
555   578  
556 // Write the smallest line. 579 // Write the smallest line.
557 if(tmpMin != NULL) { 580 if(tmpMin != NULL) {
558 fprintf(fp, "%s\n", tmpMin); 581 fprintf(fp, "%s\n", tmpMin);
559 free(tmpMin); 582 free(tmpMin);
560 } 583 }
561 } 584 }
562   585  
563 // Write out any remaining contents from the temporary files. 586 // Write out any remaining contents from the temporary files.
564 for(i = 0; i < files; ++i) { 587 for(i = 0; i < files; ++i) {
565 tmp = ReadDatabaseLine(tp[i]); 588 tmp = ReadDatabaseLine(tp[i]);
566 if(tmp == NULL) { 589 if(tmp == NULL) {
567 continue; 590 continue;
568 } 591 }
569 fprintf(fp, "%s\n", tmp); 592 fprintf(fp, "%s\n", tmp);
570 } 593 }
571   594  
572 // Close and delete all temporary files. 595 // Close and delete all temporary files.
573 for(i = 0; i < files; ++i) { 596 for(i = 0; i < files; ++i) {
574 fclose(tp[i]); 597 fclose(tp[i]);
575 // Delete temporary file. 598 // Delete temporary file.
576 remove(tmpNames[i]); 599 remove(tmpNames[i]);
577 } 600 }
578   601  
579 if(verbose) { 602 if(verbose) {
580 fprintf(stdout, "\n"); 603 fprintf(stdout, "\n");
581 } 604 }
582   605  
583 fclose(fp); 606 fclose(fp);
584 } 607 }
585   608  
586 /* 609 /*
587 * 610 *
588 * Indexes a "path" by creating a database "dbFile". 611 * Indexes a "path" by creating a database "dbFile".
589 */ 612 */
590 void Gather(char *dbFile, char *path) { 613 void Gather(char *dbFile, char *path) {
591 stringStack *stack = stringStackCreate(1); 614 stringStack *stack = stringStackCreate(1);
592 stats *stats = malloc(sizeof(stats)); 615 stats *stats = malloc(sizeof(stats));
593 char **tmpNames; 616 char **tmpNames;
594 int dbSize, dbLines, tmpFiles, tmpLines; 617 int dbSize, dbLines, tmpFiles, tmpLines;
595 int i; 618 int i;
596   619  
597 // Initialize metrics. 620 // Initialize metrics.
598 stats->dirs = 0; 621 stats->dirs = 0;
599 stats->files = 0; 622 stats->files = 0;
600   623  
601 // Push the first path onto the stack. 624 // Push the first path onto the stack.
602 stringStackPush(stack, path); 625 stringStackPush(stack, path);
603   626  
604 // Generate the database file. 627 // Generate the database file.
605 UpdateDatabase(dbFile, stack, stats); 628 UpdateDatabase(dbFile, stack, stats);
606   629  
607 // Get the database metrics. 630 // Get the database metrics.
608 dbSize = GetDatabaseSize(dbFile); 631 dbSize = GetDatabaseSize(dbFile);
609 dbLines = CountDatabaseLines(dbFile); 632 dbLines = CountDatabaseLines(dbFile);
610   633  
611 // Compute the amount of temporary files needed. 634 // Compute the amount of temporary files needed.
612 tmpFiles = dbSize / MAX_MEM; 635 tmpFiles = dbSize / MAX_MEM;
613   636  
614 // In case no temporary files are required, 637 // In case no temporary files are required,
615 // just sort the database and terminate. 638 // just sort the database and terminate.
616 if(tmpFiles <= 1) { 639 if(tmpFiles <= 1) {
617 SortDatabase(dbFile); 640 SortDatabase(dbFile);
618 return; 641 return;
619 } 642 }
620   643  
621 tmpLines = dbLines / tmpFiles; 644 tmpLines = dbLines / tmpFiles;
622   645  
623 // Create temporary files. 646 // Create temporary files.
624 if((tmpNames = CreateTempFiles(tmpFiles)) == NULL) { 647 if((tmpNames = CreateTempFiles(tmpFiles)) == NULL) {
625 fprintf(stderr, "Unable to create temporary files.\n"); 648 fprintf(stderr, "Unable to create temporary files.\n");
626 return; 649 return;
627 } 650 }
628   651  
629 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile". 652 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile".
630 WriteTempFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines); 653 WriteTempFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines);
631   654  
632 // Sort the temporary files. 655 // Sort the temporary files.
633 for(i = 0; i < tmpFiles; ++i) { 656 for(i = 0; i < tmpFiles; ++i) {
634 SortDatabase(tmpNames[i]); 657 SortDatabase(tmpNames[i]);
635 } 658 }
636   659  
637 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines); 660 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines);
638 } 661 }
-   662  
-   663 void usage(char *name) {
-   664 fprintf(stdout, "Hunt & Gather - %s, a file index generating tool. \n", name);
-   665 fprintf(stdout, " \n");
-   666 fprintf(stdout, "SYNTAX: %s [-q] DATABASE \n", name);
-   667 fprintf(stdout, " \n");
-   668 fprintf(stdout, " -q Do not print out any messages. \n");
-   669 fprintf(stdout, " \n");
-   670 fprintf(stdout, "DATABASE is a path to where the indexed results will be \n");
-   671 fprintf(stdout, "stored for searching with the Hunt tool. \n");
-   672 fprintf(stdout, " \n");
-   673 fprintf(stdout, "(c) 2021 Wizardry and Steamworks, MIT. \n");
-   674 }
639   675  
640 /* 676 /*
641 * 677 *
642 * Main entry point. 678 * Main entry point.
643 */ 679 */
644 int main(int argc, char **argv) { 680 int main(int argc, char **argv) {
645 int option; 681 int option;
646 char *dbFile; 682 char *dbFile;
647 struct stat dirStat; 683 struct stat dirStat;
648   684  
649 // Bind handler to SIGINT. 685 // Bind handler to SIGINT.
650 signal(SIGINT, SignalHandler); 686 signal(SIGINT, SignalHandler);
651   687  
652 dbFile = DEFAULT_DATABASE_FILE; 688 dbFile = DEFAULT_DATABASE_FILE;
653 while((option = getopt(argc, argv, "hqd:")) != -1) { 689 while((option = getopt(argc, argv, "hqd:")) != -1) {
654 switch(option) { 690 switch(option) {
655 case 'd': 691 case 'd':
656 dbFile = optarg; 692 dbFile = optarg;
657 break; 693 break;
658 case 'q': 694 case 'q':
659 verbose = FALSE; 695 verbose = FALSE;
660 break; 696 break;
661 case 'h': 697 case 'h':
662 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); 698 usage(argv[0]);
663 return 0; 699 return 0;
664 case '?': 700 case '?':
665 fprintf(stderr, "Invalid option %ct.\n", optopt); 701 fprintf(stderr, "Invalid option %ct.\n", optopt);
666 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); -  
667 return 1; 702 return 1;
668 } 703 }
669 } 704 }
670   705  
671   706  
672 if(optind >= argc) { 707 if(optind >= argc) {
673 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); 708 usage(argv[0]);
674 return 1; 709 return 1;
675 } 710 }
676   711  
677 stat(argv[optind], &dirStat); 712 stat(argv[optind], &dirStat);
678 if(!S_ISDIR(dirStat.st_mode)) { 713 if(!S_ISDIR(dirStat.st_mode)) {
679 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]); 714 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]);
680 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); -  
681 return 1; 715 return 1;
682 } 716 }
683   717  
684 if(verbose) { 718 if(verbose) {
685 fprintf(stdout, "Gathering to database file: %s\n", dbFile); 719 fprintf(stdout, "Gathering to database file: %s\n", dbFile);
686 } 720 }
687   721  
688 // Gather. 722 // Gather.
689 Gather(dbFile, argv[optind]); 723 Gather(dbFile, argv[optind]);
690   724  
691 return 0; 725 return 0;
692 } 726 }
693   727