HuntnGather – Blame information for rev 30

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