/*
** dirlist.d (C) Helmut Leitner 2003
** first D program, don't rely on it
** will become a module under FDL when ready
*/

import string;
import c.stdio;
import pavel.windows;

const int DFF_FILES = 1;
const int DFF_DIRS = 2;
const int DFF_RECURSE = 4;

alias WIN32_FIND_DATA FILEINFO;

int FileInfoRetDirFlag(FILEINFO *fb)
{
    int flag = 0;

    if(fb.cFileName[0] != '.' && (fb.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) == 0) {
        if(fb.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            flag = 1;
        }
    }
    return flag;
}

int FileInfoRetFileFlag(FILEINFO *fb)
{
    int flag = 0;

    if(fb.cFileName[0] != '.' && (fb.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) == 0) {
        if((fb.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0) {
            flag = 1;
        }
    }
    return flag;
}

int FileExtCmp(char *s1,char *s2)
{
    while(*s1 && *s2) {
        if(*s1 == '*' || *s2 == '*') {
            return 0;
        }
        if(*s1 != *s2 && *s1 != '?' && *s2 != '?') {
            return -1;
        }
        s1++; s2++;
    }
    if(*s1 == '*' || *s2 == '*') {
        return 0;
    }
    if(*s1 == *s2) {
        return 0;
    }
    return -1;
}

int FileNameCmp(char [] fnam1,char [] fnam2)
{
    char [][] a1 = split(toupper(fnam1),'.');
    char [][] a2 = split(toupper(fnam2),'.');

    if(a1.length < 2) {
        a1 ~= '';
    }
    if(a2.length < 2) {
        a2 ~= '';
    }

    if(FileExtCmp(a1[0],a2[0])) {
        return -1;
    }
    if(FileExtCmp(a1[1],a2[1])) {
        return -1;
    }

    return 0;
}

int DirFindFileCall(char [] dir, char [] fspec,int delegate (char [] d,char [] fn,WIN32_FIND_DATA *b) f, int flags)
{
    WIN32_FIND_DATA b;
    BOOL done = false;
    int err = 0;
    char [] fnam2;
    char [] dir2;

    HANDLE hd=FindFirstFileA(dir ~ "*.*", &b);
    while((hd != INVALID_HANDLE_VALUE) && (done == false))
    {
        fnam2 = toString(b.cFileName); // !!! has me bitten
        //printf("%.*s\n",fnam2);
        if(FileInfoRetFileFlag(&b)) {
            if(flags & DFF_FILES) {
                if(FileNameCmp(fnam2,fspec) == 0) {
                    if(f(dir,fnam2,&b)) {
                        goto do_exit;
                    }
                }
            }
        }
        if(FileInfoRetDirFlag(&b)) {
            if(flags & DFF_DIRS) {
                if(f(dir,fnam2,&b)) {
                    err = -1;
                    goto do_exit;
                }
            }
            if(flags & DFF_RECURSE) {
                dir2 = dir ~ fnam2 ~ '\';
                if(DirFindFileCall(dir2,fspec,f,flags)) {
                    goto do_exit;
                }
            }
        }
        done = (FindNextFileA(hd,&b) == FALSE);
    }
do_exit:
    if(hd) {
        FindClose(hd);
    }
    return err;
}

char [][] DirFindFile(char [] dir,char [] fspec, int flags)
{
    char [][] files;

    DirFindFileCall(dir,fspec,
        delegate int (char [] dir, char [] fnam, WIN32_FIND_DATA *b)
        {
            files ~= (dir ~ fnam);
            return 0;
        }
        ,flags
    );
    return files;
}

int main (char [][] args)
{
    char [][] paths;

    printf("Files via DirFindFileCall:\n");
    DirFindFileCall('c:\d\','*.d',
        delegate int (char [] dir, char [] fnam, WIN32_FIND_DATA *b)
        {
            printf("%.*s%.*s\n",dir,fnam); return 0;
        }
        ,DFF_FILES|DFF_RECURSE
    );
    printf("\n");

    printf("Files via DirFindFile:\n");
    paths = DirFindFile('c:\d\','*.d',DFF_FILES|DFF_RECURSE);
    for(int i = 0; i<paths.length; i++) {
        printf("File[%d] via DFF: %.*s\n",i,paths[i]);
    }
    printf("\n");

    printf("Directories via DirFindFile:\n");
    paths = DirFindFile('c:\d\','*.*',DFF_DIRS|DFF_RECURSE);
    for(int i = 0; i<paths.length; i++) {
        printf("Dir[%d] via DFF: %.*s\n",i,paths[i]);
    }
    return 0;
}
