diff --git a/src/modules/files/stat.c b/src/modules/files/stat.c index 39bf0b985c986f3cf6b4f8181dadfb3db8f2f9c0..c2042ed2d73ff7bcff8263417ed92d7e216cdb37 100644 --- a/src/modules/files/stat.c +++ b/src/modules/files/stat.c @@ -1,9 +1,9 @@ /* - * $Id: stat.c,v 1.7 2000/08/28 16:32:00 mast Exp $ + * $Id: stat.c,v 1.8 2000/08/29 01:18:56 mast Exp $ */ #include "global.h" -RCSID("$Id: stat.c,v 1.7 2000/08/28 16:32:00 mast Exp $"); +RCSID("$Id: stat.c,v 1.8 2000/08/29 01:18:56 mast Exp $"); #include "fdlib.h" #include "interpret.h" #include "svalue.h" @@ -12,31 +12,17 @@ RCSID("$Id: stat.c,v 1.7 2000/08/28 16:32:00 mast Exp $"); #include "object.h" #include "builtin_functions.h" #include "operators.h" +#include "opcodes.h" +#include "program_id.h" #include <sys/stat.h> #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif /* HAVE_SYS_PARAM_H */ -struct program *stat_program=NULL; - -struct stat_storage -{ - struct stat s; -}; - -static struct mapping *stat_map=NULL; - -enum stat_query -{STAT_DEV=1, STAT_INO, STAT_MODE, STAT_NLINK, STAT_UID, STAT_GID, STAT_RDEV, - STAT_SIZE, STAT_BLKSIZE, STAT_BLOCKS, STAT_ATIME, STAT_MTIME, STAT_CTIME, -/* is... */ - STAT_ISLNK, STAT_ISREG, STAT_ISDIR, STAT_ISCHR, - STAT_ISBLK, STAT_ISFIFO, STAT_ISSOCK, -/* special */ - STAT_TYPE, STAT_MODE_STRING}; - -#define THIS_STAT ((struct stat_storage*)(fp->current_storage)) +/* Let's define these mode flags if they don't exist, so reading and + * writing the Stat structure will behave identically regardless of + * OS. */ #ifndef S_IFMT #define S_IFMT 0xf000 @@ -44,6 +30,24 @@ enum stat_query #ifndef S_IFREG #define S_IFREG 0x8000 #endif /* !S_IFREG */ +#ifndef S_IFLNK +#define S_IFLNK 0xA000 +#endif /* !S_IFLNK */ +#ifndef S_IFDIR +#define S_IFDIR 0x4000 +#endif /* !S_IFDIR */ +#ifndef S_IFCHR +#define S_IFCHR 0x2000 +#endif /* !S_IFCHR */ +#ifndef S_IFBLK +#define S_IFBLK 0x6000 +#endif /* !S_IFBLK */ +#ifndef S_IFIFO +#define S_IFIFO 0x1000 +#endif /* !S_IFIFO */ +#ifndef S_IFSOCK +#define S_IFSOCK 0xC000 +#endif /* !S_IFSOCK */ #ifndef S_IRUSR #define S_IRUSR 0400 @@ -73,9 +77,74 @@ enum stat_query #define S_IXOTH 01 #endif /* !S_IXOTH */ -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#endif /* !S_ISREG */ +#ifndef S_ISUID +#define S_ISUID 0x800 +#endif /* !S_ISUID */ +#ifndef S_ISGID +#define S_ISGID 0x400 +#endif /* !S_ISGID */ +#ifndef S_ISVTX +#define S_ISVTX 0x200 +#endif /* !S_ISVTX */ + +struct program *stat_program=NULL; + +struct stat_storage +{ + /* Note: stat_create assumes there are no refs in here. */ + struct stat s; +}; + +static struct mapping *stat_map=NULL; + +enum stat_query +{STAT_DEV=1, STAT_INO, STAT_MODE, STAT_NLINK, STAT_UID, STAT_GID, STAT_RDEV, + STAT_SIZE, STAT_BLKSIZE, STAT_BLOCKS, STAT_ATIME, STAT_MTIME, STAT_CTIME, +/* is... */ + STAT_ISLNK, STAT_ISREG, STAT_ISDIR, STAT_ISCHR, + STAT_ISBLK, STAT_ISFIFO, STAT_ISSOCK, +/* special */ + STAT_TYPE, STAT_MODE_STRING, +/* end marker */ + STAT_ENUM_END}; + +static struct pike_string *stat_index_strs[STAT_ENUM_END]; + +static struct pike_string *str_type_reg, *str_type_dir, *str_type_lnk, + *str_type_chr, *str_type_blk, *str_type_fifo, *str_type_sock, *str_type_unknown; + +#define THIS_STAT ((struct stat_storage*)(fp->current_storage)) + +static void stat_index_set (INT32 args); + +static int stat_compat_set (size_t pos, INT64 val) +{ + switch (pos) { + case 0: THIS_STAT->s.st_mode = (mode_t) val; break; + case 1: + if (val >= 0) { + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFREG; + THIS_STAT->s.st_size = (off_t) val; + } + else { + THIS_STAT->s.st_size = 0; + if (val == -2) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFDIR; + else if (val == -3) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFLNK; + else + THIS_STAT->s.st_mode = THIS_STAT->s.st_mode & ~S_IFMT; + } + break; + case 2: THIS_STAT->s.st_atime = (time_t) val; break; + case 3: THIS_STAT->s.st_mtime = (time_t) val; break; + case 4: THIS_STAT->s.st_ctime = (time_t) val; break; + case 5: THIS_STAT->s.st_uid = (uid_t) val; break; + case 6: THIS_STAT->s.st_gid = (gid_t) val; break; + default: return 0; + } + return 1; +} static void stat_push_compat(INT_TYPE n) { @@ -90,9 +159,7 @@ static void stat_push_compat(INT_TYPE n) break; case S_IFDIR: push_int(-2); break; -#ifdef S_IFLNK case S_IFLNK: push_int(-3); break; -#endif default: #ifdef DEBUG_FILE fprintf(stderr, "encode_stat(): mode:%ld\n", @@ -105,8 +172,8 @@ static void stat_push_compat(INT_TYPE n) case 2: push_int64(THIS_STAT->s.st_atime); break; case 3: push_int64(THIS_STAT->s.st_mtime); break; case 4: push_int64(THIS_STAT->s.st_ctime); break; - case 5: push_int64(THIS_STAT->s.st_uid); break; - case 6: push_int64(THIS_STAT->s.st_gid); break; + case 5: push_int(THIS_STAT->s.st_uid); break; + case 6: push_int(THIS_STAT->s.st_gid); break; default: { INT32 args=1; @@ -115,6 +182,78 @@ static void stat_push_compat(INT_TYPE n) } } +static void stat_create (INT32 args) +{ + if (args >= 1) { + pop_n_elems (args - 1); + args = 1; + + if (sp[-1].type == T_OBJECT) + if (sp[-1].u.object->prog == stat_program) { + *THIS_STAT = *(struct stat_storage *) sp[-1].u.object->storage; + pop_stack(); + return; + } + + if ((1 << sp[-1].type) & (BIT_PROGRAM|BIT_OBJECT|BIT_MAPPING)) { +#define ASSIGN_INDEX(ENUM) \ + do { \ + stack_dup(); \ + ref_push_string (stat_index_strs[ENUM]); \ + sp[-1].subtype = 1; \ + o_index(); \ + if (!IS_UNDEFINED (sp-1)) { \ + ref_push_string (stat_index_strs[ENUM]); \ + stack_swap(); \ + stat_index_set (2); \ + } \ + pop_stack(); \ + } while (0) + + ASSIGN_INDEX (STAT_MODE); + ASSIGN_INDEX (STAT_SIZE); + ASSIGN_INDEX (STAT_ATIME); + ASSIGN_INDEX (STAT_MTIME); + ASSIGN_INDEX (STAT_CTIME); + ASSIGN_INDEX (STAT_UID); + ASSIGN_INDEX (STAT_GID); + ASSIGN_INDEX (STAT_DEV); + ASSIGN_INDEX (STAT_INO); + ASSIGN_INDEX (STAT_NLINK); + ASSIGN_INDEX (STAT_RDEV); + ASSIGN_INDEX (STAT_BLKSIZE); + ASSIGN_INDEX (STAT_BLOCKS); + } + + else if (sp[-1].type == T_ARRAY) { + struct array *a = sp[-1].u.array; + size_t i; + if (a->size != 7) + SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "stat array with 7 elements"); + for (i = 0; i < 7; i++) { + INT64 val; + if (ITEM(a)[i].type == T_INT) val = ITEM(a)[i].u.integer; + else if (ITEM(a)[i].type == T_OBJECT && + is_bignum_object (ITEM(a)[i].u.object)) { + if (!int64_from_bignum (&val, ITEM(a)[i].u.object)) + error ("Stat create: Too big integer in stat array.\n"); + } + else + SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "array(int)"); + stat_compat_set (i, val); + } + } + + else + SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "void|Stdio.Stat|array(int)"); + } + + else + MEMSET ((char *) &THIS_STAT->s, 0, sizeof (THIS_STAT->s)); + + pop_n_elems (args); +} + void f_min(INT32 args); void f_max(INT32 args); @@ -151,101 +290,38 @@ static void stat_index(INT32 args) case STAT_GID: push_int(THIS_STAT->s.st_gid); break; case STAT_RDEV: push_int(THIS_STAT->s.st_rdev); break; case STAT_SIZE: push_int(THIS_STAT->s.st_size); break; -#ifdef STAT_BLKSIZE case STAT_BLKSIZE: push_int(THIS_STAT->s.st_blksize); break; -#endif -#ifdef STAT_BLOCKS case STAT_BLOCKS: push_int(THIS_STAT->s.st_blocks); break; -#endif case STAT_ATIME: push_int64(THIS_STAT->s.st_atime); break; case STAT_MTIME: push_int64(THIS_STAT->s.st_mtime); break; case STAT_CTIME: push_int64(THIS_STAT->s.st_ctime); break; case STAT_ISREG: - push_int(S_ISREG(THIS_STAT->s.st_mode)); - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFREG); break; case STAT_ISLNK: -#ifdef S_ISLNK - push_int(S_ISLNK(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFLNK); break; case STAT_ISDIR: -#ifdef S_ISDIR - push_int(S_ISDIR(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFDIR); break; case STAT_ISCHR: -#ifdef S_ISCHR - push_int(S_ISCHR(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFCHR); break; case STAT_ISBLK: -#ifdef S_ISBLK - push_int(S_ISBLK(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFBLK); break; case STAT_ISFIFO: -#ifdef S_ISFIFO - push_int(S_ISFIFO(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; - case STAT_ISSOCK: -#ifdef S_ISSOCK - push_int(S_ISSOCK(THIS_STAT->s.st_mode)); -#else - push_int(0); -#endif - break; + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFIFO); break; + case STAT_ISSOCK: + push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFSOCK); break; case STAT_TYPE: switch (THIS_STAT->s.st_mode & S_IFMT) { - case S_IFREG: - push_constant_text("reg"); - break; -#ifdef S_IFDIR - case S_IFDIR: - push_constant_text("dir"); - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: - push_constant_text("lnk"); - break; -#endif -#ifdef S_IFCHR - case S_IFCHR: - push_constant_text("chr"); - break; -#endif -#ifdef S_IFBLK - case S_IFBLK: - push_constant_text("blk"); - break; -#endif -#ifdef S_IFFIFO - case S_IFFIFO: - push_constant_text("fifo"); - break; -#endif -#ifdef S_IFSOCK - case S_IFSOCK: - push_constant_text("sock"); - break; -#endif - default: - push_constant_text("unknown"); - break; + case S_IFREG: ref_push_string(str_type_reg); break; + case S_IFDIR: ref_push_string(str_type_dir); break; + case S_IFLNK: ref_push_string(str_type_lnk); break; + case S_IFCHR: ref_push_string(str_type_chr); break; + case S_IFBLK: ref_push_string(str_type_blk); break; + case S_IFIFO: ref_push_string(str_type_fifo); break; + case S_IFSOCK: ref_push_string(str_type_sock); break; + default: ref_push_string(str_type_unknown); break; } break; @@ -255,36 +331,24 @@ static void stat_index(INT32 args) case S_IFREG: push_constant_text("-"); break; -#ifdef S_IFDIR case S_IFDIR: push_constant_text("d"); break; -#endif -#ifdef S_IFLNK case S_IFLNK: push_constant_text("l"); break; -#endif -#ifdef S_IFCHR case S_IFCHR: push_constant_text("c"); break; -#endif -#ifdef S_IFBLK case S_IFBLK: push_constant_text("b"); break; -#endif -#ifdef S_IFFIFO - case S_IFFIFO: + case S_IFIFO: push_constant_text("f"); break; -#endif -#ifdef S_IFSOCK case S_IFSOCK: push_constant_text("s"); break; -#endif default: push_constant_text("?"); break; @@ -300,20 +364,16 @@ static void stat_index(INT32 args) else push_constant_text("-"); -#ifdef S_ISVTX - if ( (THIS_STAT->s.st_mode & S_ISVTX) ) - push_constant_text("S"); - else -#endif -#ifdef S_ISUID - if ( (THIS_STAT->s.st_mode & S_ISUID) ) - push_constant_text("s"); - else -#endif - if ( (THIS_STAT->s.st_mode & S_IXUSR) ) - push_constant_text("x"); - else - push_constant_text("-"); + if ( (THIS_STAT->s.st_mode & S_ISUID) ) + if ( (THIS_STAT->s.st_mode & S_IXUSR) ) + push_constant_text("s"); + else + push_constant_text("S"); + else + if ( (THIS_STAT->s.st_mode & S_IXUSR) ) + push_constant_text("x"); + else + push_constant_text("-"); if ( (THIS_STAT->s.st_mode & S_IRGRP) ) push_constant_text("r"); @@ -325,11 +385,12 @@ static void stat_index(INT32 args) else push_constant_text("-"); -#ifdef S_ISUID if ( (THIS_STAT->s.st_mode & S_ISGID) ) - push_constant_text("s"); - else -#endif + if ( (THIS_STAT->s.st_mode & S_IXGRP) ) + push_constant_text("s"); + else + push_constant_text("S"); + else if ( (THIS_STAT->s.st_mode & S_IXGRP) ) push_constant_text("x"); else @@ -345,14 +406,24 @@ static void stat_index(INT32 args) else push_constant_text("-"); - if ( (THIS_STAT->s.st_mode & S_IXOTH) ) - push_constant_text("x"); + if ( (THIS_STAT->s.st_mode & S_ISVTX) ) + if ( (THIS_STAT->s.st_mode & S_IXOTH) ) + push_constant_text("t"); + else + push_constant_text("T"); else - push_constant_text("-"); + if ( (THIS_STAT->s.st_mode & S_IXOTH) ) + push_constant_text("x"); + else + push_constant_text("-"); f_add(10); break; + + default: + push_int (0); + sp[-1].subtype = 1; } } else @@ -394,6 +465,200 @@ static void stat_index(INT32 args) } } +static void stat_index_set (INT32 args) +{ + int got_int_val = 0; + INT64 int_val; + + if (args < 2) + SIMPLE_TOO_FEW_ARGS_ERROR ("Stat `[]=", 2); + + pop_n_elems (args - 2); + args = 2; + + if (sp[-1].type == T_INT) int_val = sp[-1].u.integer, got_int_val = 1; + else if (sp[-1].type == T_OBJECT && is_bignum_object (sp[-1].u.object)) { + if (!int64_from_bignum (&int_val, sp[-1].u.object)) + error ("Stat `[]=: Too big integer as value.\n"); + else + got_int_val = 1; + } + + if (sp[-2].type == T_INT) { + if (!got_int_val) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, + "integer when the first argument is an integer"); + if (!stat_compat_set (sp[-2].u.integer, int_val)) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "int(0..6)|string"); + } + + else if (sp[-2].type == T_STRING) { + INT_TYPE code; + stack_swap(); + + ref_push_mapping (stat_map); + stack_swap(); + f_index (2); + code = sp[-1].u.integer; + pop_stack(); + + switch (code) { + case STAT_MODE_STRING: + if (sp[-1].type != T_STRING) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); + + /* FIXME: Handle modes on the form u+rw, perhaps? */ + + if (sp[-1].u.string->len != 10) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "mode string with 10 chars"); + + { + PCHARP str = MKPCHARP_STR (sp[-1].u.string); + int mode = THIS_STAT->s.st_mode; + + switch (INDEX_PCHARP (str, 0)) { + case '-': mode = (mode & ~S_IFMT) | S_IFREG; break; + case 'd': mode = (mode & ~S_IFMT) | S_IFDIR; break; + case 'l': mode = (mode & ~S_IFMT) | S_IFLNK; break; + case 'c': mode = (mode & ~S_IFMT) | S_IFCHR; break; + case 'b': mode = (mode & ~S_IFMT) | S_IFBLK; break; + case 'f': mode = (mode & ~S_IFMT) | S_IFIFO; break; + case 's': mode = (mode & ~S_IFMT) | S_IFSOCK; break; + } + + switch (INDEX_PCHARP (str, 1)) { + case '-': mode &= ~S_IRUSR; break; + case 'r': mode |= S_IRUSR; break; + } + switch (INDEX_PCHARP (str, 2)) { + case '-': mode &= ~S_IWUSR; break; + case 'w': mode |= S_IWUSR; break; + } + switch (INDEX_PCHARP (str, 3)) { + case '-': mode &= ~(S_IXUSR | S_ISUID); break; + case 'x': mode = (mode & ~S_ISUID) | S_IXUSR; break; + case 'S': mode = (mode & ~S_IXUSR) | S_ISUID; break; + case 's': mode |= S_IXUSR | S_ISUID; break; + } + + switch (INDEX_PCHARP (str, 4)) { + case '-': mode &= ~S_IRGRP; break; + case 'r': mode |= S_IRGRP; break; + } + switch (INDEX_PCHARP (str, 5)) { + case '-': mode &= ~S_IWGRP; break; + case 'w': mode |= S_IWGRP; break; + } + switch (INDEX_PCHARP (str, 6)) { + case '-': mode &= ~(S_IXGRP | S_ISGID); break; + case 'x': mode = (mode & ~S_ISGID) | S_IXGRP; break; + case 'S': mode = (mode & ~S_IXGRP) | S_ISGID; break; + case 's': mode |= S_IXGRP | S_ISGID; break; + } + + switch (INDEX_PCHARP (str, 7)) { + case '-': mode &= ~S_IROTH; break; + case 'r': mode |= S_IROTH; break; + } + switch (INDEX_PCHARP (str, 8)) { + case '-': mode &= ~S_IWOTH; break; + case 'w': mode |= S_IWOTH; break; + } + switch (INDEX_PCHARP (str, 9)) { + case '-': mode &= ~(S_IXOTH | S_ISVTX); break; + case 'x': mode = (mode & ~S_ISVTX) | S_IXOTH; break; + case 'T': mode = (mode & ~S_IXOTH) | S_ISVTX; break; + case 't': mode |= S_IXOTH | S_ISVTX; break; + } + + THIS_STAT->s.st_mode = mode; + } + break; + + case STAT_TYPE: + if (sp[-1].type != T_STRING) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); + + if (sp[-1].u.string == str_type_reg) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFREG; + else if (sp[-1].u.string == str_type_dir) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFDIR; + else if (sp[-1].u.string == str_type_lnk) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFLNK; + else if (sp[-1].u.string == str_type_chr) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFCHR; + else if (sp[-1].u.string == str_type_blk) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFBLK; + else if (sp[-1].u.string == str_type_fifo) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFIFO; + else if (sp[-1].u.string == str_type_sock) + THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFSOCK; + else if (sp[-1].u.string == str_type_unknown) + THIS_STAT->s.st_mode = THIS_STAT->s.st_mode & ~S_IFMT; + else + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "valid type string"); + break; + + case STAT_ISREG: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFREG; + break; + case STAT_ISDIR: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFDIR; + break; + case STAT_ISLNK: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFLNK; + break; + case STAT_ISCHR: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFCHR; + break; + case STAT_ISBLK: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFBLK; + break; + case STAT_ISFIFO: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFIFO; + break; + case STAT_ISSOCK: + THIS_STAT->s.st_mode &= ~S_IFMT; + if (!IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFSOCK; + break; + + default: + if (!got_int_val) + SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "integer"); + + switch (code) { + case STAT_DEV: THIS_STAT->s.st_dev = (dev_t) int_val; break; + case STAT_INO: THIS_STAT->s.st_ino = (ino_t) int_val; break; + case STAT_MODE: THIS_STAT->s.st_mode = (mode_t) int_val; break; + case STAT_NLINK: THIS_STAT->s.st_nlink = (nlink_t) int_val; break; + case STAT_UID: THIS_STAT->s.st_uid = (uid_t) int_val; break; + case STAT_GID: THIS_STAT->s.st_gid = (gid_t) int_val; break; + case STAT_RDEV: THIS_STAT->s.st_rdev = (dev_t) int_val; break; + case STAT_SIZE: THIS_STAT->s.st_size = (off_t) int_val; break; + case STAT_BLKSIZE: THIS_STAT->s.st_blksize = (long) int_val; break; + case STAT_BLOCKS: THIS_STAT->s.st_blocks = (blkcnt_t) int_val; break; + case STAT_ATIME: THIS_STAT->s.st_atime = (time_t) int_val; break; + case STAT_MTIME: THIS_STAT->s.st_mtime = (time_t) int_val; break; + case STAT_CTIME: THIS_STAT->s.st_ctime = (time_t) int_val; break; + + default: + fatal ("stat_index_set is not kept up-to-date with stat_map.\n"); + } + } + } + + else SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "int(0..6)|string"); + + stack_swap(); + pop_stack(); +} + static void stat_cast(INT32 args) { if (!args) @@ -431,13 +696,13 @@ static void stat__sprintf(INT32 args) n++; push_constant_text("Stat("); ref_push_object(fp->current_object); - push_constant_text("mode_string"); + ref_push_string(stat_index_strs[STAT_MODE_STRING]); n++; f_index(2); n++; push_constant_text(" "); ref_push_object(fp->current_object); - push_constant_text("size"); + ref_push_string(stat_index_strs[STAT_SIZE]); n++; f_index(2); n++; push_constant_text("b)"); f_add(n); @@ -492,47 +757,71 @@ void init_files_stat() { INT_TYPE n=0; - n++; push_text("dev"); push_int(STAT_DEV); - n++; push_text("ino"); push_int(STAT_INO); - n++; push_text("mode"); push_int(STAT_MODE); - n++; push_text("nlink"); push_int(STAT_NLINK); - n++; push_text("uid"); push_int(STAT_UID); - n++; push_text("gid"); push_int(STAT_GID); - n++; push_text("rdev"); push_int(STAT_RDEV); - n++; push_text("size"); push_int(STAT_SIZE); - n++; push_text("blksize"); push_int(STAT_BLKSIZE); - n++; push_text("blocks"); push_int(STAT_BLOCKS); - n++; push_text("atime"); push_int(STAT_ATIME); - n++; push_text("mtime"); push_int(STAT_MTIME); - n++; push_text("ctime"); push_int(STAT_CTIME); - - n++; push_text("islnk"); push_int(STAT_ISLNK); - n++; push_text("isreg"); push_int(STAT_ISREG); - n++; push_text("isdir"); push_int(STAT_ISDIR); - n++; push_text("ischr"); push_int(STAT_ISCHR); - n++; push_text("isblk"); push_int(STAT_ISBLK); - n++; push_text("isfifo"); push_int(STAT_ISFIFO); - n++; push_text("issock"); push_int(STAT_ISSOCK); - - n++; push_text("type"); push_int(STAT_TYPE); - n++; push_text("mode_string"); push_int(STAT_MODE_STRING); - + MAKE_CONSTANT_SHARED_STRING (str_type_reg, "reg"); + MAKE_CONSTANT_SHARED_STRING (str_type_dir, "dir"); + MAKE_CONSTANT_SHARED_STRING (str_type_lnk, "lnk"); + MAKE_CONSTANT_SHARED_STRING (str_type_chr, "chr"); + MAKE_CONSTANT_SHARED_STRING (str_type_blk, "blk"); + MAKE_CONSTANT_SHARED_STRING (str_type_fifo, "fifo"); + MAKE_CONSTANT_SHARED_STRING (str_type_sock, "sock"); + MAKE_CONSTANT_SHARED_STRING (str_type_unknown, "unknown"); + +#define INIT_INDEX(ENUM, TXT) do { \ + MAKE_CONSTANT_SHARED_STRING (stat_index_strs[ENUM], TXT); \ + n++; ref_push_string (stat_index_strs[ENUM]); push_int (ENUM); \ + } while (0) + + INIT_INDEX (STAT_DEV, "dev"); + INIT_INDEX (STAT_INO, "ino"); + INIT_INDEX (STAT_MODE, "mode"); + INIT_INDEX (STAT_NLINK, "nlink"); + INIT_INDEX (STAT_UID, "uid"); + INIT_INDEX (STAT_GID, "gid"); + INIT_INDEX (STAT_RDEV, "rdev"); + INIT_INDEX (STAT_SIZE, "size"); + INIT_INDEX (STAT_BLKSIZE, "blksize"); + INIT_INDEX (STAT_BLOCKS, "blocks"); + INIT_INDEX (STAT_ATIME, "atime"); + INIT_INDEX (STAT_MTIME, "mtime"); + INIT_INDEX (STAT_CTIME, "ctime"); + + INIT_INDEX (STAT_ISLNK, "islnk"); + INIT_INDEX (STAT_ISREG, "isreg"); + INIT_INDEX (STAT_ISDIR, "isdir"); + INIT_INDEX (STAT_ISCHR, "ischr"); + INIT_INDEX (STAT_ISBLK, "isblk"); + INIT_INDEX (STAT_ISFIFO, "isfifo"); + INIT_INDEX (STAT_ISSOCK, "issock"); + + INIT_INDEX (STAT_TYPE, "type"); + INIT_INDEX (STAT_MODE_STRING, "mode_string"); + f_aggregate_mapping(n*2); stat_map=sp[-1].u.mapping; sp--; dmalloc_touch_svalue(sp); - start_new_program(); + START_NEW_PROGRAM_ID(STDIO_STAT); ADD_STORAGE(struct stat_storage); + ADD_FUNCTION ("create", stat_create, + tFunc(tOr5(tVoid,tObjImpl_STDIO_STAT,tProgram,tMapping,tArr(tInt)), + tVoid), ID_STATIC); + ADD_FUNCTION("`[]",stat_index, - tOr(tFunc(tOr(tStr,tIntPos),tOr3(tStr,tInt,tFunction)), + tOr(tFunc(tOr(tStr,tInt06),tOr3(tStr,tInt,tFunction)), tFunc(tInt tInt,tArr(tInt))),0); - ADD_FUNCTION("`->",stat_index, - tOr(tFunc(tOr(tStr,tIntPos),tOr3(tStr,tInt,tFunction)), + tOr(tFunc(tOr(tStr,tInt06),tOr3(tStr,tInt,tFunction)), tFunc(tInt tInt,tArr(tInt))),0); + ADD_FUNCTION ("`[]=", stat_index_set, + tOr(tFunc(tInt06 tSetvar(0,tInt),tVar(0)), + tFunc(tString tSetvar(1,tOr(tInt,tString)),tVar(1))), 0); + ADD_FUNCTION ("`->=", stat_index_set, + tOr(tFunc(tInt06 tSetvar(0,tInt),tVar(0)), + tFunc(tString tSetvar(1,tOr(tInt,tString)),tVar(1))), 0); + ADD_FUNCTION("cast",stat_cast,tFunc(tStr,tArray),0); ADD_FUNCTION("_sprintf",stat__sprintf, tFunc(tInt tOr(tVoid,tMapping),tString),0); @@ -547,6 +836,20 @@ void init_files_stat() void exit_files_stat() { + size_t i; + free_program(stat_program); free_mapping(stat_map); + + for (i = 1; i < STAT_ENUM_END; i++) + free_string (stat_index_strs[i]); + + free_string (str_type_reg); + free_string (str_type_dir); + free_string (str_type_lnk); + free_string (str_type_chr); + free_string (str_type_blk); + free_string (str_type_fifo); + free_string (str_type_sock); + free_string (str_type_unknown); }