HuntnGather – Blame information for rev 26

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