HuntnGather – Blame information for rev 31
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (C) 2021 Wizardry and Steamworks - License: MIT // |
||
3 | /////////////////////////////////////////////////////////////////////////// |
||
4 | |||
5 | #include <stdio.h> |
||
6 | #include <stdlib.h> |
||
7 | #include <string.h> |
||
29 | office | 8 | #if !defined ___AmigaOS___ |
1 | office | 9 | #include <dirent.h> |
29 | office | 10 | #include <sys/stat.h> |
1 | office | 11 | #include <signal.h> |
27 | office | 12 | #endif |
1 | office | 13 | |
14 | #include <sys/types.h> |
||
19 | office | 15 | #include <sys/syslimits.h> |
1 | office | 16 | |
26 | office | 17 | #if defined ___AmigaOS___ |
1 | office | 18 | #include <proto/dos.h> |
19 | #include <proto/exec.h> |
||
26 | office | 20 | #include <proto/locale.h> |
21 | #endif |
||
1 | office | 22 | |
22 | office | 23 | #if defined ___AsyncIO___ |
24 | #include <asyncio.h> |
||
25 | #endif |
||
26 | |||
5 | office | 27 | #if !defined ___HAVE_GETOPT___ |
1 | office | 28 | #include "getopt.h" |
29 | #endif |
||
30 | |||
31 | office | 31 | #include "StringStack.h" |
32 | |||
33 | // MemLib memory debugging. |
||
34 | #if defined MWDEBUG |
||
35 | #include "memwatch.h" |
||
36 | #endif |
||
37 | |||
26 | office | 38 | #define PROGRAM_VERSION "1.7.4" |
19 | office | 39 | |
5 | office | 40 | #if defined ___AmigaOS___ |
41 | /*************************************************************************/ |
||
42 | /* Version string used for querrying the program version. */ |
||
43 | /*************************************************************************/ |
||
44 | TEXT version_string[] = |
||
19 | office | 45 | "\0$VER: Gather " PROGRAM_VERSION " "__DATE__" by Wizardry and Steamworks"; |
5 | office | 46 | #endif |
1 | office | 47 | |
48 | #if !defined TRUE |
||
49 | #define TRUE 1; |
||
50 | #endif |
||
51 | |||
52 | #if !defined FALSE |
||
53 | #define FALSE 0; |
||
54 | #endif |
||
55 | |||
22 | office | 56 | #define ASYNC_BUF 8192 |
2 | office | 57 | #define MAX_MEM 262144 |
11 | office | 58 | #define LINE_BUF 256 |
2 | office | 59 | #define DEFAULT_DATABASE_FILE "S:gather.db" |
1 | office | 60 | |
61 | typedef struct { |
||
62 | unsigned int dirs; |
||
63 | unsigned int files; |
||
64 | } stats; |
||
65 | |||
26 | office | 66 | typedef struct { |
67 | char *name; |
||
68 | char *path; |
||
69 | } dbEntry; |
||
1 | office | 70 | |
26 | office | 71 | typedef struct { |
72 | char **database; |
||
73 | unsigned int count; |
||
74 | } dbArray; |
||
75 | |||
76 | enum MODE { |
||
77 | NONE, |
||
78 | GATHER, |
||
79 | REMOVE, |
||
80 | CREATE |
||
81 | } operation; |
||
82 | |||
83 | unsigned int run = TRUE; |
||
84 | unsigned int verbose = TRUE; |
||
85 | unsigned int maxmem = MAX_MEM; |
||
86 | // Define global locale for string compare. |
||
87 | #if defined ___AmigaOS___ |
||
88 | struct Locale *locale; |
||
89 | #endif |
||
90 | |||
1 | office | 91 | void SignalHandler(int sig) { |
92 | // Toggle the run flag to stop execution. |
||
93 | run = FALSE; |
||
94 | } |
||
95 | |||
26 | office | 96 | /* |
97 | * |
||
98 | * Used for sorting database lines. |
||
99 | */ |
||
100 | int QsortCompare(const void *a, const void *b) { |
||
101 | #if defined ___AmigaOS___ |
||
31 | office | 102 | return StrnCmp( |
103 | locale, |
||
104 | (STRPTR)(*(const char **)a), |
||
105 | (STRPTR)*((const char **)b), |
||
106 | -1, |
||
107 | SC_ASCII |
||
108 | ); |
||
26 | office | 109 | #else |
31 | office | 110 | return strcmp(*(const char **)a, *(const char **)b); |
26 | office | 111 | #endif |
1 | office | 112 | } |
113 | |||
114 | /* |
||
115 | * |
||
26 | office | 116 | * Gets the absolute path to file by name. |
1 | office | 117 | */ |
26 | office | 118 | char *PathToAbsolute(char *path) { |
119 | char *abs; |
||
120 | #if defined ___AmigaOS___ |
||
121 | BPTR lock; |
||
122 | #endif |
||
123 | |||
124 | #if defined ___AmigaOS___ |
||
125 | if((abs = malloc(PATH_MAX * sizeof(*abs))) == NULL) { |
||
126 | fprintf(stderr, "Memory allocation failure.\n"); |
||
127 | return NULL; |
||
128 | } |
||
129 | if((lock = Lock(path, SHARED_LOCK)) == 0) { |
||
130 | fprintf(stderr, "Lock on %s failed.\n", path); |
||
131 | return NULL; |
||
132 | } |
||
133 | if(NameFromLock(lock, abs, PATH_MAX) == FALSE) { |
||
134 | fprintf(stderr, "Lock on %s failed.\n", path); |
||
135 | UnLock(lock); |
||
136 | return NULL; |
||
137 | } |
||
138 | UnLock(lock); |
||
139 | #else |
||
30 | office | 140 | //abs = realpath(path, NULL); |
141 | if((abs = malloc((strlen(path) + 1) * sizeof(*abs))) == NULL) { |
||
142 | fprintf(stderr, "Memory allocation failure.\n"); |
||
143 | return NULL; |
||
144 | } |
||
145 | sprintf(abs, "%s", path); |
||
26 | office | 146 | #endif |
147 | |||
148 | return abs; |
||
149 | } |
||
150 | |||
151 | /* |
||
152 | * |
||
153 | * Compares path parts for equality. |
||
154 | */ |
||
155 | #if defined ___AmigaOS___ |
||
156 | BOOL PathCompare(char *path, char *look) { |
||
157 | #else |
||
158 | int PathCompare(char *path, char *look) { |
||
159 | #endif |
||
160 | char *a; |
||
161 | char *b; |
||
162 | |||
163 | for(a = path, b = look; *a != '\0' && *b != '\0'; ++a, ++b) { |
||
164 | if(*b != '\0' && *a != *b) { |
||
165 | return FALSE; |
||
166 | } |
||
167 | } |
||
168 | |||
169 | return *b == '\0'; |
||
170 | } |
||
171 | |||
172 | /* |
||
173 | * |
||
174 | * Gets the size of a file by name. |
||
175 | */ |
||
176 | int GetFileSize(char *dbFile) { |
||
22 | office | 177 | #if defined ___AsyncIO___ |
178 | struct AsyncFile *fp; |
||
26 | office | 179 | LONG size; |
22 | office | 180 | #else |
1 | office | 181 | FILE *fp; |
26 | office | 182 | int size; |
22 | office | 183 | #endif |
1 | office | 184 | |
22 | office | 185 | #if defined ___AsyncIO___ |
186 | if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { |
||
187 | #else |
||
1 | office | 188 | if((fp = fopen(dbFile, "r")) == NULL) { |
22 | office | 189 | #endif |
24 | office | 190 | fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile); |
26 | office | 191 | return -1; |
1 | office | 192 | } |
193 | |||
26 | office | 194 | #if defined ___AsyncIO___ |
195 | if(SeekAsync(fp, 0, MODE_END) == -1) { |
||
196 | #else |
||
30 | office | 197 | if(fseek(fp, 0L, SEEK_END) != 0) { |
26 | office | 198 | #endif |
199 | fprintf(stderr, "Seek in file %s failed.\n", dbFile); |
||
200 | #if defined ___AsyncIO___ |
||
201 | CloseAsync(fp); |
||
202 | #else |
||
203 | fclose(fp); |
||
204 | #endif |
||
205 | return -1; |
||
206 | } |
||
207 | #if defined ___AsyncIO___ |
||
208 | if((size = SeekAsync(fp, 0, MODE_CURRENT)) == -1) { |
||
209 | fprintf(stderr, "Seek in file %s failed.\n", dbFile); |
||
210 | CloseAsync(fp); |
||
211 | return -1; |
||
212 | } |
||
213 | #else |
||
214 | size = ftell(fp); |
||
215 | #endif |
||
22 | office | 216 | |
26 | office | 217 | #if defined ___AsyncIO___ |
218 | CloseAsync(fp); |
||
219 | #else |
||
220 | fclose(fp); |
||
221 | #endif |
||
1 | office | 222 | |
26 | office | 223 | return size; |
224 | } |
||
225 | |||
226 | /* |
||
227 | * |
||
228 | * Counts the lines of a file. |
||
229 | */ |
||
230 | int CountFileLines(char *dbFile) { |
||
231 | #if defined ___AsyncIO___ |
||
232 | struct AsyncFile *fp; |
||
233 | LONG c; |
||
234 | #else |
||
235 | FILE *fp; |
||
236 | char c; |
||
237 | #endif |
||
238 | int lines; |
||
239 | |||
240 | #if defined ___AsyncIO___ |
||
241 | if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { |
||
242 | #else |
||
243 | if((fp = fopen(dbFile, "r")) == NULL) { |
||
244 | #endif |
||
245 | fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile); |
||
246 | return -1; |
||
1 | office | 247 | } |
24 | office | 248 | |
26 | office | 249 | lines = 0; |
30 | office | 250 | if(verbose) { |
251 | fprintf(stdout, "Lines in '%s' so far: %d\r", dbFile, lines); |
||
252 | } |
||
253 | |||
22 | office | 254 | #if defined ___AsyncIO___ |
255 | while(run && (c = ReadCharAsync(fp)) != -1) { |
||
256 | #else |
||
1 | office | 257 | while(run && fscanf(fp, "%c", &c) == 1) { |
22 | office | 258 | #endif |
1 | office | 259 | #if defined ___AmigaOS___ |
260 | // Check if CTRL+C was pressed and abort the program. |
||
26 | office | 261 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
1 | office | 262 | run = FALSE; |
263 | continue; |
||
264 | } |
||
265 | #endif |
||
266 | switch(c) { |
||
267 | case '\n': |
||
26 | office | 268 | ++lines; |
30 | office | 269 | |
270 | if(verbose) { |
||
271 | fprintf(stdout, "Lines in '%s' so far: %d\r", dbFile, lines); |
||
272 | } |
||
1 | office | 273 | break; |
274 | } |
||
275 | } |
||
276 | |||
22 | office | 277 | #if defined ___AsyncIO___ |
278 | CloseAsync(fp); |
||
279 | #else |
||
1 | office | 280 | fclose(fp); |
22 | office | 281 | #endif |
1 | office | 282 | |
30 | office | 283 | if(verbose) { |
284 | fprintf(stdout, "\n"); |
||
285 | } |
||
286 | |||
26 | office | 287 | return lines; |
288 | } |
||
1 | office | 289 | |
26 | office | 290 | /* |
291 | * |
||
292 | * Creates a temporary file and returns its name. |
||
293 | */ |
||
294 | char *CreateTemporaryFile(void) { |
||
295 | char *name; |
||
296 | |||
297 | name = tmpnam(NULL); |
||
298 | |||
299 | return name; |
||
300 | } |
||
301 | |||
302 | /* |
||
303 | * |
||
304 | * Create multiple temporary files and return their names. |
||
305 | */ |
||
306 | char **CreateTemporaryFiles(int files) { |
||
307 | char **tmpNames; |
||
308 | int count; |
||
309 | |||
310 | if((tmpNames = malloc(files * sizeof(*tmpNames))) == NULL) { |
||
311 | fprintf(stderr, "Memory allocation failure.\n"); |
||
312 | return NULL; |
||
313 | } |
||
314 | |||
315 | if(verbose) { |
||
316 | fprintf(stdout, "Creating temporary files...\r"); |
||
317 | } |
||
318 | |||
319 | count = files; |
||
320 | while(run && --count > -1) { |
||
321 | #if defined ___AmigaOS___ |
||
322 | // Check if CTRL+C was pressed and abort the program. |
||
323 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
324 | run = FALSE; |
||
325 | continue; |
||
326 | } |
||
327 | #endif |
||
328 | tmpNames[count] = CreateTemporaryFile(); |
||
329 | |||
330 | if(verbose) { |
||
331 | fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0)); |
||
332 | } |
||
333 | } |
||
334 | |||
335 | if(verbose) { |
||
336 | fprintf(stdout, "\n"); |
||
337 | } |
||
338 | |||
339 | return tmpNames; |
||
340 | } |
||
341 | |||
342 | |||
343 | /* |
||
344 | * |
||
345 | * Skips a line in a file. |
||
346 | */ |
||
22 | office | 347 | #if defined ___AsyncIO___ |
26 | office | 348 | void SkipLine(struct AsyncFile *fp) { |
349 | LONG c; |
||
350 | while(run && (c = ReadCharAsync(fp)) != -1) { |
||
22 | office | 351 | #else |
26 | office | 352 | void SkipLine(FILE *fp) { |
353 | char c; |
||
354 | while(run && fscanf(fp, "%c", &c) == 1) { |
||
22 | office | 355 | #endif |
23 | office | 356 | #if defined ___AmigaOS___ |
357 | // Check if CTRL+C was pressed and abort the program. |
||
26 | office | 358 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
23 | office | 359 | run = FALSE; |
360 | continue; |
||
361 | } |
||
362 | #endif |
||
26 | office | 363 | switch(c) { |
364 | case '\n': |
||
365 | return; |
||
366 | } |
||
367 | } |
||
368 | } |
||
369 | |||
370 | /* |
||
371 | * |
||
372 | * Peeks at a line from a file. |
||
373 | */ |
||
22 | office | 374 | #if defined ___AsyncIO___ |
26 | office | 375 | char *PeekLine(struct AsyncFile *fp) { |
376 | LONG c; |
||
22 | office | 377 | #else |
26 | office | 378 | char *PeekLine(FILE *fp) { |
379 | char c; |
||
22 | office | 380 | #endif |
31 | office | 381 | char *line = NULL; |
382 | char *real = NULL; |
||
26 | office | 383 | unsigned int size; |
384 | int i; |
||
385 | |||
386 | size = LINE_BUF; |
||
387 | if((line = malloc(size * sizeof(*line))) == NULL) { |
||
388 | fprintf(stderr, "Memory allocation failure.\n"); |
||
389 | return NULL; |
||
1 | office | 390 | } |
391 | |||
26 | office | 392 | i = 0; |
22 | office | 393 | #if defined ___AsyncIO___ |
26 | office | 394 | while(run && (c = ReadCharAsync(fp)) != -1) { |
22 | office | 395 | #else |
26 | office | 396 | while(run && fscanf(fp, "%c", &c) == 1) { |
22 | office | 397 | #endif |
26 | office | 398 | #if defined ___AmigaOS___ |
399 | // Check if CTRL+C was pressed and abort the program. |
||
400 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
401 | run = FALSE; |
||
402 | continue; |
||
403 | } |
||
404 | #endif |
||
405 | switch(c) { |
||
406 | case '\n': |
||
407 | // Rewind the file by the number of read characters. |
||
408 | #if defined ___AsyncIO___ |
||
409 | if(SeekAsync(fp, -(i + 1), MODE_CURRENT) == -1) { |
||
410 | fprintf(stderr, "Could not seek in file.\n"); |
||
411 | free(line); |
||
412 | return NULL; |
||
413 | } |
||
414 | #else |
||
30 | office | 415 | if(fseek(fp, -(i + 1), SEEK_CUR) != 0) { |
416 | fprintf(stderr, "Could not seek in file.\n"); |
||
417 | free(line); |
||
418 | return NULL; |
||
419 | } |
||
26 | office | 420 | #endif |
421 | return line; |
||
422 | default: |
||
423 | if(strlen(line) == size) { |
||
424 | size = size * 1.5; |
||
31 | office | 425 | real = realloc(line, size * sizeof(*line)); |
426 | if(real == NULL) { |
||
427 | fprintf(stderr, "Memory reallocation failure.\n"); |
||
428 | free(line); |
||
429 | return NULL; |
||
430 | } |
||
431 | line = real; |
||
26 | office | 432 | } |
433 | line[i] = c; |
||
434 | line[i + 1] = '\0'; |
||
435 | break; |
||
436 | } |
||
437 | ++i; |
||
438 | } |
||
22 | office | 439 | |
31 | office | 440 | if(line != NULL) { |
441 | free(line); |
||
442 | } |
||
443 | |||
26 | office | 444 | return NULL; |
1 | office | 445 | } |
446 | |||
447 | /* |
||
448 | * |
||
26 | office | 449 | * Read a line from a file. |
1 | office | 450 | */ |
22 | office | 451 | #if defined ___AsyncIO___ |
26 | office | 452 | char *ReadLine(struct AsyncFile *fp) { |
453 | LONG c; |
||
22 | office | 454 | #else |
26 | office | 455 | char *ReadLine(FILE *fp) { |
456 | char c; |
||
22 | office | 457 | #endif |
31 | office | 458 | char *line = NULL; |
459 | char *real = NULL; |
||
1 | office | 460 | unsigned int size; |
26 | office | 461 | unsigned int i; |
1 | office | 462 | |
26 | office | 463 | size = LINE_BUF; |
464 | if((line = malloc(size * sizeof(*line))) == NULL) { |
||
465 | fprintf(stderr, "Memory allication failure.\n"); |
||
466 | return NULL; |
||
467 | } |
||
468 | |||
469 | i = 0; |
||
22 | office | 470 | #if defined ___AsyncIO___ |
26 | office | 471 | while(run && (c = ReadCharAsync(fp)) != -1) { |
22 | office | 472 | #else |
26 | office | 473 | while(run && fscanf(fp, "%c", &c) == 1) { |
22 | office | 474 | #endif |
1 | office | 475 | #if defined ___AmigaOS___ |
476 | // Check if CTRL+C was pressed and abort the program. |
||
477 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
478 | run = FALSE; |
||
23 | office | 479 | continue; |
1 | office | 480 | } |
481 | #endif |
||
26 | office | 482 | switch(c) { |
483 | case '\n': |
||
484 | return line; |
||
485 | default: |
||
486 | if(strlen(line) == size) { |
||
487 | size = size * 1.5; |
||
31 | office | 488 | real = realloc(line, size * sizeof(*line)); |
489 | if(real == NULL) { |
||
490 | fprintf(stderr, "Memory reallocation failure.\n"); |
||
491 | free(line); |
||
492 | return NULL; |
||
493 | } |
||
494 | line = real; |
||
26 | office | 495 | } |
496 | line[i] = c; |
||
497 | line[i + 1] = '\0'; |
||
498 | break; |
||
1 | office | 499 | } |
26 | office | 500 | ++i; |
501 | } |
||
1 | office | 502 | |
31 | office | 503 | if(line != NULL) { |
504 | free(line); |
||
505 | } |
||
506 | |||
26 | office | 507 | return NULL; |
508 | } |
||
1 | office | 509 | |
26 | office | 510 | /* |
511 | * |
||
512 | * Delete a file. |
||
513 | */ |
||
1 | office | 514 | #if defined ___AmigaOS___ |
26 | office | 515 | BOOL RemoveFile(char *name) { |
516 | return DeleteFile(name); |
||
517 | #else |
||
518 | int RemoveFile(char *name) { |
||
519 | return remove(name) == 0; |
||
1 | office | 520 | #endif |
26 | office | 521 | } |
1 | office | 522 | |
26 | office | 523 | /* |
524 | * |
||
525 | * Deletes files. |
||
526 | */ |
||
527 | void RemoveFiles(char **names, int count) { |
||
528 | unsigned int i; |
||
529 | for(i = 0; i < count; ++i) { |
||
530 | if(RemoveFile(names[i]) == FALSE) { |
||
531 | fprintf(stderr, "Unable to remove %s...\n", names[i]); |
||
532 | continue; |
||
533 | } |
||
534 | fprintf(stderr, "Removing file: %s\n", names[i]); |
||
535 | } |
||
536 | } |
||
1 | office | 537 | |
26 | office | 538 | /* |
539 | * |
||
540 | * Copies a file to another file by name. |
||
541 | */ |
||
542 | void CopyFile(char *a, char *b) { |
||
543 | #if defined ___AsyncIO___ |
||
544 | struct AsyncFile *ap; |
||
545 | struct AsyncFile *bp; |
||
546 | LONG c; |
||
547 | #else |
||
548 | FILE *ap; |
||
549 | FILE *bp; |
||
550 | char c; |
||
551 | #endif |
||
1 | office | 552 | |
26 | office | 553 | // Open database file for writing. |
554 | #if defined ___AsyncIO___ |
||
555 | if((ap = OpenAsync(a, MODE_READ, ASYNC_BUF)) == NULL) { |
||
556 | #else |
||
557 | if((ap = fopen(a, "r")) == NULL) { |
||
558 | #endif |
||
559 | fprintf(stderr, "Unable to open '%s' for reading.\n", a); |
||
560 | return; |
||
561 | } |
||
15 | office | 562 | |
26 | office | 563 | // Open temporary file for reading. |
564 | #if defined ___AsyncIO___ |
||
565 | if((bp = OpenAsync(b, MODE_WRITE, ASYNC_BUF)) == NULL) { |
||
566 | #else |
||
30 | office | 567 | if((bp = fopen(b, "w")) == NULL) { |
15 | office | 568 | #endif |
26 | office | 569 | fprintf(stderr, "Unable to open file '%s' for writing.\n", b); |
15 | office | 570 | |
26 | office | 571 | // Close database file. |
22 | office | 572 | #if defined ___AsyncIO___ |
26 | office | 573 | CloseAsync(ap); |
22 | office | 574 | #else |
26 | office | 575 | fclose(ap); |
22 | office | 576 | #endif |
1 | office | 577 | |
26 | office | 578 | return; |
1 | office | 579 | } |
580 | |||
26 | office | 581 | #if defined ___AsyncIO___ |
582 | while(run && (c = ReadCharAsync(ap)) != -1) { |
||
583 | #else |
||
584 | while(run && fscanf(ap, "%c", &c) == 1) { |
||
585 | #endif |
||
586 | #if defined ___AmigaOS___ |
||
587 | // Check if CTRL+C was pressed and abort the program. |
||
30 | office | 588 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
26 | office | 589 | run = FALSE; |
590 | continue; |
||
591 | } |
||
592 | #endif |
||
593 | #if defined ___AsyncIO___ |
||
594 | if(WriteCharAsync(bp, (UBYTE)c) != 1) { |
||
595 | #else |
||
596 | if(fprintf(bp, "%c", c) != 1) { |
||
597 | #endif |
||
598 | fprintf(stderr, "Unable to write to '%s'.\n", b); |
||
599 | break; |
||
600 | } |
||
1 | office | 601 | } |
602 | |||
22 | office | 603 | #if defined ___AsyncIO___ |
26 | office | 604 | CloseAsync(ap); |
605 | CloseAsync(bp); |
||
22 | office | 606 | #else |
26 | office | 607 | fclose(ap); |
608 | fclose(bp); |
||
22 | office | 609 | #endif |
1 | office | 610 | } |
611 | |||
612 | /* |
||
613 | * |
||
26 | office | 614 | * Write lines to a file. |
1 | office | 615 | */ |
26 | office | 616 | void WriteLinesToFile(char *dbFile, char **lines, unsigned int count) { |
23 | office | 617 | #if defined ___AsyncIO___ |
618 | struct AsyncFile *fp; |
||
619 | #else |
||
1 | office | 620 | FILE *fp; |
23 | office | 621 | #endif |
30 | office | 622 | unsigned int i; |
26 | office | 623 | char *rem; |
1 | office | 624 | |
26 | office | 625 | // Write the database lines back to the database. |
23 | office | 626 | #if defined ___AsyncIO___ |
26 | office | 627 | if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { |
23 | office | 628 | #else |
26 | office | 629 | if((fp = fopen(dbFile, "w")) == NULL) { |
23 | office | 630 | #endif |
26 | office | 631 | fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile); |
632 | return; |
||
1 | office | 633 | } |
634 | |||
26 | office | 635 | rem = NULL; |
636 | for(i = 0; i < count; ++i) { |
||
637 | #if defined ___AmigaOS___ |
||
638 | // Check if CTRL+C was pressed and abort the program. |
||
30 | office | 639 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
26 | office | 640 | run = FALSE; |
641 | continue; |
||
642 | } |
||
643 | #endif |
||
644 | |||
645 | if(rem != NULL) { |
||
646 | #if defined ___AmigaOS___ |
||
647 | if(StrnCmp(locale, lines[i], rem, -1, SC_ASCII) == 0) { |
||
648 | #else |
||
27 | office | 649 | if(strcmp(lines[i], rem) == 0) { |
26 | office | 650 | #endif |
651 | continue; |
||
652 | } |
||
653 | } |
||
654 | |||
23 | office | 655 | #if defined ___AsyncIO___ |
26 | office | 656 | WriteAsync(fp, lines[i], (LONG)strlen(lines[i])); |
657 | WriteAsync(fp, "\n", 1); |
||
23 | office | 658 | #else |
26 | office | 659 | fprintf(fp, "%s\n", lines[i]); |
23 | office | 660 | #endif |
1 | office | 661 | |
26 | office | 662 | if(rem != NULL) { |
663 | free(rem); |
||
664 | } |
||
665 | |||
666 | rem = malloc(strlen(lines[i]) + 1); |
||
667 | sprintf(rem, "%s", lines[i]); |
||
668 | } |
||
669 | |||
31 | office | 670 | if(rem != NULL) { |
671 | free(rem); |
||
672 | } |
||
673 | |||
23 | office | 674 | #if defined ___AsyncIO___ |
26 | office | 675 | CloseAsync(fp); |
23 | office | 676 | #else |
1 | office | 677 | fclose(fp); |
23 | office | 678 | #endif |
26 | office | 679 | } |
23 | office | 680 | |
26 | office | 681 | /* |
682 | * |
||
683 | * Create a database entry from a line of text. |
||
684 | */ |
||
31 | office | 685 | dbEntry* CreateDatabaseEntry(char *line) { |
26 | office | 686 | dbEntry *entry; |
687 | char *ptr; |
||
688 | unsigned int side; |
||
689 | unsigned int i; |
||
690 | unsigned int j; |
||
691 | |||
692 | if((entry = malloc(1 * sizeof(*entry))) == NULL) { |
||
693 | fprintf(stderr, "Memory allocation failure.\n"); |
||
694 | return NULL; |
||
695 | } |
||
696 | |||
31 | office | 697 | if((entry->name = malloc((strlen(line) + 1) * sizeof(*entry->name))) == NULL) { |
26 | office | 698 | fprintf(stderr, "Memory allocation failure.\n"); |
699 | return NULL; |
||
700 | } |
||
701 | |||
31 | office | 702 | if((entry->path = malloc((strlen(line) + 1) * sizeof(*entry->path))) == NULL) { |
26 | office | 703 | fprintf(stderr, "Memory allocation failure.\n"); |
704 | return NULL; |
||
705 | } |
||
706 | |||
707 | for(ptr = line, side = 0, i = 0, j = 0; run && *ptr != '\0'; ++ptr) { |
||
708 | #if defined ___AmigaOS___ |
||
709 | // Check if CTRL+C was pressed and abort the program. |
||
31 | office | 710 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
26 | office | 711 | run = FALSE; |
712 | continue; |
||
713 | } |
||
714 | #endif |
||
715 | switch(*ptr) { |
||
716 | case '\t': |
||
717 | entry->name[i] = '\0'; |
||
718 | ++side; |
||
719 | break; |
||
720 | case '\n': |
||
721 | entry->path[j] = '\0'; |
||
722 | return entry; |
||
723 | default: |
||
724 | switch(side) { |
||
725 | case 0: |
||
726 | entry->name[i++] = *ptr; |
||
727 | break; |
||
728 | case 1: |
||
729 | entry->path[j++] = *ptr; |
||
730 | break; |
||
731 | } |
||
732 | break; |
||
733 | } |
||
734 | } |
||
735 | |||
736 | return entry; |
||
1 | office | 737 | } |
738 | |||
739 | /* |
||
740 | * |
||
26 | office | 741 | * |
1 | office | 742 | */ |
26 | office | 743 | dbArray *GetDatabaseArray(char *dbFile) { |
22 | office | 744 | #if defined ___AsyncIO___ |
745 | struct AsyncFile *fp; |
||
746 | #else |
||
1 | office | 747 | FILE *fp; |
22 | office | 748 | #endif |
26 | office | 749 | dbArray *array; |
750 | dbEntry *entry; |
||
31 | office | 751 | char *line = NULL; |
752 | char *real = NULL; |
||
26 | office | 753 | unsigned int count; |
1 | office | 754 | |
26 | office | 755 | // Open database file for reading. |
22 | office | 756 | #if defined ___AsyncIO___ |
757 | if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { |
||
758 | #else |
||
1 | office | 759 | if((fp = fopen(dbFile, "r")) == NULL) { |
22 | office | 760 | #endif |
24 | office | 761 | fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile); |
26 | office | 762 | return NULL; |
1 | office | 763 | } |
764 | |||
31 | office | 765 | if((array = malloc(1 * sizeof(*array))) == NULL) { |
766 | fprintf(stderr, "Memory allocation failure.\n"); |
||
767 | #if defined ___AsyncIO___ |
||
768 | CloseAsync(fp); |
||
769 | #else |
||
770 | fclose(fp); |
||
771 | #endif |
||
772 | return NULL; |
||
773 | } |
||
774 | |||
26 | office | 775 | count = 0; |
776 | while(run && (line = ReadLine(fp)) != NULL) { |
||
23 | office | 777 | #if defined ___AmigaOS___ |
778 | // Check if CTRL+C was pressed and abort the program. |
||
26 | office | 779 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
23 | office | 780 | run = FALSE; |
781 | continue; |
||
782 | } |
||
783 | #endif |
||
31 | office | 784 | if((entry = CreateDatabaseEntry(line)) == NULL) { |
26 | office | 785 | fprintf(stderr, "Unable to create database entry.\n"); |
31 | office | 786 | free(line); |
26 | office | 787 | #if defined ___AsyncIO___ |
788 | CloseAsync(fp); |
||
789 | #else |
||
790 | fclose(fp); |
||
791 | #endif |
||
792 | return NULL; |
||
1 | office | 793 | } |
26 | office | 794 | |
795 | // Load up the name and path into the database variable. |
||
31 | office | 796 | real = realloc(array->database, (count + 1) * sizeof(*array->database)); |
797 | if(real == NULL) { |
||
798 | fprintf(stderr, "Memory reallocation failure.\n"); |
||
799 | free(entry->name); |
||
800 | free(entry->path); |
||
801 | free(entry); |
||
802 | free(line); |
||
803 | #if defined ___AsyncIO___ |
||
804 | CloseAsync(fp); |
||
805 | #else |
||
806 | fclose(fp); |
||
807 | #endif |
||
808 | return NULL; |
||
809 | } |
||
810 | array->database = real; |
||
811 | |||
26 | office | 812 | if((array->database[count] = malloc((strlen(entry->name) + strlen(entry->path) + 1 + 1) * sizeof(*array->database[count]))) == NULL) { |
813 | fprintf(stderr, "Memory allocation failure.\n"); |
||
31 | office | 814 | free(entry->name); |
815 | free(entry->path); |
||
26 | office | 816 | free(entry); |
817 | free(line); |
||
818 | #if defined ___AsyncIO___ |
||
819 | CloseAsync(fp); |
||
820 | #else |
||
821 | fclose(fp); |
||
822 | #endif |
||
823 | return NULL; |
||
824 | } |
||
825 | sprintf(array->database[count], "%s\t%s", entry->name, entry->path); |
||
826 | ++count; |
||
827 | |||
30 | office | 828 | // Free the database entry. |
829 | free(entry->name); |
||
830 | free(entry->path); |
||
26 | office | 831 | free(entry); |
30 | office | 832 | |
26 | office | 833 | free(line); |
1 | office | 834 | } |
835 | |||
31 | office | 836 | if(line != NULL) { |
837 | free(line); |
||
838 | } |
||
839 | |||
22 | office | 840 | #if defined ___AsyncIO___ |
841 | CloseAsync(fp); |
||
842 | #else |
||
1 | office | 843 | fclose(fp); |
22 | office | 844 | #endif |
1 | office | 845 | |
26 | office | 846 | array->count = count; |
847 | return array; |
||
1 | office | 848 | } |
849 | |||
850 | /* |
||
851 | * |
||
26 | office | 852 | * Sorts a database file lexicographically. |
1 | office | 853 | */ |
26 | office | 854 | void SortDatabase(char *dbFile) { |
855 | dbArray *array; |
||
30 | office | 856 | int i; |
1 | office | 857 | |
26 | office | 858 | if(verbose) { |
859 | fprintf(stdout, "Sorting '%s'...\n", dbFile); |
||
860 | } |
||
1 | office | 861 | |
26 | office | 862 | // Retrieve the database as an array. |
863 | if((array = GetDatabaseArray(dbFile)) == NULL) { |
||
864 | fprintf(stderr, "Unable to read '%s' as a database file.\n", dbFile); |
||
865 | return; |
||
866 | } |
||
867 | |||
868 | // Sort the database. |
||
869 | qsort(array->database, array->count, sizeof(char *), QsortCompare); |
||
870 | |||
871 | // Write back the database to the database file. |
||
872 | WriteLinesToFile(dbFile, array->database, array->count); |
||
873 | |||
30 | office | 874 | // Deallocate all the lines. |
875 | for(i = 0; i < array->count; ++i) { |
||
876 | free(array->database[i]); |
||
877 | } |
||
878 | |||
26 | office | 879 | free(array); |
880 | } |
||
881 | |||
882 | /* |
||
883 | * |
||
884 | * Updates a database file "dbFile". |
||
885 | */ |
||
886 | stats *CollectFiles(char *dbFile, char **paths, unsigned int count) { |
||
887 | #if defined ___AsyncIO___ |
||
888 | struct AsyncFile *fp; |
||
889 | #else |
||
890 | FILE *fp; |
||
891 | #endif |
||
28 | office | 892 | #if defined ___AmigaOS___ |
893 | struct FileInfoBlock *FIBp, *FIBq; |
||
894 | BPTR lockp, lockq; |
||
895 | #else |
||
26 | office | 896 | DIR *dir; |
897 | struct dirent *entry; |
||
29 | office | 898 | struct stat dirStat; |
28 | office | 899 | #endif |
900 | stringStack *stack; |
||
31 | office | 901 | stats *stats = NULL; |
26 | office | 902 | int i; |
903 | char *path; |
||
28 | office | 904 | char *sub; |
26 | office | 905 | |
906 | #if defined ___AsyncIO___ |
||
907 | if((fp = OpenAsync(dbFile, MODE_APPEND, ASYNC_BUF)) == NULL) { |
||
908 | #else |
||
30 | office | 909 | if((fp = fopen(dbFile, "a")) == NULL) { |
26 | office | 910 | #endif |
911 | fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile); |
||
31 | office | 912 | return NULL; |
26 | office | 913 | } |
914 | |||
1 | office | 915 | if(verbose) { |
26 | office | 916 | fprintf(stdout, "Collecting files...\r"); |
1 | office | 917 | } |
918 | |||
31 | office | 919 | // Initialize metrics. |
920 | if((stats = malloc(sizeof(*stats))) == NULL) { |
||
921 | fprintf(stderr, "Memory allocation failure.\n"); |
||
922 | #if defined ___AsyncIO___ |
||
923 | CloseAsync(fp); |
||
924 | #else |
||
925 | fclose(fp); |
||
926 | #endif |
||
927 | return NULL; |
||
928 | } |
||
929 | |||
930 | stats->dirs = 0; |
||
931 | stats->files = 0; |
||
932 | |||
26 | office | 933 | // Push the first path onto the stack. |
934 | stack = stringStackCreate(count); |
||
935 | for(i = 0; run && i < count; ++i) { |
||
936 | stringStackPush(stack, paths[i]); |
||
937 | } |
||
938 | |||
939 | while(run && !stringStackIsEmpty(stack)) { |
||
1 | office | 940 | #if defined ___AmigaOS___ |
941 | // Check if CTRL+C was pressed and abort the program. |
||
942 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
943 | run = FALSE; |
||
23 | office | 944 | continue; |
1 | office | 945 | } |
946 | #endif |
||
26 | office | 947 | if((path = stringStackPop(stack)) == NULL) { |
948 | break; |
||
949 | } |
||
1 | office | 950 | |
28 | office | 951 | #if defined ___AmigaOS___ |
952 | if((lockp = Lock(path, ACCESS_READ)) == NULL) { |
||
953 | fprintf(stderr, "Could not lock path '%s' for reading.\n", path); |
||
954 | free(path); |
||
955 | continue; |
||
26 | office | 956 | } |
24 | office | 957 | |
30 | office | 958 | if((FIBp = AllocDosObject(DOS_FIB, NULL)) == NULL) { |
28 | office | 959 | fprintf(stderr, "Path '%s' info block allocation failure.\n", path); |
960 | UnLock(lockp); |
||
961 | free(path); |
||
962 | continue; |
||
963 | } |
||
964 | |||
965 | if(Examine(lockp, FIBp) == FALSE) { |
||
966 | fprintf(stderr, "Path '%s' could not be examined.\n", path); |
||
967 | FreeDosObject(DOS_FIB, FIBp); |
||
968 | UnLock(lockp); |
||
969 | free(path); |
||
970 | continue; |
||
971 | } |
||
972 | |||
973 | while(run && ExNext(lockp, FIBp)) { |
||
26 | office | 974 | // Check if CTRL+C was pressed and abort the program. |
975 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
976 | run = FALSE; |
||
31 | office | 977 | continue; |
26 | office | 978 | } |
28 | office | 979 | #else |
980 | |||
981 | if((dir = opendir(path)) == NULL) { |
||
982 | fprintf(stderr, "Unable to open '%s' for reading.\n", path); |
||
983 | free(path); |
||
984 | continue; |
||
985 | } |
||
986 | |||
987 | while(run && (entry = readdir(dir)) != NULL) { |
||
26 | office | 988 | #endif |
989 | switch(path[strlen(path) - 1]) { |
||
990 | case '/': |
||
991 | case ':': // This is a drive path. |
||
28 | office | 992 | #if defined ___AmigaOS___ |
30 | office | 993 | if((sub = malloc(strlen(path) + strlen(FIBp->fib_FileName) + 1)) == NULL) { |
28 | office | 994 | #else |
30 | office | 995 | if((sub = malloc(strlen(path) + strlen(entry->d_name) + 1)) == NULL) { |
28 | office | 996 | #endif |
26 | office | 997 | fprintf(stderr, "Memory allocation failure.\n"); |
28 | office | 998 | #if defined ___AmigaOS___ |
999 | FreeDosObject(DOS_FIB, FIBp); |
||
1000 | UnLock(lockp); |
||
1001 | #else |
||
26 | office | 1002 | closedir(dir); |
28 | office | 1003 | #endif |
26 | office | 1004 | free(path); |
1005 | stringStackDestroy(stack); |
||
1006 | #if defined ___AsyncIO___ |
||
1007 | CloseAsync(fp); |
||
1008 | #else |
||
1009 | fclose(fp); |
||
1010 | #endif |
||
1011 | return NULL; |
||
1012 | } |
||
28 | office | 1013 | #if defined ___AmigaOS___ |
1014 | sprintf(sub, "%s%s", path, FIBp->fib_FileName); |
||
1015 | #else |
||
1016 | sprintf(sub, "%s%s", path, entry->d_name); |
||
1017 | #endif |
||
26 | office | 1018 | break; |
1019 | default: |
||
28 | office | 1020 | #if defined ___AmigaOS___ |
30 | office | 1021 | if((sub = malloc(strlen(path) + strlen(FIBp->fib_FileName) + 1 + 1)) == NULL) { |
28 | office | 1022 | #else |
30 | office | 1023 | if((sub = malloc(strlen(path) + strlen(entry->d_name) + 1 + 1)) == NULL) { |
28 | office | 1024 | #endif |
26 | office | 1025 | fprintf(stderr, "Memory allocation failure.\n"); |
28 | office | 1026 | #if defined ___AmigaOS___ |
1027 | FreeDosObject(DOS_FIB, FIBp); |
||
1028 | UnLock(lockp); |
||
1029 | #else |
||
26 | office | 1030 | closedir(dir); |
28 | office | 1031 | #endif |
26 | office | 1032 | free(path); |
1033 | stringStackDestroy(stack); |
||
1034 | #if defined ___AsyncIO___ |
||
1035 | CloseAsync(fp); |
||
1036 | #else |
||
1037 | fclose(fp); |
||
1038 | #endif |
||
1039 | return NULL; |
||
1040 | } |
||
28 | office | 1041 | #if defined ___AmigaOS___ |
1042 | sprintf(sub, "%s/%s", path, FIBp->fib_FileName); |
||
1043 | #else |
||
1044 | sprintf(sub, "%s/%s", path, entry->d_name); |
||
1045 | #endif |
||
26 | office | 1046 | break; |
1047 | } |
||
28 | office | 1048 | |
30 | office | 1049 | |
28 | office | 1050 | #if defined ___AmigaOS___ |
1051 | if((lockq = Lock(sub, ACCESS_READ)) == NULL) { |
||
1052 | fprintf(stderr, "Could not lock path '%s' for reading.\n", sub); |
||
1053 | free(sub); |
||
1054 | continue; |
||
1055 | } |
||
1056 | |||
30 | office | 1057 | if((FIBq = AllocDosObject(DOS_FIB, NULL)) == NULL) { |
28 | office | 1058 | fprintf(stderr, "Path '%s' info block allocation failure.\n", sub); |
1059 | UnLock(lockq); |
||
1060 | free(sub); |
||
1061 | continue; |
||
1062 | } |
||
1063 | |||
1064 | if(Examine(lockq, FIBq) == FALSE) { |
||
1065 | fprintf(stderr, "Path '%s' could not be examined.\n", sub); |
||
1066 | FreeDosObject(DOS_FIB, FIBq); |
||
1067 | UnLock(lockq); |
||
1068 | free(sub); |
||
1069 | continue; |
||
1070 | } |
||
1071 | |||
1072 | if(FIBq->fib_DirEntryType > 0) { |
||
1073 | #else |
||
1074 | stat(sub, &dirStat); |
||
26 | office | 1075 | if(S_ISDIR(dirStat.st_mode)) { |
28 | office | 1076 | #endif |
1077 | stringStackPush(stack, sub); |
||
26 | office | 1078 | |
1079 | ++stats->dirs; |
||
1080 | |||
1081 | if(verbose) { |
||
1082 | fprintf(stdout, |
||
1083 | "Gathered %d directories and %d files.\r", |
||
1084 | stats->dirs, |
||
1085 | stats->files); |
||
1086 | } |
||
1087 | |||
28 | office | 1088 | #if defined ___AmigaOS___ |
1089 | FreeDosObject(DOS_FIB, FIBq); |
||
1090 | UnLock(lockq); |
||
1091 | #endif |
||
1092 | free(sub); |
||
26 | office | 1093 | continue; |
1094 | } |
||
1095 | |||
28 | office | 1096 | #if defined ___AmigaOS___ |
1097 | FreeDosObject(DOS_FIB, FIBq); |
||
1098 | UnLock(lockq); |
||
1099 | #endif |
||
1100 | |||
30 | office | 1101 | ++stats->files; |
1102 | |||
1103 | if(verbose) { |
||
1104 | fprintf(stdout, |
||
1105 | "Gathered %d directories and %d files.\r", |
||
1106 | stats->dirs, |
||
1107 | stats->files); |
||
1108 | } |
||
1109 | |||
26 | office | 1110 | #if defined ___NOCASE_FS___ |
28 | office | 1111 | #if defined ___AmigaOS___ |
1112 | strupr(FIBp->fib_FileName); |
||
1113 | #else |
||
26 | office | 1114 | strupr(entry->d_name); |
1115 | #endif |
||
28 | office | 1116 | #endif |
30 | office | 1117 | |
1118 | |||
26 | office | 1119 | // Write to database file. |
1120 | #if defined ___AsyncIO___ |
||
28 | office | 1121 | #if defined ___AmigaOS___ |
1122 | WriteAsync(fp, FIBp->fib_FileName, (LONG)strlen(FIBp->fib_FileName)); |
||
1123 | #else |
||
26 | office | 1124 | WriteAsync(fp, entry->d_name, (LONG)strlen(entry->d_name)); |
28 | office | 1125 | #endif |
26 | office | 1126 | WriteAsync(fp, "\t", 1); |
28 | office | 1127 | WriteAsync(fp, sub, (LONG)strlen(sub)); |
26 | office | 1128 | WriteAsync(fp, "\n", 1); |
1129 | #else |
||
28 | office | 1130 | #if defined ___AmigaOS___ |
1131 | fprintf(fp, "%s\t%s\n", FIBp->fib_FileName, sub); |
||
1132 | #else |
||
1133 | fprintf(fp, "%s\t%s\n", entry->d_name, sub); |
||
26 | office | 1134 | #endif |
28 | office | 1135 | #endif |
1136 | free(sub); |
||
26 | office | 1137 | } |
1138 | |||
28 | office | 1139 | #if defined ___AmigaOS___ |
1140 | FreeDosObject(DOS_FIB, FIBp); |
||
1141 | UnLock(lockp); |
||
1142 | #else |
||
26 | office | 1143 | closedir(dir); |
28 | office | 1144 | #endif |
26 | office | 1145 | free(path); |
1 | office | 1146 | } |
1147 | |||
1148 | if(verbose) { |
||
1149 | fprintf(stdout, "\n"); |
||
1150 | } |
||
1151 | |||
26 | office | 1152 | stringStackDestroy(stack); |
1153 | |||
1154 | #if defined ___AsyncIO___ |
||
1155 | CloseAsync(fp); |
||
1156 | #else |
||
1157 | fclose(fp); |
||
1158 | #endif |
||
1159 | |||
1160 | return stats; |
||
1161 | |||
1 | office | 1162 | } |
1163 | |||
1164 | /* |
||
1165 | * |
||
1166 | * Writes lines from the database "dbFile" to temporary filenames "tmpNames". |
||
1167 | */ |
||
23 | office | 1168 | void WriteTemporaryFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) { |
22 | office | 1169 | #if defined ___AsyncIO___ |
1170 | struct AsyncFile *fp, *tp; |
||
1171 | LONG c; |
||
1172 | #else |
||
1 | office | 1173 | FILE *fp, *tp; |
1174 | char c; |
||
22 | office | 1175 | #endif |
1 | office | 1176 | int lines; |
26 | office | 1177 | int write; |
1 | office | 1178 | |
22 | office | 1179 | #if defined ___AsyncIO___ |
1180 | if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { |
||
1181 | #else |
||
1 | office | 1182 | if((fp = fopen(dbFile, "r")) == NULL) { |
22 | office | 1183 | #endif |
24 | office | 1184 | fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile); |
1 | office | 1185 | return; |
1186 | } |
||
1187 | |||
22 | office | 1188 | #if defined ___AsyncIO___ |
23 | office | 1189 | if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { |
22 | office | 1190 | #else |
23 | office | 1191 | if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { |
22 | office | 1192 | #endif |
24 | office | 1193 | fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]); |
1194 | #if defined ___AsyncIO___ |
||
1195 | CloseAsync(fp); |
||
1196 | #else |
||
1197 | fclose(fp); |
||
1198 | #endif |
||
1 | office | 1199 | return; |
1200 | } |
||
1201 | |||
1202 | if(verbose) { |
||
24 | office | 1203 | fprintf(stdout, "Writing to temporary files...\r"); |
1 | office | 1204 | } |
1205 | |||
26 | office | 1206 | write = 0; |
1 | office | 1207 | lines = 0; |
22 | office | 1208 | #if defined ___AsyncIO___ |
1209 | while(run && (c = ReadCharAsync(fp)) != -1) { |
||
1210 | #else |
||
1 | office | 1211 | while(run && fscanf(fp, "%c", &c) == 1) { |
22 | office | 1212 | #endif |
1 | office | 1213 | #if defined ___AmigaOS___ |
1214 | // Check if CTRL+C was pressed and abort the program. |
||
1215 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
1216 | run = FALSE; |
||
23 | office | 1217 | continue; |
1 | office | 1218 | } |
1219 | #endif |
||
1220 | switch(c) { |
||
1221 | case '\n': |
||
1222 | // Increment the total written lines. |
||
26 | office | 1223 | ++write; |
1 | office | 1224 | |
1225 | if(verbose) { |
||
26 | office | 1226 | fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)write / total) * 100.0)); |
1 | office | 1227 | } |
1228 | |||
1229 | // Write the newline character back. |
||
22 | office | 1230 | #if defined ___AsyncIO___ |
1231 | if(WriteCharAsync(tp, (UBYTE)c) != 1) { |
||
1232 | #else |
||
1 | office | 1233 | if(fprintf(tp, "%c", c) != 1) { |
22 | office | 1234 | #endif |
24 | office | 1235 | fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]); |
22 | office | 1236 | #if defined ___AsyncIO___ |
1237 | CloseAsync(tp); |
||
1238 | CloseAsync(fp); |
||
1239 | #else |
||
19 | office | 1240 | fclose(tp); |
1 | office | 1241 | fclose(fp); |
22 | office | 1242 | #endif |
1 | office | 1243 | return; |
1244 | } |
||
1245 | // Switch to the next temporary file. |
||
1246 | if(++lines >= tmpLines) { |
||
1247 | // If there are no temporary files left then run till the end. |
||
1248 | if(tmpFiles - 1 < 0) { |
||
1249 | break; |
||
1250 | } |
||
1251 | |||
1252 | // Close the previous temporary file and write to the next temporary file. |
||
22 | office | 1253 | #if defined ___AsyncIO___ |
1254 | CloseAsync(tp); |
||
23 | office | 1255 | if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { |
22 | office | 1256 | #else |
1 | office | 1257 | fclose(tp); |
23 | office | 1258 | if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { |
22 | office | 1259 | #endif |
24 | office | 1260 | fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]); |
22 | office | 1261 | #if defined ___AsyncIO___ |
1262 | CloseAsync(fp); |
||
1263 | #else |
||
1 | office | 1264 | fclose(fp); |
22 | office | 1265 | #endif |
24 | office | 1266 | return; |
1 | office | 1267 | } |
1268 | lines = 0; |
||
1269 | break; |
||
1270 | } |
||
1271 | break; |
||
1272 | default: |
||
22 | office | 1273 | #if defined ___AsyncIO___ |
1274 | if(WriteCharAsync(tp, (UBYTE)c) != 1) { |
||
1275 | #else |
||
1 | office | 1276 | if(fprintf(tp, "%c", c) != 1) { |
22 | office | 1277 | #endif |
24 | office | 1278 | fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]); |
22 | office | 1279 | #if defined ___AsyncIO___ |
1280 | CloseAsync(tp); |
||
1281 | CloseAsync(fp); |
||
1282 | #else |
||
1 | office | 1283 | fclose(tp); |
1284 | fclose(fp); |
||
22 | office | 1285 | #endif |
1 | office | 1286 | return; |
1287 | } |
||
1288 | break; |
||
1289 | } |
||
1290 | } |
||
1291 | |||
24 | office | 1292 | if(verbose) { |
1293 | fprintf(stdout, "\n"); |
||
1294 | } |
||
1 | office | 1295 | |
22 | office | 1296 | #if defined ___AsyncIO___ |
1297 | CloseAsync(tp); |
||
1298 | CloseAsync(fp); |
||
1299 | #else |
||
1 | office | 1300 | fclose(tp); |
1301 | fclose(fp); |
||
22 | office | 1302 | #endif |
1 | office | 1303 | } |
1304 | |||
1305 | /* |
||
1306 | * |
||
1307 | * Merges temporary files "tmpNames" into a database "dbFile". |
||
1308 | */ |
||
24 | office | 1309 | void MergeTemporaryFiles(char *dbFile, char **tmpNames, int files, int lines) { |
22 | office | 1310 | #if defined ___AsyncIO___ |
1311 | struct AsyncFile *fp; |
||
1312 | struct AsyncFile **tp; |
||
1313 | #else |
||
1 | office | 1314 | FILE *fp; |
1315 | FILE **tp; |
||
22 | office | 1316 | #endif |
31 | office | 1317 | unsigned int i; |
1318 | unsigned int j; |
||
1 | office | 1319 | char *tmp; |
26 | office | 1320 | char *rem; |
14 | office | 1321 | char *min; |
1 | office | 1322 | int count; |
1323 | |||
22 | office | 1324 | #if defined ___AsyncIO___ |
23 | office | 1325 | if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { |
22 | office | 1326 | #else |
23 | office | 1327 | if((fp = fopen(dbFile, "w")) == NULL) { |
22 | office | 1328 | #endif |
24 | office | 1329 | fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile); |
1 | office | 1330 | return; |
1331 | } |
||
1332 | |||
1333 | // Allocate as many file pointers as temporary files. |
||
26 | office | 1334 | if((tp = malloc(files * sizeof(*tp))) == NULL) { |
1335 | fprintf(stderr, "Memory allocation failure.\n"); |
||
1336 | #if defined ___AsyncIO___ |
||
1337 | CloseAsync(fp); |
||
1338 | #else |
||
1339 | fclose(fp); |
||
1340 | #endif |
||
1341 | return; |
||
1342 | } |
||
1 | office | 1343 | |
1344 | // Open all temporary files for reading. |
||
1345 | for(i = 0; i < files; ++i) { |
||
22 | office | 1346 | #if defined ___AsyncIO___ |
1347 | if((tp[i] = OpenAsync(tmpNames[i], MODE_READ, ASYNC_BUF)) == NULL) { |
||
1348 | #else |
||
1 | office | 1349 | if((tp[i] = fopen(tmpNames[i], "r")) == NULL) { |
22 | office | 1350 | #endif |
24 | office | 1351 | fprintf(stderr, "Unable to open '%s' for reading.\n", tmpNames[i]); |
1 | office | 1352 | // Close all temporary files. |
24 | office | 1353 | while(--i > -1) { |
22 | office | 1354 | #if defined ___AsyncIO___ |
1355 | CloseAsync(tp[i]); |
||
1356 | #else |
||
1 | office | 1357 | fclose(tp[i]); |
22 | office | 1358 | #endif |
1 | office | 1359 | } |
24 | office | 1360 | #if defined ___AsyncIO___ |
1361 | CloseAsync(fp); |
||
1362 | #else |
||
1363 | fclose(fp); |
||
1364 | #endif |
||
1 | office | 1365 | return; |
1366 | } |
||
1367 | } |
||
1368 | |||
1369 | if(verbose) { |
||
24 | office | 1370 | fprintf(stdout, "Merging all files...\r"); |
1 | office | 1371 | } |
1372 | |||
26 | office | 1373 | rem = NULL; |
1 | office | 1374 | count = lines; |
14 | office | 1375 | j = 0; |
1 | office | 1376 | while(run && --count > -1) { |
1377 | #if defined ___AmigaOS___ |
||
1378 | // Check if CTRL+C was pressed and abort the program. |
||
1379 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
1380 | run = FALSE; |
||
23 | office | 1381 | continue; |
1 | office | 1382 | } |
1383 | #endif |
||
1384 | // Find the smallest line in all temporary files. |
||
1385 | if(verbose) { |
||
24 | office | 1386 | fprintf(stdout, "Merging all files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0)); |
1 | office | 1387 | } |
1388 | |||
14 | office | 1389 | min = NULL; |
1 | office | 1390 | for(i = 0; i < files; ++i) { |
26 | office | 1391 | tmp = PeekLine(tp[i]); |
1 | office | 1392 | if(tmp == NULL) { |
1393 | continue; |
||
1394 | } |
||
26 | office | 1395 | #if defined ___AmigaOS___ |
1396 | if(min == NULL || StrnCmp(locale, tmp, min, -1, SC_ASCII) < 0) { |
||
1397 | #else |
||
27 | office | 1398 | if(min == NULL || strcmp(tmp, min) < 0) { |
26 | office | 1399 | #endif |
14 | office | 1400 | if(min != NULL) { |
2 | office | 1401 | // Free previous instance. |
14 | office | 1402 | free(min); |
2 | office | 1403 | } |
26 | office | 1404 | if((min = malloc((strlen(tmp) + 1) * sizeof(*min))) == NULL) { |
1405 | fprintf(stderr, "Memory allication failure.\n"); |
||
1406 | free(tmp); |
||
1407 | if(min != NULL) { |
||
1408 | free(min); |
||
1409 | } |
||
1410 | if(rem != NULL) { |
||
1411 | free(rem); |
||
1412 | } |
||
1413 | #if defined ___AsyncIO___ |
||
1414 | CloseAsync(fp); |
||
1415 | #else |
||
1416 | fclose(fp); |
||
1417 | #endif |
||
1418 | return; |
||
1419 | } |
||
14 | office | 1420 | sprintf(min, "%s", tmp); |
1 | office | 1421 | // Remember the index of the file where the smallest entry has been found. |
14 | office | 1422 | j = i; |
1 | office | 1423 | } |
1424 | free(tmp); |
||
1425 | } |
||
1426 | |||
1427 | // Forward the file where the smallest line was found. |
||
23 | office | 1428 | SkipLine(tp[j]); |
1 | office | 1429 | |
1430 | // Write the smallest line. |
||
14 | office | 1431 | if(min != NULL) { |
26 | office | 1432 | // If current minimum line is identical to previous minimum line then skip to remove duplicates. |
1433 | if(rem != NULL) { |
||
1434 | #if defined ___AmigaOS___ |
||
1435 | if(StrnCmp(locale, min, rem, -1, SC_ASCII) == 0) { |
||
1436 | #else |
||
28 | office | 1437 | if(strcmp(min, rem) == 0) { |
26 | office | 1438 | #endif |
1439 | free(min); |
||
1440 | continue; |
||
1441 | } |
||
1442 | } |
||
1443 | |||
22 | office | 1444 | #if defined ___AsyncIO___ |
26 | office | 1445 | WriteAsync(fp, min, (LONG)strlen(min)); |
1446 | WriteAsync(fp, "\n", 1); |
||
22 | office | 1447 | #else |
14 | office | 1448 | fprintf(fp, "%s\n", min); |
22 | office | 1449 | #endif |
26 | office | 1450 | |
1451 | if(rem != NULL) { |
||
1452 | free(rem); |
||
1453 | } |
||
1454 | |||
1455 | if((rem = malloc((strlen(min) + 1) * sizeof(*rem))) == NULL) { |
||
1456 | fprintf(stderr, "Memory allocation failure.\n"); |
||
1457 | free(min); |
||
1458 | #if defined ___AsyncIO___ |
||
1459 | CloseAsync(fp); |
||
1460 | #else |
||
1461 | fclose(fp); |
||
1462 | #endif |
||
1463 | return; |
||
1464 | } |
||
1465 | |||
1466 | sprintf(rem, "%s", min); |
||
14 | office | 1467 | free(min); |
1 | office | 1468 | } |
1469 | } |
||
1470 | |||
26 | office | 1471 | if(rem != NULL) { |
1472 | free(rem); |
||
1473 | } |
||
1474 | |||
1 | office | 1475 | // Write out any remaining contents from the temporary files. |
24 | office | 1476 | for(i = 0; run && i < files; ++i) { |
1477 | #if defined ___AmigaOS___ |
||
1478 | // Check if CTRL+C was pressed and abort the program. |
||
1479 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
1480 | run = FALSE; |
||
1481 | continue; |
||
1482 | } |
||
1483 | #endif |
||
23 | office | 1484 | tmp = ReadLine(tp[i]); |
1 | office | 1485 | if(tmp == NULL) { |
1486 | continue; |
||
1487 | } |
||
22 | office | 1488 | #if defined ___AsyncIO___ |
26 | office | 1489 | WriteAsync(fp, tmp, (LONG)strlen(tmp)); |
1490 | WriteAsync(fp, "\n", 1); |
||
22 | office | 1491 | #else |
1 | office | 1492 | fprintf(fp, "%s\n", tmp); |
22 | office | 1493 | #endif |
14 | office | 1494 | free(tmp); |
1 | office | 1495 | } |
1496 | |||
24 | office | 1497 | // Close all temporary files. |
1 | office | 1498 | for(i = 0; i < files; ++i) { |
22 | office | 1499 | #if defined ___AsyncIO___ |
1500 | CloseAsync(tp[i]); |
||
1501 | #else |
||
1 | office | 1502 | fclose(tp[i]); |
22 | office | 1503 | #endif |
1 | office | 1504 | } |
1505 | |||
1506 | if(verbose) { |
||
1507 | fprintf(stdout, "\n"); |
||
1508 | } |
||
1509 | |||
22 | office | 1510 | #if defined ___AsyncIO___ |
1511 | CloseAsync(fp); |
||
1512 | #else |
||
1 | office | 1513 | fclose(fp); |
22 | office | 1514 | #endif |
1 | office | 1515 | } |
1516 | |||
1517 | /* |
||
26 | office | 1518 | * |
1519 | * Filter the paths inside the database with provided paths. |
||
1520 | */ |
||
1521 | void FilterDatabasePaths(char *dbFile, char *tmpName, char **paths, unsigned int count) { |
||
1522 | #if defined ___AsyncIO___ |
||
1523 | struct AsyncFile *fp; |
||
1524 | struct AsyncFile *tp; |
||
1525 | #else |
||
1526 | FILE *fp; |
||
1527 | FILE *tp; |
||
1528 | #endif |
||
1529 | char *line; |
||
31 | office | 1530 | unsigned int lines; |
26 | office | 1531 | int i; |
1532 | dbEntry *entry; |
||
24 | office | 1533 | |
26 | office | 1534 | // Open database file for reading. |
1535 | #if defined ___AsyncIO___ |
||
1536 | if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { |
||
1537 | #else |
||
1538 | if((fp = fopen(dbFile, "r")) == NULL) { |
||
1539 | #endif |
||
1540 | fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile); |
||
1541 | return; |
||
24 | office | 1542 | } |
1543 | |||
26 | office | 1544 | // Open temporary file for writing. |
1545 | #if defined ___AsyncIO___ |
||
1546 | if((tp = OpenAsync(tmpName, MODE_WRITE, ASYNC_BUF)) == NULL) { |
||
1547 | #else |
||
1548 | if((tp = fopen(tmpName, "w")) == NULL) { |
||
1549 | #endif |
||
1550 | fprintf(stderr, "Unable to open '%s' for writing.\n", tmpName); |
||
24 | office | 1551 | |
26 | office | 1552 | // Close database file. |
1553 | #if defined ___AsyncIO___ |
||
1554 | CloseAsync(fp); |
||
1555 | #else |
||
1556 | fclose(fp); |
||
1557 | #endif |
||
1558 | |||
1559 | return; |
||
24 | office | 1560 | } |
26 | office | 1561 | |
31 | office | 1562 | if(verbose) { |
1563 | fprintf(stdout, "Removing lines...\r"); |
||
1564 | } |
||
1565 | |||
1566 | lines = 0; |
||
26 | office | 1567 | while(run && (line = ReadLine(fp)) != NULL) { |
1568 | #if defined ___AmigaOS___ |
||
1569 | // Check if CTRL+C was pressed and abort the program. |
||
1570 | if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { |
||
1571 | run = FALSE; |
||
1572 | continue; |
||
1573 | } |
||
1574 | #endif |
||
31 | office | 1575 | if((entry = CreateDatabaseEntry(line)) == NULL) { |
26 | office | 1576 | fprintf(stderr, "Unable to create database entry.\n"); |
31 | office | 1577 | free(line); |
26 | office | 1578 | continue; |
1579 | } |
||
31 | office | 1580 | |
26 | office | 1581 | for(i = 0; i < count; ++i) { |
1582 | if(PathCompare(entry->path, paths[i]) == TRUE) { |
||
31 | office | 1583 | ++lines; |
1584 | if(verbose) { |
||
1585 | fprintf(stdout, "Removing lines: %d\r", lines); |
||
1586 | } |
||
26 | office | 1587 | continue; |
1588 | } |
||
1589 | #if defined ___AsyncIO___ |
||
1590 | WriteAsync(tp, line, (LONG)strlen(line)); |
||
1591 | WriteAsync(tp, "\n", 1); |
||
1592 | #else |
||
1593 | fprintf(tp, "%s\n", line); |
||
1594 | #endif |
||
1595 | break; |
||
1596 | } |
||
1597 | |||
31 | office | 1598 | |
1599 | free(entry->name); |
||
1600 | free(entry->path); |
||
26 | office | 1601 | free(entry); |
31 | office | 1602 | |
26 | office | 1603 | free(line); |
1604 | } |
||
1605 | |||
31 | office | 1606 | if(verbose) { |
1607 | fprintf(stdout, "\n"); |
||
1608 | } |
||
26 | office | 1609 | |
31 | office | 1610 | |
26 | office | 1611 | #if defined ___AsyncIO___ |
1612 | CloseAsync(fp); |
||
1613 | CloseAsync(tp); |
||
1614 | #else |
||
1615 | fclose(fp); |
||
1616 | fclose(tp); |
||
1617 | #endif |
||
24 | office | 1618 | } |
1619 | |||
1620 | /* |
||
1621 | * |
||
1 | office | 1622 | * Indexes a "path" by creating a database "dbFile". |
1623 | */ |
||
26 | office | 1624 | void GatherDatabaseFiles(char *dbFile, char **paths, unsigned int count) { |
1625 | stats *stats; |
||
1 | office | 1626 | char **tmpNames; |
26 | office | 1627 | int dbSize; |
1628 | int dbLines; |
||
1629 | int tmpFiles; |
||
1630 | int tmpLines; |
||
1 | office | 1631 | int i; |
1632 | |||
26 | office | 1633 | // Generate the database file from the supplied paths. |
1634 | if((stats = CollectFiles(dbFile, paths, count)) == NULL) { |
||
1635 | fprintf(stderr, "Collecting files failed.\n"); |
||
1636 | return; |
||
1637 | } |
||
1638 | free(stats); |
||
1 | office | 1639 | |
26 | office | 1640 | // Compute the amount of temporary files needed. |
23 | office | 1641 | dbSize = GetFileSize(dbFile); |
26 | office | 1642 | if(dbSize == -1) { |
1643 | fprintf(stderr, "File size for '%s' failed.\n", dbFile); |
||
1644 | return; |
||
1645 | } |
||
1646 | tmpFiles = dbSize / maxmem; |
||
1 | office | 1647 | |
26 | office | 1648 | /* In case no temporary files are required, |
1649 | * just sort the database and terminate. |
||
1650 | */ |
||
2 | office | 1651 | if(tmpFiles <= 1) { |
1 | office | 1652 | SortDatabase(dbFile); |
1653 | return; |
||
1654 | } |
||
1655 | |||
26 | office | 1656 | // Get the database metrics. |
1657 | dbLines = CountFileLines(dbFile); |
||
1658 | if(dbLines == -1) { |
||
1659 | fprintf(stderr, "Counting lines of '%s' failed.\n", dbFile); |
||
1660 | } |
||
1 | office | 1661 | tmpLines = dbLines / tmpFiles; |
1662 | |||
1663 | // Create temporary files. |
||
23 | office | 1664 | if((tmpNames = CreateTemporaryFiles(tmpFiles)) == NULL) { |
1 | office | 1665 | fprintf(stderr, "Unable to create temporary files.\n"); |
1666 | return; |
||
1667 | } |
||
1668 | |||
24 | office | 1669 | // Write "tmpLines" to temporary files in "tmpNames" from "dbFile". |
23 | office | 1670 | WriteTemporaryFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines); |
1 | office | 1671 | |
1672 | // Sort the temporary files. |
||
31 | office | 1673 | for(i = 0; i < tmpFiles; ++i) { |
1 | office | 1674 | SortDatabase(tmpNames[i]); |
1675 | } |
||
1676 | |||
24 | office | 1677 | // Merge all the temporary files to the database file. |
1678 | MergeTemporaryFiles(dbFile, tmpNames, tmpFiles, dbLines); |
||
1679 | |||
1680 | // Remove all temporary files. |
||
26 | office | 1681 | RemoveFiles(tmpNames, tmpFiles); |
1682 | |||
31 | office | 1683 | // Free temporary file names. |
26 | office | 1684 | free(tmpNames); |
1 | office | 1685 | } |
1686 | |||
26 | office | 1687 | void RemoveDatabaseFiles(char *dbFile, char **paths, unsigned int count) { |
1688 | char *tmpName; |
||
1689 | |||
1690 | // Create a temporary file to hold the changes. |
||
1691 | if((tmpName = CreateTemporaryFile()) == NULL) { |
||
1692 | fprintf(stderr, "Unable to create temporary file.\n"); |
||
1693 | return; |
||
1694 | } |
||
1695 | |||
1696 | // Filter the database of the provided paths. |
||
1697 | FilterDatabasePaths(dbFile, tmpName, paths, count); |
||
1698 | |||
1699 | // Overwrite the database file with the filtered paths. |
||
1700 | CopyFile(tmpName, dbFile); |
||
1701 | |||
1702 | // Remove temporary file. |
||
31 | office | 1703 | if(RemoveFile(tmpName) == FALSE) { |
1704 | fprintf(stderr, "Temporary file could not be removed.\n"); |
||
1705 | return; |
||
1706 | } |
||
26 | office | 1707 | } |
1708 | |||
11 | office | 1709 | void usage(char *name) { |
1710 | fprintf(stdout, "Hunt & Gather - %s, a file index generating tool. \n", name); |
||
19 | office | 1711 | fprintf(stdout, "Version: %s \n", PROGRAM_VERSION); |
11 | office | 1712 | fprintf(stdout, " \n"); |
26 | office | 1713 | fprintf(stdout, "SYNTAX: %s [-q] <-a|-r|-c> <PATH PATH PATH...> \n", name); |
1714 | fprintf(stdout, " \n"); |
||
1715 | fprintf(stdout, "Required: \n"); |
||
27 | office | 1716 | fprintf(stdout, " -a [PATH...] Add files. \n"); |
1717 | fprintf(stdout, " -c [PATH...] Create from scratch. \n"); |
||
26 | office | 1718 | fprintf(stdout, " -r [PATH...] Remove files. \n"); |
1719 | fprintf(stdout, " \n"); |
||
1720 | fprintf(stdout, "Optional: \n"); |
||
1721 | fprintf(stdout, " -d [FIILE] Where to store the database. \n"); |
||
1722 | fprintf(stdout, " -m BYTES Memory to use (default: %d). \n", maxmem); |
||
11 | office | 1723 | fprintf(stdout, " -q Do not print out any messages. \n"); |
26 | office | 1724 | fprintf(stdout, " \n"); |
11 | office | 1725 | fprintf(stdout, "DATABASE is a path to where the indexed results will be \n"); |
1726 | fprintf(stdout, "stored for searching with the Hunt tool. \n"); |
||
1727 | fprintf(stdout, " \n"); |
||
1728 | fprintf(stdout, "(c) 2021 Wizardry and Steamworks, MIT. \n"); |
||
1729 | } |
||
1730 | |||
1 | office | 1731 | /* |
1732 | * |
||
1733 | * Main entry point. |
||
1734 | */ |
||
1735 | int main(int argc, char **argv) { |
||
28 | office | 1736 | #if defined ___AmigaOS___ |
1737 | struct FileInfoBlock *FIB; |
||
1738 | BPTR lock; |
||
1739 | #else |
||
1740 | struct stat dirStat; |
||
1741 | #endif |
||
1 | office | 1742 | int option; |
26 | office | 1743 | unsigned int i; |
1744 | unsigned int count; |
||
2 | office | 1745 | char *dbFile; |
19 | office | 1746 | char *path; |
26 | office | 1747 | char **paths; |
1 | office | 1748 | |
1749 | // Bind handler to SIGINT. |
||
26 | office | 1750 | #if !defined ___AmigaOS___ |
1 | office | 1751 | signal(SIGINT, SignalHandler); |
26 | office | 1752 | #endif |
1 | office | 1753 | |
2 | office | 1754 | dbFile = DEFAULT_DATABASE_FILE; |
26 | office | 1755 | while((option = getopt(argc, argv, "hqdm:arc")) != -1) { |
1 | office | 1756 | switch(option) { |
26 | office | 1757 | case 'a': |
1758 | operation = GATHER; |
||
1759 | break; |
||
1760 | case 'r': |
||
1761 | operation = REMOVE; |
||
1762 | break; |
||
1763 | case 'c': |
||
1764 | operation = CREATE; |
||
1765 | break; |
||
1766 | case 'm': |
||
1767 | maxmem = strtoul(optarg, NULL, 10); |
||
1768 | break; |
||
2 | office | 1769 | case 'd': |
1770 | dbFile = optarg; |
||
1771 | break; |
||
1 | office | 1772 | case 'q': |
1773 | verbose = FALSE; |
||
1774 | break; |
||
1775 | case 'h': |
||
11 | office | 1776 | usage(argv[0]); |
2 | office | 1777 | return 0; |
1 | office | 1778 | case '?': |
1779 | fprintf(stderr, "Invalid option %ct.\n", optopt); |
||
1780 | return 1; |
||
1781 | } |
||
1782 | } |
||
1783 | |||
26 | office | 1784 | if(operation == NONE) { |
1785 | usage(argv[0]); |
||
1786 | return 1; |
||
1787 | } |
||
10 | office | 1788 | |
1789 | if(optind >= argc) { |
||
11 | office | 1790 | usage(argv[0]); |
1 | office | 1791 | return 1; |
1792 | } |
||
1793 | |||
26 | office | 1794 | // Go through all supplied arguments and add paths to search. |
1795 | if((paths = malloc((argc - optind) * sizeof(*paths))) == NULL) { |
||
1796 | fprintf(stderr, "Memory allocation failure.\n"); |
||
1 | office | 1797 | return 1; |
1798 | } |
||
31 | office | 1799 | |
1800 | count = 0; |
||
1801 | for(i = optind, count = 0; i < argc; ++i) { |
||
28 | office | 1802 | if((path = PathToAbsolute(argv[i])) == NULL) { |
26 | office | 1803 | fprintf(stderr, "Absolute path for '%s' failed to resolve.\n", argv[optind]); |
1804 | continue; |
||
1805 | } |
||
1 | office | 1806 | |
26 | office | 1807 | // Check that the path is a directory. |
28 | office | 1808 | #if defined ___AmigaOS___ |
1809 | if((lock = Lock(path, ACCESS_READ)) == NULL) { |
||
1810 | fprintf(stderr, "Path '%s' is not accessible.\n", path); |
||
1811 | free(path); |
||
1812 | continue; |
||
1813 | } |
||
1814 | |||
1815 | if((FIB = AllocDosObject(DOS_FIB, NULL)) == NULL) { |
||
1816 | fprintf(stderr, "Path '%s' file information block not accessible.\n", path); |
||
1817 | UnLock(lock); |
||
1818 | free(path); |
||
1819 | continue; |
||
1820 | } |
||
1821 | |||
1822 | if(Examine(lock, FIB) == FALSE) { |
||
1823 | fprintf(stderr, "Path '%s' information unexaminable.\n", path); |
||
1824 | UnLock(lock); |
||
1825 | FreeDosObject(DOS_FIB, FIB); |
||
1826 | free(path); |
||
1827 | continue; |
||
1828 | } |
||
1829 | |||
1830 | if(FIB->fib_DirEntryType < 0) { |
||
1831 | #else |
||
26 | office | 1832 | stat(path, &dirStat); |
1833 | if(!S_ISDIR(dirStat.st_mode)) { |
||
28 | office | 1834 | #endif |
26 | office | 1835 | fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]); |
28 | office | 1836 | #if defined ___AmigaOS___ |
1837 | UnLock(lock); |
||
1838 | FreeDosObject(DOS_FIB, FIB); |
||
1839 | #endif |
||
26 | office | 1840 | free(path); |
1841 | return 1; |
||
1842 | } |
||
1843 | |||
1844 | if(verbose) { |
||
1845 | fprintf(stdout, "Will process path: '%s'\n", path); |
||
1846 | } |
||
1847 | |||
1848 | // Add the path to the array of paths. |
||
30 | office | 1849 | if((paths[count] = malloc((strlen(path) + 1) * sizeof(*paths[count]))) == NULL) { |
26 | office | 1850 | fprintf(stderr, "Memory allocation failure."); |
1851 | return 1; |
||
1852 | } |
||
28 | office | 1853 | |
26 | office | 1854 | sprintf(paths[count], "%s", path); |
31 | office | 1855 | ++count; |
28 | office | 1856 | |
1857 | #if defined ___AmigaOS___ |
||
1858 | UnLock(lock); |
||
1859 | FreeDosObject(DOS_FIB, FIB); |
||
1860 | #endif |
||
26 | office | 1861 | free(path); |
28 | office | 1862 | |
26 | office | 1863 | } |
1864 | |||
31 | office | 1865 | if(count == 0) { |
1866 | fprintf(stderr, "No valid paths are available.\n"); |
||
1867 | free(paths); |
||
1868 | return 1; |
||
1869 | } |
||
1870 | |||
2 | office | 1871 | if(verbose) { |
26 | office | 1872 | fprintf(stdout, "Gathering to: '%s'\n", dbFile); |
2 | office | 1873 | } |
1874 | |||
26 | office | 1875 | #if defined ___AmigaOS___ |
1876 | locale = OpenLocale(NULL); |
||
1877 | #endif |
||
1878 | |||
1879 | switch(operation) { |
||
1880 | case CREATE: |
||
1881 | if(verbose) { |
||
1882 | fprintf(stdout, "Removing '%s' and creating a new database.\n", dbFile); |
||
1883 | } |
||
31 | office | 1884 | if(RemoveFile(dbFile) == FALSE) { |
1885 | fprintf(stderr, "File '%s' could not be removed.\n", dbFile); |
||
1886 | break; |
||
1887 | } |
||
26 | office | 1888 | case GATHER: |
1889 | if(verbose) { |
||
1890 | fprintf(stdout, "Gathering files to database...\n"); |
||
1891 | } |
||
1892 | GatherDatabaseFiles(dbFile, paths, count); |
||
1893 | break; |
||
1894 | case REMOVE: |
||
1895 | if(verbose) { |
||
1896 | fprintf(stdout, "Removing files from database...\n"); |
||
1897 | } |
||
1898 | RemoveDatabaseFiles(dbFile, paths, count); |
||
1899 | break; |
||
1900 | default: |
||
31 | office | 1901 | fprintf(stderr, "Unknown operation.\n"); |
26 | office | 1902 | break; |
1903 | } |
||
1 | office | 1904 | |
26 | office | 1905 | #if defined ___AmigaOS___ |
1906 | CloseLocale(locale); |
||
1907 | #endif |
||
19 | office | 1908 | |
26 | office | 1909 | free(paths); |
1910 | |||
31 | office | 1911 | #if defined MWDEBUG |
1912 | /* Generate a memory usage report */ |
||
1913 | MWReport("At end of main()", MWR_FULL); |
||
1914 | #endif |
||
1915 | |||
26 | office | 1916 | return 0; |
1 | office | 1917 | } |