HuntnGather – Rev 24
?pathlinks?
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Wizardry and Steamworks - License: MIT //
///////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <proto/dos.h>
#include <proto/exec.h>
#if defined ___AsyncIO___
#include <asyncio.h>
#endif
#if !defined ___HAVE_GETOPT___
#include "getopt.h"
#endif
#define PROGRAM_VERSION "1.7.3"
#if defined ___AmigaOS___
/*************************************************************************/
/* Version string used for querrying the program version. */
/*************************************************************************/
TEXT version_string[] =
"\0$VER: Hunt " PROGRAM_VERSION " "__DATE__" by Wizardry and Steamworks";
#endif
#if !defined TRUE
#define TRUE 1;
#endif
#if !defined FALSE
#define FALSE 0;
#endif
#define ASYNC_BUF 8192
#define NAME_BUF 32
#define PATH_BUF 128
#define DEFAULT_DATABASE_FILE "S:gather.db"
int run = TRUE;
void SignalHandler(int sig) {
// Toggle the run flag to stop execution.
run = FALSE;
}
/*
* Compare two strings.
*/
int compare(char *a, char *b) {
#if defined ___AmigaOS___
ULONG size;
int success;
UBYTE *pattern;
char *e = a;
char *n = b;
#if defined ___NOCASE_FS___
e = strupr(e);
n = strupr(n);
#endif
// "must be at least 2 times as large plus 2 bytes"
size = strlen(n) * 2 + 2;
success = FALSE;
if(pattern = AllocVec(size, MEMF_ANY|MEMF_CLEAR)) {
switch(ParsePatternNoCase(n, pattern, (LONG)size)) {
case 1: // the pattern contains wildcards
success = MatchPatternNoCase(pattern, e);
break;
case 0: // no wildcards so fall back to exact name match
success = (strstr(e, n) != NULL);
break;
}
FreeVec(pattern);
}
return success;
#else
int success;
char *e = a;
char *n = b;
success = FALSE;
#if defined ___NOCASE_FS___
e = strupr(e);
n = strupr(n);
#endif
success = (strstr(e, n) != NULL);
return success;
#endif
}
/*
*
* Search the database for a matching string.
*/
void SearchDatabase(char *dbFile, char* needle) {
#if defined ___AsyncIO___
struct AsyncFile *fp;
LONG c;
#else
FILE *fp;
char c;
#endif
char *name;
int name_size;
char *path;
int path_size;
int i;
int side;
int match;
int total;
#if defined ___AsyncIO___
if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
#else
if((fp = fopen(dbFile, "r")) == NULL) {
#endif
fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
return;
}
name_size = NAME_BUF;
name = malloc(name_size * sizeof(*name));
path_size = PATH_BUF;
path = malloc(path_size * sizeof(*path));
i = 0;
side = 0;
match = FALSE;
total = 0;
#if defined ___AsyncIO___
while(run && (c = ReadCharAsync(fp)) != -1) {
#else
while(run && fscanf(fp, "%c", &c) == 1) {
#endif
#if defined ___AmigaOS___
// Check if CTRL+C was pressed and abort the program.
if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
run = FALSE;
break;
}
#endif
switch(c) {
case '\n':
++total;
if(match) {
fprintf(stdout, "%s\n", path);
match = FALSE;
}
if(name != NULL) {
free(name);
name_size = NAME_BUF;
name = malloc(name_size * sizeof(*name));
}
--side;
i = 0;
break;
case '\t':
// Case insensitive match.
if(compare(name, needle)) {
match = TRUE;
}
if(path != NULL) {
free(path);
path_size = PATH_BUF;
path = malloc(path_size * sizeof(*name));
}
++side;
i = 0;
break;
default:
switch(side) {
case 0:
if(strlen(name) == name_size) {
name_size = 1.5 * name_size;
name = realloc(name, name_size * sizeof(*name));
}
//name = realloc(name, (i + 1 + 1) * sizeof(*name));
name[i] = c;
name[i + 1] = '\0';
break;
case 1:
if(strlen(path) == path_size) {
path_size = 1.5 * path_size;
path = realloc(path, path_size * sizeof(*path));
}
//path = realloc(path, (i + 1 + 1) * sizeof(*path));
path[i] = c;
path[i + 1] = '\0';
break;
default:
fprintf(stderr, "Database corrupted.\n");
break;
}
++i;
break;
}
}
free(name);
free(path);
#if defined ___AsyncIO___
CloseAsync(fp);
#else
fclose(fp);
#endif
}
/*
*
* Search the database for the matching string.
*/
void Hunt(char *dbFile, char *needle) {
// Search the database for the matching string.
SearchDatabase(dbFile, needle);
}
void usage(char *name) {
fprintf(stdout, "Hunt & Gather - %s, a file index search tool. \n", name);
fprintf(stdout, "Version: %s \n", PROGRAM_VERSION);
fprintf(stdout, " \n");
fprintf(stdout, "SYNTAX: %s [-d DATABASE] PATTERN \n", name);
fprintf(stdout, " \n");
fprintf(stdout, " -d DATABASE A path to a database generated by the \n");
fprintf(stdout, " Gather tool that should be searched. \n");
fprintf(stdout, " \n");
fprintf(stdout, "PATTERN is an AmigaOS DOS pattern to match file names. \n");
fprintf(stdout, " \n");
fprintf(stdout, "(c) 2021 Wizardry and Steamworks, MIT. \n");
}
int main(int argc, char **argv) {
int option;
char *dbFile;
struct stat path;
// Bind handler to SIGINT.
signal(SIGINT, SignalHandler);
dbFile = DEFAULT_DATABASE_FILE;
while((option = getopt(argc, argv, "hd:")) != -1) {
switch(option) {
case 'd':
dbFile = optarg;
break;
case 'h':
usage(argv[0]);
return 0;
case '?':
fprintf(stderr, "Invalid option %c.\n", optopt);;
return 1;
}
}
if(optind >= argc) {
usage(argv[0]);
return 1;
}
stat(dbFile, &path);
if(!S_ISREG(path.st_mode)) {
fprintf(stderr, "Database file '%s' is not a file.\n", dbFile);
return 1;
}
Hunt(dbFile, argv[optind]);
return 0;
}