Path: utzoo!attcan!uunet!wyse!vsi1!ames!elroy!jpl-devvax!lwall From: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Newsgroups: comp.sources.bugs Subject: perl 2.0 patch #18 Summary: This is an official patch for perl 2.0. Please apply it. Message-ID: <3575@jpl-devvax.JPL.NASA.GOV> Date: 22 Nov 88 10:07:33 GMT Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 920 System: perl version 2.0 Patch #: 18 Priority: MEDIUM-HOT Subject: declaration of origargv needed to be outside #ifdef DOSUID Subject: string variables referenced numerically can later lose string value Subject: manual page now contains current Release and Patchlevel Subject: "make realclean" removes more files Subject: removed extraneous EXT from struct definition in cmd.h Subject: added $: to specify breakable characters in formats Subject: continuation did not work with right justified or centered fields Subject: makedepend shouldn't search subdirectories for *.[ch] files Subject: documented non-initialization of SIG array Subject: initialization of ENV must be forced if TAINT defined Subject: $) wouldn't interpolate in "eff gid = $)" Subject: dependencies in the wrong order in Makefile Description: Sorry, I'm only one person. I didn't test the changes in patch17 when DOSUID is undefined, and so missed the undefined origargv thing. The fix is simply to move the declaration of origargv outside the #ifdef DOSUID. When you reference a string variable in a numeric context, the variable retains both a numeric value and a string value. It doesn't matter if the string variable isn't a legal number--if it's looked at in a string context, you still get the string value. Unfortunately there was a class of operation in perl that could inadvertently destroy the string value. Among these were array copies and postincrement/decrement. This has been fixed. The manual page now contains current Release and Patchlevel. "make realclean" now removes more files, as several people suggested. There was an extraneous EXT on a struct definition in cmd.h that declared no objects. Now there isn't. Continuation fields in formats break a variable in multiple fields so you can do "filled" text. It used to be you could only break these lines on spaces. Now by default they are broken on spaces and hyphens, and you can change that by assigning the list of break characters to $:. Continuation fields used to work only for left-justified text. Now it works for centered and right justified text. (It's still not perfect but at least it doesn't blow up.) The makedepend script had patterns like */*.c and */*.h that were holdovers from when it was used for rn. These patterns have been removed. The SIG array does not initialize itself to the all possible signals, but only holds the signals that have explicitly been set. This has now been documented. Setuid scripts that didn't explicitly reference ENV blew up because of the implicit reference when checking for an untainted PATH. The ENV array is now always initialized when TAINT is defined. $) wouldn't interpolate in "eff gid = $)". This was because it was mistakenly seen as a terminating $ in a subpattern. It now works correctly in "" and ``. There were some dependencies in the wrong order in the make file. Fix: From rn, say "| patch -p -N -d DIR", where DIR is your perl source directory. Outside of rn, say "cd DIR; patch -p -N #define PATCHLEVEL 18 Index: Makefile.SH Prereq: 2.0.1.6 *** Makefile.SH.old Tue Nov 22 01:20:29 1988 --- Makefile.SH Tue Nov 22 01:20:31 1988 *************** *** 25,33 **** echo "Extracting Makefile (with variable substitutions)" cat >Makefile <Makefile <perl.man install: all # won't work with csh --- 248,256 ---- touch $@ perl.man: perl.man.1 perl.man.2 ! ./perl -e '($$r,$$p)=$$]=~/(\d+\.\d+).*\n\D*(\d+)/; \ ! print ".ds RP Release $$r Patchlevel $$p\n";' >perl.man ! cat perl.man.1 perl.man.2 >>perl.man install: all # won't work with csh *************** *** 289,294 **** --- 296,303 ---- realclean: rm -f perl *.orig */*.orig *~ */*~ *.o core $(addedbyconf) perl.man + rm -f perl.c perly.h t/perl Makefile config.h makedepend makedir + rm -f x2p/Makefile # The following lint has practically everything turned on. Unfortunately, # you have to wade through a lot of mumbo jumbo that can't be suppressed. Index: cmd.h Prereq: 2.0 *** cmd.h.old Tue Nov 22 01:20:36 1988 --- cmd.h Tue Nov 22 01:20:37 1988 *************** *** 1,6 **** ! /* $Header: cmd.h,v 2.0 88/06/05 00:08:28 root Exp $ * * $Log: cmd.h,v $ * Revision 2.0 88/06/05 00:08:28 root * Baseline version 2.0. * --- 1,9 ---- ! /* $Header: cmd.h,v 2.0.1.1 88/11/22 01:05:06 lwall Locked $ * * $Log: cmd.h,v $ + * Revision 2.0.1.1 88/11/22 01:05:06 lwall + * patch18: removed extraneous EXT from struct definition in cmd.h + * * Revision 2.0 88/06/05 00:08:28 root * Baseline version 2.0. * *************** *** 120,126 **** EXT CMD *main_root INIT(Nullcmd); EXT CMD *eval_root INIT(Nullcmd); ! EXT struct compcmd { CMD *comp_true; CMD *comp_alt; }; --- 123,129 ---- EXT CMD *main_root INIT(Nullcmd); EXT CMD *eval_root INIT(Nullcmd); ! struct compcmd { CMD *comp_true; CMD *comp_alt; }; Index: form.c Prereq: 2.0.1.2 *** form.c.old Tue Nov 22 01:20:41 1988 --- form.c Tue Nov 22 01:20:42 1988 *************** *** 1,6 **** ! /* $Header: form.c,v 2.0.1.2 88/08/05 01:26:20 root Exp $ * * $Log: form.c,v $ * Revision 2.0.1.2 88/08/05 01:26:20 root * patch13: no form feeds first * --- 1,10 ---- ! /* $Header: form.c,v 2.0.1.3 88/11/22 01:07:10 lwall Locked $ * * $Log: form.c,v $ + * Revision 2.0.1.3 88/11/22 01:07:10 lwall + * patch18: added $: to specify breakable characters in formats + * patch18: continuation did not work with right justified or centered fields + * * Revision 2.0.1.2 88/08/05 01:26:20 root * patch13: no form feeds first * *************** *** 67,73 **** chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if ((*d++ = *s++) == ' ') chophere = s; } if (size) --- 71,77 ---- chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if (index(chopset,(*d++ = *s++))) chophere = s; } if (size) *************** *** 103,116 **** } break; case F_RIGHT: ! t = s = str_get(eval(fcmd->f_expr,Null(STR***),-1)); size = fcmd->f_size; CHKLEN(size); chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if (*s++ == ' ') ! chophere = s; } if (size) chophere = s; --- 107,121 ---- } break; case F_RIGHT: ! str = eval(fcmd->f_expr,Null(STR***),-1); ! t = s = str_get(str); size = fcmd->f_size; CHKLEN(size); chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if (index(chopset,*s++)) ! chophere = s; } if (size) chophere = s; *************** *** 118,142 **** if (!chophere) chophere = s; size += (s - chophere); - d -= (s - chophere); - if (fcmd->f_flags & FC_MORE && - *chophere && strNE(chophere,"\n")) { - while (size < 3) { - d--; - size++; - } - while (d[-1] == ' ' && size < fcmd->f_size) { - d--; - size++; - } - *d++ = '.'; - *d++ = '.'; - *d++ = '.'; - } s = chophere; while (*chophere == ' ' || *chophere == '\n') chophere++; - str_chop(str,chophere); } tmpchar = *s; *s = '\0'; --- 123,131 ---- *************** *** 148,165 **** bcopy(t,d,size); d += size; *s = tmpchar; break; case F_CENTER: { int halfsize; ! t = s = str_get(eval(fcmd->f_expr,Null(STR***),-1)); size = fcmd->f_size; CHKLEN(size); chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if (*s++ == ' ') ! chophere = s; } if (size) chophere = s; --- 137,157 ---- bcopy(t,d,size); d += size; *s = tmpchar; + if (fcmd->f_flags & FC_CHOP) + str_chop(str,chophere); break; case F_CENTER: { int halfsize; ! str = eval(fcmd->f_expr,Null(STR***),-1); ! t = s = str_get(str); size = fcmd->f_size; CHKLEN(size); chophere = Nullch; while (size && *s && *s != '\n') { size--; ! if (index(chopset,*s++)) ! chophere = s; } if (size) chophere = s; *************** *** 167,191 **** if (!chophere) chophere = s; size += (s - chophere); - d -= (s - chophere); - if (fcmd->f_flags & FC_MORE && - *chophere && strNE(chophere,"\n")) { - while (size < 3) { - d--; - size++; - } - while (d[-1] == ' ' && size < fcmd->f_size) { - d--; - size++; - } - *d++ = '.'; - *d++ = '.'; - *d++ = '.'; - } s = chophere; while (*chophere == ' ' || *chophere == '\n') chophere++; - str_chop(str,chophere); } tmpchar = *s; *s = '\0'; --- 159,167 ---- *************** *** 206,211 **** --- 182,189 ---- size--; *d++ = ' '; } + if (fcmd->f_flags & FC_CHOP) + str_chop(str,chophere); break; } case F_LINES: Index: form.h Prereq: 2.0 *** form.h.old Tue Nov 22 01:20:45 1988 --- form.h Tue Nov 22 01:20:46 1988 *************** *** 1,6 **** ! /* $Header: form.h,v 2.0 88/06/05 00:09:01 root Exp $ * * $Log: form.h,v $ * Revision 2.0 88/06/05 00:09:01 root * Baseline version 2.0. * --- 1,9 ---- ! /* $Header: form.h,v 2.0.1.1 88/11/22 01:08:49 lwall Locked $ * * $Log: form.h,v $ + * Revision 2.0.1.1 88/11/22 01:08:49 lwall + * patch18: added $: to specify breakable characters in formats + * * Revision 2.0 88/06/05 00:09:01 root * Baseline version 2.0. * *************** *** 27,29 **** --- 30,34 ---- #define FC_MORE 4 #define Nullfcmd Null(FCMD*) + + EXT char *chopset INIT(" -"); Index: makedepend.SH Prereq: 2.0 *** makedepend.SH.old Tue Nov 22 01:20:50 1988 --- makedepend.SH Tue Nov 22 01:20:50 1988 *************** *** 15,23 **** echo "Extracting makedepend (with variable substitutions)" $spitshell >makedepend <makedepend <.clist) for file in `$cat .clist`; do # for file in `cat /dev/null`; do case "$file" in --- 85,91 ---- esac make clist || ($echo "Searching for .c files..."; \ ! $echo *.c | $tr ' ' '\012' | $egrep -v '\*' >.clist) for file in `$cat .clist`; do # for file in `cat /dev/null`; do case "$file" in *************** *** 109,115 **** $sed Makefile.new -e '1,/^# AUTOMATICALLY/!d' make shlist || ($echo "Searching for .SH files..."; \ ! $echo *.SH */*.SH | $tr ' ' '\012' | $egrep -v '\*' >.shlist) if $test -s .deptmp; then for file in `cat .shlist`; do $echo `$expr X$file : 'X\(.*\).SH`: $file config.sh \; \ --- 112,118 ---- $sed Makefile.new -e '1,/^# AUTOMATICALLY/!d' make shlist || ($echo "Searching for .SH files..."; \ ! $echo *.SH | $tr ' ' '\012' | $egrep -v '\*' >.shlist) if $test -s .deptmp; then for file in `cat .shlist`; do $echo `$expr X$file : 'X\(.*\).SH`: $file config.sh \; \ *************** *** 122,128 **** >>Makefile.new else make hlist || ($echo "Searching for .h files..."; \ ! $echo *.h */*.h | $tr ' ' '\012' | $egrep -v '\*' >.hlist) $echo "You don't seem to have a proper C preprocessor. Using grep instead." $egrep '^#include ' `cat .clist` `cat .hlist` >.deptmp $echo "Updating Makefile..." --- 125,131 ---- >>Makefile.new else make hlist || ($echo "Searching for .h files..."; \ ! $echo *.h | $tr ' ' '\012' | $egrep -v '\*' >.hlist) $echo "You don't seem to have a proper C preprocessor. Using grep instead." $egrep '^#include ' `cat .clist` `cat .hlist` >.deptmp $echo "Updating Makefile..." Index: perl.man.1 Prereq: 2.0.1.7 *** perl.man.1.old Tue Nov 22 01:21:02 1988 --- perl.man.1 Tue Nov 22 01:21:08 1988 *************** *** 1,7 **** .rn '' }` ! ''' $Header: perl.man.1,v 2.0.1.7 88/11/18 23:59:52 lwall Locked $ ''' ''' $Log: perl.man.1,v $ ''' Revision 2.0.1.7 88/11/18 23:59:52 lwall ''' patch16: added getc function ''' --- 1,10 ---- .rn '' }` ! ''' $Header: perl.man.1,v 2.0.1.8 88/11/22 01:10:59 lwall Locked $ ''' ''' $Log: perl.man.1,v $ + ''' Revision 2.0.1.8 88/11/22 01:10:59 lwall + ''' patch18: manual page now contains current Release and Patchlevel + ''' ''' Revision 2.0.1.7 88/11/18 23:59:52 lwall ''' patch16: added getc function ''' *************** *** 70,76 **** .ds L' ` .ds R' ' 'br\} ! .TH PERL 1 LOCAL .UC .SH NAME perl \- Practical Extraction and Report Language --- 73,79 ---- .ds L' ` .ds R' ' 'br\} ! .TH PERL 1 "\*(RP" .UC .SH NAME perl \- Practical Extraction and Report Language Index: perl.man.2 Prereq: 2.0.1.8 *** perl.man.2.old Tue Nov 22 01:21:24 1988 --- perl.man.2 Tue Nov 22 01:21:31 1988 *************** *** 1,7 **** ''' Beginning of part 2 ! ''' $Header: perl.man.2,v 2.0.1.8 88/11/19 00:03:12 lwall Locked $ ''' ''' $Log: perl.man.2,v $ ''' Revision 2.0.1.8 88/11/19 00:03:12 lwall ''' patch16: added $] to return rcsid and patchlevel ''' patch16: documented how to write secure setuid perl scripts --- 1,11 ---- ''' Beginning of part 2 ! ''' $Header: perl.man.2,v 2.0.1.9 88/11/22 01:13:02 lwall Locked $ ''' ''' $Log: perl.man.2,v $ + ''' Revision 2.0.1.9 88/11/22 01:13:02 lwall + ''' patch18: added $: to specify breakable characters in formats + ''' patch18: documented non-initialization of SIG array + ''' ''' Revision 2.0.1.8 88/11/19 00:03:12 lwall ''' patch16: added $] to return rcsid and patchlevel ''' patch16: documented how to write secure setuid perl scripts *************** *** 1101,1106 **** --- 1105,1112 ---- out a block of text. If you like, you can end the final field with .\|.\|., which will appear in the output if the text was too long to appear in its entirety. + You can change which characters are legal to break on by changing the + variable $: to a list of the desired characters. .PP Since use of ^ fields can produce variable length records if the text to be formatted is short, you can suppress blank lines by putting the tilde (~) *************** *** 1430,1435 **** --- 1436,1446 ---- .Sp Note: $<, $>, $( and $) can only be set on machines that support the corresponding set[re][ug]id() routine. + .Ip $: 8 2 + The current set of characters after which a string may be broken to + fill continuation fields (starting with ^) in a format. + Default is "\ -", to break on spaces or hyphens. + (Mnemonic: a \*(L"colon\*(R" in poetry is a part of a line.) .Ip @ARGV 8 3 The array ARGV contains the command line arguments intended for the script. Note that $#ARGV is the generally number of arguments minus one, since *************** *** 1469,1474 **** --- 1480,1487 ---- $SIG{\'QUIT\'} = \'IGNORE\'; # ignore SIGQUIT .fi + The SIG array only contains values for the signals actually set within + the perl script. .Sh "Setuid Scripts" .I Perl is designed to make it easy to write secure setuid and setgid scripts. Index: perly.c Prereq: 2.0.1.9 *** perly.c.old Tue Nov 22 01:21:51 1988 --- perly.c Tue Nov 22 01:21:59 1988 *************** *** 1,6 **** ! char rcsid[] = "$Header: perly.c,v 2.0.1.9 88/11/19 00:14:36 lwall Exp $\nPatch level: ###\n"; /* * $Log: perly.c,v $ * Revision 2.0.1.9 88/11/19 00:14:36 lwall * patch16: added $] to return rcsid and patchlevel * patch16: added code to check for kernel setuid script bug --- 1,11 ---- ! char rcsid[] = "$Header: perly.c,v 2.0.1.10 88/11/22 01:14:58 lwall Locked $\nPatch level: ###\n"; /* * $Log: perly.c,v $ + * Revision 2.0.1.10 88/11/22 01:14:58 lwall + * patch18: declaration of origargv needed to be outside #ifdef DOSUID + * patch18: initialization of ENV must be forced if TAINT defined + * patch18: added $: to specify breakable characters in formats + * * Revision 2.0.1.9 88/11/19 00:14:36 lwall * patch16: added $] to return rcsid and patchlevel * patch16: added code to check for kernel setuid script bug *************** *** 102,109 **** register char *s; char *index(), *strcpy(), *getenv(); bool dosearch = FALSE; - #ifdef DOSUID char **origargv = argv; char *validarg = ""; #endif int gid = (int)getgid(); --- 107,114 ---- register char *s; char *index(), *strcpy(), *getenv(); bool dosearch = FALSE; char **origargv = argv; + #ifdef DOSUID char *validarg = ""; #endif int gid = (int)getgid(); *************** *** 569,574 **** --- 574,582 ---- apush(argvstab->stab_array,str_make(argv[0])); } } + #ifdef TAINT + (void) stabent("ENV",TRUE); /* must test PATH and IFS */ + #endif if (envstab = stabent("ENV",allstabs)) { hadd(envstab); for (; *env; env++) { *************** *** 587,598 **** if (sigstab = stabent("SIG",allstabs)) hadd(sigstab); ! magicalize("!#?^~=-%0123456789.+&*()<>,\\/[|`'"); amperstab = stabent("&",allstabs); leftstab = stabent("`",allstabs); rightstab = stabent("'",allstabs); sawampersand = (amperstab || leftstab || rightstab); /* these aren't necessarily magical */ if (tmpstab = stabent(";",allstabs)) --- 595,608 ---- if (sigstab = stabent("SIG",allstabs)) hadd(sigstab); ! magicalize("!#?^~=-%0123456789.+&*()<>,\\/[|`':"); amperstab = stabent("&",allstabs); leftstab = stabent("`",allstabs); rightstab = stabent("'",allstabs); sawampersand = (amperstab || leftstab || rightstab); + if (tmpstab = stabent(":",allstabs)) + str_set(STAB_STR(tmpstab),chopset); /* these aren't necessarily magical */ if (tmpstab = stabent(";",allstabs)) Index: stab.c Prereq: 2.0.1.6 *** stab.c.old Tue Nov 22 01:22:11 1988 --- stab.c Tue Nov 22 01:22:14 1988 *************** *** 1,6 **** ! /* $Header: stab.c,v 2.0.1.6 88/11/19 00:19:26 lwall Exp $ * * $Log: stab.c,v $ * Revision 2.0.1.6 88/11/19 00:19:26 lwall * patch16: $@ now reports correct error line after do EXPR * patch16: now makes use of setre[ug]id() if available --- 1,9 ---- ! /* $Header: stab.c,v 2.0.1.7 88/11/22 01:15:37 lwall Locked $ * * $Log: stab.c,v $ + * Revision 2.0.1.7 88/11/22 01:15:37 lwall + * patch18: added $: to specify breakable characters in formats + * * Revision 2.0.1.6 88/11/19 00:19:26 lwall * patch16: $@ now reports correct error line after do EXPR * patch16: now makes use of setre[ug]id() if available *************** *** 372,377 **** --- 375,383 ---- fatal("setegid() not implemented"); #endif #endif + break; + case ':': + chopset = str_get(str); break; case '.': case '+': Index: str.c Prereq: 2.0.1.4 *** str.c.old Tue Nov 22 01:22:20 1988 --- str.c Tue Nov 22 01:22:22 1988 *************** *** 1,6 **** ! /* $Header: str.c,v 2.0.1.4 88/11/19 00:21:57 lwall Exp $ * * $Log: str.c,v $ * Revision 2.0.1.4 88/11/19 00:21:57 lwall * patch16: "taint" checks for setuid scripts * --- 1,9 ---- ! /* $Header: str.c,v 2.0.1.5 88/11/22 01:18:37 lwall Locked $ * * $Log: str.c,v $ + * Revision 2.0.1.5 88/11/22 01:18:37 lwall + * patch18: string variables referenced numerically can later lose string value + * * Revision 2.0.1.4 88/11/19 00:21:57 lwall * patch16: "taint" checks for setuid scripts * *************** *** 165,174 **** #endif if (!sstr) str_nset(dstr,No,0); else if (sstr->str_nok) str_numset(dstr,sstr->str_nval); - else if (sstr->str_pok) - str_nset(dstr,sstr->str_ptr,sstr->str_cur); else str_nset(dstr,"",0); } --- 168,182 ---- #endif if (!sstr) str_nset(dstr,No,0); + else if (sstr->str_pok) { + str_nset(dstr,sstr->str_ptr,sstr->str_cur); + if (sstr->str_nok) { + dstr->str_nval = sstr->str_nval; + dstr->str_nok = 1; + } + } else if (sstr->str_nok) str_numset(dstr,sstr->str_nval); else str_nset(dstr,"",0); } Index: toke.c Prereq: 2.0.1.6 *** toke.c.old Tue Nov 22 01:22:31 1988 --- toke.c Tue Nov 22 01:22:35 1988 *************** *** 1,6 **** ! /* $Header: toke.c,v 2.0.1.6 88/11/19 00:25:21 lwall Exp $ * * $Log: toke.c,v $ * Revision 2.0.1.6 88/11/19 00:25:21 lwall * patch16: added getc function * patch16: variables in patterns are no longer hidden from -w typo detection --- 1,9 ---- ! /* $Header: toke.c,v 2.0.1.7 88/11/22 01:20:15 lwall Locked $ * * $Log: toke.c,v $ + * Revision 2.0.1.7 88/11/22 01:20:15 lwall + * patch18: $) wouldn't interpolate in "eff gid = $)" + * * Revision 2.0.1.6 88/11/19 00:25:21 lwall * patch16: added getc function * patch16: variables in patterns are no longer hidden from -w typo detection *************** *** 1075,1080 **** --- 1078,1084 ---- register ARG *arg; register bool makesingle = FALSE; register STAB *stab; + bool alwaysdollar = FALSE; char *leave = "\\$nrtfb0123456789"; /* which backslash sequences to keep */ arg = op_new(1); *************** *** 1207,1216 **** --- 1211,1222 ---- case '"': arg[1].arg_type = A_DOUBLE; makesingle = TRUE; /* maybe disable runtime scanning */ + alwaysdollar = TRUE; /* treat $) and $| as variables */ term = *s; goto snarf_it; case '`': arg[1].arg_type = A_BACKTICK; + alwaysdollar = TRUE; /* treat $) and $| as variables */ term = *s; snarf_it: { *************** *** 1241,1250 **** s = tmpstr->str_ptr; while (*s) { /* see if we can make SINGLE */ if (*s == '\\' && s[1] && isdigit(s[1]) && !isdigit(s[2]) && ! !index("`\"",term) ) *s = '$'; /* grandfather \digit in subst */ if (*s == '$' && s[1] && ! (index("`\"",term) || (s[1] != ')' && s[1] != '|'))) { makesingle = FALSE; /* force interpretation */ } else if (*s == '\\' && s[1]) { --- 1247,1256 ---- s = tmpstr->str_ptr; while (*s) { /* see if we can make SINGLE */ if (*s == '\\' && s[1] && isdigit(s[1]) && !isdigit(s[2]) && ! !alwaysdollar ) *s = '$'; /* grandfather \digit in subst */ if (*s == '$' && s[1] && ! (alwaysdollar || (s[1] != ')' && s[1] != '|'))) { makesingle = FALSE; /* force interpretation */ } else if (*s == '\\' && s[1]) { *************** *** 1254,1260 **** } s = d = tmpstr->str_ptr; /* assuming shrinkage only */ while (*s) { ! if (*s == '$' && s[1] && s[1] != ')' && s[1] != '|') { int len; len = scanreg(s,tokenbuf) - s; --- 1260,1267 ---- } s = d = tmpstr->str_ptr; /* assuming shrinkage only */ while (*s) { ! if (*s == '$' && s[1] && ! (alwaysdollar || (s[1] != ')' && s[1] != '|')) ) { int len; len = scanreg(s,tokenbuf) - s;