/*
 * expansion of lharc's filename handling
 * Robert Stabl April 1990
 * 
 * see copyright notice below
 *
 * Wild card expansion
 *
 * $Id: wild.c,v 1.3 1991/06/05 13:55:14 bammi Exp $
 *
 * $Log: wild.c,v $
 * Revision 1.3  1991/06/05  13:55:14  bammi
 * minor patches
 *
 * Revision 1.2  1990/12/16  14:02:16  bammi
 * cleanup
 *
 * Revision 1.1  90/08/30  16:52:57  bammi
 * after asm
 * 
 * Revision 1.4  89/02/20  20:03:40  dclemans
 * Add RCS identifiers
 * 
 */
#include <stdio.h>
#ifdef atarist
#include <stdlib.h>
#endif
#include <sys/types.h>
#ifndef USG
#include <sys/dir.h>
#else
#include <dirent.h>
#endif  /* USG */

#define ESCAPE_CHAR	'\\'
#define DIR_SEPARATOR	'/'
#define WILDCARDS       "*?["

#define new_string(a)	(char *)malloc((size_t)(a))

/**** Start of "glob" package ****/
/* This software is copyright (c) 1986 by Stichting Mathematisch Centrum.
 * You may use, modify and copy it, provided this notice is present in all
 * copies, modified or unmodified, and provided you don't make money for it.
 *
 * Written 86-jun-28 by Guido van Rossum, CWI, Amsterdam <guido@mcvax.uucp>
 * Stripped down for local use, more portability by Dave Clemans
 */

/* Pattern matching function for filenames */
/* Each occurrence of the * pattern causes a recursion level */

#define EOS '\0'

#define BOOL int
#define NO 0
#define YES 1

#define M_ALL '\001'        /* * */
#define M_ONE '\002'        /* ? */
#define M_SET '\003'        /* [ */
#define M_CMP '\004'        /* ^ */
#define M_RNG '\005'        /* - */
#define M_END '\006'        /* ] */

static BOOL match(name, pat)
    char *name;
    char *pat;
{
    register char c, k;
    BOOL ok,cmp;

    for (c = *pat++; c != EOS; c = *pat++) {
        switch (c) {

        case M_ONE:
            if (*name++ == EOS)
                return NO;
            break;

        case M_ALL:
            if (*pat == EOS)
                return YES;
            for (; *name != EOS; ++name) {
                if (match(name, pat))
                    return YES;
            }
            return NO;

        case M_SET:
            cmp= NO;
            ok= NO;
            k= *name++;
            while ((c= *pat++) != M_END) {
                if (c == M_CMP)
                    cmp= YES;
                else if (*pat == M_RNG) {
                    if (c <= k && k <= pat[1])
                        ok= YES;
                    pat += 2;
                }
                else if (c == k)
                    ok= YES;
            }
            if (!cmp && !ok)
                return NO;
            if (cmp && ok)
                return NO;
            break;

        default:
            if (*name++ != c)
                return NO;
            break;

        }
    }
    return *name == EOS;
}
/**** End of "glob" package ****/

char *wild_compile(pattern,upcase)
char *pattern;
int upcase;
{
    register char *compiled;
    register char *in,*out;

    compiled = (char *)malloc((size_t)(strlen(pattern)+1));
    if (compiled == (char *)NULL)
    {   /* enough memory? */
        fprintf(stderr,"Not enough memory\n");
        return (char *)NULL;
    }
    out = compiled;
    for (in = pattern; *in; in++)
    {   /* copy, "compiling" the pattern */
        switch (*in)
        {   /* a "special" character? */
            case '\'':
                in++;
                while (*in && *in != '\'')
                    *out++ = *in++;
                if (*in != '\'')
                    break;
                break;
            case '"':
                in++;
                while (*in && *in != '"')
                {   /* scan the string */
                    if (*in == ESCAPE_CHAR)
                    {   /* embedded escape char? */
                        in++;
                        if (*in == '\0')
                            break;
                    }
                    *out++ = *in++;
                }
                if (*in != '"')
                    break;
                break;
            case ESCAPE_CHAR:
                in++;
                if (*in == '\0')
                    break;
                *out++ = *in;
                break;
            case '*':
                *out++ = M_ALL;
                break;
            case '?':
                *out++ = M_ONE;
                break;
            case '[':
                *out++ = M_SET;
                in++;
                while (*in && *in != ']')
                {   /* scan the set */
                    if (*in == '-' &&
                       (in[-1] == '[' || (in[-1] == '^' && in[-2] == '[')))
                        *out++ = '-';
                    else if (*in == '-')
                        *out++ = M_RNG;
                    else if (*in == '^' && in[-1] == '[')
                        *out++ = M_CMP;
                    else if (*in == '^')
                        *out++ = '^';
                    else if (*in == ESCAPE_CHAR && in[1] != '\0')
                        *out++ = *++in;
                    else if (*in == ESCAPE_CHAR)
                        *out++ = ESCAPE_CHAR;
                    else *out++ = *in;
                    in++;
                }
                if (*in != ']')
                {   /* if error found */
                    fprintf(stderr,"incomplete character class: missing ']'\n");
                    free(compiled);
                    return (char *)NULL;
                }
                *out++ = M_END;
                break;
            default:
                *out++ = *in;
                break;
        }
        if (*in == '\0')
            break;
    }
#ifdef  GEMDOS
    *out = '\0';
    for (out = compiled; *out; out++)
    {   /* fixups for mono-case matching */
        if (!upcase)
            continue;
        if (islower(*out))
            *out = _toupper(*out);
    }
#endif  /* GEMDOS */
    *out = '\0';

    /* finally done, return compiled string */
    return compiled;
}   /* end of wild_compile */

int wild_match(string,pattern)
char *string;
char *pattern;
{
    register char *compiled;
    int rc;

    if (string == NULL || pattern == NULL)
     {
      return 0;
     }
    compiled = wild_compile(pattern,0);
    if (compiled == (char *)NULL)
    {   /* any errors? message already printed */
        return 0;
    }
    rc = match(string,compiled);
    free(compiled);
    return rc;
}   /* end of wild_match */

#ifdef TEST
int main(void)
{
 char string[100];
 char pattern[100];
 
 printf("pattern> "); fflush(stdout); gets(pattern);
 printf("string> "); fflush(stdout); gets(string);

 printf("wild_match(%s, %s) = %d\n",string, pattern, wild_match(string, pattern));
 return(0);
} 
#endif
