// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
// by Jonathon Fowler (jf@jonof.id.au)

#include "compat.h"
#include "kplib.h"

// Glibc doesn't provide this function, so for the sake of less ugliess
// for all platforms, here's a replacement just for this program.
static void jstrupr(char *s) { while (*s) { *s = Btoupper(*s); s++; } }

#define MAXFILES 4096

static char buf[65536];        // These limits should be abolished one day

static int numfiles;
static char filespec[MAXFILES][128], filelist[MAXFILES][16];
static int fileleng[MAXFILES];


static char const * matchstr = "*.*";
int checkmatch(const struct Bdirent *a)
{
    if (a->mode & BS_IFDIR) return 0;    // is a directory
    if (a->namlen > 12) return 0;    // name too long
    return Bwildmatch(a->name, matchstr);
}

int filesize(const char *path, const char *name)
{
    char p[BMAX_PATH];
    struct stat st;

    strcpy(p, path);
    strcat(p, "/");
    strcat(p, name);

    if (!stat(p, &st)) return st.st_size;
    return 0;
}

void findfiles(const char *dafilespec)
{
    struct Bdirent *name;
    int daspeclen;
    char daspec[128];
    char const * dir;
    BDIR *di;

    strcpy(daspec,dafilespec);
    daspeclen=strlen(daspec);
    while ((daspec[daspeclen] != '\\') && (daspec[daspeclen] != '/') && (daspeclen > 0)) daspeclen--;
    if (daspeclen > 0) {
        daspec[daspeclen]=0;
        dir = daspec;
        matchstr = &daspec[daspeclen+1];
    } else {
        dir = ".";
        matchstr = daspec;
    }

    di = Bopendir(dir);
    if (!di) return;

    while ((name = Breaddir(di))) {
        if (!checkmatch(name)) continue;

        strcpy(&filelist[numfiles][0],name->name);
        jstrupr(&filelist[numfiles][0]);
        fileleng[numfiles] = name->size;
        filelist[numfiles][12] = (char)(fileleng[numfiles]&255);
        filelist[numfiles][13] = (char)((fileleng[numfiles]>>8)&255);
        filelist[numfiles][14] = (char)((fileleng[numfiles]>>16)&255);
        filelist[numfiles][15] = (char)((fileleng[numfiles]>>24)&255);

        strcpy(filespec[numfiles],dir);
        strcat(filespec[numfiles], "/");
        strcat(filespec[numfiles],name->name);

        numfiles++;
        if (numfiles > MAXFILES)
        {
            Bprintf("FATAL ERROR: TOO MANY FILES SELECTED! (MAX is 4096)\n");
            exit(0);
        }
    }

    Bclosedir(di);
}

int main(int argc, char **argv)
{
    int i, j, k, l, fil, fil2;

    if (argc < 3)
    {
        Bprintf("KGROUP <grouped file><@file or filespec...>               by Kenneth Silverman\n");
        Bprintf("   This program collects many files into 1 big uncompressed file called a\n");
        Bprintf("   group file\n");
        Bprintf("   Ex: kgroup stuff.dat *.art *.map *.k?? palette.dat tables.dat\n");
        Bprintf("      (stuff.dat is the group file, the rest are the files to add)\n");
        exit(0);
    }

    engineCreateAllocator();

    numfiles = 0;
    for(i=argc-1;i>1;i--)
    {
        if (argv[i][0] == '@')
        {
            if ((fil = Bopen(&argv[i][1],BO_BINARY|BO_RDONLY,BS_IREAD)) != -1)
            {
                l = Bread(fil,buf,65536);
                j = 0;
                while ((j < l) && (buf[j] <= 32)) j++;
                while (j < l)
                {
                    k = j;
                    while ((k < l) && (buf[k] > 32)) k++;

                    buf[k] = 0;
                    findfiles(&buf[j]);
                    j = k+1;

                    while ((j < l) && (buf[j] <= 32)) j++;
                }
                Bclose(fil);
            }
        }
        else
            findfiles(argv[i]);
    }

    if ((fil = Bopen(argv[1],BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1)
    {
        Bprintf("Error: %s could not be opened\n",argv[1]);
        exit(0);
    }
    Bwrite(fil,"KenSilverman",12);
    Bwrite(fil,&numfiles,4);
    Bwrite(fil,filelist,numfiles<<4);

    for(i=0;i<numfiles;i++)
    {
        Bprintf("Adding %s...\n",filespec[i]);
        if ((fil2 = Bopen(filespec[i],BO_BINARY|BO_RDONLY,BS_IREAD)) == -1)
        {
            Bprintf("Error: %s not found\n",filespec[i]);
            Bclose(fil);
            return(0);
        }
        for(j=0;j<fileleng[i];j+=65536)
        {
            k = min(fileleng[i]-j,65536);
            Bread(fil2,buf,k);
            if (Bwrite(fil,buf,k) < k)
            {
                Bclose(fil2);
                Bclose(fil);
                Bprintf("OUT OF HD SPACE!\n");
                return(0);
            }
        }
        Bclose(fil2);
    }
    Bclose(fil);
    Bprintf("Saved to %s.\n",argv[1]);

    return 0;
}

