/* 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
}