📄 doarg.c
字号:
/* $RCSfile: doarg.c,v $$Revision: 4.0.1.8 $$Date: 1993/02/05 19:32: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: doarg.c,v $ * Revision 4.0.1.8 1993/02/05 19:32:27 lwall * patch36: substitution didn't always invalidate numericity * * Revision 4.0.1.7 92/06/11 21:07:11 lwall * patch34: join with null list attempted negative allocation * patch34: sprintf("%6.4s", "abcdefg") didn't print "abcd " * * Revision 4.0.1.6 92/06/08 12:34:30 lwall * patch20: removed implicit int declarations on funcions * patch20: pattern modifiers i and o didn't interact right * patch20: join() now pre-extends target string to avoid excessive copying * patch20: fixed confusion between a *var's real name and its effective name * patch20: subroutines didn't localize $`, $&, $', $1 et al correctly * patch20: usersub routines didn't reclaim temp values soon enough * patch20: ($<,$>) = ... didn't work on some architectures * patch20: added Atari ST portability * * Revision 4.0.1.5 91/11/11 16:31:58 lwall * patch19: added little-endian pack/unpack options * * Revision 4.0.1.4 91/11/05 16:35:06 lwall * patch11: /$foo/o optimizer could access deallocated data * patch11: minimum match length calculation in regexp is now cumulative * patch11: added some support for 64-bit integers * patch11: prepared for ctype implementations that don't define isascii() * patch11: sprintf() now supports any length of s field * patch11: indirect subroutine calls through magic vars (e.g. &$1) didn't work * patch11: defined(&$foo) and undef(&$foo) didn't work * * Revision 4.0.1.3 91/06/10 01:18:41 lwall * patch10: pack(hh,1) dumped core * * Revision 4.0.1.2 91/06/07 10:42:17 lwall * patch4: new copyright notice * 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: added global modifier for pattern matches * patch4: undef @array disabled "@array" interpolation * patch4: chop("") was returning "\0" rather than "" * patch4: vector logical operations &, | and ^ sometimes returned null string * patch4: syscall couldn't pass numbers with most significant bit set on sparcs * * Revision 4.0.1.1 91/04/11 17:40:14 lwall * patch1: fixed undefined environ problem * patch1: fixed debugger coredump on subroutines * * Revision 4.0 91/03/20 01:06:42 lwall * 4.0 baseline. * */#include "EXTERN.h"#include "perl.h"#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)#include <signal.h>#endifextern unsigned char fold[];#ifdef BUGGY_MSC #pragma function(memcmp)#endif /* BUGGY_MSC */static void doencodes();intdo_subst(str,arg,sp)STR *str;ARG *arg;int sp;{ register SPAT *spat; SPAT *rspat; register STR *dstr; register char *s = str_get(str); char *strend = s + str->str_cur; register char *m; char *c; register char *d; int clen; int iters = 0; int maxiters = (strend - s) + 10; register int i; bool once; char *orig; int safebase; rspat = spat = arg[2].arg_ptr.arg_spat; if (!spat || !s) fatal("panic: do_subst"); else if (spat->spat_runtime) { nointrp = "|)"; (void)eval(spat->spat_runtime,G_SCALAR,sp); m = str_get(dstr = stack->ary_array[sp+1]); nointrp = ""; if (spat->spat_regexp) { regfree(spat->spat_regexp); spat->spat_regexp = Null(REGEXP*); /* required if regcomp pukes */ } spat->spat_regexp = regcomp(m,m+dstr->str_cur, spat->spat_flags & SPAT_FOLD); if (spat->spat_flags & SPAT_KEEP) { if (!(spat->spat_flags & SPAT_FOLD)) scanconst(spat, m, dstr->str_cur); 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); } } }#ifdef DEBUGGING if (debug & 8) { deb("2.SPAT /%s/\n",spat->spat_regexp->precomp); }#endif safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) && !sawampersand); if (!spat->spat_regexp->prelen && lastspat) spat = lastspat; orig = m = s; if (hint) { if (hint < s || hint > strend) fatal("panic: hint in do_match"); s = hint; hint = Nullch; if (spat->spat_regexp->regback >= 0) { s -= spat->spat_regexp->regback; if (s < m) s = m; } else s = m; } else if (spat->spat_short) { if (spat->spat_flags & SPAT_SCANFIRST) { if (str->str_pok & SP_STUDIED) { if (screamfirst[spat->spat_short->str_rare] < 0) goto nope; else if (!(s = screaminstr(str,spat->spat_short))) goto nope; }#ifndef lint else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend, spat->spat_short))) goto nope;#endif if (s && spat->spat_regexp->regback >= 0) { ++spat->spat_short->str_u.str_useful; s -= spat->spat_regexp->regback; if (s < m) s = m; } else s = m; } 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 */ } } once = !(rspat->spat_flags & SPAT_GLOBAL); if (rspat->spat_flags & SPAT_CONST) { /* known replacement string? */ if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE) dstr = rspat->spat_repl[1].arg_ptr.arg_str; else { /* constant over loop, anyway */ (void)eval(rspat->spat_repl,G_SCALAR,sp); dstr = stack->ary_array[sp+1]; } c = str_get(dstr); clen = dstr->str_cur; if (clen <= spat->spat_regexp->minlen) { /* can do inplace substitution */ if (regexec(spat->spat_regexp, s, strend, orig, 0, str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) { if (spat->spat_regexp->subbase) /* oops, no we can't */ goto long_way; d = s; lastspat = spat; str->str_pok = SP_VALID; /* disable possible screamer */ if (once) { m = spat->spat_regexp->startp[0]; d = spat->spat_regexp->endp[0]; s = orig; if (m - s > strend - d) { /* faster to shorten from end */ if (clen) { Copy(c, m, clen, char); m += clen; } i = strend - d; if (i > 0) { Move(d, m, i, char); m += i; } *m = '\0'; str->str_cur = m - s; STABSET(str); str_numset(arg->arg_ptr.arg_str, 1.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } /*SUPPRESS 560*/ else if (i = m - s) { /* faster from front */ d -= clen; m = d; str_chop(str,d-i); s += i; while (i--) *--d = *--s; if (clen) Copy(c, m, clen, char); STABSET(str); str_numset(arg->arg_ptr.arg_str, 1.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } else if (clen) { d -= clen; str_chop(str,d); Copy(c,d,clen,char); STABSET(str); str_numset(arg->arg_ptr.arg_str, 1.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } else { str_chop(str,d); STABSET(str); str_numset(arg->arg_ptr.arg_str, 1.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } /* NOTREACHED */ } do { if (iters++ > maxiters) fatal("Substitution loop"); m = spat->spat_regexp->startp[0]; /*SUPPRESS 560*/ if (i = m - s) { if (s != d) Move(s,d,i,char); d += i; } if (clen) { Copy(c,d,clen,char); d += clen; } s = spat->spat_regexp->endp[0]; } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr, TRUE)); /* (don't match same null twice) */ if (s != d) { i = strend - s; str->str_cur = d - str->str_ptr + i; Move(s,d,i+1,char); /* include the Null */ } STABSET(str); str_numset(arg->arg_ptr.arg_str, (double)iters); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } str_numset(arg->arg_ptr.arg_str, 0.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; return sp; } } else c = Nullch; if (regexec(spat->spat_regexp, s, strend, orig, 0, str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) { long_way: dstr = Str_new(25,str_len(str)); str_nset(dstr,m,s-m); if (spat->spat_regexp->subbase) curspat = spat; lastspat = spat; do { if (iters++ > maxiters) fatal("Substitution loop"); 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]; str_ncat(dstr,s,m-s); s = spat->spat_regexp->endp[0]; if (c) { if (clen) str_ncat(dstr,c,clen); } else { char *mysubbase = spat->spat_regexp->subbase; spat->spat_regexp->subbase = Nullch; /* so recursion works */ (void)eval(rspat->spat_repl,G_SCALAR,sp); str_scat(dstr,stack->ary_array[sp+1]); if (spat->spat_regexp->subbase) Safefree(spat->spat_regexp->subbase); spat->spat_regexp->subbase = mysubbase; } if (once) break; } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr, safebase)); str_ncat(dstr,s,strend - s); str_replace(str,dstr); STABSET(str); str_numset(arg->arg_ptr.arg_str, (double)iters); stack->ary_array[++sp] = arg->arg_ptr.arg_str; str->str_nok = 0; return sp; } str_numset(arg->arg_ptr.arg_str, 0.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; return sp;nope: ++spat->spat_short->str_u.str_useful; str_numset(arg->arg_ptr.arg_str, 0.0); stack->ary_array[++sp] = arg->arg_ptr.arg_str; return sp;}#ifdef BUGGY_MSC #pragma intrinsic(memcmp)#endif /* BUGGY_MSC */intdo_trans(str,arg)STR *str;ARG *arg;{ register short *tbl; register char *s; register int matches = 0; register int ch; register char *send; register char *d; register int squash = arg[2].arg_len & 1; tbl = (short*) arg[2].arg_ptr.arg_cval; s = str_get(str); send = s + str->str_cur; if (!tbl || !s) fatal("panic: do_trans");#ifdef DEBUGGING if (debug & 8) { deb("2.TBL\n"); }#endif if (!arg[2].arg_len) { while (s < send) { if ((ch = tbl[*s & 0377]) >= 0) { matches++; *s = ch; } s++; } } else { d = s; while (s < send) { if ((ch = tbl[*s & 0377]) >= 0) { *d = ch; if (matches++ && squash) { if (d[-1] == *d) matches--; else d++; } else d++; } else if (ch == -1) /* -1 is unmapped character */ *d++ = *s; /* -2 is delete character */ s++; } matches += send - d; /* account for disappeared chars */ *d = '\0'; str->str_cur = d - str->str_ptr; } STABSET(str); return matches;}voiddo_join(str,arglast)register STR *str;int *arglast;{ register STR **st = stack->ary_array; int sp = arglast[1]; register int items = arglast[2] - sp; register char *delim = str_get(st[sp]); register STRLEN len; int delimlen = st[sp]->str_cur; st += sp + 1; len = (items > 0 ? (delimlen * (items - 1) ) : 0); if (str->str_len < len + items) { /* current length is way too short */ while (items-- > 0) { if (*st) len += (*st)->str_cur; st++; } STR_GROW(str, len + 1); /* so try to pre-extend */ items = arglast[2] - sp; st -= items; } if (items-- > 0) str_sset(str, *st++); else str_set(str,""); len = delimlen; if (len) { for (; items > 0; items--,st++) { str_ncat(str,delim,len); str_scat(str,*st); } } else { for (; items > 0; items--,st++) str_scat(str,*st); } STABSET(str);}voiddo_pack(str,arglast)register STR *str;int *arglast;{ register STR **st = stack->ary_array; register int sp = arglast[1]; register int items; register char *pat = str_get(st[sp]); register char *patend = pat + st[sp]->str_cur; register int len; int datumtype; STR *fromstr; /*SUPPRESS 442*/ static char *null10 = "\0\0\0\0\0\0\0\0\0\0"; static char *space10 = " "; /* These must not be in registers: */ char achar; short ashort; int aint; unsigned int auint; long along; unsigned long aulong;#ifdef QUAD quad aquad; unsigned quad auquad;#endif char *aptr; float afloat; double adouble; items = arglast[2] - sp; st += ++sp; str_nset(str,"",0); while (pat < patend) {#define NEXTFROM (items-- > 0 ? *st++ : &str_no) datumtype = *pat++; if (*pat == '*') { len = index("@Xxu",datumtype) ? 0 : items; pat++; } else if (isDIGIT(*pat)) { len = *pat++ - '0'; while (isDIGIT(*pat)) len = (len * 10) + (*pat++ - '0'); } else len = 1; switch(datumtype) { default: break; case '%': fatal("% may only be used in unpack"); case '@': len -= str->str_cur; if (len > 0) goto grow; len = -len; if (len > 0) goto shrink; break; case 'X': shrink: if (str->str_cur < len) fatal("X outside of string"); str->str_cur -= len; str->str_ptr[str->str_cur] = '\0'; break; case 'x': grow: while (len >= 10) { str_ncat(str,null10,10); len -= 10; } str_ncat(str,null10,len); break; case 'A': case 'a': fromstr = NEXTFROM; aptr = str_get(fromstr); if (pat[-1] == '*') len = fromstr->str_cur; if (fromstr->str_cur > len) str_ncat(str,aptr,len); else { str_ncat(str,aptr,fromstr->str_cur); len -= fromstr->str_cur; if (datumtype == 'A') { while (len >= 10) { str_ncat(str,space10,10); len -= 10; } str_ncat(str,space10,len); } else { while (len >= 10) { str_ncat(str,null10,10); len -= 10; } str_ncat(str,null10,len); } } break; case 'B': case 'b': { char *savepat = pat; int saveitems; fromstr = NEXTFROM; saveitems = items; aptr = str_get(fromstr); if (pat[-1] == '*') len = fromstr->str_cur; pat = aptr; aint = str->str_cur; str->str_cur += (len+7)/8; STR_GROW(str, str->str_cur + 1); aptr = str->str_ptr + aint; if (len > fromstr->str_cur) len = fromstr->str_cur; aint = len; items = 0; if (datumtype == 'B') { for (len = 0; len++ < aint;) { items |= *pat++ & 1; if (len & 7) items <<= 1; else { *aptr++ = items & 0xff; items = 0; } } } else { for (len = 0; len++ < aint;) { if (*pat++ & 1) items |= 128; if (len & 7) items >>= 1; else { *aptr++ = items & 0xff; items = 0; } } } if (aint & 7) { if (datumtype == 'B') items <<= 7 - (aint & 7); else items >>= 7 - (aint & 7); *aptr++ = items & 0xff; } pat = str->str_ptr + str->str_cur; while (aptr <= pat) *aptr++ = '\0'; pat = savepat; items = saveitems; } break; case 'H': case 'h':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -