HuntnGather – Diff between revs 2 and 5

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 2 Rev 5
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2021 Wizardry and Steamworks - License: MIT // 2 // Copyright (C) 2021 Wizardry and Steamworks - License: MIT //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4   4  
5 #include <stdio.h> 5 #include <stdio.h>
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <string.h> 7 #include <string.h>
8 #include <dirent.h> 8 #include <dirent.h>
9 #include <signal.h> 9 #include <signal.h>
10   10  
11 #include <sys/types.h> 11 #include <sys/types.h>
12 #include <sys/stat.h> 12 #include <sys/stat.h>
13   13  
14 #include <proto/dos.h> 14 #include <proto/dos.h>
15 #include <proto/exec.h> 15 #include <proto/exec.h>
16   16  
17 #include "StringStack.h" 17 #include "StringStack.h"
18   18  
19 #if defined ___AmigaOS___ 19 #if !defined ___HAVE_GETOPT___
20 #include "getopt.h" 20 #include "getopt.h"
21 #endif 21 #endif
-   22  
-   23 #if defined ___AmigaOS___
-   24 #include <dos/dos.h>
-   25 #include <dos/rdargs.h>
-   26 #define TEMPLATE "Q=Quiet/S,D=Database/K,P=Path/A/F"
-   27 #define OPT_QUIET 0
-   28 #define OPT_DATABASE 1
-   29 #define OPT_PATH 2
-   30 #define OPT_COUNT 3
-   31 LONG result[OPT_COUNT];
-   32 /*************************************************************************/
-   33 /* Version string used for querrying the program version. */
-   34 /*************************************************************************/
-   35 TEXT version_string[] =
-   36 "\0$VER: Gather 1.4 "__DATE__" by Wizardry and Steamworks";
22   37 #endif
23   38  
24 #if !defined TRUE 39 #if !defined TRUE
25 #define TRUE 1; 40 #define TRUE 1;
26 #endif 41 #endif
27   42  
28 #if !defined FALSE 43 #if !defined FALSE
29 #define FALSE 0; 44 #define FALSE 0;
30 #endif 45 #endif
31   46  
32 #define MAX_MEM 262144 47 #define MAX_MEM 262144
33 #define DEFAULT_DATABASE_FILE "S:gather.db" 48 #define DEFAULT_DATABASE_FILE "S:gather.db"
34   -  
35 /*************************************************************************/ -  
36 /* Version string used for querrying the program version. */ -  
37 /*************************************************************************/ -  
38 TEXT version_string[] = -  
39 "\0$VER: Gather 1.3 "__DATE__" by Wizardry and Steamworks"; -  
40   49  
41 typedef struct { 50 typedef struct {
42 unsigned int dirs; 51 unsigned int dirs;
43 unsigned int files; 52 unsigned int files;
44 } stats; 53 } stats;
45   54  
46 int run = TRUE; 55 int run = TRUE;
47 int verbose = TRUE; 56 int verbose = TRUE;
48   57  
49 void SignalHandler(int sig) { 58 void SignalHandler(int sig) {
50 // Toggle the run flag to stop execution. 59 // Toggle the run flag to stop execution.
51 run = FALSE; 60 run = FALSE;
52 } 61 }
53   62  
54 int compare(const void *a, const void *b) { 63 int compare(const void *a, const void *b) {
55 const char **p = (const char **)a; 64 const char **p = (const char **)a;
56 const char **q = (const char **)b; 65 const char **q = (const char **)b;
57 return strcmp(*p, *q); 66 return strcmp(*p, *q);
58 } 67 }
59   68  
60 /* 69 /*
61 * 70 *
62 * Sorts a database file lexicographically. 71 * Sorts a database file lexicographically.
63 */ 72 */
64 void SortDatabase(char *dbFile) { 73 void SortDatabase(char *dbFile) {
65 FILE *fp; 74 FILE *fp;
66 char *name = NULL; 75 char *name = NULL;
67 char *path = NULL; 76 char *path = NULL;
68 char **database; 77 char **database;
69 char c; 78 char c;
70 int i; 79 int i;
71 int side; 80 int side;
72 unsigned int line; 81 unsigned int line;
73   82  
74 // Open database file for reading. 83 // Open database file for reading.
75 if((fp = fopen(dbFile, "r")) == NULL) { 84 if((fp = fopen(dbFile, "r")) == NULL) {
76 fprintf(stderr, "Unable to open gather database for reading.\n"); 85 fprintf(stderr, "Unable to open gather database for reading.\n");
77 return; 86 return;
78 } 87 }
79   88  
80 database = (char **) malloc(sizeof(char *)); 89 database = (char **) malloc(sizeof(char *));
81 name = (char *) malloc(sizeof(char)); 90 name = (char *) malloc(sizeof(char));
82 path = (char *) malloc(sizeof(char)); 91 path = (char *) malloc(sizeof(char));
83 line = 0; 92 line = 0;
84 side = 0; 93 side = 0;
85 i = 0; 94 i = 0;
86   95  
87 if(verbose) { 96 if(verbose) {
88 fprintf(stdout, "Sorting database: '%s'\n", dbFile); 97 fprintf(stdout, "Sorting database: '%s'\n", dbFile);
89 } 98 }
90   99  
91 while(run && fscanf(fp, "%c", &c) == 1) { 100 while(run && fscanf(fp, "%c", &c) == 1) {
92 #if defined ___AmigaOS___ 101 #if defined ___AmigaOS___
93 // Check if CTRL+C was pressed and abort the program. 102 // Check if CTRL+C was pressed and abort the program.
94 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 103 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
95 run = FALSE; 104 run = FALSE;
96 continue; 105 continue;
97 } 106 }
98 #endif 107 #endif
99 switch(c) { 108 switch(c) {
100 case '\n': 109 case '\n':
101 // Load up the name and path into the database variable. 110 // Load up the name and path into the database variable.
102 database = (char **) realloc(database, (line + 1) * sizeof(char *)); 111 database = (char **) realloc(database, (line + 1) * sizeof(char *));
103 database[line] = (char *) malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(char)); 112 database[line] = (char *) malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(char));
104 sprintf(database[line], "%s\t%s", name, path); 113 sprintf(database[line], "%s\t%s", name, path);
105 ++line; 114 ++line;
106   115  
107 free(name); 116 free(name);
108 name = (char *) malloc(sizeof(char)); 117 name = (char *) malloc(sizeof(char));
109 --side; 118 --side;
110 i = 0; 119 i = 0;
111   120  
112 break; 121 break;
113 case '\t': 122 case '\t':
114 free(path); 123 free(path);
115 path = (char *) malloc(sizeof(char)); 124 path = (char *) malloc(sizeof(char));
116 ++side; 125 ++side;
117 i = 0; 126 i = 0;
118 break; 127 break;
119 default: 128 default:
120 switch(side) { 129 switch(side) {
121 case 0: 130 case 0:
122 name = (char *) realloc(name, (i + 1 + 1) * sizeof(char)); 131 name = (char *) realloc(name, (i + 1 + 1) * sizeof(char));
123 name[i] = c; 132 name[i] = c;
124 name[i + 1] = '\0'; 133 name[i + 1] = '\0';
125 break; 134 break;
126 case 1: 135 case 1:
127 path = (char *) realloc(path, (i + 1 + 1) * sizeof(char)); 136 path = (char *) realloc(path, (i + 1 + 1) * sizeof(char));
128 path[i] = c; 137 path[i] = c;
129 path[i + 1] = '\0'; 138 path[i + 1] = '\0';
130 break; 139 break;
131 default: 140 default:
132 fprintf(stderr, "Database corrupted.\n"); 141 fprintf(stderr, "Database corrupted.\n");
133 break; 142 break;
134 } 143 }
135 ++i; 144 ++i;
136 break; 145 break;
137 } 146 }
138 } 147 }
139   148  
140 fclose(fp); 149 fclose(fp);
141   150  
142 // Sort the database. 151 // Sort the database.
143 qsort(database, line, sizeof(char *), compare); 152 qsort(database, line, sizeof(char *), compare);
144   153  
145 // Write the database lines back to the database. 154 // Write the database lines back to the database.
146 if((fp = fopen(dbFile, "w+")) == NULL) { 155 if((fp = fopen(dbFile, "w+")) == NULL) {
147 fprintf(stderr, "Unable to open gather database for writing.\n"); 156 fprintf(stderr, "Unable to open gather database for writing.\n");
148 return; 157 return;
149 } 158 }
150   159  
151 for(i = 0; i < line; ++i) { 160 for(i = 0; i < line; ++i) {
152 fprintf(fp, "%s\n", database[i]); 161 fprintf(fp, "%s\n", database[i]);
153 } 162 }
154   163  
155 free(database); 164 free(database);
156 fclose(fp); 165 fclose(fp);
157 } 166 }
158   167  
159 /* 168 /*
160 * 169 *
161 * Updates a database file "dbFile". 170 * Updates a database file "dbFile".
162 */ 171 */
163 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) { 172 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) {
164 FILE *fp; 173 FILE *fp;
165 DIR *dir; 174 DIR *dir;
166 struct dirent *dirEntry; 175 struct dirent *dirEntry;
167 struct stat dirStat; 176 struct stat dirStat;
168 unsigned int size; 177 unsigned int size;
169 char *path; 178 char *path;
170 char *subPath; 179 char *subPath;
171   180  
172 if((fp = fopen(dbFile, "w+")) == NULL) { 181 if((fp = fopen(dbFile, "w+")) == NULL) {
173 fprintf(stderr, "Unable to open gather database for writing.\n"); 182 fprintf(stderr, "Unable to open gather database for writing.\n");
174 return; 183 return;
175 } 184 }
176   185  
177 while(run && !stringStackIsEmpty(dirStack)) { 186 while(run && !stringStackIsEmpty(dirStack)) {
178 #if defined ___AmigaOS___ 187 #if defined ___AmigaOS___
179 // Check if CTRL+C was pressed and abort the program. 188 // Check if CTRL+C was pressed and abort the program.
180 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 189 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
181 run = FALSE; 190 run = FALSE;
182 } 191 }
183 #endif 192 #endif
184 if((path = stringStackPop(dirStack)) == NULL) { 193 if((path = stringStackPop(dirStack)) == NULL) {
185 return; 194 return;
186 } 195 }
187   196  
188 if((dir = opendir(path)) == NULL) { 197 if((dir = opendir(path)) == NULL) {
189 return; 198 return;
190 } 199 }
191   200  
192 while(run && (dirEntry = readdir(dir)) != NULL) { 201 while(run && (dirEntry = readdir(dir)) != NULL) {
193 #if defined ___AmigaOS___ 202 #if defined ___AmigaOS___
194 // Check if CTRL+C was pressed and abort the program. 203 // Check if CTRL+C was pressed and abort the program.
195 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 204 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
196 run = FALSE; 205 run = FALSE;
197 } 206 }
198 #endif 207 #endif
199 size = sizeof(path) + sizeof(dirEntry->d_name) + 1; 208 size = sizeof(path) + sizeof(dirEntry->d_name) + 1;
200 switch(path[strlen(path) - 1]) { 209 switch(path[strlen(path) - 1]) {
201 case '/': 210 case '/':
202 case ':': // This is a drive path. 211 case ':': // This is a drive path.
203 subPath = (char *) malloc(size); 212 subPath = (char *) malloc(size);
204 sprintf(subPath, "%s%s", path, dirEntry->d_name); 213 sprintf(subPath, "%s%s", path, dirEntry->d_name);
205 break; 214 break;
206 default: 215 default:
207 subPath = (char *) malloc(size + 1); 216 subPath = (char *) malloc(size + 1);
208 sprintf(subPath, "%s/%s", path, dirEntry->d_name); 217 sprintf(subPath, "%s/%s", path, dirEntry->d_name);
209 break; 218 break;
210 } 219 }
211 stat(subPath, &dirStat); 220 stat(subPath, &dirStat);
212 if(S_ISDIR(dirStat.st_mode)) { 221 if(S_ISDIR(dirStat.st_mode)) {
213 stringStackPush(dirStack, subPath); 222 stringStackPush(dirStack, subPath);
214   223  
215 ++stats->dirs; 224 ++stats->dirs;
216   225  
217 if(verbose) { 226 if(verbose) {
218 fprintf(stdout, 227 fprintf(stdout,
219 "Gathered %d directories and %d files.\r", 228 "Gathered %d directories and %d files.\r",
220 stats->dirs, 229 stats->dirs,
221 stats->files); 230 stats->files);
222 } 231 }
223   232  
224 free(subPath); 233 free(subPath);
225 continue; 234 continue;
226 } 235 }
227   236  
228 // Write to database file. 237 // Write to database file.
229 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath); 238 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath);
230   239  
231 ++stats->files; 240 ++stats->files;
232   241  
233 if(verbose) { 242 if(verbose) {
234 fprintf(stdout, 243 fprintf(stdout,
235 "Gathered %d directories and %d files.\r", 244 "Gathered %d directories and %d files.\r",
236 stats->dirs, 245 stats->dirs,
237 stats->files); 246 stats->files);
238 } 247 }
239   248  
240 free(subPath); 249 free(subPath);
241 } 250 }
242   251  
243 closedir(dir); 252 closedir(dir);
244 free(path); 253 free(path);
245 } 254 }
246   255  
247 if(verbose) { 256 if(verbose) {
248 fprintf(stdout, "\n"); 257 fprintf(stdout, "\n");
249 } 258 }
250   259  
251 fclose(fp); 260 fclose(fp);
252   261  
253 } 262 }
254   263  
255 /* 264 /*
256 * 265 *
257 * Gets the size of a database "dbFle". 266 * Gets the size of a database "dbFle".
258 */ 267 */
259 int GetDatabaseSize(char *dbFile) { 268 int GetDatabaseSize(char *dbFile) {
260 FILE *fp; 269 FILE *fp;
261 int size; 270 int size;
262   271  
263 if((fp = fopen(dbFile, "r")) == NULL) { 272 if((fp = fopen(dbFile, "r")) == NULL) {
264 fprintf(stderr, "Unable to open gather database for reading.\n"); 273 fprintf(stderr, "Unable to open gather database for reading.\n");
265 fclose(fp); 274 fclose(fp);
266 return 0; 275 return 0;
267 } 276 }
268   277  
269 fseek(fp, 0L, SEEK_END); 278 fseek(fp, 0L, SEEK_END);
270 size = ftell(fp); 279 size = ftell(fp);
271   280  
272 fclose(fp); 281 fclose(fp);
273 return size; 282 return size;
274 } 283 }
275   284  
276 /* 285 /*
277 * 286 *
278 * Counts the lines in a database file "dbFile". 287 * Counts the lines in a database file "dbFile".
279 */ 288 */
280 int CountDatabaseLines(char *dbFile) { 289 int CountDatabaseLines(char *dbFile) {
281 FILE *fp; 290 FILE *fp;
282 int lines; 291 int lines;
283 char c; 292 char c;
284   293  
285 if((fp = fopen(dbFile, "r")) == NULL) { 294 if((fp = fopen(dbFile, "r")) == NULL) {
286 fprintf(stderr, "Unable to open gather database for reading.\n"); 295 fprintf(stderr, "Unable to open gather database for reading.\n");
287 fclose(fp); 296 fclose(fp);
288 return 0; 297 return 0;
289 } 298 }
290   299  
291 lines = 0; 300 lines = 0;
292 while(fscanf(fp, "%c", &c) == 1) { 301 while(fscanf(fp, "%c", &c) == 1) {
293 switch(c) { 302 switch(c) {
294 case '\n': 303 case '\n':
295 ++lines; 304 ++lines;
296 break; 305 break;
297 } 306 }
298 } 307 }
299   308  
300 fclose(fp); 309 fclose(fp);
301   310  
302 return lines; 311 return lines;
303 } 312 }
304   313  
305 /* 314 /*
306 * 315 *
307 * Creates "files" temporary filenames. 316 * Creates "files" temporary filenames.
308 */ 317 */
309 char **CreateTempFiles(int files) { 318 char **CreateTempFiles(int files) {
310 char **tmpNames; 319 char **tmpNames;
311 int count; 320 int count;
312   321  
313 tmpNames = (char **) malloc(files * sizeof(char *)); 322 tmpNames = (char **) malloc(files * sizeof(char *));
314   323  
315 if(verbose) { 324 if(verbose) {
316 fprintf(stdout, "Creating temporary files.\r"); 325 fprintf(stdout, "Creating temporary files.\r");
317 } 326 }
318   327  
319 count = files; 328 count = files;
320 while(--count > -1) { 329 while(--count > -1) {
321 #if defined ___AmigaOS___ 330 #if defined ___AmigaOS___
322 // Check if CTRL+C was pressed and abort the program. 331 // Check if CTRL+C was pressed and abort the program.
323 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 332 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
324 run = FALSE; 333 run = FALSE;
325 } 334 }
326 #endif 335 #endif
327 tmpNames[count] = tmpnam(NULL); 336 tmpNames[count] = tmpnam(NULL);
328   337  
329 if(verbose) { 338 if(verbose) {
330 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0)); 339 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0));
331 } 340 }
332 } 341 }
333   342  
334 if(verbose) { 343 if(verbose) {
335 fprintf(stdout, "\n"); 344 fprintf(stdout, "\n");
336 } 345 }
337   346  
338 return tmpNames; 347 return tmpNames;
339 } 348 }
340   349  
341 /* 350 /*
342 * 351 *
343 * Writes lines from the database "dbFile" to temporary filenames "tmpNames". 352 * Writes lines from the database "dbFile" to temporary filenames "tmpNames".
344 */ 353 */
345 void WriteTempFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) { 354 void WriteTempFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) {
346 FILE *fp, *tp; 355 FILE *fp, *tp;
347 char c; 356 char c;
348 int lines; 357 int lines;
349 int linesWritten; 358 int linesWritten;
350   359  
351 if((fp = fopen(dbFile, "r")) == NULL) { 360 if((fp = fopen(dbFile, "r")) == NULL) {
352 fprintf(stderr, "Unable to open gather database for reading.\n"); 361 fprintf(stderr, "Unable to open gather database for reading.\n");
353 return; 362 return;
354 } 363 }
355   364  
356 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) { 365 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) {
357 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 366 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]);
358 fclose(fp); 367 fclose(fp);
359 return; 368 return;
360 } 369 }
361   370  
362 if(verbose) { 371 if(verbose) {
363 fprintf(stdout, "Writing to temporary files.\r"); 372 fprintf(stdout, "Writing to temporary files.\r");
364 } 373 }
365   374  
366 linesWritten = 0; 375 linesWritten = 0;
367 lines = 0; 376 lines = 0;
368 while(run && fscanf(fp, "%c", &c) == 1) { 377 while(run && fscanf(fp, "%c", &c) == 1) {
369 #if defined ___AmigaOS___ 378 #if defined ___AmigaOS___
370 // Check if CTRL+C was pressed and abort the program. 379 // Check if CTRL+C was pressed and abort the program.
371 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 380 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
372 run = FALSE; 381 run = FALSE;
373 } 382 }
374 #endif 383 #endif
375 switch(c) { 384 switch(c) {
376 case '\n': 385 case '\n':
377 // Increment the total written lines. 386 // Increment the total written lines.
378 ++linesWritten; 387 ++linesWritten;
379   388  
380 if(verbose) { 389 if(verbose) {
381 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0)); 390 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0));
382 } 391 }
383   392  
384 // Write the newline character back. 393 // Write the newline character back.
385 if(fprintf(tp, "%c", c) != 1) { 394 if(fprintf(tp, "%c", c) != 1) {
386 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 395 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]);
387 fclose(tp); 396 fclose(tp);
388 fclose(fp); 397 fclose(fp);
389 return; 398 return;
390 } 399 }
391 // Switch to the next temporary file. 400 // Switch to the next temporary file.
392 if(++lines >= tmpLines) { 401 if(++lines >= tmpLines) {
393 // If there are no temporary files left then run till the end. 402 // If there are no temporary files left then run till the end.
394 if(tmpFiles - 1 < 0) { 403 if(tmpFiles - 1 < 0) {
395 break; 404 break;
396 } 405 }
397   406  
398 // Close the previous temporary file and write to the next temporary file. 407 // Close the previous temporary file and write to the next temporary file.
399 fclose(tp); 408 fclose(tp);
400 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) { 409 if((tp = fopen(tmpNames[--tmpFiles], "w+")) == NULL) {
401 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 410 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]);
402 fclose(tp); 411 fclose(tp);
403 fclose(fp); 412 fclose(fp);
404 } 413 }
405 lines = 0; 414 lines = 0;
406 break; 415 break;
407 } 416 }
408 break; 417 break;
409 default: 418 default:
410 if(fprintf(tp, "%c", c) != 1) { 419 if(fprintf(tp, "%c", c) != 1) {
411 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 420 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]);
412 fclose(tp); 421 fclose(tp);
413 fclose(fp); 422 fclose(fp);
414 return; 423 return;
415 } 424 }
416 break; 425 break;
417 } 426 }
418 } 427 }
419   428  
420 fprintf(stdout, "\n"); 429 fprintf(stdout, "\n");
421   430  
422 fclose(tp); 431 fclose(tp);
423 fclose(fp); 432 fclose(fp);
424 } 433 }
425   434  
426 /* 435 /*
427 * 436 *
428 * Skips a line in a database file "fp". 437 * Skips a line in a database file "fp".
429 */ 438 */
430 void SkipDatabaseLine(FILE *fp) { 439 void SkipDatabaseLine(FILE *fp) {
431 char c; 440 char c;
432   441  
433 while(fscanf(fp, "%c", &c) == 1) { 442 while(fscanf(fp, "%c", &c) == 1) {
434 if(c == '\n') { 443 if(c == '\n') {
435 break; 444 break;
436 } 445 }
437 } 446 }
438   447  
439 return; 448 return;
440 } 449 }
441   450  
442 /* 451 /*
443 * 452 *
444 * Reads a line from the database file "fp". 453 * Reads a line from the database file "fp".
445 */ 454 */
446 char *ReadDatabaseLine(FILE *fp) { 455 char *ReadDatabaseLine(FILE *fp) {
447 char c; 456 char c;
448 char *line; 457 char *line;
449 int chars; 458 int chars;
450   459  
451 line = (char *) malloc(sizeof(char)); 460 line = (char *) malloc(sizeof(char));
452   461  
453 chars = 0; 462 chars = 0;
454 while(run && fscanf(fp, "%c", &c) == 1) { 463 while(run && fscanf(fp, "%c", &c) == 1) {
455 #if defined ___AmigaOS___ 464 #if defined ___AmigaOS___
456 // Check if CTRL+C was pressed and abort the program. 465 // Check if CTRL+C was pressed and abort the program.
457 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 466 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
458 run = FALSE; 467 run = FALSE;
459 } 468 }
460 #endif 469 #endif
461 switch(c) { 470 switch(c) {
462 case '\n': 471 case '\n':
463 // Rewind the file by the number of read characters. 472 // Rewind the file by the number of read characters.
464 fseek(fp, -(chars + 1), SEEK_CUR); 473 fseek(fp, -(chars + 1), SEEK_CUR);
465 return line; 474 return line;
466 default: 475 default:
467 line = (char *) realloc(line, (chars + 1 + 1) * sizeof(char)); 476 line = (char *) realloc(line, (chars + 1 + 1) * sizeof(char));
468 line[chars] = c; 477 line[chars] = c;
469 line[chars + 1] = '\0'; 478 line[chars + 1] = '\0';
470 break; 479 break;
471 } 480 }
472 ++chars; 481 ++chars;
473 } 482 }
474   483  
475 return NULL; 484 return NULL;
476 } 485 }
477   486  
478 /* 487 /*
479 * 488 *
480 * Merges temporary files "tmpNames" into a database "dbFile". 489 * Merges temporary files "tmpNames" into a database "dbFile".
481 */ 490 */
482 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) { 491 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) {
483 FILE *fp; 492 FILE *fp;
484 FILE **tp; 493 FILE **tp;
485 int i; 494 int i;
486 char *tmp; 495 char *tmp;
487 char *tmpMin; 496 char *tmpMin;
488 int idxMin; 497 int idxMin;
489 int count; 498 int count;
490   499  
491 if((fp = fopen(dbFile, "w+")) == NULL) { 500 if((fp = fopen(dbFile, "w+")) == NULL) {
492 fprintf(stderr, "Unable to open gather database for writing.\n"); 501 fprintf(stderr, "Unable to open gather database for writing.\n");
493 return; 502 return;
494 } 503 }
495   504  
496 // Allocate as many file pointers as temporary files. 505 // Allocate as many file pointers as temporary files.
497 tp = (FILE **) malloc(files * sizeof(FILE *)); 506 tp = (FILE **) malloc(files * sizeof(FILE *));
498   507  
499 // Open all temporary files for reading. 508 // Open all temporary files for reading.
500 for(i = 0; i < files; ++i) { 509 for(i = 0; i < files; ++i) {
501 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) { 510 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) {
502 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]); 511 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]);
503 // Close all temporary files. 512 // Close all temporary files.
504 --i; 513 --i;
505 while(i >= 0) { 514 while(i >= 0) {
506 fclose(tp[i]); 515 fclose(tp[i]);
507 } 516 }
508 return; 517 return;
509 } 518 }
510 } 519 }
511   520  
512 if(verbose) { 521 if(verbose) {
513 fprintf(stdout, "Merging all database lines in temporary files.\r"); 522 fprintf(stdout, "Merging all database lines in temporary files.\r");
514 } 523 }
515   524  
516 count = lines; 525 count = lines;
517 idxMin = 0; 526 idxMin = 0;
518 while(run && --count > -1) { 527 while(run && --count > -1) {
519 #if defined ___AmigaOS___ 528 #if defined ___AmigaOS___
520 // Check if CTRL+C was pressed and abort the program. 529 // Check if CTRL+C was pressed and abort the program.
521 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 530 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
522 run = FALSE; 531 run = FALSE;
523 } 532 }
524 #endif 533 #endif
525 // Find the smallest line in all temporary files. 534 // Find the smallest line in all temporary files.
526 if(verbose) { 535 if(verbose) {
527 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0)); 536 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0));
528 } 537 }
529   538  
530 tmpMin = NULL; 539 tmpMin = NULL;
531 for(i = 0; i < files; ++i) { 540 for(i = 0; i < files; ++i) {
532 tmp = ReadDatabaseLine(tp[i]); 541 tmp = ReadDatabaseLine(tp[i]);
533 if(tmp == NULL) { 542 if(tmp == NULL) {
534 free(tmp); 543 free(tmp);
535 continue; 544 continue;
536 } 545 }
537 if(tmpMin == NULL || strcmp(tmp, tmpMin) < 0) { 546 if(tmpMin == NULL || strcmp(tmp, tmpMin) < 0) {
538 if(tmpMin != NULL) { 547 if(tmpMin != NULL) {
539 // Free previous instance. 548 // Free previous instance.
540 free(tmpMin); 549 free(tmpMin);
541 } 550 }
542 tmpMin = (char *) malloc((strlen(tmp) + 1) * sizeof(char)); 551 tmpMin = (char *) malloc((strlen(tmp) + 1) * sizeof(char));
543 sprintf(tmpMin, "%s", tmp); 552 sprintf(tmpMin, "%s", tmp);
544 // Remember the index of the file where the smallest entry has been found. 553 // Remember the index of the file where the smallest entry has been found.
545 idxMin = i; 554 idxMin = i;
546 free(tmp); 555 free(tmp);
547 continue; 556 continue;
548 } 557 }
549 free(tmp); 558 free(tmp);
550 } 559 }
551   560  
552 // Forward the file where the smallest line was found. 561 // Forward the file where the smallest line was found.
553 SkipDatabaseLine(tp[idxMin]); 562 SkipDatabaseLine(tp[idxMin]);
554   563  
555 // Write the smallest line. 564 // Write the smallest line.
556 if(tmpMin != NULL) { 565 if(tmpMin != NULL) {
557 fprintf(fp, "%s\n", tmpMin); 566 fprintf(fp, "%s\n", tmpMin);
558 free(tmpMin); 567 free(tmpMin);
559 } 568 }
560 } 569 }
561   570  
562 // Write out any remaining contents from the temporary files. 571 // Write out any remaining contents from the temporary files.
563 for(i = 0; i < files; ++i) { 572 for(i = 0; i < files; ++i) {
564 tmp = ReadDatabaseLine(tp[i]); 573 tmp = ReadDatabaseLine(tp[i]);
565 if(tmp == NULL) { 574 if(tmp == NULL) {
566 continue; 575 continue;
567 } 576 }
568 fprintf(fp, "%s\n", tmp); 577 fprintf(fp, "%s\n", tmp);
569 } 578 }
570   579  
571 // Close and delete all temporary files. 580 // Close and delete all temporary files.
572 for(i = 0; i < files; ++i) { 581 for(i = 0; i < files; ++i) {
573 fclose(tp[i]); 582 fclose(tp[i]);
574 // Delete temporary file. 583 // Delete temporary file.
575 remove(tmpNames[i]); 584 remove(tmpNames[i]);
576 } 585 }
577   586  
578 if(verbose) { 587 if(verbose) {
579 fprintf(stdout, "\n"); 588 fprintf(stdout, "\n");
580 } 589 }
581   590  
582 fclose(fp); 591 fclose(fp);
583 } 592 }
584   593  
585 /* 594 /*
586 * 595 *
587 * Indexes a "path" by creating a database "dbFile". 596 * Indexes a "path" by creating a database "dbFile".
588 */ 597 */
589 void Gather(char *dbFile, char *path) { 598 void Gather(char *dbFile, char *path) {
590 stringStack *stack = stringStackCreate(1); 599 stringStack *stack = stringStackCreate(1);
591 stats *stats = malloc(sizeof(stats)); 600 stats *stats = malloc(sizeof(stats));
592 char **tmpNames; 601 char **tmpNames;
593 int dbSize, dbLines, tmpFiles, tmpLines; 602 int dbSize, dbLines, tmpFiles, tmpLines;
594 int i; 603 int i;
595   604  
596 // Initialize metrics. 605 // Initialize metrics.
597 stats->dirs = 0; 606 stats->dirs = 0;
598 stats->files = 0; 607 stats->files = 0;
599   608  
600 // Push the first path onto the stack. 609 // Push the first path onto the stack.
601 stringStackPush(stack, path); 610 stringStackPush(stack, path);
602   611  
603 // Generate the database file. 612 // Generate the database file.
604 UpdateDatabase(dbFile, stack, stats); 613 UpdateDatabase(dbFile, stack, stats);
605   614  
606 // Get the database metrics. 615 // Get the database metrics.
607 dbSize = GetDatabaseSize(dbFile); 616 dbSize = GetDatabaseSize(dbFile);
608 dbLines = CountDatabaseLines(dbFile); 617 dbLines = CountDatabaseLines(dbFile);
609   618  
610 // Compute the amount of temporary files needed. 619 // Compute the amount of temporary files needed.
611 tmpFiles = dbSize / MAX_MEM; 620 tmpFiles = dbSize / MAX_MEM;
612   621  
613 // In case no temporary files are required, 622 // In case no temporary files are required,
614 // just sort the database and terminate. 623 // just sort the database and terminate.
615 if(tmpFiles <= 1) { 624 if(tmpFiles <= 1) {
616 SortDatabase(dbFile); 625 SortDatabase(dbFile);
617 return; 626 return;
618 } 627 }
619   628  
620 tmpLines = dbLines / tmpFiles; 629 tmpLines = dbLines / tmpFiles;
621   630  
622 // Create temporary files. 631 // Create temporary files.
623 if((tmpNames = CreateTempFiles(tmpFiles)) == NULL) { 632 if((tmpNames = CreateTempFiles(tmpFiles)) == NULL) {
624 fprintf(stderr, "Unable to create temporary files.\n"); 633 fprintf(stderr, "Unable to create temporary files.\n");
625 return; 634 return;
626 } 635 }
627   636  
628 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile". 637 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile".
629 WriteTempFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines); 638 WriteTempFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines);
630   639  
631 // Sort the temporary files. 640 // Sort the temporary files.
632 for(i = 0; i < tmpFiles; ++i) { 641 for(i = 0; i < tmpFiles; ++i) {
633 SortDatabase(tmpNames[i]); 642 SortDatabase(tmpNames[i]);
634 } 643 }
635   644  
636 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines); 645 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines);
637 } 646 }
638   647  
639 /* 648 /*
640 * 649 *
641 * Main entry point. 650 * Main entry point.
642 */ 651 */
643 int main(int argc, char **argv) { 652 int main(int argc, char **argv) {
-   653 #if defined ___AmigaOS___
-   654 struct RDArgs *rdargs;
-   655 struct stat statPath;
-   656 UBYTE *dbFile;
-   657 UBYTE *argPath;
-   658  
-   659 dbFile = DEFAULT_DATABASE_FILE;
-   660 argPath = NULL;
-   661 if(rdargs = (struct RDArgs *) AllocDosObject(DOS_RDARGS, NULL)) {
-   662 if(ReadArgs(TEMPLATE, result, rdargs) == NULL) {
-   663 FreeArgs(rdargs);
-   664 FreeDosObject(DOS_RDARGS, rdargs);
-   665 return 1;
-   666 }
-   667  
-   668 if(result[OPT_DATABASE] != NULL) {
-   669 dbFile = (UBYTE *) result[OPT_DATABASE];
-   670 }
-   671  
-   672 if(result[OPT_QUIET]) {
-   673 verbose = FALSE;
-   674 }
-   675  
-   676 argPath = (UBYTE *) result[OPT_PATH];
-   677  
-   678 FreeArgs(rdargs);
-   679 FreeDosObject(DOS_RDARGS, rdargs);
-   680 }
-   681  
-   682 stat(argPath, &statPath);
-   683 if(!S_ISDIR(statPath.st_mode)) {
-   684 fprintf(stderr, "Path '%s' is not a directory.\n", argPath);
-   685 return 1;
-   686 }
-   687  
-   688 if(verbose) {
-   689 fprintf(stdout, "Gathering to database file: %s\n", dbFile);
-   690 }
-   691  
-   692 Gather(dbFile, argPath);
-   693 #else
644 int option; 694 int option;
645 char *dbFile; 695 char *dbFile;
646 struct stat path; 696 struct stat path;
647   697  
648 // Bind handler to SIGINT. 698 // Bind handler to SIGINT.
649 signal(SIGINT, SignalHandler); 699 signal(SIGINT, SignalHandler);
650   700  
651 dbFile = DEFAULT_DATABASE_FILE; 701 dbFile = DEFAULT_DATABASE_FILE;
652 while((option = getopt(argc, argv, "hqd:")) != -1) { 702 while((option = getopt(argc, argv, "hqd:")) != -1) {
653 switch(option) { 703 switch(option) {
654 case 'd': 704 case 'd':
655 dbFile = optarg; 705 dbFile = optarg;
656 break; 706 break;
657 case 'q': 707 case 'q':
658 verbose = FALSE; 708 verbose = FALSE;
659 break; 709 break;
660 case 'h': 710 case 'h':
661 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); 711 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]);
662 return 0; 712 return 0;
663 case '?': 713 case '?':
664 fprintf(stderr, "Invalid option %ct.\n", optopt); 714 fprintf(stderr, "Invalid option %ct.\n", optopt);
665 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); 715 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]);
666 return 1; 716 return 1;
667 } 717 }
668 } 718 }
669   719  
670 if(optind > argc) { 720 if(optind > argc) {
671 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]); 721 fprintf(stdout, "SYNTAX: %s [-q] [-d DATABASE] DIRECTORY\n", argv[0]);
672 return 1; 722 return 1;
673 } 723 }
674   724  
675 stat(argv[optind], &path); 725 stat(argv[optind], &path);
676 if(!S_ISDIR(path.st_mode)) { 726 if(!S_ISDIR(path.st_mode)) {
677 fprintf(stderr, "%s is not a directory.\n", argv[optind]); 727 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]);
678 return 1; 728 return 1;
679 } 729 }
680   730  
681 if(verbose) { 731 if(verbose) {
682 fprintf(stdout, "Gathering to database file: %s\n", dbFile); 732 fprintf(stdout, "Gathering to database file: %s\n", dbFile);
683 } 733 }
684   734  
685 // Gather. 735 // Gather.
686 Gather(dbFile, argv[optind]); 736 Gather(dbFile, argv[optind]);
-   737 #endif
687   738  
688 return 0; 739 return 0;
689 } 740 }
690   741