406 lines
8.1 KiB
C
406 lines
8.1 KiB
C
/* emtexdir.c -- written by Eberhard Mattes, donated to the public domain */
|
|
|
|
#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);
|
|
}
|
|
|
|
|
|
/*static */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);
|
|
|
|
/* ".." is allowed -- don't return EDT_INVALID for the next
|
|
dot. */
|
|
|
|
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 /* wkim */
|
|
/* disabled for Win95's long file name support */
|
|
/* -- Wonkoo Kim (wkim+@pitt.edu), May 18, 1997 */
|
|
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 /* wkim */
|
|
{
|
|
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
|