HuntnGather – Rev 35

Subversion Repositories:
Rev:
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2021 Wizardry and Steamworks - License: MIT          //
///////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined ___AmigaOS___
#include <dirent.h>
#include <sys/stat.h>
#include <signal.h>
#endif

#include <sys/types.h>
#include <sys/syslimits.h>

#if defined ___AmigaOS___
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/locale.h>
#include <clib/utility_protos.h>
#endif

#if defined ___AsyncIO___
#include <asyncio.h>
#endif

#include "/shared/utilities.h"

/*
        *
        * Returns largest of strings.
        */
#if defined ___AmigaOS___
LONG StringLenMax(char *a, char *b) {
        LONG p = strlen(a);
        LONG q = strlen(b);
#else
int StrlenMax(char *a, char *b) {
        int q = strlen(a);
        int p = strien(b);
#endif
        return p > q ? p : q;
}

/*
        *
        * Converts a string to case.
        */
void StrUpr(char *s) {
        while(*s != '\0') {
#if defined ___AmigaOS___
                *s = ToUpper(*s);
#else
                *s = toupper((unsigned char)*s);
#endif
                ++s;
        }
}

/*
        *
        * Gets the filesystem type of a file or directory.
        */
FS_TYPE GetFsType(char *path) {
#if defined ___AmigaOS___
        struct FileInfoBlock *FIB;
        BPTR lock;
#else
        struct stat dirStat;
#endif

#if defined ___AmigaOS___
        if((lock = Lock(path, ACCESS_READ)) == NULL) {
                fprintf(stderr, "Lock failed for path '%s'.\n", path);
                return UNKNOWN;
        }

        if((FIB = AllocDosObject(DOS_FIB, NULL)) == NULL) {
                fprintf(stderr, "Could not allocated file information block for path '%s'.\n", path);
                UnLock(lock);
                return UNKNOWN;
        }

        if(Examine(lock, FIB) == FALSE) {
                fprintf(stderr, "Path '%s' could not be examined.\n", path);
                UnLock(lock);
                FreeDosObject(DOS_FIB, FIB);
                return UNKNOWN;
        }

        if(FIB->fib_DirEntryType < 0) {
                UnLock(lock);
                FreeDosObject(DOS_FIB, FIB);
                return REGULAR;
#else
        stat(path, &dirStat);
        if(!S_ISDIR(dirStat.st_mode)) {
                return REGULAR;
#endif
        }

#if defined ___AmigaOS___
        UnLock(lock);
        FreeDosObject(DOS_FIB, FIB);
#endif

        return DIRECTORY;
}

/*
        *
        * Counts the lines of a file.
        */
int CountFileLines(char *dbFile) {
#if defined ___AsyncIO___
        struct AsyncFile *fp;
        LONG c;
#else
        FILE *fp;
        char c;
#endif
        int lines;

#if defined ___AsyncIO___
        if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
#else
        if((fp = fopen(dbFile, "r")) == NULL) {
#endif
                fprintf(stderr, "Could not open file '%s' for reading.\n", dbFile);
                return -1;
        }

        lines = 0;
        if(PROGRAM_VERBOSE) {
                fprintf(stdout, "Counting lines in '%s'...\r", dbFile);
        }

#if defined ___AsyncIO___
        while(PROGRAM_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) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                switch(c) {
                        case '\n':
                                ++lines;

                                if(PROGRAM_VERBOSE) {
                                        fprintf(stdout, "Counting lines in '%s': %d.\r", dbFile, lines);
                                }
                                break;
                }
        }

#if defined ___AsyncIO___
        CloseAsync(fp);
#else
        fclose(fp);
#endif

        if(PROGRAM_VERBOSE) {
                fprintf(stdout, "\n");
        }

        return lines;
}

/*
        *
        * Gets the absolute path to file by name.
        */
char *PathToAbsolute(char *path) {
        char *abs;
#if defined ___AmigaOS___
        BPTR lock;
#endif

#if defined ___AmigaOS___
        if((abs = malloc(PATH_MAX * sizeof(*abs))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }
        if((lock = Lock(path, SHARED_LOCK)) == 0) {
                fprintf(stderr, "Lock failed for path '%s'.\n", path);
                return NULL;
        }
        if(NameFromLock(lock, abs, PATH_MAX) == FALSE) {
                fprintf(stderr, "Full path for '%s' could not be retrieved.\n", path);
                UnLock(lock);
                return NULL;
        }
        UnLock(lock);
#else
        /*
         * On POSIX this should be:
         * abs = realpath(path, NULL);
         *
         */
        if((abs = malloc((strlen(path) + 1) * sizeof(*abs))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }
        sprintf(abs, "%s", path);
#endif

        return abs;
}

/*
        *
        * Compares path parts for equality.
        */
#if defined ___AmigaOS___
BOOL PathCompare(char *path, char *look) {
#else
int PathCompare(char *path, char *look) {
#endif
        char *a;
        char *b;

        for(a = path, b = look; *a != '\0' && *b != '\0'; ++a, ++b) {
                if(*b != '\0' && *a != *b) {
                        return FALSE;
                }
        }

        return *b == '\0';
}

/*
        *
        * Creates a temporary file and returns its name.
        */
char *CreateTemporaryFile(void) {
        char *name;

        name = tmpnam(NULL);

        return name;
}

/*
        *
        * Create multiple temporary files and return their names.
        */
char **CreateTemporaryFiles(int files) {
        char **tmpNames;
        int count;

        if((tmpNames = malloc(files * sizeof(*tmpNames))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        if(PROGRAM_VERBOSE) {
                fprintf(stdout, "Creating temporary files...\r");
        }

        count = files;
        while(PROGRAM_RUN && --count > -1) {
#if defined ___AmigaOS___
                // Check if CTRL+C was pressed and abort the program.
                if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                tmpNames[count] = CreateTemporaryFile();

                if(PROGRAM_VERBOSE) {
                        fprintf(stdout, "Creating temporary files: %d%%.\r", 100 - (int)(((float)count / files) * 100.0));
                }
        }

        if(PROGRAM_VERBOSE) {
                fprintf(stdout, "\n");
        }

        return tmpNames;
}

/*
        *
        * Skips a line in a file.
        */
#if defined ___AsyncIO___
void SkipLine(struct AsyncFile *fp) {
        LONG c;
        while(PROGRAM_RUN && (c = ReadCharAsync(fp)) != -1) {
#else
void SkipLine(FILE *fp) {
        char c;
        while(PROGRAM_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) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                switch(c) {
                        case '\n':
                                return;
                }
        }
}


/*
        *
        * Peeks at a line from a file.
        */
#if defined ___AsyncIO___
char *PeekLine(struct AsyncFile *fp) {
        LONG c;
#else
char *PeekLine(FILE *fp) {
        char c;
#endif
        char *line = NULL;
        char *real = NULL;
        int size;
        int i;

        size = LINE_BUF;
        if((line = malloc(size * sizeof(*line))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        i = 0;
#if defined ___AsyncIO___
        while(PROGRAM_RUN && (c = ReadCharAsync(fp)) != -1) {
#else
        while(PROGRAM_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) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                switch(c) {
                        case '\n':
                                // Rewind the file by the number of read characters.
#if defined ___AsyncIO___
                                if(SeekAsync(fp, -(i + 1), MODE_CURRENT) == -1) {
                                        fprintf(stderr, "Could not seek in file.\n");
                                        free(line);
                                        return NULL;
                                }
#else
                                if(fseek(fp, -(i + 1), SEEK_CUR) != 0) {
                                        fprintf(stderr, "Could not seek in file.\n");
                                        free(line);
                                        return NULL;
                                }
#endif
                                return line;
                        default:
                                if(strlen(line) == size) {
                                        size = size * 1.5;
                                        real = realloc(line, size * sizeof(*line));
                                        if(real == NULL) {
                                                fprintf(stderr, "Memory reallocation failure.\n");
                                                free(line);
                                                return NULL;
                                        }
                                        line = real;
                                }
                                line[i] = c;
                                line[i + 1] = '\0';
                                break;
                }
                ++i;
        }

        if(line != NULL) {
                free(line);
        }

        return NULL;
}

/*
        *
        * Read a line from a file.
        */
#if defined ___AsyncIO___
char *ReadLine(struct AsyncFile *fp) {
        LONG c;
#else
char *ReadLine(FILE *fp) {
        char c;
#endif
        char *line = NULL;
        char *real = NULL;
        int size;
        int i;

        size = LINE_BUF;
        if((line = malloc(size * sizeof(*line))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        i = 0;
#if defined ___AsyncIO___
        while(PROGRAM_RUN && (c = ReadCharAsync(fp)) != -1) {
#else
        while(PROGRAM_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) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                switch(c) {
                        case '\n':
                                return line;
                        default:
                                if(strlen(line) == size) {
                                        size = size * 1.5;
                                        real = realloc(line, size * sizeof(*line));
                                        if(real == NULL) {
                                                fprintf(stderr, "Memory reallocation failure.\n");
                                                free(line);
                                                return NULL;
                                        }
                                        line = real;
                                }
                                line[i] = c;
                                line[i + 1] = '\0';
                                break;
                }
                ++i;
        }

        if(line != NULL) {
                free(line);
        }

        return NULL;
}

/*
  *
  * Delete a file.
  */
#if defined ___AmigaOS___
BOOL RemoveFile(char *name) {
        return DeleteFile(name);
#else
int RemoveFile(char *name) {
        return remove(name) == 0;
#endif
}


/*
        *
        * Deletes files.
        */
void RemoveFiles(char **names, int count) {
        int i;
        for(i = 0; i < count; ++i) {
                if(RemoveFile(names[i]) == FALSE) {
                        fprintf(stderr, "Could not remove file '%s'.\n", names[i]);
                        continue;
                }
                fprintf(stderr, "Removing file '%s'\n", names[i]);
        }
}

/*
        *
        * Copies a file to another file by name.
        */
void CopyFile(char *a, char *b) {
#if defined ___AsyncIO___
        struct AsyncFile *ap;
        struct AsyncFile *bp;
        LONG c;
#else
        FILE *ap;
        FILE *bp;
        char c;
#endif

        // Open database file for writing.
#if defined ___AsyncIO___
        if((ap = OpenAsync(a, MODE_READ, ASYNC_BUF)) == NULL) {
#else
        if((ap = fopen(a, "r")) == NULL) {
#endif
                fprintf(stderr, "Could not open file '%s' for reading.\n", a);
                return;
        }

        // Open temporary file for reading.
#if defined ___AsyncIO___
        if((bp = OpenAsync(b, MODE_WRITE, ASYNC_BUF)) == NULL) {
#else
        if((bp = fopen(b, "w")) == NULL) {
#endif
                fprintf(stderr, "Could not open file '%s' for writing.\n", b);

                // Close database file.
#if defined ___AsyncIO___
                CloseAsync(ap);
#else
                fclose(ap);
#endif

                return;
        }

#if defined ___AsyncIO___
        while(PROGRAM_RUN && (c = ReadCharAsync(ap)) != -1) {
#else
        while(PROGRAM_RUN && fscanf(ap, "%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) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
#if defined ___AsyncIO___
                if(WriteCharAsync(bp, (UBYTE)c) != 1) {
#else
                if(fprintf(bp, "%c", c) != 1) {
#endif
                        fprintf(stderr, "Could not write to file '%s'.\n", b);
                        break;
                }
        }

#if defined ___AsyncIO___
        CloseAsync(ap);
        CloseAsync(bp);
#else
        fclose(ap);
        fclose(bp);
#endif
}


/*
        *
        * Create a database entry from a line of text.
        */
dbEntry* CreateDatabaseEntry(char *line) {
        dbEntry *entry;
        char *ptr;
        int side;
        int i;
        int j;

        if((entry = malloc(1 * sizeof(*entry))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        if((entry->name = malloc((strlen(line) + 1) * sizeof(*entry->name))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        if((entry->path = malloc((strlen(line) + 1) * sizeof(*entry->path))) == NULL) {
                fprintf(stderr, "Memory allocation failure.\n");
                return NULL;
        }

        for(ptr = line, side = 0, i = 0, j = 0; PROGRAM_RUN && *ptr != '\0'; ++ptr) {
#if defined ___AmigaOS___
                // Check if CTRL+C was pressed and abort the program.
                if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
                        PROGRAM_RUN = FALSE;
                        continue;
                }
#endif
                switch(*ptr) {
                        case '\t':
                                entry->name[i] = '\0';
                                ++side;
                                break;
                        case '\n':
                                entry->path[j] = '\0';
                                return entry;
                        default:
                                switch(side) {
                                        case 0:
                                                entry->name[i++] = *ptr;
                                                break;
                                        case 1:
                                                entry->path[j++] = *ptr;
                                                break;
                                }
                                break;
                }
        }

        return entry;
}