/* emtexdir.c -- written by Eberhard Mattes, donated to the public domain */ #if defined (__EMX__) #include #else #include "emdir.h" #endif #if defined(DJGPP) || defined(GO32) #include #endif #include #include #include #include #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 int main (int argc, char *argv[]) { struct emtex_dir ed; int i; unsigned flags1, flags2; char path[260]; if (argc != 6) { puts ("Usage: emtexdir "); 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