sima/autoconf/
sima/hosts/i386/
sima/mudlib/
sima/mudlib/kernel/
sima/mudlib/obj/
sima/mudlib/sys/
sima/synhash/mips/
/* 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
}