/* Copyright 1993, 1994, 1995, 1997 J"orn Rennecke */ #include "common.h" #include "interpret.h" #include "exec.h" #include "object.h" #include "uid.h" #include "stdio.h" #include <sys/stat.h> #if defined(DIRENT) || defined(_POSIX_VERSION) #include <dirent.h> #define generic_dirent dirent #define DIRENT_NLENGTH(dirent) (strlen((dirent)->d_name)) #else /* not (DIRENT or _POSIX_VERSION) */ #define generic_dirent direct #define DIRENT_NLENGTH(dirent) ((dirent)->d_namlen) #ifdef SYSNDIR #include <sys/ndir.h> #endif /* SYSNDIR */ #ifdef SYSDIR #include <sys/dir.h> #endif /* SYSDIR */ #ifdef NDIR #include <ndir.h> #endif /* NDIR */ #endif /* not (DIRENT or _POSIX_VERSION) */ extern char *mudlib; int legal_path(char *path, mp_int len) { for(;(len -= 2) >= 0;) { if (path[len] == '.') if (path[len+1] == '.' || (len && path[len-1] == '.')) return 0; } return *path - '/'; } int match_string(char *match, mp_int matchlen, char *str, mp_int len) { for (;; match++, matchlen--, str++) { if (!matchlen) return !len; switch(*match) { case '\\': match++; if (!--matchlen) return 0; default: if (--len >= 0 && *match == *str) continue; return 0; case '*': { char *str2; mp_int patlen; char c; for (;;) { if (!--matchlen) return len >= 0; switch (*++match) { case '?': --len; str++; case '*': continue; case '\\': match++; if (!--matchlen) return 0; default: break; } break; } if (len <= 0) return 0; c = match[matchlen]; match[matchlen] = 0; str2 = strpbrk(match + 1, "?*\\"); match[matchlen] = c; if (!str2) { if (matchlen > len) return 0; return strncmp(match, str + len - matchlen, matchlen) == 0; } patlen = str2 - match; matchlen -= patlen; /* patlen >= 1 */ if ((len -= patlen) >= 0) do { if ( !(str2 = memmem(match, patlen, str, len + patlen)) ) return 0; len -= str2 - str; if (match_string(match + patlen, matchlen, str2 + patlen, len)) return 1; str = str2 + 1; } while (--len >= 0); return 0; } case '?': if (--len < 0) return 0; continue; } } } static int alphacmp(const void *file0, const void *file1) { return sv_strcmp(*(svalue *)file0, *(svalue *)file1); } /* 0x0001: include name 0x0002: include size 0x0004: include mtime 0x0008: include atime 0x0020: don't sort 0x0040: fold in alist fashion (not implemented) 0x0080: fold in mapping fashion (not implemented) */ svalue *f_get_dir(svalue *sp, struct frame *fp) { svalue dir, mask_sv, match_sv; struct counted_string path, match; int mask, nqueries, nfiles; DIR *dirp; struct generic_dirent *de; svalue names, a, *svp; mask_sv = sp[-1]; if (!SV_IS_NUMBER (mask_sv)) { bad_efun_arg(1); return sp; } match_sv = sp[0]; if (SV_IS_NUMBER(match_sv) ? match_sv.i : ! SV_IS_STRING(match_sv)) { bad_efun_arg(2); return sp; } if (! SV_IS_NUMBER(match_sv)) { match_sv = COPY_SVALUE(match_sv); match = sv_string2(match_sv); } inter_sp = sp; inter_fp = fp; dir = call_hook(driver_hook[H_VALID_GET_DIR], fp->object, 3); sp -= 2; if (SV_IS_NUMBER(dir) || !SV_IS_STRING(dir)) { *sp = dir; return sp; } path = sv_string2(dir); while (path.len && path.start[0] == '/') { path.len--; path.start++; } if (path.len && ! legal_path (path.start, path.len)) { *sp = dir; return sp; } mask = mask_sv.i; nqueries = (mask>>1 &1) + (mask>>2 &1) + (mask>>3 &1) + (mask>>4 &1); if (path.len) { char c = path.start[path.len]; int res; path.start[path.len] = '\0'; res = chdir(path.start); path.start[path.len] = c; if (res) { sp->i = 0; return sp; } } dirp = opendir("."); for (names = SV_NULL, nfiles = 0; de = readdir(dirp); ) { char *name = de->d_name; mp_int len = DIRENT_NLENGTH(de); svalue str; if (match_sv.p) { if (!match_string(match.start, match.len, name, len)) continue; } else { /* skip '.' and '..' */ if (len <= 2 && name[0] == '.' && (len == 1 || name[1] == '.' ) ) continue; } nfiles++; str = make_string(name, len); SV_GENERIC_ISTRING(str) = names; names = str; } a = allocate_array(nfiles * nqueries, SV_OBJECT(fp->object).x.uid->self); if (a.p) { svp = &SV_ARRAY(a).member[0]; while (names.p) { svalue str = names; struct stat st; names = SV_GENERIC_ISTRING(names); if (mask & (1 << 1)) { *svp++ = str; } else { FREE_ALLOCED_SVALUE(str); } if (mask & ((2|4|8) << 1)) { struct counted_string name = sv_string2(str); char c = name.start[name.len]; int res; name.start[name.len] = 0; res = stat(name.start, &st); name.start[name.len] = c; if (res) { /* File might have been deleted in the meantime. */ st.st_size = -1; st.st_mtime = 0; } else if (S_IFDIR & st.st_mode) { st.st_size = -2; } } if (mask & (2 << 1)) *svp++ = st.st_size << 1; if (mask & (4 << 1)) *svp++ = st.st_mtime << 1; if (mask & (8 << 1)) *svp++ = st.st_atime << 1; } chdir(mudlib); FREE_SVALUE(match_sv); FREE_ALLOCED_SVALUE(dir); if (! inter_errno && ((mask >> 1) & 0x21) == 1) qsort(&SV_ARRAY(a).member[0], nfiles, sizeof(svalue) * nqueries, alphacmp); } *sp = a; return sp; } svalue *f_write_file(svalue *sp, struct frame *fp) { FILE *f; #if 1 { struct counted_string str0, str1; str0 = sv_string2(sp[-1]); str1 = sv_string2(sp[0]); printf("write_file '%.*s' '%.*s'\n", str0.len, str0.start, str1.len, str1.start); FREE_SVALUE(*sp); sp--; FREE_SVALUE(*sp); sp->i = 1; return sp; } #else #endif }