HuntnGather – Blame information for rev 28

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