lwall@netlabs.com (Larry Wall) (04/16/91)
Submitted-by: Larry Wall <lwall@netlabs.com> Posting-number: Volume 18, Issue 31 Archive-name: perl/part13 [There are 36 kits for perl version 4.0.] #! /bin/sh # Make a new directory for the perl sources, cd to it, and run kits 1 # thru 36 through sh. When all 36 kits have been run, read README. echo "This is perl 4.0 kit 13 (of 36). If kit 13 is complete, the line" echo '"'"End of kit 13 (of 36)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir msdos x2p 2>/dev/null echo Extracting cons.c sed >cons.c <<'!STUFFY!FUNK!' -e 's/X//' X/* $Header: cons.c,v 4.0 91/03/20 01:05:51 lwall Locked $ X * X * Copyright (c) 1989, Larry Wall X * X * You may distribute under the terms of the GNU General Public License X * as specified in the README file that comes with the perl 3.0 kit. X * X * $Log: cons.c,v $ X * Revision 4.0 91/03/20 01:05:51 lwall X * 4.0 baseline. X * X */ X X#include "EXTERN.h" X#include "perl.h" X#include "perly.h" X Xextern char *tokename[]; Xextern int yychar; X Xstatic int cmd_tosave(); Xstatic int arg_tosave(); Xstatic int spat_tosave(); X Xstatic bool saw_return; X XSUBR * Xmake_sub(name,cmd) Xchar *name; XCMD *cmd; X{ X register SUBR *sub; X STAB *stab = stabent(name,TRUE); X X Newz(101,sub,1,SUBR); X if (stab_sub(stab)) { X if (dowarn) { X CMD *oldcurcmd = curcmd; X X if (cmd) X curcmd = cmd; X warn("Subroutine %s redefined",name); X curcmd = oldcurcmd; X } X if (stab_sub(stab)->cmd) { X cmd_free(stab_sub(stab)->cmd); X stab_sub(stab)->cmd = Nullcmd; X afree(stab_sub(stab)->tosave); X } X Safefree(stab_sub(stab)); X } X stab_sub(stab) = sub; X sub->filestab = curcmd->c_filestab; X saw_return = FALSE; X tosave = anew(Nullstab); X tosave->ary_fill = 0; /* make 1 based */ X (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */ X sub->tosave = tosave; X if (saw_return) { X struct compcmd mycompblock; X X mycompblock.comp_true = cmd; X mycompblock.comp_alt = Nullcmd; X cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock)); X saw_return = FALSE; X cmd->c_flags |= CF_TERM; X } X sub->cmd = cmd; X if (perldb) { X STR *str; X STR *tmpstr = str_mortal(&str_undef); X X sprintf(buf,"%s:%ld",stab_val(curcmd->c_filestab)->str_ptr, X (long)subline); X str = str_make(buf,0); X str_cat(str,"-"); X sprintf(buf,"%ld",(long)curcmd->c_line); X str_cat(str,buf); X name = str_get(subname); X stab_fullname(tmpstr,stab); X hstore(stab_xhash(DBsub), tmpstr->str_ptr, tmpstr->str_cur, str, 0); X str_set(subname,"main"); X } X subline = 0; X return sub; X} X XSUBR * Xmake_usub(name, ix, subaddr, filename) Xchar *name; Xint ix; Xint (*subaddr)(); Xchar *filename; X{ X register SUBR *sub; X STAB *stab = stabent(name,allstabs); X X if (!stab) /* unused function */ X return Null(SUBR*); X Newz(101,sub,1,SUBR); X if (stab_sub(stab)) { X if (dowarn) X warn("Subroutine %s redefined",name); X if (stab_sub(stab)->cmd) { X cmd_free(stab_sub(stab)->cmd); X stab_sub(stab)->cmd = Nullcmd; X afree(stab_sub(stab)->tosave); X } X Safefree(stab_sub(stab)); X } X stab_sub(stab) = sub; X sub->filestab = fstab(filename); X sub->usersub = subaddr; X sub->userindex = ix; X return sub; X} X Xmake_form(stab,fcmd) XSTAB *stab; XFCMD *fcmd; X{ X if (stab_form(stab)) { X FCMD *tmpfcmd; X FCMD *nextfcmd; X X for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) { X nextfcmd = tmpfcmd->f_next; X if (tmpfcmd->f_expr) X arg_free(tmpfcmd->f_expr); X if (tmpfcmd->f_unparsed) X str_free(tmpfcmd->f_unparsed); X if (tmpfcmd->f_pre) X Safefree(tmpfcmd->f_pre); X Safefree(tmpfcmd); X } X } X stab_form(stab) = fcmd; X} X XCMD * Xblock_head(tail) Xregister CMD *tail; X{ X CMD *head; X register int opt; X register int last_opt = 0; X register STAB *last_stab = Nullstab; X register int count = 0; X register CMD *switchbeg = Nullcmd; X X if (tail == Nullcmd) { X return tail; X } X head = tail->c_head; X X for (tail = head; tail; tail = tail->c_next) { X X /* save one measly dereference at runtime */ X if (tail->c_type == C_IF) { X if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next)) X tail->c_flags |= CF_TERM; X } X else if (tail->c_type == C_EXPR) { X ARG *arg; X X if (tail->ucmd.acmd.ac_expr) X arg = tail->ucmd.acmd.ac_expr; X else X arg = tail->c_expr; X if (arg) { X if (arg->arg_type == O_RETURN) X tail->c_flags |= CF_TERM; X else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) X tail->c_flags |= CF_TERM; X } X } X if (!tail->c_next) X tail->c_flags |= CF_TERM; X X if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE) X opt_arg(tail,1, tail->c_type == C_EXPR); X X /* now do a little optimization on case-ish structures */ X switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) { X case CFT_ANCHOR: X if (stabent("*",FALSE)) { /* bad assumption here!!! */ X opt = 0; X break; X } X /* FALL THROUGH */ X case CFT_STROP: X opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0; X break; X case CFT_CCLASS: X opt = CFT_STROP; X break; X case CFT_NUMOP: X opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP); X if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE)) X opt = 0; X break; X default: X opt = 0; X } X if (opt && opt == last_opt && tail->c_stab == last_stab) X count++; X else { X if (count >= 3) { /* is this the breakeven point? */ X if (last_opt == CFT_NUMOP) X make_nswitch(switchbeg,count); X else X make_cswitch(switchbeg,count); X } X if (opt) { X count = 1; X switchbeg = tail; X } X else X count = 0; X } X last_opt = opt; X last_stab = tail->c_stab; X } X if (count >= 3) { /* is this the breakeven point? */ X if (last_opt == CFT_NUMOP) X make_nswitch(switchbeg,count); X else X make_cswitch(switchbeg,count); X } X return head; X} X X/* We've spotted a sequence of CMDs that all test the value of the same X * spat. Thus we can insert a SWITCH in front and jump directly X * to the correct one. X */ Xmake_cswitch(head,count) Xregister CMD *head; Xint count; X{ X register CMD *cur; X register CMD **loc; X register int i; X register int min = 255; X register int max = 0; X X /* make a new head in the exact same spot */ X New(102,cur, 1, CMD); X#ifdef STRUCTCOPY X *cur = *head; X#else X Copy(head,cur,1,CMD); X#endif X Zero(head,1,CMD); X head->c_type = C_CSWITCH; X head->c_next = cur; /* insert new cmd at front of list */ X head->c_stab = cur->c_stab; X X Newz(103,loc,258,CMD*); X loc++; /* lie a little */ X while (count--) { X if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) { X for (i = 0; i <= 255; i++) { X if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) { X loc[i] = cur; X if (i < min) X min = i; X if (i > max) X max = i; X } X } X } X else { X i = *cur->c_short->str_ptr & 255; X if (!loc[i]) { X loc[i] = cur; X if (i < min) X min = i; X if (i > max) X max = i; X } X } X cur = cur->c_next; X } X max++; X if (min > 0) X Copy(&loc[min],&loc[0], max - min, CMD*); X loc--; X min--; X max -= min; X for (i = 0; i <= max; i++) X if (!loc[i]) X loc[i] = cur; X Renew(loc,max+1,CMD*); /* chop it down to size */ X head->ucmd.scmd.sc_offset = min; X head->ucmd.scmd.sc_max = max; X head->ucmd.scmd.sc_next = loc; X} X Xmake_nswitch(head,count) Xregister CMD *head; Xint count; X{ X register CMD *cur = head; X register CMD **loc; X register int i; X register int min = 32767; X register int max = -32768; X int origcount = count; X double value; /* or your money back! */ X short changed; /* so triple your money back! */ X X while (count--) { X i = (int)str_gnum(cur->c_short); X value = (double)i; X if (value != cur->c_short->str_u.str_nval) X return; /* fractional values--just forget it */ X changed = i; X if (changed != i) X return; /* too big for a short */ X if (cur->c_slen == O_LE) X i++; X else if (cur->c_slen == O_GE) /* we only do < or > here */ X i--; X if (i < min) X min = i; X if (i > max) X max = i; X cur = cur->c_next; X } X count = origcount; X if (max - min > count * 2 + 10) /* too sparse? */ X return; X X /* now make a new head in the exact same spot */ X New(104,cur, 1, CMD); X#ifdef STRUCTCOPY X *cur = *head; X#else X Copy(head,cur,1,CMD); X#endif X Zero(head,1,CMD); X head->c_type = C_NSWITCH; X head->c_next = cur; /* insert new cmd at front of list */ X head->c_stab = cur->c_stab; X X Newz(105,loc, max - min + 3, CMD*); X loc++; X max -= min; X max++; X while (count--) { X i = (int)str_gnum(cur->c_short); X i -= min; X switch(cur->c_slen) { X case O_LE: X i++; X case O_LT: X for (i--; i >= -1; i--) X if (!loc[i]) X loc[i] = cur; X break; X case O_GE: X i--; X case O_GT: X for (i++; i <= max; i++) X if (!loc[i]) X loc[i] = cur; X break; X case O_EQ: X if (!loc[i]) X loc[i] = cur; X break; X } X cur = cur->c_next; X } X loc--; X min--; X max++; X for (i = 0; i <= max; i++) X if (!loc[i]) X loc[i] = cur; X head->ucmd.scmd.sc_offset = min; X head->ucmd.scmd.sc_max = max; X head->ucmd.scmd.sc_next = loc; X} X XCMD * Xappend_line(head,tail) Xregister CMD *head; Xregister CMD *tail; X{ X if (tail == Nullcmd) X return head; X if (!tail->c_head) /* make sure tail is well formed */ X tail->c_head = tail; X if (head != Nullcmd) { X tail = tail->c_head; /* get to start of tail list */ X if (!head->c_head) X head->c_head = head; /* start a new head list */ X while (head->c_next) { X head->c_next->c_head = head->c_head; X head = head->c_next; /* get to end of head list */ X } X head->c_next = tail; /* link to end of old list */ X tail->c_head = head->c_head; /* propagate head pointer */ X } X while (tail->c_next) { X tail->c_next->c_head = tail->c_head; X tail = tail->c_next; X } X return tail; X} X XCMD * Xdodb(cur) XCMD *cur; X{ X register CMD *cmd; X register CMD *head = cur->c_head; X STR *str; X X if (!head) X head = cur; X if (!head->c_line) X return cur; X str = afetch(stab_xarray(curcmd->c_filestab),(int)head->c_line,FALSE); X if (str == &str_undef || str->str_nok) X return cur; X str->str_u.str_nval = (double)head->c_line; X str->str_nok = 1; X Newz(106,cmd,1,CMD); X str_magic(str, curcmd->c_filestab, 0, Nullch, 0); X str->str_magic->str_u.str_cmd = cmd; X cmd->c_type = C_EXPR; X cmd->ucmd.acmd.ac_stab = Nullstab; X cmd->ucmd.acmd.ac_expr = Nullarg; X cmd->c_expr = make_op(O_SUBR, 2, X stab2arg(A_WORD,DBstab), X Nullarg, X Nullarg); X cmd->c_flags |= CF_COND|CF_DBSUB|CFT_D0; X cmd->c_line = head->c_line; X cmd->c_label = head->c_label; X cmd->c_filestab = curcmd->c_filestab; X cmd->c_stash = curstash; X return append_line(cmd, cur); X} X XCMD * Xmake_acmd(type,stab,cond,arg) Xint type; XSTAB *stab; XARG *cond; XARG *arg; X{ X register CMD *cmd; X X Newz(107,cmd,1,CMD); X cmd->c_type = type; X cmd->ucmd.acmd.ac_stab = stab; X cmd->ucmd.acmd.ac_expr = arg; X cmd->c_expr = cond; X if (cond) X cmd->c_flags |= CF_COND; X if (cmdline == NOLINE) X cmd->c_line = curcmd->c_line; X else { X cmd->c_line = cmdline; X cmdline = NOLINE; X } X cmd->c_filestab = curcmd->c_filestab; X cmd->c_stash = curstash; X if (perldb) X cmd = dodb(cmd); X return cmd; X} X XCMD * Xmake_ccmd(type,arg,cblock) Xint type; XARG *arg; Xstruct compcmd cblock; X{ X register CMD *cmd; X X Newz(108,cmd, 1, CMD); X cmd->c_type = type; X cmd->c_expr = arg; X cmd->ucmd.ccmd.cc_true = cblock.comp_true; X cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; X if (arg) X cmd->c_flags |= CF_COND; X if (cmdline == NOLINE) X cmd->c_line = curcmd->c_line; X else { X cmd->c_line = cmdline; X cmdline = NOLINE; X } X cmd->c_filestab = curcmd->c_filestab; X cmd->c_stash = curstash; X if (perldb) X cmd = dodb(cmd); X return cmd; X} X XCMD * Xmake_icmd(type,arg,cblock) Xint type; XARG *arg; Xstruct compcmd cblock; X{ X register CMD *cmd; X register CMD *alt; X register CMD *cur; X register CMD *head; X struct compcmd ncblock; X X Newz(109,cmd, 1, CMD); X head = cmd; X cmd->c_type = type; X cmd->c_expr = arg; X cmd->ucmd.ccmd.cc_true = cblock.comp_true; X cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; X if (arg) X cmd->c_flags |= CF_COND; X if (cmdline == NOLINE) X cmd->c_line = curcmd->c_line; X else { X cmd->c_line = cmdline; X cmdline = NOLINE; X } X cmd->c_filestab = curcmd->c_filestab; X cmd->c_stash = curstash; X cur = cmd; X alt = cblock.comp_alt; X while (alt && alt->c_type == C_ELSIF) { X cur = alt; X alt = alt->ucmd.ccmd.cc_alt; X } X if (alt) { /* a real life ELSE at the end? */ X ncblock.comp_true = alt; X ncblock.comp_alt = Nullcmd; X alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock)); X cur->ucmd.ccmd.cc_alt = alt; X } X else X alt = cur; /* no ELSE, so cur is proxy ELSE */ X X cur = cmd; X while (cmd) { /* now point everyone at the ELSE */ X cur = cmd; X cmd = cur->ucmd.ccmd.cc_alt; X cur->c_head = head; X if (cur->c_type == C_ELSIF) X cur->c_type = C_IF; X if (cur->c_type == C_IF) X cur->ucmd.ccmd.cc_alt = alt; X if (cur == alt) X break; X cur->c_next = cmd; X } X if (perldb) X cur = dodb(cur); X return cur; X} X Xvoid Xopt_arg(cmd,fliporflop,acmd) Xregister CMD *cmd; Xint fliporflop; Xint acmd; X{ X register ARG *arg; X int opt = CFT_EVAL; X int sure = 0; X ARG *arg2; X int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */ X int flp = fliporflop; X X if (!cmd) X return; X if (!(arg = cmd->c_expr)) { X cmd->c_flags &= ~CF_COND; X return; X } X X /* Can we turn && and || into if and unless? */ X X if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) && X (arg->arg_type == O_AND || arg->arg_type == O_OR) ) { X dehoist(arg,1); X arg[2].arg_type &= A_MASK; /* don't suppress eval */ X dehoist(arg,2); X cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg; X cmd->c_expr = arg[1].arg_ptr.arg_arg; X if (arg->arg_type == O_OR) X cmd->c_flags ^= CF_INVERT; /* || is like unless */ X arg->arg_len = 0; X free_arg(arg); X arg = cmd->c_expr; X } X X /* Turn "if (!expr)" into "unless (expr)" */ X X if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */ X while (arg->arg_type == O_NOT) { X dehoist(arg,1); X cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */ X cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */ X free_arg(arg); X arg = cmd->c_expr; /* here we go again */ X } X } X X if (!arg->arg_len) { /* sanity check */ X cmd->c_flags |= opt; X return; X } X X /* for "cond .. cond" we set up for the initial check */ X X if (arg->arg_type == O_FLIP) X context |= 4; X X /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */ X X morecontext: X if (arg->arg_type == O_AND) X context |= 1; X else if (arg->arg_type == O_OR) X context |= 2; X if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) { X arg = arg[flp].arg_ptr.arg_arg; X flp = 1; X if (arg->arg_type == O_AND || arg->arg_type == O_OR) X goto morecontext; X } X if ((context & 3) == 3) X return; X X if (arg[flp].arg_flags & (AF_PRE|AF_POST)) { X cmd->c_flags |= opt; X if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) X && cmd->c_expr->arg_type == O_ITEM) { X arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */ X arg[flp].arg_flags |= AF_PRE; /* if value not wanted */ X } X return; /* side effect, can't optimize */ X } X X if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP || X arg->arg_type == O_AND || arg->arg_type == O_OR) { X if ((arg[flp].arg_type & A_MASK) == A_SINGLE) { X opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE); X cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str); X goto literal; X } X else if ((arg[flp].arg_type & A_MASK) == A_STAB || X (arg[flp].arg_type & A_MASK) == A_LVAL) { X cmd->c_stab = arg[flp].arg_ptr.arg_stab; X if (!context) X arg[flp].arg_ptr.arg_stab = Nullstab; X opt = CFT_REG; X literal: X if (!context) { /* no && or ||? */ X arg_free(arg); X cmd->c_expr = Nullarg; X } X if (!(context & 1)) X cmd->c_flags |= CF_EQSURE; X if (!(context & 2)) X cmd->c_flags |= CF_NESURE; X } X } X else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST || X arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) { X if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && X (arg[2].arg_type & A_MASK) == A_SPAT && X arg[2].arg_ptr.arg_spat->spat_short ) { X cmd->c_stab = arg[1].arg_ptr.arg_stab; X cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short); X cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen; X if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL && X !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) && X (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) ) X sure |= CF_EQSURE; /* (SUBST must be forced even */ X /* if we know it will work.) */ X if (arg->arg_type != O_SUBST) { X arg[2].arg_ptr.arg_spat->spat_short = Nullstr; X arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */ X } X sure |= CF_NESURE; /* normally only sure if it fails */ X if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) X cmd->c_flags |= CF_FIRSTNEG; X if (context & 1) { /* only sure if thing is false */ X if (cmd->c_flags & CF_FIRSTNEG) X sure &= ~CF_NESURE; X else X sure &= ~CF_EQSURE; X } X else if (context & 2) { /* only sure if thing is true */ X if (cmd->c_flags & CF_FIRSTNEG) X sure &= ~CF_EQSURE; X else X sure &= ~CF_NESURE; X } X if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/ X if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST) X opt = CFT_SCAN; X else X opt = CFT_ANCHOR; X if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */ X && arg->arg_type == O_MATCH X && context & 4 X && fliporflop == 1) { X spat_free(arg[2].arg_ptr.arg_spat); X arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */ X } X else X cmd->c_spat = arg[2].arg_ptr.arg_spat; X cmd->c_flags |= sure; X } X } X } X else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE || X arg->arg_type == O_SLT || arg->arg_type == O_SGT) { X if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { X if (arg[2].arg_type == A_SINGLE) { X char *junk = str_get(arg[2].arg_ptr.arg_str); X X cmd->c_stab = arg[1].arg_ptr.arg_stab; X cmd->c_short = str_smake(arg[2].arg_ptr.arg_str); X cmd->c_slen = cmd->c_short->str_cur+1; X switch (arg->arg_type) { X case O_SLT: case O_SGT: X sure |= CF_EQSURE; X cmd->c_flags |= CF_FIRSTNEG; X break; X case O_SNE: X cmd->c_flags |= CF_FIRSTNEG; X /* FALL THROUGH */ X case O_SEQ: X sure |= CF_NESURE|CF_EQSURE; X break; X } X if (context & 1) { /* only sure if thing is false */ X if (cmd->c_flags & CF_FIRSTNEG) X sure &= ~CF_NESURE; X else X sure &= ~CF_EQSURE; X } X else if (context & 2) { /* only sure if thing is true */ X if (cmd->c_flags & CF_FIRSTNEG) X sure &= ~CF_EQSURE; X else X sure &= ~CF_NESURE; X } X if (sure & (CF_EQSURE|CF_NESURE)) { X opt = CFT_STROP; X cmd->c_flags |= sure; X } X } X } X } X else if (arg->arg_type == O_EQ || arg->arg_type == O_NE || X arg->arg_type == O_LE || arg->arg_type == O_GE || X arg->arg_type == O_LT || arg->arg_type == O_GT) { X if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { X if (arg[2].arg_type == A_SINGLE) { X cmd->c_stab = arg[1].arg_ptr.arg_stab; X if (dowarn) { X STR *str = arg[2].arg_ptr.arg_str; X X if ((!str->str_nok && !looks_like_number(str))) X warn("Possible use of == on string value"); X } X cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str)); X cmd->c_slen = arg->arg_type; X sure |= CF_NESURE|CF_EQSURE; X if (context & 1) { /* only sure if thing is false */ X sure &= ~CF_EQSURE; X } X else if (context & 2) { /* only sure if thing is true */ X sure &= ~CF_NESURE; X } X if (sure & (CF_EQSURE|CF_NESURE)) { X opt = CFT_NUMOP; X cmd->c_flags |= sure; X } X } X } X } X else if (arg->arg_type == O_ASSIGN && X (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && X arg[1].arg_ptr.arg_stab == defstab && X arg[2].arg_type == A_EXPR ) { X arg2 = arg[2].arg_ptr.arg_arg; X if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) { X opt = CFT_GETS; X cmd->c_stab = arg2[1].arg_ptr.arg_stab; X if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) { X free_arg(arg2); X arg[2].arg_ptr.arg_arg = Nullarg; X free_arg(arg); X cmd->c_expr = Nullarg; X } X } X } X else if (arg->arg_type == O_CHOP && X (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) { X opt = CFT_CHOP; X cmd->c_stab = arg[1].arg_ptr.arg_stab; X free_arg(arg); X cmd->c_expr = Nullarg; X } X if (context & 4) X opt |= CF_FLIP; X cmd->c_flags |= opt; X X if (cmd->c_flags & CF_FLIP) { X if (fliporflop == 1) { X arg = cmd->c_expr; /* get back to O_FLIP arg */ X New(110,arg[3].arg_ptr.arg_cmd, 1, CMD); X Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD); X New(111,arg[4].arg_ptr.arg_cmd,1,CMD); X Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD); X opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd); X arg->arg_len = 2; /* this is a lie */ X } X else { X if ((opt & CF_OPTIMIZE) == CFT_EVAL) X cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP; X } X } X} X XCMD * Xadd_label(lbl,cmd) Xchar *lbl; Xregister CMD *cmd; X{ X if (cmd) X cmd->c_label = lbl; X return cmd; X} X XCMD * Xaddcond(cmd, arg) Xregister CMD *cmd; Xregister ARG *arg; X{ X cmd->c_expr = arg; X cmd->c_flags |= CF_COND; X return cmd; X} X XCMD * Xaddloop(cmd, arg) Xregister CMD *cmd; Xregister ARG *arg; X{ X void while_io(); X X cmd->c_expr = arg; X cmd->c_flags |= CF_COND|CF_LOOP; X X if (!(cmd->c_flags & CF_INVERT)) X while_io(cmd); /* add $_ =, if necessary */ X X if (cmd->c_type == C_BLOCK) X cmd->c_flags &= ~CF_COND; X else { X arg = cmd->ucmd.acmd.ac_expr; X if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) X cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */ X if (arg && (arg->arg_flags & AF_DEPR) && X (arg->arg_type == O_SUBR || arg->arg_type == O_DBSUBR) ) X cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */ X } X return cmd; X} X XCMD * Xinvert(cmd) XCMD *cmd; X{ X register CMD *targ = cmd; X if (targ->c_head) X targ = targ->c_head; X if (targ->c_flags & CF_DBSUB) X targ = targ->c_next; X targ->c_flags ^= CF_INVERT; X return cmd; X} X Xyyerror(s) Xchar *s; X{ X char tmpbuf[258]; X char tmp2buf[258]; X char *tname = tmpbuf; X X if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 && X oldoldbufptr != oldbufptr && oldbufptr != bufptr) { X while (isspace(*oldoldbufptr)) X oldoldbufptr++; X strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr); X tmp2buf[bufptr - oldoldbufptr] = '\0'; X sprintf(tname,"next 2 tokens \"%s\"",tmp2buf); X } X else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 && X oldbufptr != bufptr) { X while (isspace(*oldbufptr)) X oldbufptr++; X strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr); X tmp2buf[bufptr - oldbufptr] = '\0'; X sprintf(tname,"next token \"%s\"",tmp2buf); X } X else if (yychar > 256) X tname = "next token ???"; X else if (!yychar) X (void)strcpy(tname,"at EOF"); X else if (yychar < 32) X (void)sprintf(tname,"next char ^%c",yychar+64); X else if (yychar == 127) X (void)strcpy(tname,"at EOF"); X else X (void)sprintf(tname,"next char %c",yychar); X (void)sprintf(buf, "%s in file %s at line %d, %s\n", X s,stab_val(curcmd->c_filestab)->str_ptr,curcmd->c_line,tname); X if (curcmd->c_line == multi_end && multi_start < multi_end) X sprintf(buf+strlen(buf), X " (Might be a runaway multi-line %c%c string starting on line %d)\n", X multi_open,multi_close,multi_start); X if (in_eval) X str_cat(stab_val(stabent("@",TRUE)),buf); X else X fputs(buf,stderr); X if (++error_count >= 10) X fatal("%s has too many errors.\n", X stab_val(curcmd->c_filestab)->str_ptr); X} X Xvoid Xwhile_io(cmd) Xregister CMD *cmd; X{ X register ARG *arg = cmd->c_expr; X STAB *asgnstab; X X /* hoist "while (<channel>)" up into command block */ X X if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) { X cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ X cmd->c_flags |= CFT_GETS; /* and set it to do the input */ X cmd->c_stab = arg[1].arg_ptr.arg_stab; X if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) { X cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */ X stab2arg(A_LVAL,defstab), arg, Nullarg)); X } X else { X free_arg(arg); X cmd->c_expr = Nullarg; X } X } X else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) { X cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ X cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */ X cmd->c_stab = arg[1].arg_ptr.arg_stab; X free_arg(arg); X cmd->c_expr = Nullarg; X } X else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) { X if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) X asgnstab = cmd->c_stab; X else X asgnstab = defstab; X cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */ X stab2arg(A_LVAL,asgnstab), arg, Nullarg)); X cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ X } X} X XCMD * Xwopt(cmd) Xregister CMD *cmd; X{ X register CMD *tail; X CMD *newtail; X register int i; X X if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE) X opt_arg(cmd,1, cmd->c_type == C_EXPR); X X while_io(cmd); /* add $_ =, if necessary */ X X /* First find the end of the true list */ X X tail = cmd->ucmd.ccmd.cc_true; X if (tail == Nullcmd) X return cmd; X New(112,newtail, 1, CMD); /* guaranteed continue */ X for (;;) { X /* optimize "next" to point directly to continue block */ X if (tail->c_type == C_EXPR && X tail->ucmd.acmd.ac_expr && X tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && X (tail->ucmd.acmd.ac_expr->arg_len == 0 || X (cmd->c_label && X strEQ(cmd->c_label, X tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) X { X arg_free(tail->ucmd.acmd.ac_expr); X tail->ucmd.acmd.ac_expr = Nullarg; X tail->c_type = C_NEXT; X if (cmd->ucmd.ccmd.cc_alt != Nullcmd) X tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; X else X tail->ucmd.ccmd.cc_alt = newtail; X tail->ucmd.ccmd.cc_true = Nullcmd; X } X else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { X if (cmd->ucmd.ccmd.cc_alt != Nullcmd) X tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; X else X tail->ucmd.ccmd.cc_alt = newtail; X } X else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { X if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { X for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) X if (!tail->ucmd.scmd.sc_next[i]) X tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt; X } X else { X for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) X if (!tail->ucmd.scmd.sc_next[i]) X tail->ucmd.scmd.sc_next[i] = newtail; X } X } X X if (!tail->c_next) X break; X tail = tail->c_next; X } X X /* if there's a continue block, link it to true block and find end */ X X if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { X tail->c_next = cmd->ucmd.ccmd.cc_alt; X tail = tail->c_next; X for (;;) { X /* optimize "next" to point directly to continue block */ X if (tail->c_type == C_EXPR && X tail->ucmd.acmd.ac_expr && X tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && X (tail->ucmd.acmd.ac_expr->arg_len == 0 || X (cmd->c_label && X strEQ(cmd->c_label, X tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) X { X arg_free(tail->ucmd.acmd.ac_expr); X tail->ucmd.acmd.ac_expr = Nullarg; X tail->c_type = C_NEXT; X tail->ucmd.ccmd.cc_alt = newtail; X tail->ucmd.ccmd.cc_true = Nullcmd; X } X else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { X tail->ucmd.ccmd.cc_alt = newtail; X } X else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { X for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) X if (!tail->ucmd.scmd.sc_next[i]) X tail->ucmd.scmd.sc_next[i] = newtail; X } X X if (!tail->c_next) X break; X tail = tail->c_next; X } X for ( ; tail->c_next; tail = tail->c_next) ; X } X X /* Here's the real trick: link the end of the list back to the beginning, X * inserting a "last" block to break out of the loop. This saves one or X * two procedure calls every time through the loop, because of how cmd_exec X * does tail recursion. X */ X X tail->c_next = newtail; X tail = newtail; X if (!cmd->ucmd.ccmd.cc_alt) X cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */ X X#ifndef lint X (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD)); X#endif X tail->c_type = C_EXPR; X tail->c_flags ^= CF_INVERT; /* turn into "last unless" */ X tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */ X tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg); X tail->ucmd.acmd.ac_stab = Nullstab; X return cmd; X} X XCMD * Xover(eachstab,cmd) XSTAB *eachstab; Xregister CMD *cmd; X{ X /* hoist "for $foo (@bar)" up into command block */ X X cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ X cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */ X cmd->c_stab = eachstab; X cmd->c_short = str_new(0); /* just to save a field in struct cmd */ X cmd->c_short->str_u.str_useful = -1; X X return cmd; X} X Xcmd_free(cmd) Xregister CMD *cmd; X{ X register CMD *tofree; X register CMD *head = cmd; X X while (cmd) { X if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */ X if (cmd->c_label) { X Safefree(cmd->c_label); X cmd->c_label = Nullch; X } X if (cmd->c_short) { X str_free(cmd->c_short); X cmd->c_short = Nullstr; X } X if (cmd->c_expr) { X arg_free(cmd->c_expr); X cmd->c_expr = Nullarg; X } X } X switch (cmd->c_type) { X case C_WHILE: X case C_BLOCK: X case C_ELSE: X case C_IF: X if (cmd->ucmd.ccmd.cc_true) { X cmd_free(cmd->ucmd.ccmd.cc_true); X cmd->ucmd.ccmd.cc_true = Nullcmd; X } X break; X case C_EXPR: X if (cmd->ucmd.acmd.ac_expr) { X arg_free(cmd->ucmd.acmd.ac_expr); X cmd->ucmd.acmd.ac_expr = Nullarg; X } X break; X } X tofree = cmd; X cmd = cmd->c_next; X if (tofree != head) /* to get Saber to shut up */ X Safefree(tofree); X if (cmd && cmd == head) /* reached end of while loop */ X break; X } X Safefree(head); X} X Xarg_free(arg) Xregister ARG *arg; X{ X register int i; X X for (i = 1; i <= arg->arg_len; i++) { X switch (arg[i].arg_type & A_MASK) { X case A_NULL: X if (arg->arg_type == O_TRANS) { X Safefree(arg[i].arg_ptr.arg_cval); X arg[i].arg_ptr.arg_cval = Nullch; X } X break; X case A_LEXPR: X if (arg->arg_type == O_AASSIGN && X arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) { X char *name = X stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab); X X if (strnEQ("_GEN_",name, 5)) /* array for foreach */ X hdelete(defstash,name,strlen(name)); X } X /* FALL THROUGH */ X case A_EXPR: X arg_free(arg[i].arg_ptr.arg_arg); X arg[i].arg_ptr.arg_arg = Nullarg; X break; X case A_CMD: X cmd_free(arg[i].arg_ptr.arg_cmd); X arg[i].arg_ptr.arg_cmd = Nullcmd; X break; X case A_WORD: X case A_STAB: X case A_LVAL: X case A_READ: X case A_GLOB: X case A_ARYLEN: X case A_LARYLEN: X case A_ARYSTAB: X case A_LARYSTAB: X break; X case A_SINGLE: X case A_DOUBLE: X case A_BACKTICK: X str_free(arg[i].arg_ptr.arg_str); X arg[i].arg_ptr.arg_str = Nullstr; X break; X case A_SPAT: X spat_free(arg[i].arg_ptr.arg_spat); X arg[i].arg_ptr.arg_spat = Nullspat; X break; X } X } X free_arg(arg); X} X Xspat_free(spat) Xregister SPAT *spat; X{ X register SPAT *sp; X HENT *entry; X X if (spat->spat_runtime) { X arg_free(spat->spat_runtime); X spat->spat_runtime = Nullarg; X } X if (spat->spat_repl) { X arg_free(spat->spat_repl); X spat->spat_repl = Nullarg; X } X if (spat->spat_short) { X str_free(spat->spat_short); X spat->spat_short = Nullstr; X } X if (spat->spat_regexp) { X regfree(spat->spat_regexp); X spat->spat_regexp = Null(REGEXP*); X } X X /* now unlink from spat list */ X X for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) { X register HASH *stash; X STAB *stab = (STAB*)entry->hent_val; X X if (!stab) X continue; X stash = stab_hash(stab); X if (!stash || stash->tbl_spatroot == Null(SPAT*)) X continue; X if (stash->tbl_spatroot == spat) X stash->tbl_spatroot = spat->spat_next; X else { X for (sp = stash->tbl_spatroot; X sp && sp->spat_next != spat; X sp = sp->spat_next) X ; X if (sp) X sp->spat_next = spat->spat_next; X } X } X Safefree(spat); X} X X/* Recursively descend a command sequence and push the address of any string X * that needs saving on recursion onto the tosave array. X */ X Xstatic int Xcmd_tosave(cmd,willsave) Xregister CMD *cmd; Xint willsave; /* willsave passes down the tree */ X{ X register CMD *head = cmd; X int shouldsave = FALSE; /* shouldsave passes up the tree */ X int tmpsave; X register CMD *lastcmd = Nullcmd; X X while (cmd) { X if (cmd->c_expr) X shouldsave |= arg_tosave(cmd->c_expr,willsave); X switch (cmd->c_type) { X case C_WHILE: X if (cmd->ucmd.ccmd.cc_true) { X tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); X X /* Here we check to see if the temporary array generated for X * a foreach needs to be localized because of recursion. X */ X if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) { X if (lastcmd && X lastcmd->c_type == C_EXPR && X lastcmd->c_expr) { X ARG *arg = lastcmd->c_expr; X X if (arg->arg_type == O_ASSIGN && X arg[1].arg_type == A_LEXPR && X arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY && X strnEQ("_GEN_", X stab_name( X arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab), X 5)) { /* array generated for foreach */ X (void)localize(arg); X } X } X X /* in any event, save the iterator */ X X (void)apush(tosave,cmd->c_short); X } X shouldsave |= tmpsave; X } X break; X case C_BLOCK: X case C_ELSE: X case C_IF: X if (cmd->ucmd.ccmd.cc_true) X shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); X break; X case C_EXPR: X if (cmd->ucmd.acmd.ac_expr) X shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave); X break; X } X lastcmd = cmd; X cmd = cmd->c_next; X if (cmd && cmd == head) /* reached end of while loop */ X break; X } X return shouldsave; X} X Xstatic int Xarg_tosave(arg,willsave) Xregister ARG *arg; Xint willsave; X{ X register int i; X int shouldsave = FALSE; X X for (i = arg->arg_len; i >= 1; i--) { X switch (arg[i].arg_type & A_MASK) { X case A_NULL: X break; X case A_LEXPR: X case A_EXPR: X shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave); X break; X case A_CMD: X shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave); X break; X case A_WORD: X case A_STAB: X case A_LVAL: X case A_READ: X case A_GLOB: X case A_ARYLEN: X case A_SINGLE: X case A_DOUBLE: X case A_BACKTICK: X break; X case A_SPAT: X shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat); X break; X } X } X switch (arg->arg_type) { X case O_RETURN: X saw_return = TRUE; X break; X case O_EVAL: X case O_SUBR: X shouldsave = TRUE; X break; X } X if (willsave) X (void)apush(tosave,arg->arg_ptr.arg_str); X return shouldsave; X} X Xstatic int Xspat_tosave(spat) Xregister SPAT *spat; X{ X int shouldsave = FALSE; X X if (spat->spat_runtime) X shouldsave |= arg_tosave(spat->spat_runtime,FALSE); X if (spat->spat_repl) { X shouldsave |= arg_tosave(spat->spat_repl,FALSE); X } X X return shouldsave; X} X !STUFFY!FUNK! echo Extracting x2p/str.c sed >x2p/str.c <<'!STUFFY!FUNK!' -e 's/X//' X/* $Header: str.c,v 4.0 91/03/20 01:58:15 lwall Locked $ X * X * Copyright (c) 1989, Larry Wall X * X * You may distribute under the terms of the GNU General Public License X * as specified in the README file that comes with the perl 3.0 kit. X * X * $Log: str.c,v $ X * Revision 4.0 91/03/20 01:58:15 lwall X * 4.0 baseline. X * X */ X X#include "handy.h" X#include "EXTERN.h" X#include "util.h" X#include "a2p.h" X Xstr_numset(str,num) Xregister STR *str; Xdouble num; X{ X str->str_nval = num; X str->str_pok = 0; /* invalidate pointer */ X str->str_nok = 1; /* validate number */ X} X Xchar * Xstr_2ptr(str) Xregister STR *str; X{ X register char *s; X X if (!str) X return ""; X GROWSTR(&(str->str_ptr), &(str->str_len), 24); X s = str->str_ptr; X if (str->str_nok) { X sprintf(s,"%.20g",str->str_nval); X while (*s) s++; X } X *s = '\0'; X str->str_cur = s - str->str_ptr; X str->str_pok = 1; X#ifdef DEBUGGING X if (debug & 32) X fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr); X#endif X return str->str_ptr; X} X Xdouble Xstr_2num(str) Xregister STR *str; X{ X if (!str) X return 0.0; X if (str->str_len && str->str_pok) X str->str_nval = atof(str->str_ptr); X else X str->str_nval = 0.0; X str->str_nok = 1; X#ifdef DEBUGGING X if (debug & 32) X fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval); X#endif X return str->str_nval; X} X Xstr_sset(dstr,sstr) XSTR *dstr; Xregister STR *sstr; X{ X if (!sstr) X str_nset(dstr,No,0); X else if (sstr->str_nok) X str_numset(dstr,sstr->str_nval); X else if (sstr->str_pok) X str_nset(dstr,sstr->str_ptr,sstr->str_cur); X else X str_nset(dstr,"",0); X} X Xstr_nset(str,ptr,len) Xregister STR *str; Xregister char *ptr; Xregister int len; X{ X GROWSTR(&(str->str_ptr), &(str->str_len), len + 1); X bcopy(ptr,str->str_ptr,len); X str->str_cur = len; X *(str->str_ptr+str->str_cur) = '\0'; X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X} X Xstr_set(str,ptr) Xregister STR *str; Xregister char *ptr; X{ X register int len; X X if (!ptr) X ptr = ""; X len = strlen(ptr); X GROWSTR(&(str->str_ptr), &(str->str_len), len + 1); X bcopy(ptr,str->str_ptr,len+1); X str->str_cur = len; X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X} X Xstr_chop(str,ptr) /* like set but assuming ptr is in str */ Xregister STR *str; Xregister char *ptr; X{ X if (!(str->str_pok)) X str_2ptr(str); X str->str_cur -= (ptr - str->str_ptr); X bcopy(ptr,str->str_ptr, str->str_cur + 1); X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X} X Xstr_ncat(str,ptr,len) Xregister STR *str; Xregister char *ptr; Xregister int len; X{ X if (!(str->str_pok)) X str_2ptr(str); X GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1); X bcopy(ptr,str->str_ptr+str->str_cur,len); X str->str_cur += len; X *(str->str_ptr+str->str_cur) = '\0'; X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X} X Xstr_scat(dstr,sstr) XSTR *dstr; Xregister STR *sstr; X{ X if (!(sstr->str_pok)) X str_2ptr(sstr); X if (sstr) X str_ncat(dstr,sstr->str_ptr,sstr->str_cur); X} X Xstr_cat(str,ptr) Xregister STR *str; Xregister char *ptr; X{ X register int len; X X if (!ptr) X return; X if (!(str->str_pok)) X str_2ptr(str); X len = strlen(ptr); X GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1); X bcopy(ptr,str->str_ptr+str->str_cur,len+1); X str->str_cur += len; X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X} X Xchar * Xstr_append_till(str,from,delim,keeplist) Xregister STR *str; Xregister char *from; Xregister int delim; Xchar *keeplist; X{ X register char *to; X register int len; X X if (!from) X return Nullch; X len = strlen(from); X GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1); X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X to = str->str_ptr+str->str_cur; X for (; *from; from++,to++) { X if (*from == '\\' && from[1] && delim != '\\') { X if (!keeplist) { X if (from[1] == delim || from[1] == '\\') X from++; X else X *to++ = *from++; X } X else if (index(keeplist,from[1])) X *to++ = *from++; X else X from++; X } X else if (*from == delim) X break; X *to = *from; X } X *to = '\0'; X str->str_cur = to - str->str_ptr; X return from; X} X XSTR * Xstr_new(len) Xint len; X{ X register STR *str; X X if (freestrroot) { X str = freestrroot; X freestrroot = str->str_link.str_next; X } X else { X str = (STR *) safemalloc(sizeof(STR)); X bzero((char*)str,sizeof(STR)); X } X if (len) X GROWSTR(&(str->str_ptr), &(str->str_len), len + 1); X return str; X} X Xvoid Xstr_grow(str,len) Xregister STR *str; Xint len; X{ X if (len && str) X GROWSTR(&(str->str_ptr), &(str->str_len), len + 1); X} X X/* make str point to what nstr did */ X Xvoid Xstr_replace(str,nstr) Xregister STR *str; Xregister STR *nstr; X{ X safefree(str->str_ptr); X str->str_ptr = nstr->str_ptr; X str->str_len = nstr->str_len; X str->str_cur = nstr->str_cur; X str->str_pok = nstr->str_pok; X if (str->str_nok = nstr->str_nok) X str->str_nval = nstr->str_nval; X safefree((char*)nstr); X} X Xvoid Xstr_free(str) Xregister STR *str; X{ X if (!str) X return; X if (str->str_len) X str->str_ptr[0] = '\0'; X str->str_cur = 0; X str->str_nok = 0; X str->str_pok = 0; X str->str_link.str_next = freestrroot; X freestrroot = str; X} X Xstr_len(str) Xregister STR *str; X{ X if (!str) X return 0; X if (!(str->str_pok)) X str_2ptr(str); X if (str->str_len) X return str->str_cur; X else X return 0; X} X Xchar * Xstr_gets(str,fp) Xregister STR *str; Xregister FILE *fp; X{ X#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */ X X register char *bp; /* we're going to steal some values */ X register int cnt; /* from the stdio struct and put EVERYTHING */ X register STDCHAR *ptr; /* in the innermost loop into registers */ X register char newline = '\n'; /* (assuming at least 6 registers) */ X int i; X int bpx; X X cnt = fp->_cnt; /* get count into register */ X str->str_nok = 0; /* invalidate number */ X str->str_pok = 1; /* validate pointer */ X if (str->str_len <= cnt) /* make sure we have the room */ X GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1); X bp = str->str_ptr; /* move these two too to registers */ X ptr = fp->_ptr; X for (;;) { X while (--cnt >= 0) { X if ((*bp++ = *ptr++) == newline) X if (bp <= str->str_ptr || bp[-2] != '\\') X goto thats_all_folks; X else { X line++; X bp -= 2; X } X } X X fp->_cnt = cnt; /* deregisterize cnt and ptr */ X fp->_ptr = ptr; X i = _filbuf(fp); /* get more characters */ X cnt = fp->_cnt; X ptr = fp->_ptr; /* reregisterize cnt and ptr */ X X bpx = bp - str->str_ptr; /* prepare for possible relocation */ X GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1); X bp = str->str_ptr + bpx; /* reconstitute our pointer */ X X if (i == newline) { /* all done for now? */ X *bp++ = i; X goto thats_all_folks; X } X else if (i == EOF) /* all done for ever? */ X goto thats_all_folks; X *bp++ = i; /* now go back to screaming loop */ X } X Xthats_all_folks: X fp->_cnt = cnt; /* put these back or we're in trouble */ X fp->_ptr = ptr; X *bp = '\0'; X str->str_cur = bp - str->str_ptr; /* set length */ X X#else /* !STDSTDIO */ /* The big, slow, and stupid way */ X X static char buf[4192]; X X if (fgets(buf, sizeof buf, fp) != Nullch) X str_set(str, buf); X else X str_set(str, No); X X#endif /* STDSTDIO */ X X return str->str_cur ? str->str_ptr : Nullch; X} X Xvoid Xstr_inc(str) Xregister STR *str; X{ X register char *d; X X if (!str) X return; X if (str->str_nok) { X str->str_nval += 1.0; X str->str_pok = 0; X return; X } X if (!str->str_pok) { X str->str_nval = 1.0; X str->str_nok = 1; X return; X } X for (d = str->str_ptr; *d && *d != '.'; d++) ; X d--; X if (!isdigit(*str->str_ptr) || !isdigit(*d) ) { X str_numset(str,atof(str->str_ptr) + 1.0); /* punt */ X return; X } X while (d >= str->str_ptr) { X if (++*d <= '9') X return; X *(d--) = '0'; X } X /* oh,oh, the number grew */ X GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2); X str->str_cur++; X for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--) X *d = d[-1]; X *d = '1'; X} X Xvoid Xstr_dec(str) Xregister STR *str; X{ X register char *d; X X if (!str) X return; X if (str->str_nok) { X str->str_nval -= 1.0; X str->str_pok = 0; X return; X } X if (!str->str_pok) { X str->str_nval = -1.0; X str->str_nok = 1; X return; X } X for (d = str->str_ptr; *d && *d != '.'; d++) ; X d--; X if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) { X str_numset(str,atof(str->str_ptr) - 1.0); /* punt */ X return; X } X while (d >= str->str_ptr) { X if (--*d >= '0') X return; X *(d--) = '9'; X } X} X X/* make a string that will exist for the duration of the expression eval */ X XSTR * Xstr_mortal(oldstr) XSTR *oldstr; X{ X register STR *str = str_new(0); X static long tmps_size = -1; X X str_sset(str,oldstr); X if (++tmps_max > tmps_size) { X tmps_size = tmps_max; X if (!(tmps_size & 127)) { X if (tmps_size) X tmps_list = (STR**)saferealloc((char*)tmps_list, X (tmps_size + 128) * sizeof(STR*) ); X else X tmps_list = (STR**)safemalloc(128 * sizeof(char*)); X } X } X tmps_list[tmps_max] = str; X return str; X} X XSTR * Xstr_make(s) Xchar *s; X{ X register STR *str = str_new(0); X X str_set(str,s); X return str; X} X XSTR * Xstr_nmake(n) Xdouble n; X{ X register STR *str = str_new(0); X X str_numset(str,n); X return str; X} !STUFFY!FUNK! echo Extracting msdos/Changes.dds sed >msdos/Changes.dds <<'!STUFFY!FUNK!' -e 's/X//' XThese are the changes done by the `patches' file: X X[These patches have been applied, more or less, so I don't supply the Xpatches file--law] X XCompilation of some portions is done conditional on the definition Xof the following symbols: X XBINARY Enables the usage of setmode under MSDOS (added binmode command) XBUGGY_MSC Adds #pragma_function(memset) to avoid internal compiler error XCHOWN Enables chown XCHROOT Enables chroot XFORK Enables fork and changes the compilation of system XGETLOGIN Enables getlogin XGETPPID Enables getppid XGROUP Enables all the group access functions XKILL Enables kill XLINK Enables link XPASSWD Enables all the password access functions XPIPE Enables the pipe function XWAIT Enables the wait function XUMASK Enables the umask function X XS_IFBLK * Enables the block special device check XS_ISGID * Enables the setgid check XS_ISUID * Enables the setuid check XS_ISVTX * Enables the vtx check Xunix * Compiles globbing for Unix XMSDOS * Compiles globbing for MS-DOS X Closes stdaux and stdprn on startup X Adds a copyright message for -v X Disables the compilation of my_popen, my_pclose as the X are in a separate file. X XSymbols marked with * are defined in the compilation environment. The Xrest should be added to config.h (config.h.SH). All functions when not Xsupported give a fatal error. X XAdded documentation for the binmode function in the manual. X XFixed the following bugs: X XIn eval.c function eval if ioctl or fcntl returned something Xother than 0 or -1 the result was a random number as the Xdouble `value' variable wasn't set to `anum'. X XIn doio.c function do_exec there were two errors associated with Xfiring up the shell when the execv fails. First argv was not freed, Xsecondly an attempt was made to start up the shell with the cmd Xstring that was now cut to pieces for the execv. Also the maxible Xpossible length of argv was calculated by (s - cmd). Problem was Xthat s was not pointing to the end of the string, but to the first Xnon alpha. X X[These are incorporated in patches 15 and 16--law] X XDiomidis Spinellis, March 1990 !STUFFY!FUNK! echo " " echo "End of kit 13 (of 36)" cat /dev/null >kit13isdone run='' config='' for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36; do if test -f kit${iskit}isdone; then run="$run $iskit" else todo="$todo $iskit" fi done case $todo in '') echo "You have run all your kits. Please read README and then type Configure." for combo in *:AA; do if test -f "$combo"; then realfile=`basename $combo :AA` cat $realfile:[A-Z][A-Z] >$realfile rm -rf $realfile:[A-Z][A-Z] fi done rm -rf kit*isdone chmod 755 Configure ;; *) echo "You have run$run." echo "You still need to run$todo." ;; esac : Someone might mail this, so... exit exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.