HuntnGather – Blame information for rev 32

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