summaryrefslogtreecommitdiff
path: root/arg.c
diff options
context:
space:
mode:
authorLarry Wall <lwall@jpl-devvax.jpl.nasa.gov>1987-12-18 00:00:00 +0000
committerLarry Wall <lwall@jpl-devvax.jpl.nasa.gov>1987-12-18 00:00:00 +0000
commit8d063cd8450e59ea1c611a2f4f5a21059a2804f1 (patch)
tree9bba34a99f94e47746e40ffe1419151779d8a4fc /arg.c
downloadperl-1.0.tar.gz
a "replacement" for awk and sedperl-1.0
[ Perl is kind of designed to make awk and sed semi-obsolete. This posting will include the first 10 patches after the main source. The following description is lifted from Larry's manpage. --r$ ] Perl is a interpreted language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information. It's also a good language for many system management tasks. The language is intended to be practical (easy to use, efficient, complete) rather than beautiful (tiny, elegant, minimal). It combines (in the author's opinion, anyway) some of the best features of C, sed, awk, and sh, so people familiar with those languages should have little difficulty with it. (Language historians will also note some vestiges of csh, Pascal, and even BASIC-PLUS.) Expression syntax corresponds quite closely to C expression syntax. If you have a problem that would ordinarily use sed or awk or sh, but it exceeds their capabilities or must run a little faster, and you don't want to write the silly thing in C, then perl may be for you. There are also translators to turn your sed and awk scripts into perl scripts.
Diffstat (limited to 'arg.c')
-rw-r--r--arg.c2111
1 files changed, 2111 insertions, 0 deletions
diff --git a/arg.c b/arg.c
new file mode 100644
index 0000000000..9561bb6665
--- /dev/null
+++ b/arg.c
@@ -0,0 +1,2111 @@
+/* $Header: arg.c,v 1.0 87/12/18 13:04:33 root Exp $
+ *
+ * $Log: arg.c,v $
+ * Revision 1.0 87/12/18 13:04:33 root
+ * Initial revision
+ *
+ */
+
+#include <signal.h>
+#include "handy.h"
+#include "EXTERN.h"
+#include "search.h"
+#include "util.h"
+#include "perl.h"
+
+ARG *debarg;
+
+bool
+do_match(s,arg)
+register char *s;
+register ARG *arg;
+{
+ register SPAT *spat = arg[2].arg_ptr.arg_spat;
+ register char *d;
+ register char *t;
+
+ if (!spat || !s)
+ fatal("panic: do_match\n");
+ if (spat->spat_flags & SPAT_USED) {
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("2.SPAT USED\n");
+#endif
+ return FALSE;
+ }
+ if (spat->spat_runtime) {
+ t = str_get(eval(spat->spat_runtime,Null(STR***)));
+#ifdef DEBUGGING
+ if (debug & 8)
+ deb("2.SPAT /%s/\n",t);
+#endif
+ if (d = compile(&spat->spat_compex,t,TRUE,FALSE)) {
+#ifdef DEBUGGING
+ deb("/%s/: %s\n", t, d);
+#endif
+ return FALSE;
+ }
+ if (spat->spat_compex.complen <= 1 && curspat)
+ spat = curspat;
+ if (execute(&spat->spat_compex, s, TRUE, 0)) {
+ if (spat->spat_compex.numsubs)
+ curspat = spat;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else {
+#ifdef DEBUGGING
+ if (debug & 8) {
+ char ch;
+
+ if (spat->spat_flags & SPAT_USE_ONCE)
+ ch = '?';
+ else
+ ch = '/';
+ deb("2.SPAT %c%s%c\n",ch,spat->spat_compex.precomp,ch);
+ }
+#endif
+ if (spat->spat_compex.complen <= 1 && curspat)
+ spat = curspat;
+ if (spat->spat_first) {
+ if (spat->spat_flags & SPAT_SCANFIRST) {
+ str_free(spat->spat_first);
+ spat->spat_first = Nullstr; /* disable optimization */
+ }
+ else if (*spat->spat_first->str_ptr != *s ||
+ strnNE(spat->spat_first->str_ptr, s, spat->spat_flen) )
+ return FALSE;
+ }
+ if (execute(&spat->spat_compex, s, TRUE, 0)) {
+ if (spat->spat_compex.numsubs)
+ curspat = spat;
+ if (spat->spat_flags & SPAT_USE_ONCE)
+ spat->spat_flags |= SPAT_USED;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ /*NOTREACHED*/
+}
+
+int
+do_subst(str,arg)
+STR *str;
+register ARG *arg;
+{
+ register SPAT *spat;
+ register STR *dstr;
+ register char *s;
+ register char *m;
+
+ spat = arg[2].arg_ptr.arg_spat;
+ s = str_get(str);
+ if (!spat || !s)
+ fatal("panic: do_subst\n");
+ else if (spat->spat_runtime) {
+ char *d;
+
+ m = str_get(eval(spat->spat_runtime,Null(STR***)));
+ if (d = compile(&spat->spat_compex,m,TRUE,FALSE)) {
+#ifdef DEBUGGING
+ deb("/%s/: %s\n", m, d);
+#endif
+ return 0;
+ }
+ }
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.SPAT /%s/\n",spat->spat_compex.precomp);
+ }
+#endif
+ if (spat->spat_compex.complen <= 1 && curspat)
+ spat = curspat;
+ if (spat->spat_first) {
+ if (spat->spat_flags & SPAT_SCANFIRST) {
+ str_free(spat->spat_first);
+ spat->spat_first = Nullstr; /* disable optimization */
+ }
+ else if (*spat->spat_first->str_ptr != *s ||
+ strnNE(spat->spat_first->str_ptr, s, spat->spat_flen) )
+ return 0;
+ }
+ if (m = execute(&spat->spat_compex, s, TRUE, 1)) {
+ int iters = 0;
+
+ dstr = str_new(str_len(str));
+ if (spat->spat_compex.numsubs)
+ curspat = spat;
+ do {
+ if (iters++ > 10000)
+ fatal("Substitution loop?\n");
+ if (spat->spat_compex.numsubs)
+ s = spat->spat_compex.subbase;
+ str_ncat(dstr,s,m-s);
+ s = spat->spat_compex.subend[0];
+ str_scat(dstr,eval(spat->spat_repl,Null(STR***)));
+ if (spat->spat_flags & SPAT_USE_ONCE)
+ break;
+ } while (m = execute(&spat->spat_compex, s, FALSE, 1));
+ str_cat(dstr,s);
+ str_replace(str,dstr);
+ STABSET(str);
+ return iters;
+ }
+ return 0;
+}
+
+int
+do_trans(str,arg)
+STR *str;
+register ARG *arg;
+{
+ register char *tbl;
+ register char *s;
+ register int matches = 0;
+ register int ch;
+
+ tbl = arg[2].arg_ptr.arg_cval;
+ s = str_get(str);
+ if (!tbl || !s)
+ fatal("panic: do_trans\n");
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.TBL\n");
+ }
+#endif
+ while (*s) {
+ if (ch = tbl[*s & 0377]) {
+ matches++;
+ *s = ch;
+ }
+ s++;
+ }
+ STABSET(str);
+ return matches;
+}
+
+int
+do_split(s,spat,retary)
+register char *s;
+register SPAT *spat;
+STR ***retary;
+{
+ register STR *dstr;
+ register char *m;
+ register ARRAY *ary;
+ static ARRAY *myarray = Null(ARRAY*);
+ int iters = 0;
+ STR **sarg;
+ register char *e;
+ int i;
+
+ if (!spat || !s)
+ fatal("panic: do_split\n");
+ else if (spat->spat_runtime) {
+ char *d;
+
+ m = str_get(eval(spat->spat_runtime,Null(STR***)));
+ if (d = compile(&spat->spat_compex,m,TRUE,FALSE)) {
+#ifdef DEBUGGING
+ deb("/%s/: %s\n", m, d);
+#endif
+ return FALSE;
+ }
+ }
+#ifdef DEBUGGING
+ if (debug & 8) {
+ deb("2.SPAT /%s/\n",spat->spat_compex.precomp);
+ }
+#endif
+ if (retary)
+ ary = myarray;
+ else
+ ary = spat->spat_repl[1].arg_ptr.arg_stab->stab_array;
+ if (!ary)
+ myarray = ary = anew();
+ ary->ary_fill = -1;
+ while (*s && (m = execute(&spat->spat_compex, s, (iters == 0), 1))) {
+ if (spat->spat_compex.numsubs)
+ s = spat->spat_compex.subbase;
+ dstr = str_new(m-s);
+ str_nset(dstr,s,m-s);
+ astore(ary, iters++, dstr);
+ if (iters > 10000)
+ fatal("Substitution loop?\n");
+ s = spat->spat_compex.subend[0];
+ }
+ if (*s) { /* ignore field after final "whitespace" */
+ dstr = str_new(0); /* if they interpolate, it's null anyway */
+ str_set(dstr,s);
+ astore(ary, iters++, dstr);
+ }
+ else {
+ while (iters > 0 && !*str_get(afetch(ary,iters-1)))
+ iters--;
+ }
+ if (retary) {
+ sarg = (STR**)safemalloc((iters+2)*sizeof(STR*));
+
+ sarg[0] = Nullstr;
+ sarg[iters+1] = Nullstr;
+ for (i = 1; i <= iters; i++)
+ sarg[i] = afetch(ary,i-1);
+ *retary = sarg;
+ }
+ return iters;
+}
+
+void
+do_join(arg,delim,str)
+register ARG *arg;
+register char *delim;
+register STR *str;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+
+ (void)eval(arg[2].arg_ptr.arg_arg,&tmpary);
+ elem = tmpary+1;
+ if (*elem)
+ str_sset(str,*elem++);
+ for (; *elem; elem++) {
+ str_cat(str,delim);
+ str_scat(str,*elem);
+ }
+ STABSET(str);
+ safefree((char*)tmpary);
+}
+
+bool
+do_open(stab,name)
+STAB *stab;
+register char *name;
+{
+ FILE *fp;
+ int len = strlen(name);
+ register STIO *stio = stab->stab_io;
+
+ while (len && isspace(name[len-1]))
+ name[--len] = '\0';
+ if (!stio)
+ stio = stab->stab_io = stio_new();
+ if (stio->fp) {
+ if (stio->type == '|')
+ pclose(stio->fp);
+ else if (stio->type != '-')
+ fclose(stio->fp);
+ stio->fp = Nullfp;
+ }
+ stio->type = *name;
+ if (*name == '|') {
+ for (name++; isspace(*name); name++) ;
+ fp = popen(name,"w");
+ }
+ else if (*name == '>' && name[1] == '>') {
+ for (name += 2; isspace(*name); name++) ;
+ fp = fopen(name,"a");
+ }
+ else if (*name == '>') {
+ for (name++; isspace(*name); name++) ;
+ if (strEQ(name,"-")) {
+ fp = stdout;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,"w");
+ }
+ else {
+ if (*name == '<') {
+ for (name++; isspace(*name); name++) ;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,"r");
+ }
+ else if (name[len-1] == '|') {
+ name[--len] = '\0';
+ while (len && isspace(name[len-1]))
+ name[--len] = '\0';
+ for (; isspace(*name); name++) ;
+ fp = popen(name,"r");
+ stio->type = '|';
+ }
+ else {
+ stio->type = '<';
+ for (; isspace(*name); name++) ;
+ if (strEQ(name,"-")) {
+ fp = stdin;
+ stio->type = '-';
+ }
+ else
+ fp = fopen(name,"r");
+ }
+ }
+ if (!fp)
+ return FALSE;
+ if (stio->type != '|' && stio->type != '-') {
+ if (fstat(fileno(fp),&statbuf) < 0) {
+ fclose(fp);
+ return FALSE;
+ }
+ if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
+ (statbuf.st_mode & S_IFMT) != S_IFCHR) {
+ fclose(fp);
+ return FALSE;
+ }
+ }
+ stio->fp = fp;
+ return TRUE;
+}
+
+FILE *
+nextargv(stab)
+register STAB *stab;
+{
+ register STR *str;
+ char *oldname;
+
+ while (alen(stab->stab_array) >= 0L) {
+ str = ashift(stab->stab_array);
+ str_sset(stab->stab_val,str);
+ STABSET(stab->stab_val);
+ oldname = str_get(stab->stab_val);
+ if (do_open(stab,oldname)) {
+ if (inplace) {
+ if (*inplace) {
+ str_cat(str,inplace);
+#ifdef RENAME
+ rename(oldname,str->str_ptr);
+#else
+ UNLINK(str->str_ptr);
+ link(oldname,str->str_ptr);
+ UNLINK(oldname);
+#endif
+ }
+ sprintf(tokenbuf,">%s",oldname);
+ do_open(argvoutstab,tokenbuf);
+ defoutstab = argvoutstab;
+ }
+ str_free(str);
+ return stab->stab_io->fp;
+ }
+ else
+ fprintf(stderr,"Can't open %s\n",str_get(str));
+ str_free(str);
+ }
+ if (inplace) {
+ do_close(argvoutstab,FALSE);
+ defoutstab = stabent("stdout",TRUE);
+ }
+ return Nullfp;
+}
+
+bool
+do_close(stab,explicit)
+STAB *stab;
+bool explicit;
+{
+ bool retval = FALSE;
+ register STIO *stio = stab->stab_io;
+
+ if (!stio) /* never opened */
+ return FALSE;
+ if (stio->fp) {
+ if (stio->type == '|')
+ retval = (pclose(stio->fp) >= 0);
+ else if (stio->type == '-')
+ retval = TRUE;
+ else
+ retval = (fclose(stio->fp) != EOF);
+ stio->fp = Nullfp;
+ }
+ if (explicit)
+ stio->lines = 0;
+ stio->type = ' ';
+ return retval;
+}
+
+bool
+do_eof(stab)
+STAB *stab;
+{
+ register STIO *stio;
+ int ch;
+
+ if (!stab)
+ return TRUE;
+
+ stio = stab->stab_io;
+ if (!stio)
+ return TRUE;
+
+ while (stio->fp) {
+
+#ifdef STDSTDIO /* (the code works without this) */
+ if (stio->fp->_cnt) /* cheat a little, since */
+ return FALSE; /* this is the most usual case */
+#endif
+
+ ch = getc(stio->fp);
+ if (ch != EOF) {
+ ungetc(ch, stio->fp);
+ return FALSE;
+ }
+ if (stio->flags & IOF_ARGV) { /* not necessarily a real EOF yet? */
+ if (!nextargv(stab)) /* get another fp handy */
+ return TRUE;
+ }
+ else
+ return TRUE; /* normal fp, definitely end of file */
+ }
+ return TRUE;
+}
+
+long
+do_tell(stab)
+STAB *stab;
+{
+ register STIO *stio;
+ int ch;
+
+ if (!stab)
+ return -1L;
+
+ stio = stab->stab_io;
+ if (!stio || !stio->fp)
+ return -1L;
+
+ return ftell(stio->fp);
+}
+
+bool
+do_seek(stab, pos, whence)
+STAB *stab;
+long pos;
+int whence;
+{
+ register STIO *stio;
+
+ if (!stab)
+ return FALSE;
+
+ stio = stab->stab_io;
+ if (!stio || !stio->fp)
+ return FALSE;
+
+ return fseek(stio->fp, pos, whence) >= 0;
+}
+
+do_stat(arg,sarg,retary)
+register ARG *arg;
+register STR **sarg;
+STR ***retary;
+{
+ register ARRAY *ary;
+ static ARRAY *myarray = Null(ARRAY*);
+ int max = 13;
+ register int i;
+
+ ary = myarray;
+ if (!ary)
+ myarray = ary = anew();
+ ary->ary_fill = -1;
+ if (arg[1].arg_type == A_LVAL) {
+ tmpstab = arg[1].arg_ptr.arg_stab;
+ if (!tmpstab->stab_io ||
+ fstat(fileno(tmpstab->stab_io->fp),&statbuf) < 0) {
+ max = 0;
+ }
+ }
+ else
+ if (stat(str_get(sarg[1]),&statbuf) < 0)
+ max = 0;
+
+ if (retary) {
+ if (max) {
+ apush(ary,str_nmake((double)statbuf.st_dev));
+ apush(ary,str_nmake((double)statbuf.st_ino));
+ apush(ary,str_nmake((double)statbuf.st_mode));
+ apush(ary,str_nmake((double)statbuf.st_nlink));
+ apush(ary,str_nmake((double)statbuf.st_uid));
+ apush(ary,str_nmake((double)statbuf.st_gid));
+ apush(ary,str_nmake((double)statbuf.st_rdev));
+ apush(ary,str_nmake((double)statbuf.st_size));
+ apush(ary,str_nmake((double)statbuf.st_atime));
+ apush(ary,str_nmake((double)statbuf.st_mtime));
+ apush(ary,str_nmake((double)statbuf.st_ctime));
+ apush(ary,str_nmake((double)statbuf.st_blksize));
+ apush(ary,str_nmake((double)statbuf.st_blocks));
+ }
+ sarg = (STR**)safemalloc((max+2)*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[max+1] = Nullstr;
+ for (i = 1; i <= max; i++)
+ sarg[i] = afetch(ary,i-1);
+ *retary = sarg;
+ }
+ return max;
+}
+
+do_tms(retary)
+STR ***retary;
+{
+ register ARRAY *ary;
+ static ARRAY *myarray = Null(ARRAY*);
+ register STR **sarg;
+ int max = 4;
+ register int i;
+
+ ary = myarray;
+ if (!ary)
+ myarray = ary = anew();
+ ary->ary_fill = -1;
+ if (times(&timesbuf) < 0)
+ max = 0;
+
+ if (retary) {
+ if (max) {
+ apush(ary,str_nmake(((double)timesbuf.tms_utime)/60.0));
+ apush(ary,str_nmake(((double)timesbuf.tms_stime)/60.0));
+ apush(ary,str_nmake(((double)timesbuf.tms_cutime)/60.0));
+ apush(ary,str_nmake(((double)timesbuf.tms_cstime)/60.0));
+ }
+ sarg = (STR**)safemalloc((max+2)*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[max+1] = Nullstr;
+ for (i = 1; i <= max; i++)
+ sarg[i] = afetch(ary,i-1);
+ *retary = sarg;
+ }
+ return max;
+}
+
+do_time(tmbuf,retary)
+struct tm *tmbuf;
+STR ***retary;
+{
+ register ARRAY *ary;
+ static ARRAY *myarray = Null(ARRAY*);
+ register STR **sarg;
+ int max = 9;
+ register int i;
+ STR *str;
+
+ ary = myarray;
+ if (!ary)
+ myarray = ary = anew();
+ ary->ary_fill = -1;
+ if (!tmbuf)
+ max = 0;
+
+ if (retary) {
+ if (max) {
+ apush(ary,str_nmake((double)tmbuf->tm_sec));
+ apush(ary,str_nmake((double)tmbuf->tm_min));
+ apush(ary,str_nmake((double)tmbuf->tm_hour));
+ apush(ary,str_nmake((double)tmbuf->tm_mday));
+ apush(ary,str_nmake((double)tmbuf->tm_mon));
+ apush(ary,str_nmake((double)tmbuf->tm_year));
+ apush(ary,str_nmake((double)tmbuf->tm_wday));
+ apush(ary,str_nmake((double)tmbuf->tm_yday));
+ apush(ary,str_nmake((double)tmbuf->tm_isdst));
+ }
+ sarg = (STR**)safemalloc((max+2)*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[max+1] = Nullstr;
+ for (i = 1; i <= max; i++)
+ sarg[i] = afetch(ary,i-1);
+ *retary = sarg;
+ }
+ return max;
+}
+
+void
+do_sprintf(str,len,sarg)
+register STR *str;
+register int len;
+register STR **sarg;
+{
+ register char *s;
+ register char *t;
+ bool dolong;
+ char ch;
+
+ str_set(str,"");
+ len--; /* don't count pattern string */
+ sarg++;
+ for (s = str_get(*(sarg++)); *sarg && *s && len; len--) {
+ dolong = FALSE;
+ for (t = s; *t && *t != '%'; t++) ;
+ if (!*t)
+ break; /* not enough % patterns, oh well */
+ for (t++; *sarg && *t && t != s; t++) {
+ switch (*t) {
+ case '\0':
+ break;
+ case '%':
+ ch = *(++t);
+ *t = '\0';
+ sprintf(buf,s);
+ s = t;
+ *(t--) = ch;
+ break;
+ case 'l':
+ dolong = TRUE;
+ break;
+ case 'D': case 'X': case 'O':
+ dolong = TRUE;
+ /* FALL THROUGH */
+ case 'd': case 'x': case 'o': case 'c':
+ ch = *(++t);
+ *t = '\0';
+ if (dolong)
+ sprintf(buf,s,(long)str_gnum(*(sarg++)));
+ else
+ sprintf(buf,s,(int)str_gnum(*(sarg++)));
+ s = t;
+ *(t--) = ch;
+ break;
+ case 'E': case 'e': case 'f': case 'G': case 'g':
+ ch = *(++t);
+ *t = '\0';
+ sprintf(buf,s,str_gnum(*(sarg++)));
+ s = t;
+ *(t--) = ch;
+ break;
+ case 's':
+ ch = *(++t);
+ *t = '\0';
+ sprintf(buf,s,str_get(*(sarg++)));
+ s = t;
+ *(t--) = ch;
+ break;
+ }
+ }
+ str_cat(str,buf);
+ }
+ if (*s)
+ str_cat(str,s);
+ STABSET(str);
+}
+
+bool
+do_print(s,fp)
+char *s;
+FILE *fp;
+{
+ if (!fp || !s)
+ return FALSE;
+ fputs(s,fp);
+ return TRUE;
+}
+
+bool
+do_aprint(arg,fp)
+register ARG *arg;
+register FILE *fp;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+ register bool retval;
+ double value;
+
+ (void)eval(arg[1].arg_ptr.arg_arg,&tmpary);
+ if (arg->arg_type == O_PRTF) {
+ do_sprintf(arg->arg_ptr.arg_str,32767,tmpary);
+ retval = do_print(str_get(arg->arg_ptr.arg_str),fp);
+ }
+ else {
+ retval = FALSE;
+ for (elem = tmpary+1; *elem; elem++) {
+ if (retval && ofs)
+ do_print(ofs, fp);
+ if (ofmt && fp) {
+ if ((*elem)->str_nok || str_gnum(*elem) != 0.0)
+ fprintf(fp, ofmt, str_gnum(*elem));
+ retval = TRUE;
+ }
+ else
+ retval = do_print(str_get(*elem), fp);
+ if (!retval)
+ break;
+ }
+ if (ors)
+ retval = do_print(ors, fp);
+ }
+ safefree((char*)tmpary);
+ return retval;
+}
+
+bool
+do_aexec(arg)
+register ARG *arg;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+ register char **a;
+ register int i;
+ char **argv;
+
+ (void)eval(arg[1].arg_ptr.arg_arg,&tmpary);
+ i = 0;
+ for (elem = tmpary+1; *elem; elem++)
+ i++;
+ if (i) {
+ argv = (char**)safemalloc((i+1)*sizeof(char*));
+ a = argv;
+ for (elem = tmpary+1; *elem; elem++) {
+ *a++ = str_get(*elem);
+ }
+ *a = Nullch;
+ execvp(argv[0],argv);
+ safefree((char*)argv);
+ }
+ safefree((char*)tmpary);
+ return FALSE;
+}
+
+bool
+do_exec(cmd)
+char *cmd;
+{
+ STR **tmpary; /* must not be register */
+ register char **a;
+ register char *s;
+ char **argv;
+
+ /* see if there are shell metacharacters in it */
+
+ for (s = cmd; *s; s++) {
+ if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`",*s)) {
+ execl("/bin/sh","sh","-c",cmd,0);
+ return FALSE;
+ }
+ }
+ argv = (char**)safemalloc(((s - cmd) / 2 + 2)*sizeof(char*));
+
+ a = argv;
+ for (s = cmd; *s;) {
+ while (isspace(*s)) s++;
+ if (*s)
+ *(a++) = s;
+ while (*s && !isspace(*s)) s++;
+ if (*s)
+ *s++ = '\0';
+ }
+ *a = Nullch;
+ if (argv[0])
+ execvp(argv[0],argv);
+ safefree((char*)argv);
+ return FALSE;
+}
+
+STR *
+do_push(arg,ary)
+register ARG *arg;
+register ARRAY *ary;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+ register STR *str = &str_no;
+
+ (void)eval(arg[1].arg_ptr.arg_arg,&tmpary);
+ for (elem = tmpary+1; *elem; elem++) {
+ str = str_new(0);
+ str_sset(str,*elem);
+ apush(ary,str);
+ }
+ safefree((char*)tmpary);
+ return str;
+}
+
+do_unshift(arg,ary)
+register ARG *arg;
+register ARRAY *ary;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+ register STR *str = &str_no;
+ register int i;
+
+ (void)eval(arg[1].arg_ptr.arg_arg,&tmpary);
+ i = 0;
+ for (elem = tmpary+1; *elem; elem++)
+ i++;
+ aunshift(ary,i);
+ i = 0;
+ for (elem = tmpary+1; *elem; elem++) {
+ str = str_new(0);
+ str_sset(str,*elem);
+ astore(ary,i++,str);
+ }
+ safefree((char*)tmpary);
+}
+
+apply(type,arg,sarg)
+int type;
+register ARG *arg;
+STR **sarg;
+{
+ STR **tmpary; /* must not be register */
+ register STR **elem;
+ register int i;
+ register int val;
+ register int val2;
+
+ if (sarg)
+ tmpary = sarg;
+ else
+ (void)eval(arg[1].arg_ptr.arg_arg,&tmpary);
+ i = 0;
+ for (elem = tmpary+1; *elem; elem++)
+ i++;
+ switch (type) {
+ case O_CHMOD:
+ if (--i > 0) {
+ val = (int)str_gnum(tmpary[1]);
+ for (elem = tmpary+2; *elem; elem++)
+ if (chmod(str_get(*elem),val))
+ i--;
+ }
+ break;
+ case O_CHOWN:
+ if (i > 2) {
+ i -= 2;
+ val = (int)str_gnum(tmpary[1]);
+ val2 = (int)str_gnum(tmpary[2]);
+ for (elem = tmpary+3; *elem; elem++)
+ if (chown(str_get(*elem),val,val2))
+ i--;
+ }
+ else
+ i = 0;
+ break;
+ case O_KILL:
+ if (--i > 0) {
+ val = (int)str_gnum(tmpary[1]);
+ if (val < 0)
+ val = -val;
+ for (elem = tmpary+2; *elem; elem++)
+ if (kill(atoi(str_get(*elem)),val))
+ i--;
+ }
+ break;
+ case O_UNLINK:
+ for (elem = tmpary+1; *elem; elem++)
+ if (UNLINK(str_get(*elem)))
+ i--;
+ break;
+ }
+ if (!sarg)
+ safefree((char*)tmpary);
+ return i;
+}
+
+STR *
+do_subr(arg,sarg)
+register ARG *arg;
+register char **sarg;
+{
+ ARRAY *savearray;
+ STR *str;
+
+ savearray = defstab->stab_array;
+ defstab->stab_array = anew();
+ if (arg[1].arg_flags & AF_SPECIAL)
+ (void)do_push(arg,defstab->stab_array);
+ else if (arg[1].arg_type != A_NULL) {
+ str = str_new(0);
+ str_sset(str,sarg[1]);
+ apush(defstab->stab_array,str);
+ }
+ str = cmd_exec(arg[2].arg_ptr.arg_stab->stab_sub);
+ afree(defstab->stab_array); /* put back old $_[] */
+ defstab->stab_array = savearray;
+ return str;
+}
+
+void
+do_assign(retstr,arg)
+STR *retstr;
+register ARG *arg;
+{
+ STR **tmpary; /* must not be register */
+ register ARG *larg = arg[1].arg_ptr.arg_arg;
+ register STR **elem;
+ register STR *str;
+ register ARRAY *ary;
+ register int i;
+ register int lasti;
+ char *s;
+
+ (void)eval(arg[2].arg_ptr.arg_arg,&tmpary);
+
+ if (arg->arg_flags & AF_COMMON) {
+ if (*(tmpary+1)) {
+ for (elem=tmpary+2; *elem; elem++) {
+ *elem = str_static(*elem);
+ }
+ }
+ }
+ if (larg->arg_type == O_LIST) {
+ lasti = larg->arg_len;
+ for (i=1,elem=tmpary+1; i <= lasti; i++) {
+ if (*elem)
+ s = str_get(*(elem++));
+ else
+ s = "";
+ switch (larg[i].arg_type) {
+ case A_STAB:
+ case A_LVAL:
+ str = STAB_STR(larg[i].arg_ptr.arg_stab);
+ break;
+ case A_LEXPR:
+ str = eval(larg[i].arg_ptr.arg_arg,Null(STR***));
+ break;
+ }
+ str_set(str,s);
+ STABSET(str);
+ }
+ i = elem - tmpary - 1;
+ }
+ else { /* should be an array name */
+ ary = larg[1].arg_ptr.arg_stab->stab_array;
+ for (i=0,elem=tmpary+1; *elem; i++) {
+ str = str_new(0);
+ if (*elem)
+ str_sset(str,*(elem++));
+ astore(ary,i,str);
+ }
+ ary->ary_fill = i - 1; /* they can get the extra ones back by */
+ } /* setting an element larger than old fill */
+ str_numset(retstr,(double)i);
+ STABSET(retstr);
+ safefree((char*)tmpary);
+}
+
+int
+do_kv(hash,kv,sarg,retary)
+HASH *hash;
+int kv;
+register STR **sarg;
+STR ***retary;
+{
+ register ARRAY *ary;
+ int max = 0;
+ int i;
+ static ARRAY *myarray = Null(ARRAY*);
+ register HENT *entry;
+
+ ary = myarray;
+ if (!ary)
+ myarray = ary = anew();
+ ary->ary_fill = -1;
+
+ hiterinit(hash);
+ while (entry = hiternext(hash)) {
+ max++;
+ if (kv == O_KEYS)
+ apush(ary,str_make(hiterkey(entry)));
+ else
+ apush(ary,str_make(str_get(hiterval(entry))));
+ }
+ if (retary) { /* array wanted */
+ sarg = (STR**)saferealloc((char*)sarg,(max+2)*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[max+1] = Nullstr;
+ for (i = 1; i <= max; i++)
+ sarg[i] = afetch(ary,i-1);
+ *retary = sarg;
+ }
+ return max;
+}
+
+STR *
+do_each(hash,sarg,retary)
+HASH *hash;
+register STR **sarg;
+STR ***retary;
+{
+ static STR *mystr = Nullstr;
+ STR *retstr;
+ HENT *entry = hiternext(hash);
+
+ if (mystr) {
+ str_free(mystr);
+ mystr = Nullstr;
+ }
+
+ if (retary) { /* array wanted */
+ if (entry) {
+ sarg = (STR**)saferealloc((char*)sarg,4*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[3] = Nullstr;
+ sarg[1] = mystr = str_make(hiterkey(entry));
+ retstr = sarg[2] = hiterval(entry);
+ *retary = sarg;
+ }
+ else {
+ sarg = (STR**)saferealloc((char*)sarg,2*sizeof(STR*));
+ sarg[0] = Nullstr;
+ sarg[1] = retstr = Nullstr;
+ *retary = sarg;
+ }
+ }
+ else
+ retstr = hiterval(entry);
+
+ return retstr;
+}
+
+init_eval()
+{
+ register int i;
+
+#define A(e1,e2,e3) (e1+(e2<<1)+(e3<<2))
+ opargs[O_ITEM] = A(1,0,0);
+ opargs[O_ITEM2] = A(0,0,0);
+ opargs[O_ITEM3] = A(0,0,0);
+ opargs[O_CONCAT] = A(1,1,0);
+ opargs[O_MATCH] = A(1,0,0);
+ opargs[O_NMATCH] = A(1,0,0);
+ opargs[O_SUBST] = A(1,0,0);
+ opargs[O_NSUBST] = A(1,0,0);
+ opargs[O_ASSIGN] = A(1,1,0);
+ opargs[O_MULTIPLY] = A(1,1,0);
+ opargs[O_DIVIDE] = A(1,1,0);
+ opargs[O_MODULO] = A(1,1,0);
+ opargs[O_ADD] = A(1,1,0);
+ opargs[O_SUBTRACT] = A(1,1,0);
+ opargs[O_LEFT_SHIFT] = A(1,1,0);
+ opargs[O_RIGHT_SHIFT] = A(1,1,0);
+ opargs[O_LT] = A(1,1,0);
+ opargs[O_GT] = A(1,1,0);
+ opargs[O_LE] = A(1,1,0);
+ opargs[O_GE] = A(1,1,0);
+ opargs[O_EQ] = A(1,1,0);
+ opargs[O_NE] = A(1,1,0);
+ opargs[O_BIT_AND] = A(1,1,0);
+ opargs[O_XOR] = A(1,1,0);
+ opargs[O_BIT_OR] = A(1,1,0);
+ opargs[O_AND] = A(1,0,0); /* don't eval arg 2 (yet) */
+ opargs[O_OR] = A(1,0,0); /* don't eval arg 2 (yet) */
+ opargs[O_COND_EXPR] = A(1,0,0); /* don't eval args 2 or 3 */
+ opargs[O_COMMA] = A(1,1,0);
+ opargs[O_NEGATE] = A(1,0,0);
+ opargs[O_NOT] = A(1,0,0);
+ opargs[O_COMPLEMENT] = A(1,0,0);
+ opargs[O_WRITE] = A(1,0,0);
+ opargs[O_OPEN] = A(1,1,0);
+ opargs[O_TRANS] = A(1,0,0);
+ opargs[O_NTRANS] = A(1,0,0);
+ opargs[O_CLOSE] = A(0,0,0);
+ opargs[O_ARRAY] = A(1,0,0);
+ opargs[O_HASH] = A(1,0,0);
+ opargs[O_LARRAY] = A(1,0,0);
+ opargs[O_LHASH] = A(1,0,0);
+ opargs[O_PUSH] = A(1,0,0);
+ opargs[O_POP] = A(0,0,0);
+ opargs[O_SHIFT] = A(0,0,0);
+ opargs[O_SPLIT] = A(1,0,0);
+ opargs[O_LENGTH] = A(1,0,0);
+ opargs[O_SPRINTF] = A(1,0,0);
+ opargs[O_SUBSTR] = A(1,1,1);
+ opargs[O_JOIN] = A(1,0,0);
+ opargs[O_SLT] = A(1,1,0);
+ opargs[O_SGT] = A(1,1,0);
+ opargs[O_SLE] = A(1,1,0);
+ opargs[O_SGE] = A(1,1,0);
+ opargs[O_SEQ] = A(1,1,0);
+ opargs[O_SNE] = A(1,1,0);
+ opargs[O_SUBR] = A(1,0,0);
+ opargs[O_PRINT] = A(1,0,0);
+ opargs[O_CHDIR] = A(1,0,0);
+ opargs[O_DIE] = A(1,0,0);
+ opargs[O_EXIT] = A(1,0,0);
+ opargs[O_RESET] = A(1,0,0);
+ opargs[O_LIST] = A(0,0,0);
+ opargs[O_EOF] = A(0,0,0);
+ opargs[O_TELL] = A(0,0,0);
+ opargs[O_SEEK] = A(0,1,1);
+ opargs[O_LAST] = A(1,0,0);
+ opargs[O_NEXT] = A(1,0,0);
+ opargs[O_REDO] = A(1,0,0);
+ opargs[O_GOTO] = A(1,0,0);
+ opargs[O_INDEX] = A(1,1,0);
+ opargs[O_TIME] = A(0,0,0);
+ opargs[O_TMS] = A(0,0,0);
+ opargs[O_LOCALTIME] = A(1,0,0);
+ opargs[O_GMTIME] = A(1,0,0);
+ opargs[O_STAT] = A(1,0,0);
+ opargs[O_CRYPT] = A(1,1,0);
+ opargs[O_EXP] = A(1,0,0);
+ opargs[O_LOG] = A(1,0,0);
+ opargs[O_SQRT] = A(1,0,0);
+ opargs[O_INT] = A(1,0,0);
+ opargs[O_PRTF] = A(1,0,0);
+ opargs[O_ORD] = A(1,0,0);
+ opargs[O_SLEEP] = A(1,0,0);
+ opargs[O_FLIP] = A(1,0,0);
+ opargs[O_FLOP] = A(0,1,0);
+ opargs[O_KEYS] = A(0,0,0);
+ opargs[O_VALUES] = A(0,0,0);
+ opargs[O_EACH] = A(0,0,0);
+ opargs[O_CHOP] = A(1,0,0);
+ opargs[O_FORK] = A(1,0,0);
+ opargs[O_EXEC] = A(1,0,0);
+ opargs[O_SYSTEM] = A(1,0,0);
+ opargs[O_OCT] = A(1,0,0);
+ opargs[O_HEX] = A(1,0,0);
+ opargs[O_CHMOD] = A(1,0,0);
+ opargs[O_CHOWN] = A(1,0,0);
+ opargs[O_KILL] = A(1,0,0);
+ opargs[O_RENAME] = A(1,1,0);
+ opargs[O_UNLINK] = A(1,0,0);
+ opargs[O_UMASK] = A(1,0,0);
+ opargs[O_UNSHIFT] = A(1,0,0);
+ opargs[O_LINK] = A(1,1,0);
+ opargs[O_REPEAT] = A(1,1,0);
+}
+
+static int (*ihand)();
+static int (*qhand)();
+
+STR *
+eval(arg,retary)
+register ARG *arg;
+STR ***retary; /* where to return an array to, null if nowhere */
+{
+ register STR *str;
+ register int anum;
+ register int optype;
+ register int maxarg;
+ double value;
+ STR *quicksarg[5];
+ register STR **sarg = quicksarg;
+ register char *tmps;
+ char *tmps2;
+ int argflags;
+ long tmplong;
+ 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;
+ maxarg = arg->arg_len;
+ if (maxarg > 3 || retary) {
+ sarg = (STR **)safemalloc((maxarg+2) * sizeof(STR*));
+ }
+#ifdef DEBUGGING
+ 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;
+ re_eval:
+ switch (arg[anum].arg_type) {
+ 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
+ sarg[anum] = eval(arg[anum].arg_ptr.arg_arg, Null(STR***));
+ break;
+ case A_CMD:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ tmps = "CMD";
+ deb("%d.CMD (%lx) =>\n",anum,arg[anum].arg_ptr.arg_cmd);
+ }
+#endif
+ sarg[anum] = cmd_exec(arg[anum].arg_ptr.arg_cmd);
+ break;
+ case A_STAB:
+ sarg[anum] = STAB_STR(arg[anum].arg_ptr.arg_stab);
+#ifdef DEBUGGING
+ if (debug & 8) {
+ sprintf(buf,"STAB $%s ==",arg[anum].arg_ptr.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(arg[anum].arg_ptr.arg_arg,Null(STR***));
+ if (!str)
+ fatal("panic: A_LEXPR\n");
+ goto do_crement;
+ case A_LVAL:
+#ifdef DEBUGGING
+ if (debug & 8) {
+ sprintf(buf,"LVAL $%s ==",arg[anum].arg_ptr.arg_stab->stab_name);
+ tmps = buf;
+ }
+#endif
+ str = STAB_STR(arg[anum].arg_ptr.arg_stab);
+ if (!str)
+ fatal("panic: A_LVAL\n");
+ 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_ARYLEN:
+ sarg[anum] = str_static(&str_no);
+ str_numset(sarg[anum],
+ (double)alen(arg[anum].arg_ptr.arg_stab->stab_array));
+#ifdef DEBUGGING
+ tmps = "ARYLEN";
+#endif
+ break;
+ case A_SINGLE:
+ sarg[anum] = arg[anum].arg_ptr.arg_str;
+#ifdef DEBUGGING
+ tmps = "SINGLE";
+#endif
+ break;
+ case A_DOUBLE:
+ (void) interp(str,str_get(arg[anum].arg_ptr.arg_str));
+ sarg[anum] = str;
+#ifdef DEBUGGING
+ tmps = "DOUBLE";
+#endif
+ break;
+ case A_BACKTICK:
+ tmps = str_get(arg[anum].arg_ptr.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_READ:
+ fp = Nullfp;
+ last_in_stab = arg[anum].arg_ptr.arg_stab;
+ if (last_in_stab->stab_io) {
+ fp = last_in_stab->stab_io->fp;
+ if (!fp && (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) < 0L) {
+ 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 */
+ }
+ }
+ 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;
+ }
+ if (fp == stdin) {
+ clearerr(fp);
+ }
+ sarg[anum] = &str_no;
+ break;
+ }
+ else {
+ last_in_stab->stab_io->lines++;
+ sarg[anum] = str;
+ }
+#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 (str != sarg[1])
+ str_sset(str,sarg[1]);
+ STABSET(str);
+ break;
+ case O_ITEM2:
+ if (str != sarg[2])
+ str_sset(str,sarg[2]);
+ STABSET(str);
+ break;
+ case O_ITEM3:
+ if (str != sarg[3])
+ str_sset(str,sarg[3]);
+ 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 = (long)str_gnum(sarg[2]);
+ if (anum >= 1) {
+ tmpstr = str_new(0);
+ str_sset(tmpstr,str);
+ for (anum--; anum; anum--)
+ str_scat(str,tmpstr);
+ }
+ else
+ str_sset(str,&str_no);
+ STABSET(str);
+ break;
+ case O_MATCH:
+ str_set(str, do_match(str_get(sarg[1]),arg) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_NMATCH:
+ str_set(str, do_match(str_get(sarg[1]),arg) ? 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[2].arg_flags & AF_SPECIAL)
+ do_assign(str,arg);
+ 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_MULTIPLY:
+ value = str_gnum(sarg[1]);
+ value *= str_gnum(sarg[2]);
+ goto donumset;
+ case O_DIVIDE:
+ value = str_gnum(sarg[1]);
+ value /= str_gnum(sarg[2]);
+ goto donumset;
+ case O_MODULO:
+ value = str_gnum(sarg[1]);
+ value = (double)(((long)value) % (long)str_gnum(sarg[2]));
+ 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]);
+ value = (double)(((long)value) << (long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_RIGHT_SHIFT:
+ value = str_gnum(sarg[1]);
+ value = (double)(((long)value) >> (long)str_gnum(sarg[2]));
+ 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)(((long)value) & (long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_XOR:
+ value = str_gnum(sarg[1]);
+ value = (double)(((long)value) ^ (long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_BIT_OR:
+ value = str_gnum(sarg[1]);
+ value = (double)(((long)value) | (long)str_gnum(sarg[2]));
+ goto donumset;
+ case O_AND:
+ if (str_true(sarg[1])) {
+ anum = 2;
+ optype = O_ITEM2;
+ maxarg = 0;
+ argflags = arg[anum].arg_flags;
+ 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_set(str, sarg[1]);
+ STABSET(str);
+ }
+ else
+ str = sarg[1];
+ break;
+ }
+ else {
+ anum = 2;
+ optype = O_ITEM2;
+ maxarg = 0;
+ argflags = arg[anum].arg_flags;
+ goto re_eval;
+ }
+ case O_COND_EXPR:
+ anum = (str_true(sarg[1]) ? 2 : 3);
+ optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
+ maxarg = 0;
+ argflags = arg[anum].arg_flags;
+ 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 (do_open(arg[1].arg_ptr.arg_stab,str_get(sarg[2]))) {
+ str_set(str, Yes);
+ arg[1].arg_ptr.arg_stab->stab_io->lines = 0;
+ }
+ 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:
+ str_set(str,
+ do_close(arg[1].arg_ptr.arg_stab,TRUE) ? Yes : No );
+ STABSET(str);
+ break;
+ case O_EACH:
+ str_sset(str,do_each(arg[1].arg_ptr.arg_stab->stab_hash,sarg,retary));
+ retary = Null(STR***); /* do_each already did retary */
+ STABSET(str);
+ break;
+ case O_VALUES:
+ case O_KEYS:
+ value = (double) do_kv(arg[1].arg_ptr.arg_stab->stab_hash,
+ optype,sarg,retary);
+ retary = Null(STR***); /* do_keys already did retary */
+ goto donumset;
+ case O_ARRAY:
+ if (maxarg == 1) {
+ ary = arg[1].arg_ptr.arg_stab->stab_array;
+ maxarg = ary->ary_fill;
+ if (retary) { /* array wanted */
+ sarg =
+ (STR **)saferealloc((char*)sarg,(maxarg+3)*sizeof(STR*));
+ for (anum = 0; anum <= maxarg; anum++) {
+ sarg[anum+1] = str = afetch(ary,anum);
+ }
+ maxarg++;
+ }
+ else
+ str = afetch(ary,maxarg);
+ }
+ else
+ str = afetch(arg[2].arg_ptr.arg_stab->stab_array,
+ ((int)str_gnum(sarg[1])) - arybase);
+ if (!str)
+ return &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)
+ return &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)
+ return &str_no;
+#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)
+ return &str_no;
+#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(str_get(sarg[1]),arg[2].arg_ptr.arg_spat,retary);
+ retary = Null(STR***); /* do_split already did retary */
+ goto donumset;
+ case O_LENGTH:
+ value = (double) str_len(sarg[1]);
+ goto donumset;
+ case O_SPRINTF:
+ sarg[maxarg+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_PRTF:
+ case O_PRINT:
+ if (maxarg <= 1)
+ stab = defoutstab;
+ else {
+ stab = arg[2].arg_ptr.arg_stab;
+ if (!stab)
+ stab = defoutstab;
+ }
+ if (!stab->stab_io)
+ value = 0.0;
+ else if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)do_aprint(arg,stab->stab_io->fp);
+ else {
+ value = (double)do_print(str_get(sarg[1]),stab->stab_io->fp);
+ if (ors && optype == O_PRINT)
+ do_print(ors, stab->stab_io->fp);
+ }
+ if (stab->stab_io->flags & IOF_FLUSH)
+ fflush(stab->stab_io->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\n",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 (maxarg > 0)
+ str = sarg[maxarg]; /* unwanted list, return last item */
+ else
+ str = &str_no;
+ break;
+ case O_EOF:
+ str_set(str, do_eof(maxarg > 0 ? arg[1].arg_ptr.arg_stab : last_in_stab) ? Yes : No);
+ STABSET(str);
+ break;
+ case O_TELL:
+ value = (double)do_tell(maxarg > 0 ? arg[1].arg_ptr.arg_stab : last_in_stab);
+ goto donumset;
+ break;
+ case O_SEEK:
+ value = str_gnum(sarg[2]);
+ str_set(str, do_seek(arg[1].arg_ptr.arg_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\n", 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 = instr(tmps,str_get(sarg[2]))))
+ value = (double)(-1 + arybase);
+ else
+ value = (double)(tmps2 - tmps + arybase);
+ goto donumset;
+ case O_TIME:
+ value = (double) time(0);
+ goto donumset;
+ case O_TMS:
+ value = (double) do_tms(retary);
+ retary = Null(STR***); /* do_tms already did retary */
+ goto donumset;
+ case O_LOCALTIME:
+ tmplong = (long) str_gnum(sarg[1]);
+ value = (double) do_time(localtime(&tmplong),retary);
+ retary = Null(STR***); /* do_localtime already did retary */
+ goto donumset;
+ case O_GMTIME:
+ tmplong = (long) str_gnum(sarg[1]);
+ value = (double) do_time(gmtime(&tmplong),retary);
+ retary = Null(STR***); /* do_gmtime already did retary */
+ goto donumset;
+ case O_STAT:
+ value = (double) do_stat(arg,sarg,retary);
+ retary = Null(STR***); /* do_stat already did retary */
+ goto donumset;
+ case O_CRYPT:
+ tmps = str_get(sarg[1]);
+ str_set(str,crypt(tmps,str_get(sarg[2])));
+ 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:
+ modf(str_gnum(sarg[1]),&value);
+ goto donumset;
+ case O_ORD:
+ value = (double) *str_get(sarg[1]);
+ goto donumset;
+ case O_SLEEP:
+ tmps = str_get(sarg[1]);
+ time(&tmplong);
+ if (!tmps || !*tmps)
+ sleep((32767<<16)+32767);
+ else
+ sleep(atoi(tmps));
+ value = (double)tmplong;
+ time(&tmplong);
+ value = ((double)tmplong) - value;
+ goto donumset;
+ case O_FLIP:
+ if (str_true(sarg[1])) {
+ str_numset(str,0.0);
+ anum = 2;
+ arg->arg_type = optype = O_FLOP;
+ maxarg = 0;
+ arg[2].arg_flags &= ~AF_SPECIAL;
+ arg[1].arg_flags |= AF_SPECIAL;
+ argflags = arg[anum].arg_flags;
+ 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_SYSTEM:
+ if (anum = vfork()) {
+ ihand = signal(SIGINT, SIG_IGN);
+ qhand = signal(SIGQUIT, SIG_IGN);
+ while ((maxarg = wait(&argflags)) != anum && maxarg != -1)
+ ;
+ if (maxarg == -1)
+ argflags = -1;
+ signal(SIGINT, ihand);
+ signal(SIGQUIT, qhand);
+ value = (double)argflags;
+ goto donumset;
+ }
+ /* FALL THROUGH */
+ case O_EXEC:
+ if (arg[1].arg_flags & AF_SPECIAL)
+ value = (double)do_aexec(arg);
+ else {
+ value = (double)do_exec(str_get(sarg[1]));
+ }
+ goto donumset;
+ case O_HEX:
+ maxarg = 4;
+ goto snarfnum;
+
+ case O_OCT:
+ maxarg = 3;
+
+ snarfnum:
+ anum = 0;
+ tmps = str_get(sarg[1]);
+ for (;;) {
+ switch (*tmps) {
+ default:
+ goto out;
+ case '8': case '9':
+ if (maxarg != 4)
+ goto out;
+ /* FALL THROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ anum <<= maxarg;
+ 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 (maxarg != 4)
+ goto out;
+ anum <<= 4;
+ anum += (*tmps++ & 7) + 9;
+ break;
+ case 'x':
+ maxarg = 4;
+ tmps++;
+ break;
+ }
+ }
+ out:
+ value = (double)anum;
+ goto donumset;
+ case O_CHMOD:
+ case O_CHOWN:
+ case O_KILL:
+ case O_UNLINK:
+ 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]);
+ UNLINK(tmps2);
+ 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;
+ }
+#ifdef DEBUGGING
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str));
+#endif
+ goto freeargs;
+
+donumset:
+ str_numset(str,value);
+ STABSET(str);
+#ifdef DEBUGGING
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS \"%f\"\n",opname[optype],value);
+#endif
+
+freeargs:
+ if (sarg != quicksarg) {
+ if (retary) {
+ if (optype == O_LIST)
+ sarg[0] = &str_no;
+ else
+ sarg[0] = Nullstr;
+ sarg[maxarg+1] = Nullstr;
+ *retary = sarg; /* up to them to free it */
+ }
+ else
+ safefree(sarg);
+ }
+ return str;
+
+nullarray:
+ maxarg = 0;
+#ifdef DEBUGGING
+ dlevel--;
+ if (debug & 8)
+ deb("%s RETURNS ()\n",opname[optype],value);
+#endif
+ goto freeargs;
+}