#if defined (__EMX__)
#include <emx/syscalls.h>
#else
#include "emdir.h"
#endif
#if defined(DJGPP) || defined(GO32)
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include "emtexdir.h"
#define FALSE 0
#define TRUE 1
void (*emtex_dir_find_callback)(const char *name, int ok) = NULL;
static int setup_add (struct emtex_dir *dst, const char *path)
{
char *p;
if (dst->used >= dst->alloc)
{
dst->alloc += 8;
dst->list = realloc (dst->list, dst->alloc * sizeof (*dst->list));
if (dst->list == NULL)
return (FALSE);
}
p = strdup (path);
if (p == NULL)
return (FALSE);
dst->list[dst->used++] = p;
return (TRUE);
}
static int setup_subdir (struct emtex_dir *dst, char *path, size_t add,
unsigned flags, int recurse)
{
int ok, i, end, len;
#if defined (__EMX__)
struct _find find;
#else
struct ll_findbuffer find;
#endif
i = dst->used;
strcpy (path + add, "*.*");
#if defined (__EMX__)
ok = __findfirst (path, 0x10, &find) == 0;
#else
ok = ll_findfirst (path, 0x10, &find);
#endif
while (ok)
{
if ((find.attr & 0x10)
&& !(strcmp (find.name, ".") == 0 || strcmp (find.name, "..") == 0))
{
len = strlen (find.name);
memcpy (path + add, find.name, len);
path[add+len] = '\\';
path[add+len+1] = 0;
if (!setup_add (dst, path))
return (FALSE);
}
#if defined (__EMX__)
ok = __findnext (&find) == 0;
#else
ok = ll_findnext (&find);
#endif
}
if (recurse)
{
end = dst->used;
while (i < end)
{
strcpy (path, dst->list[i]);
if (!setup_subdir (dst, path, strlen (path), flags, TRUE))
return (FALSE);
++i;
}
}
return (TRUE);
}
static int setup_dir (struct emtex_dir *dst, char *path,
const char *base_dir, size_t base_dir_len,
const char *sub_dir,
unsigned flags)
{
size_t i, len;
memcpy (path, base_dir, base_dir_len);
i = base_dir_len;
if ((flags & EDS_BANG) && sub_dir == NULL)
{
flags &= ~(EDS_ONESUBDIR|EDS_ALLSUBDIR);
if (i >= 2 && path[i-1] == '!' && path[i-2] == '!')
{
flags |= EDS_ALLSUBDIR;
i -= 2;
}
else if (i >= 1 && path[i-1] == '!')
{
flags |= EDS_ONESUBDIR;
--i;
}
}
if (sub_dir != NULL && *sub_dir != 0)
{
if (i != 0 && path[i-1] != ':' && path[i-1] != '/' && path[i-1] != '\\')
path[i++] = '\\';
len = strlen (sub_dir);
memcpy (path+i, sub_dir, len);
i += len;
}
if (path[i-1] != ':' && path[i-1] != '/' && path[i-1] != '\\')
path[i++] = '\\';
path[i] = 0;
if (!setup_add (dst, path))
return (FALSE);
if (flags & EDS_ALLSUBDIR)
return (setup_subdir (dst, path, i, flags, TRUE));
else if (flags & EDS_ONESUBDIR)
return (setup_subdir (dst, path, i, flags, FALSE));
else
return (TRUE);
}
int setup_list (struct emtex_dir *dst, char *path,
const char *list, unsigned flags)
{
const char *end;
size_t i;
for (;;)
{
while (*list == ' ' || *list == '\t')
++list;
if (*list == 0)
return (TRUE);
end = list;
while (*end != 0 && *end != ';')
++end;
i = end - list;
while (i > 0 && (list[i-1] == ' ' || list[i-1] == '\t'))
--i;
if (i != 0 && !setup_dir (dst, path, list, i, NULL, flags))
return (FALSE);
if (*end == 0)
return (TRUE);
list = end + 1;
}
}
int emtex_dir_setup (struct emtex_dir *ed, const char *env, const char *dir,
unsigned flags)
{
const char *val;
char path[260];
ed->alloc = 0;
ed->used = 0;
ed->list = NULL;
if (env != NULL && (val = getenv (env)) != NULL)
return (setup_list (ed, path, val, flags));
else if ((val = getenv ("EMTEXDIR")) != NULL)
return (setup_dir (ed, path, val, strlen (val), dir, flags));
else
return (setup_dir (ed, path, "\\emtex", 6, dir, flags));
}
static void pretty (char *path, unsigned flags)
{
char *p;
if (flags & EDF_FSLASH)
for (p = path; *p != 0; ++p)
if (*p == '\\')
*p = '/';
}
#define ADDCHAR(C) \
if (dst_size < 1) return (EDT_TOOLONG); \
*dst++ = (C); --dst_size
int emtex_dir_trunc (char *dst, size_t dst_size, const char *src,
unsigned flags, int method)
{
int len, truncated, dot;
if (src[0] != 0 && src[1] == ':')
{
ADDCHAR (src[0]);
ADDCHAR (src[1]);
src += 2;
}
truncated = FALSE; dot = FALSE; len = 0;
for (;;)
{
switch (*src)
{
case 0:
ADDCHAR (0);
return (truncated ? EDT_CHANGED : EDT_UNCHANGED);
case ':':
return (EDT_INVALID);
case '/':
case '\\':
ADDCHAR (*src);
len = 0; dot = FALSE;
break;
case '.':
if (dot)
return (EDT_INVALID);
ADDCHAR (*src);
if (!(len == 0 && src[1] == '.'
&& (src[2] == 0 || src[2] == '/' || src[2] == '\\')))
{
len = 0; dot = TRUE;
}
break;
default:
if (dot && len == 3)
truncated = TRUE;
else if (!dot && len == 8)
{
truncated = TRUE;
if (method == 0)
{
dst[-3] = dst[-2];
dst[-2] = dst[-1];
dst[-1] = *src;
}
}
else
{
ADDCHAR (*src);
++len;
}
break;
}
++src;
}
}
static int find2 (const char *name, unsigned flags)
{
int ok;
ok = (access (name, 4) == 0);
if (flags & EDF_TRACE)
emtex_dir_find_callback (name, ok);
return (ok);
}
static int find1 (char *path, size_t path_size, const char *dir,
const char *fname, unsigned flags)
{
char buf[260];
int method, rc;
size_t len, tmp;
len = 0;
if (dir != NULL)
{
tmp = strlen (dir);
if (tmp >= sizeof (buf))
return (FALSE);
memcpy (buf, dir, tmp);
len = tmp;
}
tmp = strlen (fname);
if (len + tmp >= sizeof (buf))
return (FALSE);
memcpy (buf + len, fname, tmp + 1);
len += tmp;
#if 0
if (_osmode == DOS_MODE)
{
rc = emtex_dir_trunc (path, path_size, buf, flags, EDT_5_PLUS_3);
if ((rc == EDT_UNCHANGED || rc == EDT_CHANGED) && find2 (path, flags))
{
pretty (path, flags);
return (TRUE);
}
rc = emtex_dir_trunc (path, path_size, buf, flags, EDT_8);
if (rc == EDT_CHANGED && find2 (path, flags))
{
pretty (path, flags);
return (TRUE);
}
return (FALSE);
}
else
#endif
{
if (len < path_size && find2 (buf, flags))
{
memcpy (path, buf, len + 1);
pretty (path, flags);
return (TRUE);
}
for (method = 0; method < 2; ++method)
{
rc = emtex_dir_trunc (path, path_size, buf, flags, method);
if (rc == EDT_CHANGED && find2 (path, flags))
{
pretty (path, flags);
return (TRUE);
}
}
return (FALSE);
}
}
int emtex_dir_find (char *path, size_t path_size,
const struct emtex_dir *ed,
const char *fname, unsigned flags)
{
int i, absp;
const char *p;
absp = FALSE;
for (p = fname; *p != 0; ++p)
if (*p == ':' || *p == '/' || *p == '\\')
{
absp = TRUE;
break;
}
if (absp)
return (find1 (path, path_size, NULL, fname, flags));
if ((flags & EDF_CWD) && find1 (path, path_size, NULL, fname, flags))
return (TRUE);
for (i = 0; i < ed->used; ++i)
if (find1 (path, path_size, ed->list[i], fname, flags))
return (TRUE);
return (FALSE);
}
#if defined (TEST)
#include <stdio.h>
int main (int argc, char *argv[])
{
struct emtex_dir ed;
int i;
unsigned flags1, flags2;
char path[260];
if (argc != 6)
{
puts ("Usage: emtexdir <flags> <flags> <env> <dir> <fname>");
return (1);
}
flags1 = (unsigned)strtol (argv[1], NULL, 0);
flags2 = (unsigned)strtol (argv[2], NULL, 0);
if (!emtex_dir_setup (&ed, argv[3], argv[4], flags1))
{
fputs ("emtex_dir_setup failed\n", stderr);
return (2);
}
printf ("Directories:\n");
for (i = 0; i < ed.used; ++i)
printf (" %s\n", ed.list[i]);
if (!emtex_dir_find (path, sizeof (path), &ed, argv[5], flags2))
puts ("File not found");
else
printf ("Path: %s\n", path);
return (0);
}
#endif