HuntnGather – Diff between revs 23 and 24

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 23 Rev 24
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 #include <sys/syslimits.h> 13 #include <sys/syslimits.h>
14   14  
15 #include <proto/dos.h> 15 #include <proto/dos.h>
16 #include <proto/exec.h> 16 #include <proto/exec.h>
17   17  
18 #if defined ___AsyncIO___ 18 #if defined ___AsyncIO___
19 #include <asyncio.h> 19 #include <asyncio.h>
20 #endif 20 #endif
21   21  
22 #include "StringStack.h" 22 #include "StringStack.h"
23   23  
24 #if !defined ___HAVE_GETOPT___ 24 #if !defined ___HAVE_GETOPT___
25 #include "getopt.h" 25 #include "getopt.h"
26 #endif 26 #endif
27   27  
28 #define PROGRAM_VERSION "1.7.3" 28 #define PROGRAM_VERSION "1.7.3"
29   29  
30 #if defined ___AmigaOS___ 30 #if defined ___AmigaOS___
31 /*************************************************************************/ 31 /*************************************************************************/
32 /* Version string used for querrying the program version. */ 32 /* Version string used for querrying the program version. */
33 /*************************************************************************/ 33 /*************************************************************************/
34 TEXT version_string[] = 34 TEXT version_string[] =
35 "\0$VER: Gather " PROGRAM_VERSION " "__DATE__" by Wizardry and Steamworks"; 35 "\0$VER: Gather " PROGRAM_VERSION " "__DATE__" by Wizardry and Steamworks";
36 #endif 36 #endif
37   37  
38 #if !defined TRUE 38 #if !defined TRUE
39 #define TRUE 1; 39 #define TRUE 1;
40 #endif 40 #endif
41   41  
42 #if !defined FALSE 42 #if !defined FALSE
43 #define FALSE 0; 43 #define FALSE 0;
44 #endif 44 #endif
45   45  
46 #define ASYNC_BUF 8192 46 #define ASYNC_BUF 8192
47 #define MAX_MEM 262144 47 #define MAX_MEM 262144
48 #define NAME_BUF 32 48 #define NAME_BUF 32
49 #define PATH_BUF 128 49 #define PATH_BUF 128
50 #define LINE_BUF 256 50 #define LINE_BUF 256
51 #define DEFAULT_DATABASE_FILE "S:gather.db" 51 #define DEFAULT_DATABASE_FILE "S:gather.db"
52   52  
53 typedef struct { 53 typedef struct {
54 unsigned int dirs; 54 unsigned int dirs;
55 unsigned int files; 55 unsigned int files;
56 } stats; 56 } stats;
57   57  
58 int run = TRUE; 58 int run = TRUE;
59 int verbose = TRUE; 59 int verbose = TRUE;
60   60  
61 void SignalHandler(int sig) { 61 void SignalHandler(int sig) {
62 // Toggle the run flag to stop execution. 62 // Toggle the run flag to stop execution.
63 run = FALSE; 63 run = FALSE;
64 } 64 }
65   65  
66 int compare(const void *a, const void *b) { 66 int compare(const void *a, const void *b) {
67 const char **p = (const char **)a; 67 const char **p = (const char **)a;
68 const char **q = (const char **)b; 68 const char **q = (const char **)b;
69 return strncmp(*p, *q, strlen(*p)); 69 return strncmp(*p, *q, strlen(*p));
70 } 70 }
71   71  
72 /* 72 /*
73 * 73 *
74 * Sorts a database file lexicographically. 74 * Sorts a database file lexicographically.
75 */ 75 */
76 void SortDatabase(char *dbFile) { 76 void SortDatabase(char *dbFile) {
77 #if defined ___AsyncIO___ 77 #if defined ___AsyncIO___
78 struct AsyncFile *fp; 78 struct AsyncFile *fp;
79 LONG c; 79 LONG c;
80 #else 80 #else
81 FILE *fp; 81 FILE *fp;
82 char c; 82 char c;
83 #endif 83 #endif
84 char *name = NULL; 84 char *name = NULL;
85 char *path = NULL; 85 char *path = NULL;
86 char **database; 86 char **database;
87 int i; 87 int i;
88 int side; 88 int side;
89 unsigned int line; 89 unsigned int line;
90 int name_size; 90 int name_size;
91 int path_size; 91 int path_size;
92   92  
93 // Open database file for reading. 93 // Open database file for reading.
94 #if defined ___AsyncIO___ 94 #if defined ___AsyncIO___
95 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 95 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
96 #else 96 #else
97 if((fp = fopen(dbFile, "r")) == NULL) { 97 if((fp = fopen(dbFile, "r")) == NULL) {
98 #endif 98 #endif
99 fprintf(stderr, "Unable to open gather database for reading.\n"); 99 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
100 return; 100 return;
101 } 101 }
102   102  
103 database = malloc(sizeof(*database)); 103 database = malloc(sizeof(*database));
104 name_size = NAME_BUF; 104 name_size = NAME_BUF;
105 name = malloc(name_size * sizeof(*name)); 105 name = malloc(name_size * sizeof(*name));
106 path_size = PATH_BUF; 106 path_size = PATH_BUF;
107 path = malloc(path_size * sizeof(*path)); 107 path = malloc(path_size * sizeof(*path));
108   108  
109 line = 0; 109 line = 0;
110 side = 0; 110 side = 0;
111 i = 0; 111 i = 0;
112   112  
113 if(verbose) { 113 if(verbose) {
114 fprintf(stdout, "Sorting temporary database file: '%s'\n", dbFile); 114 fprintf(stdout, "Sorting '%s'\n", dbFile);
115 } 115 }
-   116  
116 #if defined ___AsyncIO___ 117 #if defined ___AsyncIO___
117 while(run && (c = ReadCharAsync(fp)) != -1) { 118 while(run && (c = ReadCharAsync(fp)) != -1) {
118 #else 119 #else
119 while(run && fscanf(fp, "%c", &c) == 1) { 120 while(run && fscanf(fp, "%c", &c) == 1) {
120 #endif 121 #endif
121 #if defined ___AmigaOS___ 122 #if defined ___AmigaOS___
122 // Check if CTRL+C was pressed and abort the program. 123 // Check if CTRL+C was pressed and abort the program.
123 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 124 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
124 run = FALSE; 125 run = FALSE;
125 continue; 126 continue;
126 } 127 }
127 #endif 128 #endif
128 switch(c) { 129 switch(c) {
129 case '\n': 130 case '\n':
130 // Load up the name and path into the database variable. 131 // Load up the name and path into the database variable.
131 database = realloc(database, (line + 1) * sizeof(*database)); 132 database = realloc(database, (line + 1) * sizeof(*database));
132 database[line] = malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(*database[line])); 133 database[line] = malloc((strlen(name) + strlen(path) + 1 + 1) * sizeof(*database[line]));
133 sprintf(database[line], "%s\t%s", name, path); 134 sprintf(database[line], "%s\t%s", name, path);
134 ++line; 135 ++line;
135   136  
136 free(name); 137 free(name);
137 name_size = NAME_BUF; 138 name_size = NAME_BUF;
138 name = malloc(name_size * sizeof(*name)); 139 name = malloc(name_size * sizeof(*name));
139 --side; 140 --side;
140 i = 0; 141 i = 0;
141   142  
142 break; 143 break;
143 case '\t': 144 case '\t':
144 free(path); 145 free(path);
145 path_size = PATH_BUF; 146 path_size = PATH_BUF;
146 path = malloc(path_size * sizeof(*path)); 147 path = malloc(path_size * sizeof(*path));
147 ++side; 148 ++side;
148 i = 0; 149 i = 0;
149 break; 150 break;
150 default: 151 default:
151 switch(side) { 152 switch(side) {
152 case 0: 153 case 0:
153 if(strlen(name) == name_size) { 154 if(strlen(name) == name_size) {
154 name_size = name_size * 1.5; 155 name_size = name_size * 1.5;
155 name = realloc(name, name_size * sizeof(*name)); 156 name = realloc(name, name_size * sizeof(*name));
156 } 157 }
157 //name = realloc(name, (i + 1 + 1) * sizeof(char)); 158 //name = realloc(name, (i + 1 + 1) * sizeof(char));
158 name[i] = c; 159 name[i] = c;
159 name[i + 1] = '\0'; 160 name[i + 1] = '\0';
160 break; 161 break;
161 case 1: 162 case 1:
162 if(strlen(path) == path_size) { 163 if(strlen(path) == path_size) {
163 path_size = path_size * 1.5; 164 path_size = path_size * 1.5;
164 path = realloc(path, path_size * sizeof(*path)); 165 path = realloc(path, path_size * sizeof(*path));
165 } 166 }
166 //path = realloc(path, (i + 1 + 1) * sizeof(char)); 167 //path = realloc(path, (i + 1 + 1) * sizeof(char));
167 path[i] = c; 168 path[i] = c;
168 path[i + 1] = '\0'; 169 path[i + 1] = '\0';
169 break; 170 break;
170 default: 171 default:
171 fprintf(stderr, "Database corrupted: %d\n", side); 172 fprintf(stderr, "File '%s' is corrupted.\n", dbFile);
172 break; 173 break;
173 } 174 }
174 ++i; 175 ++i;
175 break; 176 break;
176 } 177 }
177 } 178 }
178   179  
179 #if defined ___AsyncIO___ 180 #if defined ___AsyncIO___
180 CloseAsync(fp); 181 CloseAsync(fp);
181 #else 182 #else
182 fclose(fp); 183 fclose(fp);
183 #endif 184 #endif
184   185  
185 // Sort the database. 186 // Sort the database.
186 qsort(database, line, sizeof(char *), compare); 187 qsort(database, line, sizeof(char *), compare);
187   188  
188 // Write the database lines back to the database. 189 // Write the database lines back to the database.
189 #if defined ___AsyncIO___ 190 #if defined ___AsyncIO___
190 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 191 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
191 #else 192 #else
192 if((fp = fopen(dbFile, "w")) == NULL) { 193 if((fp = fopen(dbFile, "w")) == NULL) {
193 #endif 194 #endif
194 fprintf(stderr, "Unable to open gather database for writing.\n"); 195 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
195 return; 196 return;
196 } 197 }
197   198  
198 for(i = 0; i < line; ++i) { 199 for(i = 0; i < line; ++i) {
199 #if defined ___AmigaOS___ 200 #if defined ___AmigaOS___
200 // Check if CTRL+C was pressed and abort the program. 201 // Check if CTRL+C was pressed and abort the program.
201 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 202 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
202 run = FALSE; 203 run = FALSE;
203 continue; 204 continue;
204 } 205 }
205 #endif 206 #endif
206 #if defined ___AsyncIO___ 207 #if defined ___AsyncIO___
207 WriteAsync(fp, database[i], (LONG)(strlen(database[i]) * sizeof(char))); 208 WriteAsync(fp, database[i], (LONG)(strlen(database[i]) * sizeof(char)));
208 WriteAsync(fp, "\n", 1 * sizeof(char)); 209 WriteAsync(fp, "\n", 1 * sizeof(char));
209 #else 210 #else
210 fprintf(fp, "%s\n", database[i]); 211 fprintf(fp, "%s\n", database[i]);
211 #endif 212 #endif
212 } 213 }
213   214  
214 #if defined ___AsyncIO___ 215 #if defined ___AsyncIO___
215 CloseAsync(fp); 216 CloseAsync(fp);
216 #else 217 #else
217 fclose(fp); 218 fclose(fp);
218 #endif 219 #endif
219   220  
220 free(database); 221 free(database);
221 } 222 }
222   223  
223 /* 224 /*
224 * 225 *
225 * Updates a database file "dbFile". 226 * Updates a database file "dbFile".
226 */ 227 */
227 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) { 228 void CollectFiles(char *dbFile, stringStack *dirStack, stats *stats) {
228 #if defined ___AsyncIO___ 229 #if defined ___AsyncIO___
229 struct AsyncFile *fp; 230 struct AsyncFile *fp;
230 #else 231 #else
231 FILE *fp; 232 FILE *fp;
232 #endif 233 #endif
233 DIR *dir; 234 DIR *dir;
234 struct dirent *dirEntry; 235 struct dirent *dirEntry;
235 struct stat dirStat; 236 struct stat dirStat;
236 unsigned int size; 237 unsigned int size;
237 char *path; 238 char *path;
238 char *subPath; 239 char *subPath;
239   240  
240 #if defined ___AsyncIO___ 241 #if defined ___AsyncIO___
241 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 242 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
242 #else 243 #else
243 if((fp = fopen(dbFile, "w")) == NULL) { 244 if((fp = fopen(dbFile, "w")) == NULL) {
244 #endif 245 #endif
245 fprintf(stderr, "Unable to open gather database for writing.\n"); 246 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
246 return; 247 return;
247 } 248 }
-   249  
-   250 if(verbose) {
-   251 fprintf(stdout, "Collecting files...\r");
-   252 }
248   253  
249 while(run && !stringStackIsEmpty(dirStack)) { 254 while(run && !stringStackIsEmpty(dirStack)) {
250 #if defined ___AmigaOS___ 255 #if defined ___AmigaOS___
251 // Check if CTRL+C was pressed and abort the program. 256 // Check if CTRL+C was pressed and abort the program.
252 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 257 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
253 run = FALSE; 258 run = FALSE;
254 continue; 259 continue;
255 } 260 }
256 #endif 261 #endif
257 if((path = stringStackPop(dirStack)) == NULL) { 262 if((path = stringStackPop(dirStack)) == NULL) {
258 return; 263 return;
259 } 264 }
260   265  
261 if((dir = opendir(path)) == NULL) { 266 if((dir = opendir(path)) == NULL) {
-   267 fprintf(stderr, "Unable to open '%s' for reading.\n", path);
262 return; 268 return;
263 } 269 }
264   270  
265 while(run && (dirEntry = readdir(dir)) != NULL) { 271 while(run && (dirEntry = readdir(dir)) != NULL) {
266 #if defined ___AmigaOS___ 272 #if defined ___AmigaOS___
267 // Check if CTRL+C was pressed and abort the program. 273 // Check if CTRL+C was pressed and abort the program.
268 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 274 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
269 run = FALSE; 275 run = FALSE;
270 continue; 276 continue;
271 } 277 }
272 #endif 278 #endif
273 size = sizeof(path) + sizeof(dirEntry->d_name) + 1; 279 size = sizeof(path) + sizeof(dirEntry->d_name) + 1;
274 switch(path[strlen(path) - 1]) { 280 switch(path[strlen(path) - 1]) {
275 case '/': 281 case '/':
276 case ':': // This is a drive path. 282 case ':': // This is a drive path.
277 subPath = malloc(size); 283 subPath = malloc(size);
278 sprintf(subPath, "%s%s", path, dirEntry->d_name); 284 sprintf(subPath, "%s%s", path, dirEntry->d_name);
279 break; 285 break;
280 default: 286 default:
281 subPath = malloc(size + 1); 287 subPath = malloc(size + 1);
282 sprintf(subPath, "%s/%s", path, dirEntry->d_name); 288 sprintf(subPath, "%s/%s", path, dirEntry->d_name);
283 break; 289 break;
284 } 290 }
285 stat(subPath, &dirStat); 291 stat(subPath, &dirStat);
286 if(S_ISDIR(dirStat.st_mode)) { 292 if(S_ISDIR(dirStat.st_mode)) {
287 stringStackPush(dirStack, subPath); 293 stringStackPush(dirStack, subPath);
288   294  
289 ++stats->dirs; 295 ++stats->dirs;
290   296  
291 if(verbose) { 297 if(verbose) {
292 fprintf(stdout, 298 fprintf(stdout,
293 "Gathered %d directories and %d files.\r", 299 "Gathered %d directories and %d files.\r",
294 stats->dirs, 300 stats->dirs,
295 stats->files); 301 stats->files);
296 } 302 }
297   303  
298 free(subPath); 304 free(subPath);
299 continue; 305 continue;
300 } 306 }
301   307  
302 // Write to database file. 308 // Write to database file.
303   309  
304 #if defined ___NOCASE_FS___ 310 #if defined ___NOCASE_FS___
305 strupr(dirEntry->d_name); 311 strupr(dirEntry->d_name);
306 #endif 312 #endif
307   313  
308 #if defined ___AsyncIO___ 314 #if defined ___AsyncIO___
309 WriteAsync(fp, dirEntry->d_name, (LONG)(strlen(dirEntry->d_name) * sizeof(char))); 315 WriteAsync(fp, dirEntry->d_name, (LONG)(strlen(dirEntry->d_name) * sizeof(char)));
310 WriteAsync(fp, "\t", 1 * sizeof(char)); 316 WriteAsync(fp, "\t", 1 * sizeof(char));
311 WriteAsync(fp, subPath, (LONG)(strlen(subPath) * sizeof(char))); 317 WriteAsync(fp, subPath, (LONG)(strlen(subPath) * sizeof(char)));
312 WriteAsync(fp, "\n", 1 * sizeof(char)); 318 WriteAsync(fp, "\n", 1 * sizeof(char));
313 #else 319 #else
314 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath); 320 fprintf(fp, "%s\t%s\n", dirEntry->d_name, subPath);
315 #endif 321 #endif
316 ++stats->files; 322 ++stats->files;
317   323  
318 if(verbose) { 324 if(verbose) {
319 fprintf(stdout, 325 fprintf(stdout,
320 "Gathered %d directories and %d files.\r", 326 "Gathered %d directories and %d files.\r",
321 stats->dirs, 327 stats->dirs,
322 stats->files); 328 stats->files);
323 } 329 }
324   330  
325 free(subPath); 331 free(subPath);
326 } 332 }
327   333  
328 closedir(dir); 334 closedir(dir);
329 free(path); 335 free(path);
330 } 336 }
331   337  
332 if(verbose) { 338 if(verbose) {
333 fprintf(stdout, "\n"); 339 fprintf(stdout, "\n");
334 } 340 }
335   341  
336 #if defined ___AsyncIO___ 342 #if defined ___AsyncIO___
337 CloseAsync(fp); 343 CloseAsync(fp);
338 #else 344 #else
339 fclose(fp); 345 fclose(fp);
340 #endif 346 #endif
341   347  
342 } 348 }
343   349  
344 /* 350 /*
345 * 351 *
346 * Gets the size of a file "dbFle". 352 * Gets the size of a file "dbFle".
347 */ 353 */
348 int GetFileSize(char *dbFile) { 354 int GetFileSize(char *dbFile) {
349 #if defined ___AsyncIO___ 355 #if defined ___AsyncIO___
350 struct AsyncFile *fp; 356 struct AsyncFile *fp;
351 LONG size; 357 LONG size;
352 #else 358 #else
353 FILE *fp; 359 FILE *fp;
354 int size; 360 int size;
355 #endif 361 #endif
356   362  
357 #if defined ___AsyncIO___ 363 #if defined ___AsyncIO___
358 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 364 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
359 #else 365 #else
360 if((fp = fopen(dbFile, "r")) == NULL) { 366 if((fp = fopen(dbFile, "r")) == NULL) {
361 #endif 367 #endif
362 fprintf(stderr, "Unable to open gather database for reading.\n"); 368 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
363 return 0; 369 return 0;
364 } 370 }
365   371  
366 #if defined ___AsyncIO___ 372 #if defined ___AsyncIO___
367 SeekAsync(fp, 0, MODE_END); 373 SeekAsync(fp, 0, MODE_END);
368 size = SeekAsync(fp, 0, MODE_CURRENT); 374 size = SeekAsync(fp, 0, MODE_CURRENT);
369 #else 375 #else
370 fseek(fp, 0L, SEEK_END); 376 fseek(fp, 0L, SEEK_END);
371 size = ftell(fp); 377 size = ftell(fp);
372 #endif 378 #endif
373   379  
374 #if defined ___AsyncIO___ 380 #if defined ___AsyncIO___
375 CloseAsync(fp); 381 CloseAsync(fp);
376 #else 382 #else
377 fclose(fp); 383 fclose(fp);
378 #endif 384 #endif
379   385  
380 return size; 386 return size;
381 } 387 }
382   388  
383 /* 389 /*
384 * 390 *
385 * Counts the lines of a file. 391 * Counts the lines of a file.
386 */ 392 */
387 int GetFileLines(char *dbFile) { 393 int CountFileLines(char *dbFile) {
388 #if defined ___AsyncIO___ 394 #if defined ___AsyncIO___
389 struct AsyncFile *fp; 395 struct AsyncFile *fp;
390 LONG c; 396 LONG c;
391 #else 397 #else
392 FILE *fp; 398 FILE *fp;
393 char c; 399 char c;
394 #endif 400 #endif
395 int lines; 401 int lines;
396   402  
397 #if defined ___AsyncIO___ 403 #if defined ___AsyncIO___
398 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 404 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
399 #else 405 #else
400 if((fp = fopen(dbFile, "r")) == NULL) { 406 if((fp = fopen(dbFile, "r")) == NULL) {
401 #endif 407 #endif
402 fprintf(stderr, "Unable to open gather database for reading.\n"); 408 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
403 return 0; 409 return 0;
404 } 410 }
405   411  
406 lines = 0; 412 lines = 0;
407 #if defined ___AsyncIO___ 413 #if defined ___AsyncIO___
408 while(run && (c = ReadCharAsync(fp)) != -1) { 414 while(run && (c = ReadCharAsync(fp)) != -1) {
409 #else 415 #else
410 while(run && fscanf(fp, "%c", &c) == 1) { 416 while(run && fscanf(fp, "%c", &c) == 1) {
411 #endif 417 #endif
412 #if defined ___AmigaOS___ 418 #if defined ___AmigaOS___
413 // Check if CTRL+C was pressed and abort the program. 419 // Check if CTRL+C was pressed and abort the program.
414 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 420 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
415 run = FALSE; 421 run = FALSE;
416 continue; 422 continue;
417 } 423 }
418 #endif 424 #endif
419 switch(c) { 425 switch(c) {
420 case '\n': 426 case '\n':
421 ++lines; 427 ++lines;
422 break; 428 break;
423 } 429 }
424 } 430 }
425   431  
426 #if defined ___AsyncIO___ 432 #if defined ___AsyncIO___
427 CloseAsync(fp); 433 CloseAsync(fp);
428 #else 434 #else
429 fclose(fp); 435 fclose(fp);
430 #endif 436 #endif
431   437  
432 return lines; 438 return lines;
433 } 439 }
434   440  
435 /* 441 /*
436 * 442 *
437 * Creates "files" temporary filenames. 443 * Creates "files" temporary filenames.
438 */ 444 */
439 char **CreateTemporaryFiles(int files) { 445 char **CreateTemporaryFiles(int files) {
440 char **tmpNames; 446 char **tmpNames;
441 int count; 447 int count;
442   448  
443 tmpNames = malloc(files * sizeof(*tmpNames)); 449 tmpNames = malloc(files * sizeof(*tmpNames));
444   450  
445 if(verbose) { 451 if(verbose) {
446 fprintf(stdout, "Creating temporary files.\r"); 452 fprintf(stdout, "Creating temporary files...\r");
447 } 453 }
448   454  
449 count = files; 455 count = files;
450 while(run && --count > -1) { 456 while(run && --count > -1) {
451 #if defined ___AmigaOS___ 457 #if defined ___AmigaOS___
452 // Check if CTRL+C was pressed and abort the program. 458 // Check if CTRL+C was pressed and abort the program.
453 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 459 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
454 run = FALSE; 460 run = FALSE;
455 continue; 461 continue;
456 } 462 }
457 #endif 463 #endif
458 tmpNames[count] = tmpnam(NULL); 464 tmpNames[count] = tmpnam(NULL);
-   465  
-   466 // Remove file to ensure that the file is empty.
-   467 remove(tmpNames[count]);
459   468  
460 if(verbose) { 469 if(verbose) {
461 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0)); 470 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0));
462 } 471 }
463 } 472 }
464   473  
465 if(verbose) { 474 if(verbose) {
466 fprintf(stdout, "\n"); 475 fprintf(stdout, "\n");
467 } 476 }
468   477  
469 return tmpNames; 478 return tmpNames;
470 } 479 }
471   480  
472 /* 481 /*
473 * 482 *
474 * Writes lines from the database "dbFile" to temporary filenames "tmpNames". 483 * Writes lines from the database "dbFile" to temporary filenames "tmpNames".
475 */ 484 */
476 void WriteTemporaryFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) { 485 void WriteTemporaryFiles(char *dbFile, char **tmpNames, int tmpFiles, int tmpLines, int total) {
477 #if defined ___AsyncIO___ 486 #if defined ___AsyncIO___
478 struct AsyncFile *fp, *tp; 487 struct AsyncFile *fp, *tp;
479 LONG c; 488 LONG c;
480 #else 489 #else
481 FILE *fp, *tp; 490 FILE *fp, *tp;
482 char c; 491 char c;
483 #endif 492 #endif
484 int lines; 493 int lines;
485 int linesWritten; 494 int linesWritten;
486   495  
487 #if defined ___AsyncIO___ 496 #if defined ___AsyncIO___
488 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 497 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
489 #else 498 #else
490 if((fp = fopen(dbFile, "r")) == NULL) { 499 if((fp = fopen(dbFile, "r")) == NULL) {
491 #endif 500 #endif
492 fprintf(stderr, "Unable to open gather database '%s' for reading.\n", dbFile); 501 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
493 return; 502 return;
494 } 503 }
495   504  
496 #if defined ___AsyncIO___ 505 #if defined ___AsyncIO___
497 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { 506 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) {
498 #else 507 #else
499 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { 508 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) {
500 #endif 509 #endif
501 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 510 fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]);
-   511 #if defined ___AsyncIO___
-   512 CloseAsync(fp);
-   513 #else
-   514 fclose(fp);
-   515 #endif
502 return; 516 return;
503 } 517 }
504   518  
505 if(verbose) { 519 if(verbose) {
506 fprintf(stdout, "Writing to temporary files.\r"); 520 fprintf(stdout, "Writing to temporary files...\r");
507 } 521 }
508   522  
509 linesWritten = 0; 523 linesWritten = 0;
510 lines = 0; 524 lines = 0;
511 #if defined ___AsyncIO___ 525 #if defined ___AsyncIO___
512 while(run && (c = ReadCharAsync(fp)) != -1) { 526 while(run && (c = ReadCharAsync(fp)) != -1) {
513 #else 527 #else
514 while(run && fscanf(fp, "%c", &c) == 1) { 528 while(run && fscanf(fp, "%c", &c) == 1) {
515 #endif 529 #endif
516 #if defined ___AmigaOS___ 530 #if defined ___AmigaOS___
517 // Check if CTRL+C was pressed and abort the program. 531 // Check if CTRL+C was pressed and abort the program.
518 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 532 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
519 run = FALSE; 533 run = FALSE;
520 continue; 534 continue;
521 } 535 }
522 #endif 536 #endif
523 switch(c) { 537 switch(c) {
524 case '\n': 538 case '\n':
525 // Increment the total written lines. 539 // Increment the total written lines.
526 ++linesWritten; 540 ++linesWritten;
527   541  
528 if(verbose) { 542 if(verbose) {
529 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0)); 543 fprintf(stdout, "Writing to temporary files: %d%%.\r", (int)(((float)linesWritten / total) * 100.0));
530 } 544 }
531   545  
532 // Write the newline character back. 546 // Write the newline character back.
533 #if defined ___AsyncIO___ 547 #if defined ___AsyncIO___
534 if(WriteCharAsync(tp, (UBYTE)c) != 1) { 548 if(WriteCharAsync(tp, (UBYTE)c) != 1) {
535 #else 549 #else
536 if(fprintf(tp, "%c", c) != 1) { 550 if(fprintf(tp, "%c", c) != 1) {
537 #endif 551 #endif
538 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 552 fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]);
539 #if defined ___AsyncIO___ 553 #if defined ___AsyncIO___
540 CloseAsync(tp); 554 CloseAsync(tp);
541 CloseAsync(fp); 555 CloseAsync(fp);
542 #else 556 #else
543 fclose(tp); 557 fclose(tp);
544 fclose(fp); 558 fclose(fp);
545 #endif 559 #endif
546 return; 560 return;
547 } 561 }
548 // Switch to the next temporary file. 562 // Switch to the next temporary file.
549 if(++lines >= tmpLines) { 563 if(++lines >= tmpLines) {
550 // If there are no temporary files left then run till the end. 564 // If there are no temporary files left then run till the end.
551 if(tmpFiles - 1 < 0) { 565 if(tmpFiles - 1 < 0) {
552 break; 566 break;
553 } 567 }
554   568  
555 // Close the previous temporary file and write to the next temporary file. 569 // Close the previous temporary file and write to the next temporary file.
556 #if defined ___AsyncIO___ 570 #if defined ___AsyncIO___
557 CloseAsync(tp); 571 CloseAsync(tp);
558 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { 572 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) {
559 #else 573 #else
560 fclose(tp); 574 fclose(tp);
561 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { 575 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) {
562 #endif 576 #endif
563 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 577 fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]);
564 #if defined ___AsyncIO___ 578 #if defined ___AsyncIO___
565 CloseAsync(tp); -  
566 CloseAsync(fp); 579 CloseAsync(fp);
567 #else 580 #else
568 fclose(tp); -  
569 fclose(fp); 581 fclose(fp);
570 #endif 582 #endif
-   583 return;
571 } 584 }
572 lines = 0; 585 lines = 0;
573 break; 586 break;
574 } 587 }
575 break; 588 break;
576 default: 589 default:
577 #if defined ___AsyncIO___ 590 #if defined ___AsyncIO___
578 if(WriteCharAsync(tp, (UBYTE)c) != 1) { 591 if(WriteCharAsync(tp, (UBYTE)c) != 1) {
579 #else 592 #else
580 if(fprintf(tp, "%c", c) != 1) { 593 if(fprintf(tp, "%c", c) != 1) {
581 #endif 594 #endif
582 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 595 fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]);
583 #if defined ___AsyncIO___ 596 #if defined ___AsyncIO___
584 CloseAsync(tp); 597 CloseAsync(tp);
585 CloseAsync(fp); 598 CloseAsync(fp);
586 #else 599 #else
587 fclose(tp); 600 fclose(tp);
588 fclose(fp); 601 fclose(fp);
589 #endif 602 #endif
590 return; 603 return;
591 } 604 }
592 break; 605 break;
593 } 606 }
594 } 607 }
-   608  
595   609 if(verbose) {
-   610 fprintf(stdout, "\n");
596 fprintf(stdout, "\n"); 611 }
597   612  
598 #if defined ___AsyncIO___ 613 #if defined ___AsyncIO___
599 CloseAsync(tp); 614 CloseAsync(tp);
600 CloseAsync(fp); 615 CloseAsync(fp);
601 #else 616 #else
602 fclose(tp); 617 fclose(tp);
603 fclose(fp); 618 fclose(fp);
604 #endif 619 #endif
605 } 620 }
606   621  
607 /* 622 /*
608 * 623 *
609 * Skips a line in a database file "fp". 624 * Skips a line in a file.
610 */ 625 */
611   626  
612 #if defined ___AsyncIO___ 627 #if defined ___AsyncIO___
613 void SkipLine(struct AsyncFile *fp) { 628 void SkipLine(struct AsyncFile *fp) {
614 LONG c; 629 LONG c;
615 while(run && (c = ReadCharAsync(fp)) != -1) { 630 while(run && (c = ReadCharAsync(fp)) != -1) {
616 #else 631 #else
617 void SkipDatabaseLine(FILE *fp) { 632 void SkipDatabaseLine(FILE *fp) {
618 char c; 633 char c;
619 while(run && fscanf(fp, "%c", &c) == 1) { 634 while(run && fscanf(fp, "%c", &c) == 1) {
620 #endif 635 #endif
621 #if defined ___AmigaOS___ 636 #if defined ___AmigaOS___
622 // Check if CTRL+C was pressed and abort the program. 637 // Check if CTRL+C was pressed and abort the program.
623 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 638 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
624 run = FALSE; 639 run = FALSE;
625 continue; 640 continue;
626 } 641 }
627 #endif 642 #endif
628 switch(c) { 643 switch(c) {
629 case '\n': 644 case '\n':
630 return; 645 return;
631 } 646 }
632 } 647 }
633 } 648 }
634   649  
635 /* 650 /*
636 * 651 *
637 * Reads a line from the database file "fp". 652 * Reads a line from a file.
638 */ 653 */
639 #if defined ___AsyncIO___ 654 #if defined ___AsyncIO___
640 char *ReadLine(struct AsyncFile *fp) { 655 char *ReadLine(struct AsyncFile *fp) {
641 LONG c; 656 LONG c;
642 #else 657 #else
643 char *ReadLine(FILE *fp) { 658 char *ReadLine(FILE *fp) {
644 char c; 659 char c;
645 #endif 660 #endif
646 char *line; 661 char *line;
647 int line_size; 662 int line_size;
648 int i; 663 int i;
649   664  
650 line_size = LINE_BUF; 665 line_size = LINE_BUF;
651 line = malloc(line_size * sizeof(*line)); 666 line = malloc(line_size * sizeof(*line));
652   667  
653 i = 0; 668 i = 0;
654 #if defined ___AsyncIO___ 669 #if defined ___AsyncIO___
655 while(run && (c = ReadCharAsync(fp)) != -1) { 670 while(run && (c = ReadCharAsync(fp)) != -1) {
656 #else 671 #else
657 while(run && fscanf(fp, "%c", &c) == 1) { 672 while(run && fscanf(fp, "%c", &c) == 1) {
658 #endif 673 #endif
659 #if defined ___AmigaOS___ 674 #if defined ___AmigaOS___
660 // Check if CTRL+C was pressed and abort the program. 675 // Check if CTRL+C was pressed and abort the program.
661 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 676 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
662 run = FALSE; 677 run = FALSE;
663 continue; 678 continue;
664 } 679 }
665 #endif 680 #endif
666 switch(c) { 681 switch(c) {
667 case '\n': 682 case '\n':
668 // Rewind the file by the number of read characters. 683 // Rewind the file by the number of read characters.
669 #if defined ___AsyncIO___ 684 #if defined ___AsyncIO___
670 if(SeekAsync(fp, -(i + 1), MODE_CURRENT) == -1) { 685 if(SeekAsync(fp, -(i + 1), MODE_CURRENT) == -1) {
671 fprintf(stderr, "Could not seek in file.\n"); 686 fprintf(stderr, "Could not seek in file.\n");
672 return NULL; 687 return NULL;
673 } 688 }
674 #else 689 #else
675 fseek(fp, -(i + 1), SEEK_CUR); 690 fseek(fp, -(i + 1), SEEK_CUR);
676 #endif 691 #endif
677 return line; 692 return line;
678 default: 693 default:
679 if(strlen(line) == line_size) { 694 if(strlen(line) == line_size) {
680 line_size = line_size * 1.5; 695 line_size = line_size * 1.5;
681 line = realloc(line, line_size * sizeof(*line)); 696 line = realloc(line, line_size * sizeof(*line));
682 } 697 }
683 //line = realloc(line, (chars + 1 + 1) * sizeof(char)); 698 //line = realloc(line, (chars + 1 + 1) * sizeof(char));
684 line[i] = c; 699 line[i] = c;
685 line[i + 1] = '\0'; 700 line[i + 1] = '\0';
686 break; 701 break;
687 } 702 }
688 ++i; 703 ++i;
689 } 704 }
690   705  
691 return NULL; 706 return NULL;
692 } 707 }
693   708  
694 /* 709 /*
695 * 710 *
696 * Merges temporary files "tmpNames" into a database "dbFile". 711 * Merges temporary files "tmpNames" into a database "dbFile".
697 */ 712 */
698 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) { 713 void MergeTemporaryFiles(char *dbFile, char **tmpNames, int files, int lines) {
699 #if defined ___AsyncIO___ 714 #if defined ___AsyncIO___
700 struct AsyncFile *fp; 715 struct AsyncFile *fp;
701 struct AsyncFile **tp; 716 struct AsyncFile **tp;
702 #else 717 #else
703 FILE *fp; 718 FILE *fp;
704 FILE **tp; 719 FILE **tp;
705 #endif 720 #endif
706 int i; 721 int i;
707 int j; 722 int j;
708 char *tmp; 723 char *tmp;
709 char *min; 724 char *min;
710 int count; 725 int count;
711   726  
712 #if defined ___AsyncIO___ 727 #if defined ___AsyncIO___
713 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 728 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
714 #else 729 #else
715 if((fp = fopen(dbFile, "w")) == NULL) { 730 if((fp = fopen(dbFile, "w")) == NULL) {
716 #endif 731 #endif
717 fprintf(stderr, "Unable to open gather database for writing.\n"); 732 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
718 return; 733 return;
719 } 734 }
720   735  
721 // Allocate as many file pointers as temporary files. 736 // Allocate as many file pointers as temporary files.
722 tp = malloc(files * sizeof(*tp)); 737 tp = malloc(files * sizeof(*tp));
723   738  
724 // Open all temporary files for reading. 739 // Open all temporary files for reading.
725 for(i = 0; i < files; ++i) { 740 for(i = 0; i < files; ++i) {
726 #if defined ___AsyncIO___ 741 #if defined ___AsyncIO___
727 if((tp[i] = OpenAsync(tmpNames[i], MODE_READ, ASYNC_BUF)) == NULL) { 742 if((tp[i] = OpenAsync(tmpNames[i], MODE_READ, ASYNC_BUF)) == NULL) {
728 #else 743 #else
729 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) { 744 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) {
730 #endif 745 #endif
731 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]); 746 fprintf(stderr, "Unable to open '%s' for reading.\n", tmpNames[i]);
732 // Close all temporary files. 747 // Close all temporary files.
733 --i; -  
734 while(i >= 0) { 748 while(--i > -1) {
735 #if defined ___AsyncIO___ 749 #if defined ___AsyncIO___
736 CloseAsync(tp[i]); 750 CloseAsync(tp[i]);
737 #else 751 #else
738 fclose(tp[i]); 752 fclose(tp[i]);
739 #endif 753 #endif
740 } 754 }
-   755 #if defined ___AsyncIO___
-   756 CloseAsync(fp);
-   757 #else
-   758 fclose(fp);
-   759 #endif
741 return; 760 return;
742 } 761 }
743 } 762 }
744   763  
745 if(verbose) { 764 if(verbose) {
746 fprintf(stdout, "Merging all database lines in temporary files.\r"); 765 fprintf(stdout, "Merging all files...\r");
747 } 766 }
748   767  
749 count = lines; 768 count = lines;
750 j = 0; 769 j = 0;
751 while(run && --count > -1) { 770 while(run && --count > -1) {
752 #if defined ___AmigaOS___ 771 #if defined ___AmigaOS___
753 // Check if CTRL+C was pressed and abort the program. 772 // Check if CTRL+C was pressed and abort the program.
754 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 773 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
755 run = FALSE; 774 run = FALSE;
756 continue; 775 continue;
757 } 776 }
758 #endif 777 #endif
759 // Find the smallest line in all temporary files. 778 // Find the smallest line in all temporary files.
760 if(verbose) { 779 if(verbose) {
761 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0)); 780 fprintf(stdout, "Merging all files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0));
762 } 781 }
763   782  
764 min = NULL; 783 min = NULL;
765 for(i = 0; i < files; ++i) { 784 for(i = 0; i < files; ++i) {
766 tmp = ReadLine(tp[i]); 785 tmp = ReadLine(tp[i]);
767 if(tmp == NULL) { 786 if(tmp == NULL) {
768 continue; 787 continue;
769 } 788 }
770 if(min == NULL || strncmp(tmp, min, strlen(tmp)) < 0) { 789 if(min == NULL || strncmp(tmp, min, strlen(tmp)) < 0) {
771 if(min != NULL) { 790 if(min != NULL) {
772 // Free previous instance. 791 // Free previous instance.
773 free(min); 792 free(min);
774 } 793 }
775 min = malloc((strlen(tmp) + 1) * sizeof(*min)); 794 min = malloc((strlen(tmp) + 1) * sizeof(*min));
776 sprintf(min, "%s", tmp); 795 sprintf(min, "%s", tmp);
777 // Remember the index of the file where the smallest entry has been found. 796 // Remember the index of the file where the smallest entry has been found.
778 j = i; 797 j = i;
779 free(tmp); 798 free(tmp);
780 continue; 799 continue;
781 } 800 }
782 free(tmp); 801 free(tmp);
783 } 802 }
784   803  
785 // Forward the file where the smallest line was found. 804 // Forward the file where the smallest line was found.
786 SkipLine(tp[j]); 805 SkipLine(tp[j]);
787   806  
788 // Write the smallest line. 807 // Write the smallest line.
789 if(min != NULL) { 808 if(min != NULL) {
790 #if defined ___AsyncIO___ 809 #if defined ___AsyncIO___
791 WriteAsync(fp, min, (LONG)(strlen(min) * sizeof(char))); 810 WriteAsync(fp, min, (LONG)(strlen(min) * sizeof(char)));
792 WriteAsync(fp, "\n", 1 * sizeof(char)); 811 WriteAsync(fp, "\n", 1 * sizeof(char));
793 #else 812 #else
794 fprintf(fp, "%s\n", min); 813 fprintf(fp, "%s\n", min);
795 #endif 814 #endif
796 free(min); 815 free(min);
797 } 816 }
798 } 817 }
799   818  
800 // Write out any remaining contents from the temporary files. 819 // Write out any remaining contents from the temporary files.
801 for(i = 0; i < files; ++i) { 820 for(i = 0; run && i < files; ++i) {
-   821 #if defined ___AmigaOS___
-   822 // Check if CTRL+C was pressed and abort the program.
-   823 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
-   824 run = FALSE;
-   825 continue;
-   826 }
-   827 #endif
802 tmp = ReadLine(tp[i]); 828 tmp = ReadLine(tp[i]);
803 if(tmp == NULL) { 829 if(tmp == NULL) {
804 continue; 830 continue;
805 } 831 }
806 #if defined ___AsyncIO___ 832 #if defined ___AsyncIO___
807 WriteAsync(fp, tmp, (LONG)(strlen(tmp) * sizeof(char))); 833 WriteAsync(fp, tmp, (LONG)(strlen(tmp) * sizeof(char)));
808 WriteAsync(fp, "\n", 1 * sizeof(char)); 834 WriteAsync(fp, "\n", 1 * sizeof(char));
809 #else 835 #else
810 fprintf(fp, "%s\n", tmp); 836 fprintf(fp, "%s\n", tmp);
811 #endif 837 #endif
812 free(tmp); 838 free(tmp);
813 } 839 }
814   840  
815 // Close and delete all temporary files. 841 // Close all temporary files.
816 for(i = 0; i < files; ++i) { 842 for(i = 0; i < files; ++i) {
817 #if defined ___AsyncIO___ 843 #if defined ___AsyncIO___
818 CloseAsync(tp[i]); 844 CloseAsync(tp[i]);
819 #else 845 #else
820 fclose(tp[i]); 846 fclose(tp[i]);
821 #endif 847 #endif
822 // Delete temporary file. -  
823 remove(tmpNames[i]); -  
824 } 848 }
825   849  
826 if(verbose) { 850 if(verbose) {
827 fprintf(stdout, "\n"); 851 fprintf(stdout, "\n");
828 } 852 }
829   853  
830 #if defined ___AsyncIO___ 854 #if defined ___AsyncIO___
831 CloseAsync(fp); 855 CloseAsync(fp);
832 #else 856 #else
833 fclose(fp); 857 fclose(fp);
834 #endif 858 #endif
835 } 859 }
836   860  
837 /* 861 /*
838 * 862 *
-   863 * Deletes temporary files.
-   864 */
-   865 void DeleteTemporaryFiles(char **tmpNames, int tmpFiles) {
-   866 int i = tmpFiles;
-   867  
-   868 if(verbose) {
-   869 fprintf(stdout, "Deleting temporary files...\r");
-   870 }
-   871  
-   872 do {
-   873 remove(tmpNames[i]);
-   874 } while(--i > -1);
-   875  
-   876 if(verbose) {
-   877 fprintf(stdout, "\n");
-   878 }
-   879 }
-   880  
-   881 /*
-   882 *
839 * Indexes a "path" by creating a database "dbFile". 883 * Indexes a "path" by creating a database "dbFile".
840 */ 884 */
841 void Gather(char *dbFile, char *path) { 885 void Gather(char *dbFile, char *path) {
842 stringStack *stack = stringStackCreate(1); 886 stringStack *stack = stringStackCreate(1);
843 stats *stats = malloc(sizeof(stats)); 887 stats *stats = malloc(sizeof(stats));
844 char **tmpNames; 888 char **tmpNames;
845 int dbSize, dbLines, tmpFiles, tmpLines; 889 int dbSize, dbLines, tmpFiles, tmpLines;
846 int i; 890 int i;
847   891  
848 // Initialize metrics. 892 // Initialize metrics.
849 stats->dirs = 0; 893 stats->dirs = 0;
850 stats->files = 0; 894 stats->files = 0;
851   895  
852 // Push the first path onto the stack. 896 // Push the first path onto the stack.
853 stringStackPush(stack, path); 897 stringStackPush(stack, path);
854   898  
855 // Generate the database file. 899 // Generate the database file.
856 UpdateDatabase(dbFile, stack, stats); 900 CollectFiles(dbFile, stack, stats);
857   901  
858 // Get the database metrics. 902 // Get the database metrics.
859 dbSize = GetFileSize(dbFile); 903 dbSize = GetFileSize(dbFile);
860 dbLines = GetFileLines(dbFile); 904 dbLines = CountFileLines(dbFile);
861   905  
862 // Compute the amount of temporary files needed. 906 // Compute the amount of temporary files needed.
863 tmpFiles = dbSize / MAX_MEM; 907 tmpFiles = dbSize / MAX_MEM;
864   908  
865 // In case no temporary files are required, 909 // In case no temporary files are required,
866 // just sort the database and terminate. 910 // just sort the database and terminate.
867 if(tmpFiles <= 1) { 911 if(tmpFiles <= 1) {
868 SortDatabase(dbFile); 912 SortDatabase(dbFile);
869 return; 913 return;
870 } 914 }
871   915  
872 tmpLines = dbLines / tmpFiles; 916 tmpLines = dbLines / tmpFiles;
873   917  
874 // Create temporary files. 918 // Create temporary files.
875 if((tmpNames = CreateTemporaryFiles(tmpFiles)) == NULL) { 919 if((tmpNames = CreateTemporaryFiles(tmpFiles)) == NULL) {
876 fprintf(stderr, "Unable to create temporary files.\n"); 920 fprintf(stderr, "Unable to create temporary files.\n");
877 return; 921 return;
878 } 922 }
879   923  
880 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile". 924 // Write "tmpLines" to temporary files in "tmpNames" from "dbFile".
881 WriteTemporaryFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines); 925 WriteTemporaryFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines);
882   926  
883 // Sort the temporary files. 927 // Sort the temporary files.
884 for(i = 0; i < tmpFiles; ++i) { 928 for(i = 0; run && i < tmpFiles; ++i) {
885 SortDatabase(tmpNames[i]); 929 SortDatabase(tmpNames[i]);
886 } 930 }
-   931  
887   932 // Merge all the temporary files to the database file.
-   933 MergeTemporaryFiles(dbFile, tmpNames, tmpFiles, dbLines);
-   934  
-   935 // Remove all temporary files.
888 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines); 936 DeleteTemporaryFiles(tmpNames, tmpFiles);
889 } 937 }
890   938  
891 void usage(char *name) { 939 void usage(char *name) {
892 fprintf(stdout, "Hunt & Gather - %s, a file index generating tool. \n", name); 940 fprintf(stdout, "Hunt & Gather - %s, a file index generating tool. \n", name);
893 fprintf(stdout, "Version: %s \n", PROGRAM_VERSION); 941 fprintf(stdout, "Version: %s \n", PROGRAM_VERSION);
894 fprintf(stdout, " \n"); 942 fprintf(stdout, " \n");
895 fprintf(stdout, "SYNTAX: %s [-q] DATABASE \n", name); 943 fprintf(stdout, "SYNTAX: %s [-q] DATABASE \n", name);
896 fprintf(stdout, " \n"); 944 fprintf(stdout, " \n");
897 fprintf(stdout, " -q Do not print out any messages. \n"); 945 fprintf(stdout, " -q Do not print out any messages. \n");
898 fprintf(stdout, " \n"); 946 fprintf(stdout, " \n");
899 fprintf(stdout, "DATABASE is a path to where the indexed results will be \n"); 947 fprintf(stdout, "DATABASE is a path to where the indexed results will be \n");
900 fprintf(stdout, "stored for searching with the Hunt tool. \n"); 948 fprintf(stdout, "stored for searching with the Hunt tool. \n");
901 fprintf(stdout, " \n"); 949 fprintf(stdout, " \n");
902 fprintf(stdout, "(c) 2021 Wizardry and Steamworks, MIT. \n"); 950 fprintf(stdout, "(c) 2021 Wizardry and Steamworks, MIT. \n");
903 } 951 }
904   952  
905 /* 953 /*
906 * 954 *
907 * Main entry point. 955 * Main entry point.
908 */ 956 */
909 int main(int argc, char **argv) { 957 int main(int argc, char **argv) {
910 int option; 958 int option;
911 char *dbFile; 959 char *dbFile;
912 char *path; 960 char *path;
913 struct stat dirStat; 961 struct stat dirStat;
914 #if defined ___AmigaOS___ 962 #if defined ___AmigaOS___
915 BPTR lock; 963 BPTR lock;
916 #endif 964 #endif
917   965  
918 // Bind handler to SIGINT. 966 // Bind handler to SIGINT.
919 signal(SIGINT, SignalHandler); 967 signal(SIGINT, SignalHandler);
920   968  
921 dbFile = DEFAULT_DATABASE_FILE; 969 dbFile = DEFAULT_DATABASE_FILE;
922 while((option = getopt(argc, argv, "hqd:")) != -1) { 970 while((option = getopt(argc, argv, "hqd:")) != -1) {
923 switch(option) { 971 switch(option) {
924 case 'd': 972 case 'd':
925 dbFile = optarg; 973 dbFile = optarg;
926 break; 974 break;
927 case 'q': 975 case 'q':
928 verbose = FALSE; 976 verbose = FALSE;
929 break; 977 break;
930 case 'h': 978 case 'h':
931 usage(argv[0]); 979 usage(argv[0]);
932 return 0; 980 return 0;
933 case '?': 981 case '?':
934 fprintf(stderr, "Invalid option %ct.\n", optopt); 982 fprintf(stderr, "Invalid option %ct.\n", optopt);
935 return 1; 983 return 1;
936 } 984 }
937 } 985 }
938   986  
939   987  
940 if(optind >= argc) { 988 if(optind >= argc) {
941 usage(argv[0]); 989 usage(argv[0]);
942 return 1; 990 return 1;
943 } 991 }
944   992  
945 #if defined ___AmigaOS___ 993 #if defined ___AmigaOS___
946 path = malloc(PATH_MAX * sizeof(*path)); 994 path = malloc(PATH_MAX * sizeof(*path));
947 lock = Lock(argv[optind], SHARED_LOCK); 995 lock = Lock(argv[optind], SHARED_LOCK);
948 NameFromLock(lock, path, PATH_MAX); 996 NameFromLock(lock, path, PATH_MAX);
949 UnLock(lock); 997 UnLock(lock);
950 #else 998 #else
951 path = realpath(argv[optind], NULL); 999 path = realpath(argv[optind], NULL);
952 #endif 1000 #endif
953   1001  
954 stat(path, &dirStat); 1002 stat(path, &dirStat);
955 if(!S_ISDIR(dirStat.st_mode)) { 1003 if(!S_ISDIR(dirStat.st_mode)) {
956 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]); 1004 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]);
957 return 1; 1005 return 1;
958 } 1006 }
959   1007  
960 if(verbose) { 1008 if(verbose) {
961 fprintf(stdout, "Gathering to database file: %s\n", dbFile); 1009 fprintf(stdout, "Gathering to %s\n", dbFile);
962 } 1010 }
963   1011  
964 // Gather. 1012 // Gather.
965 Gather(dbFile, path); 1013 Gather(dbFile, path);
966   1014  
967 free(path); 1015 free(path);
968   1016  
969 return 0; 1017 return 0;
970 } 1018 }
971   1019