summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c1435
1 files changed, 1435 insertions, 0 deletions
diff --git a/eval.c b/eval.c
new file mode 100644
index 0000000000..78a06cb1fb
--- /dev/null
+++ b/eval.c
@@ -0,0 +1,1435 @@
+/* $Header: eval.c,v 2.0 88/06/05 00:08:48 root Exp $
+ *
+ * $Log: eval.c,v $
+ * Revision 2.0 88/06/05 00:08:48 root
+ * Baseline version 2.0.
+ *
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+
+#include <signal.h>
+#include <errno.h>
+
+extern int errno;
+
+#ifdef VOIDSIG
+static void (*ihand)();
+static void (*qhand)();
+#else
+static int (*ihand)();
+static int (*qhand)();
+#endif
+
+ARG *debarg;
+STR str_args;
+
+STR *
+eval(arg,retary,sargoff)
+register ARG *arg;
+STR ***retary; /* where to return an array to, null if nowhere */
+int sargoff; /* how many elements in sarg are already assigned */
+{
+ register STR *str;
+ register int anum;
+ register int optype;
+ int maxarg;
+ int maxsarg;
+ double value;
+ STR *quicksarg[5];
+ register STR **sarg = quicksarg;
+ register char *tmps;
+ char *tmps2;
+ int argflags;
+ int argtype;
+ union argptr argptr;
+ int cushion;
+ unsigned long tmplong;
+ long when;
+ FILE *fp;
+ STR *tmpstr;
+ FCMD *form;
+ STAB *stab;
+ ARRAY *ary;
+ bool assigning = FALSE;
+ double exp(), log(), sqrt(), modf();
+ char *crypt(), *getenv();
+
+ if (!arg)
+ return &str_no;
+ str = arg->arg_ptr.arg_str;
+ optype = arg->arg_type;
+ maxsarg = maxarg = arg->arg_len;
+ if (maxsarg > 3 || retary) {
+ if (sargoff >= 0) { /* array already exists, just append to it */
+ cushion = 10;
+ sarg = (STR **)saferealloc((char*)*retary,
+ (maxsarg+sargoff+2+cushion) * sizeof(STR*)) + sargoff;
+ /* Note that sarg points into the middle of the array */
+ }
+ else {
+ sargoff = cushion = 0;
+ sarg = (STR **)safemalloc((maxsarg+2) * sizeof(STR*));
+ }
+ }
+ else
+ sargoff = 0;
+#ifdef DEBUGGING
+ if (debug) {
+ if (debug & 8) {
+ deb("%s (%lx) %d args:\n",opname[optype],arg,maxarg);
+ }
+ debname[dlevel] = opname[optype][0];
+ debdelim[dlevel++] = ':';
+ }
+#endif
+ for (anum = 1; anum <= maxarg; anum++) {
+ argflags = arg[anum].arg_flags;
+ if (argflags & AF_SPECIAL)
+ continue;
+ argtype = arg[anum].arg_type;
+ argptr = arg[anum].arg_ptr;
+ re_eval:
+ switch (argtype) {
+ default:
+ sarg[anum] = &str_no;
+#ifdef DEBUGGING
+ tmps = "NULL";
+#endif
+ break;
+ case A_EXPR:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "EXPR";
+ deb("%d.EXPR =>\n",anum);
+ }
+#endif
+ if (retary &&
+ (optype == O_LIST || optype == O_ITEM2 || optype == O_ITEM3)) {
+ *retary = sarg - sargoff;
+ eval(argptr.arg_arg, retary, anum - 1 + sargoff);
+ sarg = *retary; /* they do realloc it... */
+ argtype = maxarg - anum; /* how many left? */
+ maxsarg = (int)(str_gnum(sarg[0])) + argtype;
+ sargoff = maxsarg - maxarg;
+ if (argtype > 9 - cushion) { /* we don't have room left */
+ sarg = (STR **)saferealloc((char*)sarg,
+ (maxsarg+2+cushion) * sizeof(STR*));
+ }
+ sarg += sargoff;
+ }
+ else
+ sarg[anum] = eval(argptr.arg_arg, Null(STR***),-1);
+ break;
+ case A_CMD:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "CMD";
+ deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd);
+ }
+#endif
+ sarg[anum] = cmd_exec(argptr.arg_cmd);
+ break;
+ case A_STAB:
+ sarg[anum] = STAB_STR(argptr.arg_stab);
+#ifdef DEBUGGING
+ if (debug & 8) {
+ sprintf(buf,"STAB $%s",argptr.arg_stab->stab_name);
+ tmps = buf;
+ }
+#endif
+ break;
+ case A_LEXPR:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "LEXPR";
+ deb("%d.LEXPR =>\n",anum);
+ }
+#endif
+ str = eval(argptr.arg_arg,Null(STR***),-1);
+ if (!str)
+ fatal("panic: A_LEXPR");
+ goto do_crement;
+ case A_LVAL:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ sprintf(buf,"LVAL $%s",argptr.arg_stab->stab_name);
+ tmps = buf;
+ }
+#endif
+ str = STAB_STR(argptr.arg_stab);
+ if (!str)
+ fatal("panic: A_LVAL");
+ do_crement:
+ assigning = TRUE;
+ if (argflags & AF_PRE) {
+ if (argflags & AF_UP)
+ str_inc(str);
+ else
+ str_dec(str);
+ STABSET(str);
+ sarg[anum] = str;
+ str = arg->arg_ptr.arg_str;
+ }
+ else if (argflags & AF_POST) {
+ sarg[anum] = str_static(str);
+ if (argflags & AF_UP)
+ str_inc(str);
+ else
+ str_dec(str);
+ STABSET(str);
+ str = arg->arg_ptr.arg_str;
+ }
+ else {
+ sarg[anum] = str;
+ }
+ break;
+ case A_LARYLEN:
+ str = sarg[anum] =
+ argptr.arg_stab->stab_array->ary_magic;
+#ifdef DEBUGGING
+ tmps = "LARYLEN";
+#endif
+ if (!str)
+ fatal("panic: A_LEXPR");
+ goto do_crement;
+ case A_ARYLEN:
+ stab = argptr.arg_stab;
+ sarg[anum] = stab->stab_array->ary_magic;
+ str_numset(sarg[anum],(double)(stab->stab_array->ary_fill+arybase));
+#ifdef DEBUGGING
+ tmps = "ARYLEN";
+#endif
+ break;
+ case A_SINGLE:
+ sarg[anum] = argptr.arg_str;
+#ifdef DEBUGGING
+ tmps = "SINGLE";
+#endif
+ break;
+ case A_DOUBLE:
+ (void) interp(str,str_get(argptr.arg_str));
+ sarg[anum] = str;
+#ifdef DEBUGGING
+ tmps = "DOUBLE";
+#endif
+ break;
+ case A_BACKTICK:
+ tmps = str_get(argptr.arg_str);
+ fp = popen(str_get(interp(str,tmps)),"r");
+ tmpstr = str_new(80);
+ str_set(str,"");
+ if (fp) {
+ while (str_gets(tmpstr,fp) != Nullch) {
+ str_scat(str,tmpstr);
+ }
+ statusvalue = pclose(fp);
+ }
+ else
+ statusvalue = -1;
+ str_free(tmpstr);
+
+ sarg[anum] = str;
+#ifdef DEBUGGING
+ tmps = "BACK";
+#endif
+ break;
+ case A_INDREAD:
+ last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE);
+ goto do_read;
+ case A_GLOB:
+ argflags |= AF_POST; /* enable newline chopping */
+ case A_READ:
+ last_in_stab = argptr.arg_stab;
+ do_read:
+ fp = Nullfp;
+ if (last_in_stab->stab_io) {
+ fp = last_in_stab->stab_io->fp;
+ if (!fp) {
+ if (last_in_stab->stab_io->flags & IOF_ARGV) {
+ if (last_in_stab->stab_io->flags & IOF_START) {
+ last_in_stab->stab_io->flags &= ~IOF_START;
+ last_in_stab->stab_io->lines = 0;
+ if (alen(last_in_stab->stab_array) < 0) {
+ tmpstr = str_make("-"); /* assume stdin */
+ apush(last_in_stab->stab_array, tmpstr);
+ }
+ }
+ fp = nextargv(last_in_stab);
+ if (!fp) /* Note: fp != last_in_stab->stab_io->fp */
+ do_close(last_in_stab,FALSE); /* now it does */
+ }
+ else if (argtype == A_GLOB) {
+ (void) interp(str,str_get(last_in_stab->stab_val));
+ tmps = str->str_ptr;
+ if (*tmps == '!')
+ sprintf(tokenbuf,"%s|",tmps+1);
+ else {
+ if (*tmps == ';')
+ sprintf(tokenbuf, "%s", tmps+1);
+ else
+ sprintf(tokenbuf, "echo %s", tmps);
+ strcat(tokenbuf,
+ "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|");
+ }
+ do_open(last_in_stab,tokenbuf);
+ fp = last_in_stab->stab_io->fp;
+ }
+ }
+ }
+ if (!fp && dowarn)
+ warn("Read on closed filehandle <%s>",last_in_stab->stab_name);
+ keepgoing:
+ if (!fp)
+ sarg[anum] = &str_no;
+ else if (!str_gets(str,fp)) {
+ if (last_in_stab->stab_io->flags & IOF_ARGV) {
+ fp = nextargv(last_in_stab);
+ if (fp)
+ goto keepgoing;
+ do_close(last_in_stab,FALSE);
+ last_in_stab->stab_io->flags |= IOF_START;
+ }
+ else if (argflags & AF_POST) {
+ do_close(last_in_stab,FALSE);
+ }
+ if (fp == stdin) {
+ clearerr(fp);
+ }
+ sarg[anum] = &str_no;
+ if (retary) {
+ maxarg = anum - 1;
+ maxsarg = maxarg + sargoff;
+ }
+ break;
+ }
+ else {
+ last_in_stab->stab_io->lines++;
+ sarg[anum] = str;
+ if (argflags & AF_POST) {
+ if (str->str_cur > 0)
+ str->str_cur--;
+ str->str_ptr[str->str_cur] = '\0';
+ }
+ if (retary) {
+ sarg[anum] = str_static(sarg[anum]);
+ anum++;
+ if (anum > maxarg) {
+ maxarg = anum + anum;
+ maxsarg = maxarg + sargoff;
+ sarg = (STR **)saferealloc((char*)(sarg-sargoff),
+ (maxsarg+2+cushion) * sizeof(STR*)) + sargoff;
+ }
+ goto keepgoing;
+ }
+ }
+ if (retary) {
+ maxarg = anum - 1;
+ maxsarg = maxarg + sargoff;
+ }
+#ifdef DEBUGGING
+ tmps = "READ";
+#endif
+ break;
+ }
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("%d.%s = '%s'\n",anum,tmps,str_peek(sarg[anum]));
+#endif
+ }
+ switch (optype) {
+ case O_ITEM:
+ if (maxarg > arg->arg_len)
+ goto array_return;
+ if (str != sarg[1])
+ str_sset(str,sarg[1]);
+ STABSET(str);
+ break;
+ case O_ITEM2:
+ if (str != sarg[--anum])
+ str_sset(str,sarg[anum]);
+ STABSET(str);
+ break;
+ case O_ITEM3:
+ if (str != sarg[--anum])
+ str_sset(str,sarg[anum]);
+ STABSET(str);
+ break;
+ case O_CONCAT:
+ if (str != sarg[1])
+ str_sset(str,sarg[1]);
+ str_scat(str,sarg[2]);
+ STABSET(str);
+ break;
+ case O_REPEAT:
+ if (str != sarg[1])
+ str_sset(str,sarg[1]);
+ anum = (int)str_gnum(sarg[2]);
+ if (anum >= 1) {
+ tmpstr = str_new(0);
+ str_sset(tmpstr,str);
+ while (--anum > 0)
+ str_scat(str,tmpstr);
+ }
+ else
+ str_sset(str,&str_no);
+ STABSET(str);
+ break;
+ case O_MATCH:
+ str_sset(str, do_match(arg,
+ retary,sarg,&maxsarg,sargoff,cushion));
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ STABSET(str);
+ break;
+ case O_NMATCH:
+ str_sset(str, do_match(arg,
+ retary,sarg,&maxsarg,sargoff,cushion));
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return; /* ignore negation */
+ }
+ str_set(str, str_true(str) ? No : Yes);
+ STABSET(str);
+ break;
+ case O_SUBST:
+ value = (double) do_subst(str, arg);
+ str = arg->arg_ptr.arg_str;
+ goto donumset;
+ case O_NSUBST:
+ str_set(arg->arg_ptr.arg_str, do_subst(str, arg) ? No : Yes);
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_ASSIGN:
+ if (arg[1].arg_flags & AF_SPECIAL)
+ do_assign(str,arg,sarg);
+ else {
+ if (str != sarg[2])
+ str_sset(str, sarg[2]);
+ STABSET(str);
+ }
+ break;
+ case O_CHOP:
+ tmps = str_get(str);
+ tmps += str->str_cur - (str->str_cur != 0);
+ str_set(arg->arg_ptr.arg_str,tmps); /* remember last char */
+ *tmps = '\0'; /* wipe it out */
+ str->str_cur = tmps - str->str_ptr;
+ str->str_nok = 0;
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_STUDY:
+ value = (double)do_study(str);
+ str = arg->arg_ptr.arg_str;
+ goto donumset;
+ case O_MULTIPLY:
+ value = str_gnum(sarg[1]);
+ value *= str_gnum(sarg[2]);
+ goto donumset;
+ case O_DIVIDE:
+ if ((value = str_gnum(sarg[2])) == 0.0)
+ fatal("Illegal division by zero");
+ value = str_gnum(sarg[1]) / value;
+ goto donumset;
+ case O_MODULO:
+ if ((tmplong = (unsigned long) str_gnum(sarg[2])) == 0L)
+ fatal("Illegal modulus zero");
+ value = str_gnum(sarg[1]);
+ value = (double)(((unsigned long)value) % tmplong);
+ goto donumset;
+ case O_ADD:
+ value = str_gnum(sarg[1]);
+ value += str_gnum(sarg[2]);
+ goto donumset;
+ case O_SUBTRACT:
+ value = str_gnum(sarg[1]);
+ value -= str_gnum(sarg[2]);
+ goto donumset;
+ case O_LEFT_SHIFT:
+ value = str_gnum(sarg[1]);
+ anum = (int)str_gnum(sarg[2]);
+ value = (double)(((unsigned long)value) << anum);
+ goto donumset;
+ case O_RIGHT_SHIFT:
+ value = str_gnum(sarg[1]);
+ anum = (int)str_gnum(sarg[2]);
+ value = (double)(((unsigned long)value) >> anum);
+ goto donumset;
+ case O_LT:
+ value = str_gnum(sarg[1]);
+ value = (double)(value < str_gnum(sarg[2]));
+ goto donumset;
+ case O_GT:
+ value = str_gnum(sarg[1]);
+ value = (double)(value > str_gnum(sarg[2]));
+ goto donumset;
+ case O_LE:
+ value = str_gnum(sarg[1]);
+ value = (double)(value <= str_gnum(sarg[2]));
+ goto donumset;
+ case O_GE:
+ value = str_gnum(sarg[1]);
+ value = (double)(value >= str_gnum(sarg[2]));
+ goto donumset;
+ case O_EQ:
+ value = str_gnum(sarg[1]);
+ value = (double)(value == str_gnum(sarg[2]));
+ goto donumset;
+ case O_NE:
+ value = str_gnum(sarg[1]);
+ value = (double)(value != str_gnum(sarg[2]));
+ goto donumset;
+ case O_BIT_AND:
+ value = str_gnum(sarg[1]);
+ value = (double)(((unsigned long)value) &
+ (unsigned long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_XOR:
+ value = str_gnum(sarg[1]);
+ value = (double)(((unsigned long)value) ^
+ (unsigned long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_BIT_OR:
+ value = str_gnum(sarg[1]);
+ value = (double)(((unsigned long)value) |
+ (unsigned long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_AND:
+ if (str_true(sarg[1])) {
+ anum = 2;
+ optype = O_ITEM2;
+ argflags = arg[anum].arg_flags;
+ argtype = arg[anum].arg_type;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ goto re_eval;
+ }
+ else {
+ if (assigning) {
+ str_sset(str, sarg[1]);
+ STABSET(str);
+ }
+ else
+ str = sarg[1];
+ break;
+ }
+ case O_OR:
+ if (str_true(sarg[1])) {
+ if (assigning) {
+ str_sset(str, sarg[1]);
+ STABSET(str);
+ }
+ else
+ str = sarg[1];
+ break;
+ }
+ else {
+ anum = 2;
+ optype = O_ITEM2;
+ argflags = arg[anum].arg_flags;
+ argtype = arg[anum].arg_type;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ goto re_eval;
+ }
+ case O_COND_EXPR:
+ anum = (str_true(sarg[1]) ? 2 : 3);
+ optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
+ argflags = arg[anum].arg_flags;
+ argtype = arg[anum].arg_type;
+ argptr = arg[anum].arg_ptr;
+ maxarg = anum = 1;
+ goto re_eval;
+ case O_COMMA:
+ str = sarg[2];
+ break;
+ case O_NEGATE:
+ value = -str_gnum(sarg[1]);
+ goto donumset;
+ case O_NOT:
+ value = (double) !str_true(sarg[1]);
+ goto donumset;
+ case O_COMPLEMENT:
+ value = (double) ~(long)str_gnum(sarg[1]);
+ goto donumset;
+ case O_SELECT:
+ if (arg[1].arg_type == A_LVAL)
+ defoutstab = arg[1].arg_ptr.arg_stab;
+ else
+ defoutstab = stabent(str_get(sarg[1]),TRUE);
+ if (!defoutstab->stab_io)
+ defoutstab->stab_io = stio_new();
+ curoutstab = defoutstab;
+ str_set(str,curoutstab->stab_io->fp ? Yes : No);
+ STABSET(str);
+ break;
+ case O_WRITE:
+ if (maxarg == 0)
+ stab = defoutstab;
+ else if (arg[1].arg_type == A_LVAL)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ if (!stab->stab_io) {
+ str_set(str, No);
+ STABSET(str);
+ break;
+ }
+ curoutstab = stab;
+ fp = stab->stab_io->fp;
+ debarg = arg;
+ if (stab->stab_io->fmt_stab)
+ form = stab->stab_io->fmt_stab->stab_form;
+ else
+ form = stab->stab_form;
+ if (!form || !fp) {
+ str_set(str, No);
+ STABSET(str);
+ break;
+ }
+ format(&outrec,form);
+ do_write(&outrec,stab->stab_io);
+ if (stab->stab_io->flags & IOF_FLUSH)
+ fflush(fp);
+ str_set(str, Yes);
+ STABSET(str);
+ break;
+ case O_OPEN:
+ if (arg[1].arg_type == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ if (do_open(stab,str_get(sarg[2]))) {
+ value = (double)forkprocess;
+ stab->stab_io->lines = 0;
+ goto donumset;
+ }
+ else
+ str_set(str, No);
+ STABSET(str);
+ break;
+ case O_TRANS:
+ value = (double) do_trans(str,arg);
+ str = arg->arg_ptr.arg_str;
+ goto donumset;
+ case O_NTRANS:
+ str_set(arg->arg_ptr.arg_str, do_trans(str,arg) == 0 ? Yes : No);
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_CLOSE:
+ if (arg[1].arg_type == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ str_set(str, do_close(stab,TRUE) ? Yes : No );
+ STABSET(str);
+ break;
+ case O_EACH:
+ str_sset(str,do_each(arg[1].arg_ptr.arg_stab->stab_hash,
+ retary,sarg,&maxsarg,sargoff,cushion));
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ STABSET(str);
+ break;
+ case O_VALUES:
+ case O_KEYS:
+ value = (double) do_kv(arg[1].arg_ptr.arg_stab->stab_hash, optype,
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_ARRAY:
+ if (maxarg == 1) {
+ ary = arg[1].arg_ptr.arg_stab->stab_array;
+ maxarg = ary->ary_fill;
+ maxsarg = maxarg + sargoff;
+ if (retary) { /* array wanted */
+ sarg = (STR **)saferealloc((char*)(sarg-sargoff),
+ (maxsarg+3+cushion)*sizeof(STR*)) + sargoff;
+ for (anum = 0; anum <= maxarg; anum++) {
+ sarg[anum+1] = str = afetch(ary,anum);
+ }
+ maxarg++;
+ maxsarg++;
+ goto array_return;
+ }
+ else
+ str = afetch(ary,maxarg);
+ }
+ else
+ str = afetch(arg[2].arg_ptr.arg_stab->stab_array,
+ ((int)str_gnum(sarg[1])) - arybase);
+ if (!str)
+ str = &str_no;
+ break;
+ case O_DELETE:
+ tmpstab = arg[2].arg_ptr.arg_stab; /* XXX */
+ str = hdelete(tmpstab->stab_hash,str_get(sarg[1]));
+ if (!str)
+ str = &str_no;
+ break;
+ case O_HASH:
+ tmpstab = arg[2].arg_ptr.arg_stab; /* XXX */
+ str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
+ if (!str)
+ str = &str_no;
+ break;
+ case O_LARRAY:
+ anum = ((int)str_gnum(sarg[1])) - arybase;
+ str = afetch(arg[2].arg_ptr.arg_stab->stab_array,anum);
+ if (!str || str == &str_no) {
+ str = str_new(0);
+ astore(arg[2].arg_ptr.arg_stab->stab_array,anum,str);
+ }
+ break;
+ case O_LHASH:
+ tmpstab = arg[2].arg_ptr.arg_stab;
+ str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
+ if (!str) {
+ str = str_new(0);
+ hstore(tmpstab->stab_hash,str_get(sarg[1]),str);
+ }
+ if (tmpstab == envstab) { /* heavy wizardry going on here */
+ str->str_link.str_magic = tmpstab;/* str is now magic */
+ envname = savestr(str_get(sarg[1]));
+ /* he threw the brick up into the air */
+ }
+ else if (tmpstab == sigstab) { /* same thing, only different */
+ str->str_link.str_magic = tmpstab;
+ signame = savestr(str_get(sarg[1]));
+ }
+ break;
+ case O_PUSH:
+ if (arg[1].arg_flags & AF_SPECIAL)
+ str = do_push(arg,arg[2].arg_ptr.arg_stab->stab_array);
+ else {
+ str = str_new(0); /* must copy the STR */
+ str_sset(str,sarg[1]);
+ apush(arg[2].arg_ptr.arg_stab->stab_array,str);
+ }
+ break;
+ case O_POP:
+ str = apop(arg[1].arg_ptr.arg_stab->stab_array);
+ if (!str) {
+ str = &str_no;
+ break;
+ }
+#ifdef STRUCTCOPY
+ *(arg->arg_ptr.arg_str) = *str;
+#else
+ bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
+#endif
+ safefree((char*)str);
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_SHIFT:
+ str = ashift(arg[1].arg_ptr.arg_stab->stab_array);
+ if (!str) {
+ str = &str_no;
+ break;
+ }
+#ifdef STRUCTCOPY
+ *(arg->arg_ptr.arg_str) = *str;
+#else
+ bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
+#endif
+ safefree((char*)str);
+ str = arg->arg_ptr.arg_str;
+ break;
+ case O_SPLIT:
+ value = (double) do_split(arg[2].arg_ptr.arg_spat,
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_LENGTH:
+ value = (double) str_len(sarg[1]);
+ goto donumset;
+ case O_SPRINTF:
+ sarg[maxsarg+1] = Nullstr;
+ do_sprintf(str,arg->arg_len,sarg);
+ break;
+ case O_SUBSTR:
+ anum = ((int)str_gnum(sarg[2])) - arybase;
+ for (tmps = str_get(sarg[1]); *tmps && anum > 0; tmps++,anum--) ;
+ anum = (int)str_gnum(sarg[3]);
+ if (anum >= 0 && strlen(tmps) > anum)
+ str_nset(str, tmps, anum);
+ else
+ str_set(str, tmps);
+ break;
+ case O_JOIN:
+ if (arg[2].arg_flags & AF_SPECIAL && arg[2].arg_type == A_EXPR)
+ do_join(arg,str_get(sarg[1]),str);
+ else
+ ajoin(arg[2].arg_ptr.arg_stab->stab_array,str_get(sarg[1]),str);
+ break;
+ case O_SLT:
+ tmps = str_get(sarg[1]);
+ value = (double) strLT(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SGT:
+ tmps = str_get(sarg[1]);
+ value = (double) strGT(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SLE:
+ tmps = str_get(sarg[1]);
+ value = (double) strLE(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SGE:
+ tmps = str_get(sarg[1]);
+ value = (double) strGE(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SEQ:
+ tmps = str_get(sarg[1]);
+ value = (double) strEQ(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SNE:
+ tmps = str_get(sarg[1]);
+ value = (double) strNE(tmps,str_get(sarg[2]));
+ goto donumset;
+ case O_SUBR:
+ str_sset(str,do_subr(arg,sarg));
+ STABSET(str);
+ break;
+ case O_SORT:
+ if (maxarg <= 1)
+ stab = defoutstab;
+ else {
+ if (arg[2].arg_type == A_WORD)
+ stab = arg[2].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[2]),TRUE);
+ if (!stab)
+ stab = defoutstab;
+ }
+ value = (double)do_sort(arg,stab,
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_PRTF:
+ case O_PRINT:
+ if (maxarg <= 1)
+ stab = defoutstab;
+ else {
+ if (arg[2].arg_type == A_WORD)
+ stab = arg[2].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[2]),TRUE);
+ if (!stab)
+ stab = defoutstab;
+ }
+ if (!stab->stab_io || !(fp = stab->stab_io->fp))
+ value = 0.0;
+ else {
+ if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)do_aprint(arg,fp);
+ else {
+ value = (double)do_print(sarg[1],fp);
+ if (ors && optype == O_PRINT)
+ fputs(ors, fp);
+ }
+ if (stab->stab_io->flags & IOF_FLUSH)
+ fflush(fp);
+ }
+ goto donumset;
+ case O_CHDIR:
+ tmps = str_get(sarg[1]);
+ if (!tmps || !*tmps)
+ tmps = getenv("HOME");
+ if (!tmps || !*tmps)
+ tmps = getenv("LOGDIR");
+ value = (double)(chdir(tmps) >= 0);
+ goto donumset;
+ case O_DIE:
+ tmps = str_get(sarg[1]);
+ if (!tmps || !*tmps)
+ exit(1);
+ fatal("%s",str_get(sarg[1]));
+ value = 0.0;
+ goto donumset;
+ case O_EXIT:
+ exit((int)str_gnum(sarg[1]));
+ value = 0.0;
+ goto donumset;
+ case O_RESET:
+ str_reset(str_get(sarg[1]));
+ value = 1.0;
+ goto donumset;
+ case O_LIST:
+ if (arg->arg_flags & AF_LOCAL)
+ savelist(sarg,maxsarg);
+ if (maxarg > 0)
+ str = sarg[maxsarg]; /* unwanted list, return last item */
+ else
+ str = &str_no;
+ if (retary)
+ goto array_return;
+ break;
+ case O_EOF:
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if (arg[1].arg_type == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ str_set(str, do_eof(stab) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_TELL:
+ if (maxarg <= 0)
+ stab = last_in_stab;
+ else if (arg[1].arg_type == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ value = (double)do_tell(stab);
+ goto donumset;
+ case O_SEEK:
+ if (arg[1].arg_type == A_WORD)
+ stab = arg[1].arg_ptr.arg_stab;
+ else
+ stab = stabent(str_get(sarg[1]),TRUE);
+ value = str_gnum(sarg[2]);
+ str_set(str, do_seek(stab,
+ (long)value, (int)str_gnum(sarg[3]) ) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_REDO:
+ case O_NEXT:
+ case O_LAST:
+ if (maxarg > 0) {
+ tmps = str_get(sarg[1]);
+ while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
+ strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Skipping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Found label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ }
+ if (loop_ptr < 0)
+ fatal("Bad label: %s", maxarg > 0 ? tmps : "<null>");
+ longjmp(loop_stack[loop_ptr].loop_env, optype);
+ case O_GOTO:/* shudder */
+ goto_targ = str_get(sarg[1]);
+ longjmp(top_env, 1);
+ case O_INDEX:
+ tmps = str_get(sarg[1]);
+ if (!(tmps2 = fbminstr(tmps, tmps + sarg[1]->str_cur, sarg[2])))
+ value = (double)(-1 + arybase);
+ else
+ value = (double)(tmps2 - tmps + arybase);
+ goto donumset;
+ case O_TIME:
+ value = (double) time(Null(long*));
+ goto donumset;
+ case O_TMS:
+ value = (double) do_tms(retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_LOCALTIME:
+ when = (long)str_gnum(sarg[1]);
+ value = (double)do_time(localtime(&when),
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_GMTIME:
+ when = (long)str_gnum(sarg[1]);
+ value = (double)do_time(gmtime(&when),
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_STAT:
+ value = (double) do_stat(arg,
+ retary,sarg,&maxsarg,sargoff,cushion);
+ if (retary) {
+ sarg = *retary; /* they realloc it */
+ goto array_return;
+ }
+ goto donumset;
+ case O_CRYPT:
+#ifdef CRYPT
+ tmps = str_get(sarg[1]);
+ str_set(str,crypt(tmps,str_get(sarg[2])));
+#else
+ fatal(
+ "The crypt() function is unimplemented due to excessive paranoia.");
+#endif
+ break;
+ case O_EXP:
+ value = exp(str_gnum(sarg[1]));
+ goto donumset;
+ case O_LOG:
+ value = log(str_gnum(sarg[1]));
+ goto donumset;
+ case O_SQRT:
+ value = sqrt(str_gnum(sarg[1]));
+ goto donumset;
+ case O_INT:
+ value = str_gnum(sarg[1]);
+ if (value >= 0.0)
+ modf(value,&value);
+ else {
+ modf(-value,&value);
+ value = -value;
+ }
+ goto donumset;
+ case O_ORD:
+ value = (double) *str_get(sarg[1]);
+ goto donumset;
+ case O_SLEEP:
+ tmps = str_get(sarg[1]);
+ time(&when);
+ if (!tmps || !*tmps)
+ sleep((32767<<16)+32767);
+ else
+ sleep((unsigned)atoi(tmps));
+ value = (double)when;
+ time(&when);
+ value = ((double)when) - value;
+ goto donumset;
+ case O_FLIP:
+ if (str_true(sarg[1])) {
+ str_numset(str,0.0);
+ anum = 2;
+ arg->arg_type = optype = O_FLOP;
+ arg[2].arg_flags &= ~AF_SPECIAL;
+ arg[1].arg_flags |= AF_SPECIAL;
+ argflags = arg[2].arg_flags;
+ argtype = arg[2].arg_type;
+ argptr = arg[2].arg_ptr;
+ goto re_eval;
+ }
+ str_set(str,"");
+ break;
+ case O_FLOP:
+ str_inc(str);
+ if (str_true(sarg[2])) {
+ arg->arg_type = O_FLIP;
+ arg[1].arg_flags &= ~AF_SPECIAL;
+ arg[2].arg_flags |= AF_SPECIAL;
+ str_cat(str,"E0");
+ }
+ break;
+ case O_FORK:
+ value = (double)fork();
+ goto donumset;
+ case O_WAIT:
+ ihand = signal(SIGINT, SIG_IGN);
+ qhand = signal(SIGQUIT, SIG_IGN);
+ value = (double)wait(&argflags);
+ signal(SIGINT, ihand);
+ signal(SIGQUIT, qhand);
+ statusvalue = (unsigned short)argflags;
+ goto donumset;
+ case O_SYSTEM:
+ while ((anum = vfork()) == -1) {
+ if (errno != EAGAIN) {
+ value = -1.0;
+ goto donumset;
+ }
+ sleep(5);
+ }
+ if (anum > 0) {
+ ihand = signal(SIGINT, SIG_IGN);
+ qhand = signal(SIGQUIT, SIG_IGN);
+ while ((argtype = wait(&argflags)) != anum && argtype != -1)
+ ;
+ signal(SIGINT, ihand);
+ signal(SIGQUIT, qhand);
+ statusvalue = (unsigned short)argflags;
+ if (argtype == -1)
+ value = -1.0;
+ else {
+ value = (double)((unsigned int)argflags & 0xffff);
+ }
+ goto donumset;
+ }
+ if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)do_aexec(arg);
+ else {
+ value = (double)do_exec(str_static(sarg[1]));
+ }
+ _exit(-1);
+ case O_EXEC:
+ if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)do_aexec(arg);
+ else {
+ value = (double)do_exec(str_static(sarg[1]));
+ }
+ goto donumset;
+ case O_HEX:
+ argtype = 4;
+ goto snarfnum;
+
+ case O_OCT:
+ argtype = 3;
+
+ snarfnum:
+ anum = 0;
+ tmps = str_get(sarg[1]);
+ for (;;) {
+ switch (*tmps) {
+ default:
+ goto out;
+ case '8': case '9':
+ if (argtype != 4)
+ goto out;
+ /* FALL THROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ anum <<= argtype;
+ anum += *tmps++ & 15;
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ if (argtype != 4)
+ goto out;
+ anum <<= 4;
+ anum += (*tmps++ & 7) + 9;
+ break;
+ case 'x':
+ argtype = 4;
+ tmps++;
+ break;
+ }
+ }
+ out:
+ value = (double)anum;
+ goto donumset;
+ case O_CHMOD:
+ case O_CHOWN:
+ case O_KILL:
+ case O_UNLINK:
+ case O_UTIME:
+ if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)apply(optype,arg,Null(STR**));
+ else {
+ sarg[2] = Nullstr;
+ value = (double)apply(optype,arg,sarg);
+ }
+ goto donumset;
+ case O_UMASK:
+ value = (double)umask((int)str_gnum(sarg[1]));
+ goto donumset;
+ case O_RENAME:
+ tmps = str_get(sarg[1]);
+#ifdef RENAME
+ value = (double)(rename(tmps,str_get(sarg[2])) >= 0);
+#else
+ tmps2 = str_get(sarg[2]);
+ if (euid || stat(tmps2,&statbuf) < 0 ||
+ (statbuf.st_mode & S_IFMT) != S_IFDIR )
+ UNLINK(tmps2); /* avoid unlinking a directory */
+ if (!(anum = link(tmps,tmps2)))
+ anum = UNLINK(tmps);
+ value = (double)(anum >= 0);
+#endif
+ goto donumset;
+ case O_LINK:
+ tmps = str_get(sarg[1]);
+ value = (double)(link(tmps,str_get(sarg[2])) >= 0);
+ goto donumset;
+ case O_UNSHIFT:
+ ary = arg[2].arg_ptr.arg_stab->stab_array;
+ if (arg[1].arg_flags & AF_SPECIAL)
+ do_unshift(arg,ary);
+ else {
+ str = str_new(0); /* must copy the STR */
+ str_sset(str,sarg[1]);
+ aunshift(ary,1);
+ astore(ary,0,str);
+ }
+ value = (double)(ary->ary_fill + 1);
+ break;
+ case O_DOFILE:
+ case O_EVAL:
+ str_sset(str,
+ do_eval(arg[1].arg_type != A_NULL ? sarg[1] : defstab->stab_val,
+ optype) );
+ STABSET(str);
+ break;
+
+ case O_FTRREAD:
+ argtype = 0;
+ anum = S_IREAD;
+ goto check_perm;
+ case O_FTRWRITE:
+ argtype = 0;
+ anum = S_IWRITE;
+ goto check_perm;
+ case O_FTREXEC:
+ argtype = 0;
+ anum = S_IEXEC;
+ goto check_perm;
+ case O_FTEREAD:
+ argtype = 1;
+ anum = S_IREAD;
+ goto check_perm;
+ case O_FTEWRITE:
+ argtype = 1;
+ anum = S_IWRITE;
+ goto check_perm;
+ case O_FTEEXEC:
+ argtype = 1;
+ anum = S_IEXEC;
+ check_perm:
+ str = &str_no;
+ if (mystat(arg,sarg[1]) < 0)
+ break;
+ if (cando(anum,argtype))
+ str = &str_yes;
+ break;
+
+ case O_FTIS:
+ if (mystat(arg,sarg[1]) >= 0)
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTEOWNED:
+ case O_FTROWNED:
+ if (mystat(arg,sarg[1]) >= 0 &&
+ statbuf.st_uid == (optype == O_FTEOWNED ? euid : uid) )
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTZERO:
+ if (mystat(arg,sarg[1]) >= 0 && !statbuf.st_size)
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTSIZE:
+ if (mystat(arg,sarg[1]) >= 0 && statbuf.st_size)
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+
+ case O_FTSOCK:
+#ifdef S_IFSOCK
+ anum = S_IFSOCK;
+ goto check_file_type;
+#else
+ str = &str_no;
+ break;
+#endif
+ case O_FTCHR:
+ anum = S_IFCHR;
+ goto check_file_type;
+ case O_FTBLK:
+ anum = S_IFBLK;
+ goto check_file_type;
+ case O_FTFILE:
+ anum = S_IFREG;
+ goto check_file_type;
+ case O_FTDIR:
+ anum = S_IFDIR;
+ check_file_type:
+ if (mystat(arg,sarg[1]) >= 0 &&
+ (statbuf.st_mode & S_IFMT) == anum )
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTPIPE:
+#ifdef S_IFIFO
+ anum = S_IFIFO;
+ goto check_file_type;
+#else
+ str = &str_no;
+ break;
+#endif
+ case O_FTLINK:
+#ifdef S_IFLNK
+ if (lstat(str_get(sarg[1]),&statbuf) >= 0 &&
+ (statbuf.st_mode & S_IFMT) == S_IFLNK )
+ str = &str_yes;
+ else
+#endif
+ str = &str_no;
+ break;
+ case O_SYMLINK:
+#ifdef SYMLINK
+ tmps = str_get(sarg[1]);
+ value = (double)(symlink(tmps,str_get(sarg[2])) >= 0);
+ goto donumset;
+#else
+ fatal("Unsupported function symlink()");
+#endif
+ case O_FTSUID:
+ anum = S_ISUID;
+ goto check_xid;
+ case O_FTSGID:
+ anum = S_ISGID;
+ goto check_xid;
+ case O_FTSVTX:
+ anum = S_ISVTX;
+ check_xid:
+ if (mystat(arg,sarg[1]) >= 0 && statbuf.st_mode & anum)
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTTTY:
+ if (arg[1].arg_flags & AF_SPECIAL) {
+ stab = arg[1].arg_ptr.arg_stab;
+ tmps = "";
+ }
+ else
+ stab = stabent(tmps = str_get(sarg[1]),FALSE);
+ if (stab && stab->stab_io && stab->stab_io->fp)
+ anum = fileno(stab->stab_io->fp);
+ else if (isdigit(*tmps))
+ anum = atoi(tmps);
+ else
+ anum = -1;
+ if (isatty(anum))
+ str = &str_yes;
+ else
+ str = &str_no;
+ break;
+ case O_FTTEXT:
+ case O_FTBINARY:
+ str = do_fttext(arg,sarg[1]);
+ break;
+ }
+ if (retary) {
+ sarg[1] = str;
+ maxsarg = sargoff + 1;
+ }
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str));
+ }
+#endif
+ goto freeargs;
+
+array_return:
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS ARRAY OF %d ARGS\n",opname[optype],maxsarg-sargoff);
+ }
+#endif
+ goto freeargs;
+
+donumset:
+ str_numset(str,value);
+ STABSET(str);
+ if (retary) {
+ sarg[1] = str;
+ maxsarg = sargoff + 1;
+ }
+#ifdef DEBUGGING
+ if (debug) {
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%f\"\n",opname[optype],value);
+ }
+#endif
+
+freeargs:
+ sarg -= sargoff;
+ if (sarg != quicksarg) {
+ if (retary) {
+ sarg[0] = &str_args;
+ str_numset(sarg[0], (double)(maxsarg));
+ sarg[maxsarg+1] = Nullstr;
+ *retary = sarg; /* up to them to free it */
+ }
+ else
+ safefree((char*)sarg);
+ }
+ return str;
+}
+
+int
+ingroup(gid,effective)
+int gid;
+int effective;
+{
+ if (gid == (effective ? getegid() : getgid()))
+ return TRUE;
+#ifdef GETGROUPS
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+ {
+ GIDTYPE gary[NGROUPS];
+ int anum;
+
+ anum = getgroups(NGROUPS,gary);
+ while (--anum >= 0)
+ if (gary[anum] == gid)
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+/* Do the permissions allow some operation? Assumes statbuf already set. */
+
+int
+cando(bit, effective)
+int bit;
+int effective;
+{
+ if ((effective ? euid : uid) == 0) { /* root is special */
+ if (bit == S_IEXEC) {
+ if (statbuf.st_mode & 0111 ||
+ (statbuf.st_mode & S_IFMT) == S_IFDIR )
+ return TRUE;
+ }
+ else
+ return TRUE; /* root reads and writes anything */
+ return FALSE;
+ }
+ if (statbuf.st_uid == (effective ? euid : uid) ) {
+ if (statbuf.st_mode & bit)
+ return TRUE; /* ok as "user" */
+ }
+ else if (ingroup((int)statbuf.st_gid,effective)) {
+ if (statbuf.st_mode & bit >> 3)
+ return TRUE; /* ok as "group" */
+ }
+ else if (statbuf.st_mode & bit >> 6)
+ return TRUE; /* ok as "other" */
+ return FALSE;
+}