📄 dolist.c
字号:
/* $RCSfile: dolist.c,v $$Revision: 4.0.1.5 $$Date: 92/06/08 13:13:27 $ * * Copyright (c) 1991, Larry Wall * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * * $Log: dolist.c,v $ * Revision 4.0.1.5 92/06/08 13:13:27 lwall * patch20: g pattern modifer sometimes returned extra values * patch20: m/$pattern/g didn't work * patch20: pattern modifiers i and o didn't interact right * patch20: @ in unpack failed too often * patch20: Perl now distinguishes overlapped copies from non-overlapped * patch20: slice on null list in scalar context returned random value * patch20: splice with negative offset didn't work with $[ = 1 * patch20: fixed some memory leaks in splice * patch20: scalar keys %array now counts keys for you * * Revision 4.0.1.4 91/11/11 16:33:19 lwall * patch19: added little-endian pack/unpack options * patch19: sort $subname was busted by changes in 4.018 * * Revision 4.0.1.3 91/11/05 17:07:02 lwall * patch11: prepared for ctype implementations that don't define isascii() * patch11: /$foo/o optimizer could access deallocated data * patch11: certain optimizations of //g in array context returned too many values * patch11: regexp with no parens in array context returned wacky $`, $& and $' * patch11: $' not set right on some //g * patch11: added some support for 64-bit integers * patch11: grep of a split lost its values * patch11: added sort {} LIST * patch11: multiple reallocations now avoided in 1 .. 100000 * * Revision 4.0.1.2 91/06/10 01:22:15 lwall * patch10: //g only worked first time through * * Revision 4.0.1.1 91/06/07 10:58:28 lwall * patch4: new copyright notice * patch4: added global modifier for pattern matches * patch4: // wouldn't use previous pattern if it started with a null character * patch4: //o and s///o now optimize themselves fully at runtime * patch4: $` was busted inside s/// * patch4: caller($arg) didn't work except under debugger * * Revision 4.0 91/03/20 01:08:03 lwall * 4.0 baseline. * */#include "EXTERN.h"#include "perl.h"static int sortcmp();static int sortsub();#ifdef BUGGY_MSC #pragma function(memcmp)#endif /* BUGGY_MSC */intdo_match(str,arg,gimme,arglast)STR *str;register ARG *arg;int gimme;int *arglast;{ register STR **st = stack->ary_array; register SPAT *spat = arg[2].arg_ptr.arg_spat; register char *t; register int sp = arglast[0] + 1; STR *srchstr = st[sp]; register char *s = str_get(st[sp]); char *strend = s + st[sp]->str_cur; STR *tmpstr; char *myhint = hint; int global; int safebase; char *truebase = s; register REGEXP *rx = spat->spat_regexp; hint = Nullch; if (!spat) { if (gimme == G_ARRAY) return --sp; str_set(str,Yes); STABSET(str); st[sp] = str; return sp; } global = spat->spat_flags & SPAT_GLOBAL; safebase = (gimme == G_ARRAY) || global; if (!s) fatal("panic: do_match"); if (spat->spat_flags & SPAT_USED) {#ifdef DEBUGGING if (debug & 8) deb("2.SPAT USED\n");#endif if (gimme == G_ARRAY) return --sp; str_set(str,No); STABSET(str); st[sp] = str; return sp; } --sp; if (spat->spat_runtime) { nointrp = "|)"; sp = eval(spat->spat_runtime,G_SCALAR,sp); st = stack->ary_array; t = str_get(tmpstr = st[sp--]); nointrp = "";#ifdef DEBUGGING if (debug & 8) deb("2.SPAT /%s/\n",t);#endif if (!global && rx) regfree(rx); spat->spat_regexp = Null(REGEXP*); /* crucial if regcomp aborts */ spat->spat_regexp = regcomp(t,t+tmpstr->str_cur, spat->spat_flags & SPAT_FOLD); if (!spat->spat_regexp->prelen && lastspat) spat = lastspat; if (spat->spat_flags & SPAT_KEEP) { if (!(spat->spat_flags & SPAT_FOLD)) scanconst(spat,spat->spat_regexp->precomp, spat->spat_regexp->prelen); if (spat->spat_runtime) arg_free(spat->spat_runtime); /* it won't change, so */ spat->spat_runtime = Nullarg; /* no point compiling again */ hoistmust(spat); if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) { curcmd->c_flags &= ~CF_OPTIMIZE; opt_arg(curcmd, 1, curcmd->c_type == C_EXPR); } } if (global) { if (rx) { if (rx->startp[0]) { s = rx->endp[0]; if (s == rx->startp[0]) s++; if (s > strend) { regfree(rx); rx = spat->spat_regexp; goto nope; } } regfree(rx); } } else if (!spat->spat_regexp->nparens) gimme = G_SCALAR; /* accidental array context? */ rx = spat->spat_regexp; if (regexec(rx, s, strend, s, 0, srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr, safebase)) { if (rx->subbase || global) curspat = spat; lastspat = spat; goto gotcha; } else { if (gimme == G_ARRAY) return sp; str_sset(str,&str_no); STABSET(str); st[++sp] = str; return sp; } } else {#ifdef DEBUGGING if (debug & 8) { char ch; if (spat->spat_flags & SPAT_ONCE) ch = '?'; else ch = '/'; deb("2.SPAT %c%s%c\n",ch,rx->precomp,ch); }#endif if (!rx->prelen && lastspat) { spat = lastspat; rx = spat->spat_regexp; } t = s; play_it_again: if (global && rx->startp[0]) { t = s = rx->endp[0]; if (s == rx->startp[0]) s++,t++; if (s > strend) goto nope; } if (myhint) { if (myhint < s || myhint > strend) fatal("panic: hint in do_match"); s = myhint; if (rx->regback >= 0) { s -= rx->regback; if (s < t) s = t; } else s = t; } else if (spat->spat_short) { if (spat->spat_flags & SPAT_SCANFIRST) { if (srchstr->str_pok & SP_STUDIED) { if (screamfirst[spat->spat_short->str_rare] < 0) goto nope; else if (!(s = screaminstr(srchstr,spat->spat_short))) goto nope; else if (spat->spat_flags & SPAT_ALL) goto yup; }#ifndef lint else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend, spat->spat_short))) goto nope;#endif else if (spat->spat_flags & SPAT_ALL) goto yup; if (s && rx->regback >= 0) { ++spat->spat_short->str_u.str_useful; s -= rx->regback; if (s < t) s = t; } else s = t; } else if (!multiline && (*spat->spat_short->str_ptr != *s || bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) )) goto nope; if (--spat->spat_short->str_u.str_useful < 0) { str_free(spat->spat_short); spat->spat_short = Nullstr; /* opt is being useless */ } } if (!rx->nparens && !global) { gimme = G_SCALAR; /* accidental array context? */ safebase = FALSE; } if (regexec(rx, s, strend, truebase, 0, srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr, safebase)) { if (rx->subbase || global) curspat = spat; lastspat = spat; if (spat->spat_flags & SPAT_ONCE) spat->spat_flags |= SPAT_USED; goto gotcha; } else { if (global) rx->startp[0] = Nullch; if (gimme == G_ARRAY) return sp; str_sset(str,&str_no); STABSET(str); st[++sp] = str; return sp; } } /*NOTREACHED*/ gotcha: if (gimme == G_ARRAY) { int iters, i, len; iters = rx->nparens; if (global && !iters) i = 1; else i = 0; if (sp + iters + i >= stack->ary_max) { astore(stack,sp + iters + i, Nullstr); st = stack->ary_array; /* possibly realloced */ } for (i = !i; i <= iters; i++) { st[++sp] = str_mortal(&str_no); /*SUPPRESS 560*/ if (s = rx->startp[i]) { len = rx->endp[i] - s; if (len > 0) str_nset(st[sp],s,len); } } if (global) { truebase = rx->subbeg; goto play_it_again; } return sp; } else { str_sset(str,&str_yes); STABSET(str); st[++sp] = str; return sp; }yup: ++spat->spat_short->str_u.str_useful; lastspat = spat; if (spat->spat_flags & SPAT_ONCE) spat->spat_flags |= SPAT_USED; if (global) { rx->subbeg = t; rx->subend = strend; rx->startp[0] = s; rx->endp[0] = s + spat->spat_short->str_cur; curspat = spat; goto gotcha; } if (sawampersand) { char *tmps; if (rx->subbase) Safefree(rx->subbase); tmps = rx->subbase = nsavestr(t,strend-t); rx->subbeg = tmps; rx->subend = tmps + (strend-t); tmps = rx->startp[0] = tmps + (s - t); rx->endp[0] = tmps + spat->spat_short->str_cur; curspat = spat; } str_sset(str,&str_yes); STABSET(str); st[++sp] = str; return sp;nope: rx->startp[0] = Nullch; if (spat->spat_short) ++spat->spat_short->str_u.str_useful; if (gimme == G_ARRAY) return sp; str_sset(str,&str_no); STABSET(str); st[++sp] = str; return sp;}#ifdef BUGGY_MSC #pragma intrinsic(memcmp)#endif /* BUGGY_MSC */intdo_split(str,spat,limit,gimme,arglast)STR *str;register SPAT *spat;register int limit;int gimme;int *arglast;{ register ARRAY *ary = stack; STR **st = ary->ary_array; register int sp = arglast[0] + 1; register char *s = str_get(st[sp]); char *strend = s + st[sp--]->str_cur; register STR *dstr; register char *m; int iters = 0; int maxiters = (strend - s) + 10; int i; char *orig; int origlimit = limit; int realarray = 0; if (!spat || !s) fatal("panic: do_split"); else if (spat->spat_runtime) { nointrp = "|)"; sp = eval(spat->spat_runtime,G_SCALAR,sp); st = stack->ary_array; m = str_get(dstr = st[sp--]); nointrp = ""; if (*m == ' ' && dstr->str_cur == 1) { str_set(dstr,"\\s+"); m = dstr->str_ptr; spat->spat_flags |= SPAT_SKIPWHITE; } if (spat->spat_regexp) { regfree(spat->spat_regexp); spat->spat_regexp = Null(REGEXP*); /* avoid possible double free */ } spat->spat_regexp = regcomp(m,m+dstr->str_cur, spat->spat_flags & SPAT_FOLD); if (spat->spat_flags & SPAT_KEEP || (spat->spat_runtime->arg_type == O_ITEM && (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) { arg_free(spat->spat_runtime); /* it won't change, so */ spat->spat_runtime = Nullarg; /* no point compiling again */ } }#ifdef DEBUGGING if (debug & 8) { deb("2.SPAT /%s/\n",spat->spat_regexp->precomp); }#endif ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab); if (ary && (gimme != G_ARRAY || (spat->spat_flags & SPAT_ONCE))) { realarray = 1; if (!(ary->ary_flags & ARF_REAL)) { ary->ary_flags |= ARF_REAL; for (i = ary->ary_fill; i >= 0; i--) ary->ary_array[i] = Nullstr; /* don't free mere refs */ } ary->ary_fill = -1; sp = -1; /* temporarily switch stacks */ } else ary = stack; orig = s; if (spat->spat_flags & SPAT_SKIPWHITE) { while (isSPACE(*s)) s++; } if (!limit) limit = maxiters + 2; if (strEQ("\\s+",spat->spat_regexp->precomp)) { while (--limit) { /*SUPPRESS 530*/ for (m = s; m < strend && !isSPACE(*m); m++) ; if (m >= strend) break; dstr = Str_new(30,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); /*SUPPRESS 530*/ for (s = m + 1; s < strend && isSPACE(*s); s++) ; } } else if (strEQ("^",spat->spat_regexp->precomp)) { while (--limit) { /*SUPPRESS 530*/ for (m = s; m < strend && *m != '\n'; m++) ; m++; if (m >= strend) break; dstr = Str_new(30,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); s = m; } } else if (spat->spat_short) { i = spat->spat_short->str_cur; if (i == 1) { int fold = (spat->spat_flags & SPAT_FOLD); i = *spat->spat_short->str_ptr; if (fold && isUPPER(i)) i = tolower(i); while (--limit) { if (fold) { for ( m = s; m < strend && *m != i && (!isUPPER(*m) || tolower(*m) != i); m++) /*SUPPRESS 530*/ ; } else /*SUPPRESS 530*/ for (m = s; m < strend && *m != i; m++) ; if (m >= strend) break; dstr = Str_new(30,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); s = m + 1; } } else {#ifndef lint while (s < strend && --limit && (m=fbminstr((unsigned char*)s, (unsigned char*)strend, spat->spat_short)) )#endif { dstr = Str_new(31,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); s = m + i; } } } else { maxiters += (strend - s) * spat->spat_regexp->nparens; while (s < strend && --limit && regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) { if (spat->spat_regexp->subbase && spat->spat_regexp->subbase != orig) { m = s; s = orig; orig = spat->spat_regexp->subbase; s = orig + (m - s); strend = s + (strend - m); } m = spat->spat_regexp->startp[0]; dstr = Str_new(32,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); if (spat->spat_regexp->nparens) { for (i = 1; i <= spat->spat_regexp->nparens; i++) { s = spat->spat_regexp->startp[i]; m = spat->spat_regexp->endp[i]; dstr = Str_new(33,m-s); str_nset(dstr,s,m-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); } } s = spat->spat_regexp->endp[0]; } } if (realarray) iters = sp + 1; else iters = sp - arglast[0]; if (iters > maxiters) fatal("Split loop"); if (s < strend || origlimit) { /* keep field after final delim? */ dstr = Str_new(34,strend-s); str_nset(dstr,s,strend-s); if (!realarray) str_2mortal(dstr); (void)astore(ary, ++sp, dstr); iters++; } else {#ifndef I286x while (iters > 0 && ary->ary_array[sp]->str_cur == 0) iters--,sp--;#else char *zaps; int zapb; if (iters > 0) { zaps = str_get(afetch(ary,sp,FALSE)); zapb = (int) *zaps; } while (iters > 0 && (!zapb)) { iters--,sp--; if (iters > 0) { zaps = str_get(afetch(ary,iters-1,FALSE)); zapb = (int) *zaps; } }#endif } if (realarray) { ary->ary_fill = sp; if (gimme == G_ARRAY) { sp++; astore(stack, arglast[0] + 1 + sp, Nullstr); Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*); return arglast[0] + sp; } } else { if (gimme == G_ARRAY) return sp; } sp = arglast[0] + 1; str_numset(str,(double)iters); STABSET(str); st[sp] = str; return sp;}intdo_unpack(str,gimme,arglast)STR *str;int gimme;int *arglast;{ STR **st = stack->ary_array; register int sp = arglast[0] + 1; register char *pat = str_get(st[sp++]); register char *s = str_get(st[sp]); char *strend = s + st[sp--]->str_cur; char *strbeg = s; register char *patend = pat + st[sp]->str_cur; int datumtype; register int len; register int bits; /* These must not be in registers: */ short ashort; int aint; long along;#ifdef QUAD quad aquad;#endif unsigned short aushort; unsigned int auint; unsigned long aulong;#ifdef QUAD unsigned quad auquad;#endif char *aptr; float afloat; double adouble; int checksum = 0; unsigned long culong; double cdouble; if (gimme != G_ARRAY) { /* arrange to do first one only */ /*SUPPRESS 530*/ for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ; if (index("aAbBhH", *patend) || *pat == '%') { patend++; while (isDIGIT(*patend) || *patend == '*') patend++; } else patend++; } sp--; while (pat < patend) { reparse: datumtype = *pat++; if (pat >= patend) len = 1; else if (*pat == '*') { len = strend - strbeg; /* long enough */ pat++; } else if (isDIGIT(*pat)) { len = *pat++ - '0'; while (isDIGIT(*pat)) len = (len * 10) + (*pat++ - '0'); } else len = (datumtype != '@'); switch(datumtype) { default: break; case '%': if (len == 1 && pat[-1] != '1')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -