-/* $Header: str.c,v 2.0 88/06/05 00:11:07 root Exp $
+/* $Header: str.c,v 3.0.1.11 90/11/13 15:27:14 lwall Locked $
+ *
+ * Copyright (c) 1989, Larry Wall
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the perl 3.0 kit.
*
* $Log: str.c,v $
- * Revision 2.0 88/06/05 00:11:07 root
- * Baseline version 2.0.
+ * Revision 3.0.1.11 90/11/13 15:27:14 lwall
+ * patch41: fixed a couple of malloc/free problems
+ *
+ * Revision 3.0.1.10 90/11/10 02:06:29 lwall
+ * patch38: temp string values are now copied less often
+ * patch38: array slurps are now faster and take less memory
+ * patch38: fixed a memory leakage on local(*foo)
+ *
+ * Revision 3.0.1.9 90/10/16 10:41:21 lwall
+ * patch29: the undefined value could get defined by devious means
+ * patch29: undefined values compared inconsistently
+ * patch29: taintperl now checks for world writable PATH components
+ *
+ * Revision 3.0.1.8 90/08/09 05:22:18 lwall
+ * patch19: the number to string converter wasn't allocating enough space
+ * patch19: tainting didn't work on setgid scripts
+ *
+ * Revision 3.0.1.7 90/03/27 16:24:11 lwall
+ * patch16: strings with prefix chopped off sometimes freed wrong
+ * patch16: taint check blows up on undefined array element
+ *
+ * Revision 3.0.1.6 90/03/12 17:02:14 lwall
+ * patch13: substr as lvalue didn't invalidate old numeric value
+ *
+ * Revision 3.0.1.5 90/02/28 18:30:38 lwall
+ * patch9: you may now undef $/ to have no input record separator
+ * patch9: nested evals clobbered their longjmp environment
+ * patch9: sometimes perl thought ordinary data was a symbol table entry
+ * patch9: insufficient space allocated for numeric string on sun4
+ * patch9: underscore in an array name in a double-quoted string not recognized
+ * patch9: "@foo{}" not recognized unless %foo defined
+ * patch9: "$foo[$[]" gives error
+ *
+ * Revision 3.0.1.4 89/12/21 20:21:35 lwall
+ * patch7: errno may now be a macro with an lvalue
+ * patch7: made nested or recursive foreach work right
+ *
+ * Revision 3.0.1.3 89/11/17 15:38:23 lwall
+ * patch5: some machines typedef unchar too
+ * patch5: substitution on leading components occasionally caused <> corruption
+ *
+ * Revision 3.0.1.2 89/11/11 04:56:22 lwall
+ * patch2: uchar gives Crays fits
+ *
+ * Revision 3.0.1.1 89/10/26 23:23:41 lwall
+ * patch1: string ordering tests were wrong
+ * patch1: $/ now works even when STDSTDIO undefined
+ *
+ * Revision 3.0 89/10/18 15:23:38 lwall
+ * 3.0 baseline
*
*/
#include "EXTERN.h"
#include "perl.h"
+#include "perly.h"
-str_reset(s)
-register char *s;
+extern char **environ;
+
+#ifndef str_get
+char *
+str_get(str)
+STR *str;
{
- register STAB *stab;
- register STR *str;
- register int i;
- register int max;
- register SPAT *spat;
+#ifdef TAINT
+ tainted |= str->str_tainted;
+#endif
+ return str->str_pok ? str->str_ptr : str_2ptr(str);
+}
+#endif
- if (!*s) { /* reset ?? searches */
- for (spat = spat_root; spat != Nullspat; spat = spat->spat_next) {
- spat->spat_flags &= ~SPAT_USED;
+/* dlb ... guess we have a "crippled cc".
+ * dlb the following functions are usually macros.
+ */
+#ifndef str_true
+str_true(Str)
+STR *Str;
+{
+ if (Str->str_pok) {
+ if (*Str->str_ptr > '0' ||
+ Str->str_cur > 1 ||
+ (Str->str_cur && *Str->str_ptr != '0'))
+ return 1;
+ return 0;
}
- return;
- }
+ if (Str->str_nok)
+ return (Str->str_u.str_nval != 0.0);
+ return 0;
+}
+#endif /* str_true */
- /* reset variables */
+#ifndef str_gnum
+double str_gnum(Str)
+STR *Str;
+{
+#ifdef TAINT
+ tainted |= Str->str_tainted;
+#endif /* TAINT*/
+ if (Str->str_nok)
+ return Str->str_u.str_nval;
+ return str_2num(Str);
+}
+#endif /* str_gnum */
+/* dlb ... end of crutch */
- while (*s) {
- i = *s;
- if (s[1] == '-') {
- s += 2;
- }
- max = *s++;
- for ( ; i <= max; i++) {
- for (stab = stab_index[i]; stab; stab = stab->stab_next) {
- str = stab->stab_val;
- str->str_cur = 0;
- str->str_nok = 0;
- if (str->str_ptr != Nullch)
- str->str_ptr[0] = '\0';
- if (stab->stab_array) {
- aclear(stab->stab_array);
- }
- if (stab->stab_hash) {
- hclear(stab->stab_hash);
- }
- }
- }
+char *
+str_grow(str,newlen)
+register STR *str;
+#ifndef MSDOS
+register int newlen;
+#else
+unsigned long newlen;
+#endif
+{
+ register char *s = str->str_ptr;
+
+#ifdef MSDOS
+ if (newlen >= 0x10000) {
+ fprintf(stderr, "Allocation too large: %lx\n", newlen);
+ exit(1);
+ }
+#endif /* MSDOS */
+ if (str->str_state == SS_INCR) { /* data before str_ptr? */
+ str->str_len += str->str_u.str_useful;
+ str->str_ptr -= str->str_u.str_useful;
+ str->str_u.str_useful = 0L;
+ bcopy(s, str->str_ptr, str->str_cur+1);
+ s = str->str_ptr;
+ str->str_state = SS_NORM; /* normal again */
+ if (newlen > str->str_len)
+ newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
}
+ if (newlen > str->str_len) { /* need more room? */
+ if (str->str_len)
+ Renew(s,newlen,char);
+ else
+ New(703,s,newlen,char);
+ str->str_ptr = s;
+ str->str_len = newlen;
+ }
+ return s;
}
str_numset(str,num)
register STR *str;
double num;
{
- str->str_nval = num;
- str->str_pok = 0; /* invalidate pointer */
- str->str_nok = 1; /* validate number */
+ if (str->str_pok) {
+ str->str_pok = 0; /* invalidate pointer */
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0);
+ }
+ str->str_u.str_nval = num;
+ str->str_state = SS_NORM;
+ str->str_nok = 1; /* validate number */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
}
-extern int errno;
-
char *
str_2ptr(str)
register STR *str;
if (!str)
return "";
- GROWSTR(&(str->str_ptr), &(str->str_len), 24);
- s = str->str_ptr;
if (str->str_nok) {
+ STR_GROW(str, 30);
+ s = str->str_ptr;
olderrno = errno; /* some Xenix systems wipe out errno here */
#if defined(scs) && defined(ns32000)
- gcvt(str->str_nval,20,s);
+ gcvt(str->str_u.str_nval,20,s);
#else
#ifdef apollo
- if (str->str_nval == 0.0)
- strcpy(s,"0");
+ if (str->str_u.str_nval == 0.0)
+ (void)strcpy(s,"0");
else
#endif /*apollo*/
- sprintf(s,"%.20g",str->str_nval);
+ (void)sprintf(s,"%.20g",str->str_u.str_nval);
#endif /*scs*/
errno = olderrno;
while (*s) s++;
+#ifdef hcx
+ if (s[-1] == '.')
+ s--;
+#endif
+ }
+ else {
+ if (str == &str_undef)
+ return No;
+ if (dowarn)
+ warn("Use of uninitialized variable");
+ STR_GROW(str, 30);
+ s = str->str_ptr;
}
- else if (dowarn)
- warn("Use of uninitialized variable");
*s = '\0';
str->str_cur = s - str->str_ptr;
str->str_pok = 1;
{
if (!str)
return 0.0;
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0); /* just force copy down */
+ str->str_state = SS_NORM;
if (str->str_len && str->str_pok)
- str->str_nval = atof(str->str_ptr);
- else {
+ str->str_u.str_nval = atof(str->str_ptr);
+ else {
+ if (str == &str_undef)
+ return 0.0;
if (dowarn)
- fprintf(stderr,"Use of uninitialized variable in %s line %ld.\n",
- filename,(long)line);
- str->str_nval = 0.0;
+ warn("Use of uninitialized variable");
+ str->str_u.str_nval = 0.0;
}
str->str_nok = 1;
#ifdef DEBUGGING
if (debug & 32)
- fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
+ fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
#endif
- return str->str_nval;
+ return str->str_u.str_nval;
}
+/* Note: str_sset() should not be called with a source string that needs
+ * be reused, since it may destroy the source string if it is marked
+ * as temporary.
+ */
+
str_sset(dstr,sstr)
STR *dstr;
register STR *sstr;
{
+#ifdef TAINT
+ if (sstr)
+ tainted |= sstr->str_tainted;
+#endif
+ if (sstr == dstr || dstr == &str_undef)
+ return;
if (!sstr)
- str_nset(dstr,No,0);
+ dstr->str_pok = dstr->str_nok = 0;
+ else if (sstr->str_pok) {
+
+ /*
+ * Check to see if we can just swipe the string. If so, it's a
+ * possible small lose on short strings, but a big win on long ones.
+ * It might even be a win on short strings if dstr->str_ptr
+ * has to be allocated and sstr->str_ptr has to be freed.
+ */
+
+ if (sstr->str_pok & SP_TEMP) { /* slated for free anyway? */
+ if (dstr->str_ptr) {
+ if (dstr->str_state == SS_INCR)
+ dstr->str_ptr -= dstr->str_u.str_useful;
+ Safefree(dstr->str_ptr);
+ }
+ dstr->str_ptr = sstr->str_ptr;
+ dstr->str_len = sstr->str_len;
+ dstr->str_cur = sstr->str_cur;
+ dstr->str_state = sstr->str_state;
+ dstr->str_pok = sstr->str_pok & ~SP_TEMP;
+#ifdef TAINT
+ dstr->str_tainted = sstr->str_tainted;
+#endif
+ sstr->str_ptr = Nullch;
+ sstr->str_len = 0;
+ sstr->str_pok = 0; /* wipe out any weird flags */
+ sstr->str_state = 0; /* so sstr frees uneventfully */
+ }
+ else /* have to copy actual string */
+ str_nset(dstr,sstr->str_ptr,sstr->str_cur);
+ if (dstr->str_nok = sstr->str_nok)
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+ else {
+#ifdef STRUCTCOPY
+ dstr->str_u = sstr->str_u;
+#else
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+#endif
+ if (dstr->str_cur == sizeof(STBP)) {
+ char *tmps = dstr->str_ptr;
+
+ if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
+ if (!dstr->str_magic) {
+ dstr->str_magic = str_smake(sstr->str_magic);
+ dstr->str_magic->str_rare = 'X';
+ }
+ }
+ }
+ }
+ }
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);
+ str_numset(dstr,sstr->str_u.str_nval);
+ else {
+ if (dstr->str_state == SS_INCR)
+ Str_Grow(dstr,0); /* just force copy down */
+
+#ifdef STRUCTCOPY
+ dstr->str_u = sstr->str_u;
+#else
+ dstr->str_u.str_nval = sstr->str_u.str_nval;
+#endif
+ dstr->str_pok = dstr->str_nok = 0;
+ }
}
str_nset(str,ptr,len)
register STR *str;
register char *ptr;
-register int len;
+register STRLEN len;
{
- GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
- bcopy(ptr,str->str_ptr,len);
+ if (str == &str_undef)
+ return;
+ STR_GROW(str, len + 1);
+ if (ptr)
+ (void)bcopy(ptr,str->str_ptr,len);
str->str_cur = len;
*(str->str_ptr+str->str_cur) = '\0';
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
}
str_set(str,ptr)
register STR *str;
register char *ptr;
{
- register int len;
+ register STRLEN len;
+ if (str == &str_undef)
+ return;
if (!ptr)
ptr = "";
len = strlen(ptr);
- GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
- bcopy(ptr,str->str_ptr,len+1);
+ STR_GROW(str, len + 1);
+ (void)bcopy(ptr,str->str_ptr,len+1);
str->str_cur = len;
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
}
str_chop(str,ptr) /* like set but assuming ptr is in str */
register STR *str;
register char *ptr;
{
+ register STRLEN delta;
+
if (!(str->str_pok))
- str_2ptr(str);
- str->str_cur -= (ptr - str->str_ptr);
- bcopy(ptr,str->str_ptr, str->str_cur + 1);
+ fatal("str_chop: internal inconsistency");
+ delta = ptr - str->str_ptr;
+ str->str_len -= delta;
+ str->str_cur -= delta;
+ str->str_ptr += delta;
+ if (str->str_state == SS_INCR)
+ str->str_u.str_useful += delta;
+ else {
+ str->str_u.str_useful = delta;
+ str->str_state = SS_INCR;
+ }
str->str_nok = 0; /* invalidate number */
- str->str_pok = 1; /* validate pointer */
+ str->str_pok = 1; /* validate pointer (and unstudy str) */
}
str_ncat(str,ptr,len)
register STR *str;
register char *ptr;
-register int len;
+register STRLEN len;
{
+ if (str == &str_undef)
+ return;
if (!(str->str_pok))
- str_2ptr(str);
- GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
- bcopy(ptr,str->str_ptr+str->str_cur,len);
+ (void)str_2ptr(str);
+ STR_GROW(str, str->str_cur + len + 1);
+ (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
str->str_cur += len;
*(str->str_ptr+str->str_cur) = '\0';
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted |= tainted;
+#endif
}
str_scat(dstr,sstr)
STR *dstr;
register STR *sstr;
{
+#ifdef TAINT
+ tainted |= sstr->str_tainted;
+#endif
if (!sstr)
return;
if (!(sstr->str_pok))
- str_2ptr(sstr);
+ (void)str_2ptr(sstr);
if (sstr)
str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
}
register STR *str;
register char *ptr;
{
- register int len;
+ register STRLEN len;
+ if (str == &str_undef)
+ return;
if (!ptr)
return;
if (!(str->str_pok))
- str_2ptr(str);
+ (void)str_2ptr(str);
len = strlen(ptr);
- GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
- bcopy(ptr,str->str_ptr+str->str_cur,len+1);
+ STR_GROW(str, str->str_cur + len + 1);
+ (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
str->str_cur += len;
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
+#ifdef TAINT
+ str->str_tainted |= tainted;
+#endif
}
char *
-str_append_till(str,from,delim,keeplist)
+str_append_till(str,from,fromend,delim,keeplist)
register STR *str;
register char *from;
+register char *fromend;
register int delim;
char *keeplist;
{
register char *to;
- register int len;
+ register STRLEN len;
+ if (str == &str_undef)
+ return Nullch;
if (!from)
return Nullch;
- len = strlen(from);
- GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
+ len = fromend - from;
+ STR_GROW(str, str->str_cur + len + 1);
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
to = str->str_ptr+str->str_cur;
- for (; *from; from++,to++) {
- if (*from == '\\' && from[1] && delim != '\\') {
+ for (; from < fromend; from++,to++) {
+ if (*from == '\\' && from+1 < fromend && delim != '\\') {
if (!keeplist) {
if (from[1] == delim || from[1] == '\\')
from++;
else
*to++ = *from++;
}
- else if (index(keeplist,from[1]))
+ else if (from[1] && index(keeplist,from[1]))
*to++ = *from++;
else
from++;
}
STR *
+#ifdef LEAKTEST
+str_new(x,len)
+int x;
+#else
str_new(len)
-int len;
+#endif
+STRLEN len;
{
register STR *str;
if (freestrroot) {
str = freestrroot;
- freestrroot = str->str_link.str_next;
- str->str_link.str_magic = Nullstab;
+ freestrroot = str->str_magic;
+ str->str_magic = Nullstr;
+ str->str_state = SS_NORM;
}
else {
- str = (STR *) safemalloc(sizeof(STR));
- bzero((char*)str,sizeof(STR));
+ Newz(700+x,str,1,STR);
}
if (len)
- GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+ STR_GROW(str, len + 1);
return str;
}
void
-str_grow(str,len)
+str_magic(str, stab, how, name, namlen)
register STR *str;
-int len;
+STAB *stab;
+int how;
+char *name;
+STRLEN namlen;
{
- if (len && str)
- GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
+ if (str == &str_undef || str->str_magic)
+ return;
+ str->str_magic = Str_new(75,namlen);
+ str = str->str_magic;
+ str->str_u.str_stab = stab;
+ str->str_rare = how;
+ if (name)
+ str_nset(str,name,namlen);
+}
+
+void
+str_insert(bigstr,offset,len,little,littlelen)
+STR *bigstr;
+STRLEN offset;
+STRLEN len;
+char *little;
+STRLEN littlelen;
+{
+ register char *big;
+ register char *mid;
+ register char *midend;
+ register char *bigend;
+ register int i;
+
+ if (bigstr == &str_undef)
+ return;
+ bigstr->str_nok = 0;
+ bigstr->str_pok = SP_VALID; /* disable possible screamer */
+
+ i = littlelen - len;
+ if (i > 0) { /* string might grow */
+ STR_GROW(bigstr, bigstr->str_cur + i + 1);
+ big = bigstr->str_ptr;
+ mid = big + offset + len;
+ midend = bigend = big + bigstr->str_cur;
+ bigend += i;
+ *bigend = '\0';
+ while (midend > mid) /* shove everything down */
+ *--bigend = *--midend;
+ (void)bcopy(little,big+offset,littlelen);
+ bigstr->str_cur += i;
+ return;
+ }
+ else if (i == 0) {
+ (void)bcopy(little,bigstr->str_ptr+offset,len);
+ return;
+ }
+
+ big = bigstr->str_ptr;
+ mid = big + offset;
+ midend = mid + len;
+ bigend = big + bigstr->str_cur;
+
+ if (midend > bigend)
+ fatal("panic: str_insert");
+
+ if (mid - big > bigend - midend) { /* faster to shorten from end */
+ if (littlelen) {
+ (void)bcopy(little, mid, littlelen);
+ mid += littlelen;
+ }
+ i = bigend - midend;
+ if (i > 0) {
+ (void)bcopy(midend, mid, i);
+ mid += i;
+ }
+ *mid = '\0';
+ bigstr->str_cur = mid - big;
+ }
+ else if (i = mid - big) { /* faster from front */
+ midend -= littlelen;
+ mid = midend;
+ str_chop(bigstr,midend-i);
+ big += i;
+ while (i--)
+ *--midend = *--big;
+ if (littlelen)
+ (void)bcopy(little, mid, littlelen);
+ }
+ else if (littlelen) {
+ midend -= littlelen;
+ str_chop(bigstr,midend);
+ (void)bcopy(little,midend,littlelen);
+ }
+ else {
+ str_chop(bigstr,midend);
+ }
+ STABSET(bigstr);
}
/* make str point to what nstr did */
register STR *str;
register STR *nstr;
{
- safefree(str->str_ptr);
+ if (str == &str_undef)
+ return;
+ if (str->str_state == SS_INCR)
+ Str_Grow(str,0); /* just force copy down */
+ if (nstr->str_state == SS_INCR)
+ Str_Grow(nstr,0);
+ if (str->str_ptr)
+ Safefree(str->str_ptr);
str->str_ptr = nstr->str_ptr;
str->str_len = nstr->str_len;
str->str_cur = nstr->str_cur;
str->str_pok = nstr->str_pok;
- if (str->str_nok = nstr->str_nok)
- str->str_nval = nstr->str_nval;
- safefree((char*)nstr);
+ str->str_nok = nstr->str_nok;
+#ifdef STRUCTCOPY
+ str->str_u = nstr->str_u;
+#else
+ str->str_u.str_nval = nstr->str_u.str_nval;
+#endif
+#ifdef TAINT
+ str->str_tainted = nstr->str_tainted;
+#endif
+ if (nstr->str_magic)
+ str_free(nstr->str_magic);
+ Safefree(nstr);
}
void
str_free(str)
register STR *str;
{
- if (!str)
+ if (!str || str == &str_undef)
return;
+ if (str->str_state) {
+ if (str->str_state == SS_FREE) /* already freed */
+ return;
+ if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
+ str->str_ptr -= str->str_u.str_useful;
+ str->str_len += str->str_u.str_useful;
+ }
+ }
+ if (str->str_magic)
+ str_free(str->str_magic);
+#ifdef LEAKTEST
if (str->str_len)
- str->str_ptr[0] = '\0';
+ Safefree(str->str_ptr);
+ if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
+ arg_free(str->str_u.str_args);
+ Safefree(str);
+#else /* LEAKTEST */
+ if (str->str_len) {
+ if (str->str_len > 127) { /* next user not likely to want more */
+ Safefree(str->str_ptr); /* so give it back to malloc */
+ str->str_ptr = Nullch;
+ str->str_len = 0;
+ }
+ else
+ str->str_ptr[0] = '\0';
+ }
+ if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
+ arg_free(str->str_u.str_args);
str->str_cur = 0;
str->str_nok = 0;
str->str_pok = 0;
- str->str_link.str_next = freestrroot;
+ str->str_state = SS_FREE;
+#ifdef TAINT
+ str->str_tainted = 0;
+#endif
+ str->str_magic = freestrroot;
freestrroot = str;
+#endif /* LEAKTEST */
}
+STRLEN
str_len(str)
register STR *str;
{
if (!str)
return 0;
if (!(str->str_pok))
- str_2ptr(str);
- if (str->str_len)
+ (void)str_2ptr(str);
+ if (str->str_ptr)
return str->str_cur;
else
return 0;
}
+str_eq(str1,str2)
+register STR *str1;
+register STR *str2;
+{
+ if (!str1 || str1 == &str_undef)
+ return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur);
+ if (!str2 || str2 == &str_undef)
+ return !str1->str_cur;
+
+ if (!str1->str_pok)
+ (void)str_2ptr(str1);
+ if (!str2->str_pok)
+ (void)str_2ptr(str2);
+
+ if (str1->str_cur != str2->str_cur)
+ return 0;
+
+ return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
+}
+
+str_cmp(str1,str2)
+register STR *str1;
+register STR *str2;
+{
+ int retval;
+
+ if (!str1 || str1 == &str_undef)
+ return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1;
+ if (!str2 || str2 == &str_undef)
+ return str1->str_cur != 0;
+
+ if (!str1->str_pok)
+ (void)str_2ptr(str1);
+ if (!str2->str_pok)
+ (void)str_2ptr(str2);
+
+ if (str1->str_cur < str2->str_cur) {
+ if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
+ return retval;
+ else
+ return -1;
+ }
+ else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
+ return retval;
+ else if (str1->str_cur == str2->str_cur)
+ return 0;
+ else
+ return 1;
+}
+
char *
-str_gets(str,fp)
+str_gets(str,fp,append)
register STR *str;
register FILE *fp;
+int append;
{
-#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
-
register char *bp; /* we're going to steal some values */
register int cnt; /* from the stdio struct and put EVERYTHING */
register STDCHAR *ptr; /* in the innermost loop into registers */
- register char newline = record_separator;/* (assuming >= 6 registers) */
+ register int newline = record_separator;/* (assuming >= 6 registers) */
int i;
- int bpx;
- int obpx;
+ STRLEN bpx;
+ STRLEN obpx;
register int get_paragraph;
register char *oldbp;
+ int shortbuffered;
- if (get_paragraph = !newline) { /* yes, that's an assignment */
+ if (str == &str_undef)
+ return Nullch;
+ if (get_paragraph = !rslen) { /* yes, that's an assignment */
newline = '\n';
oldbp = Nullch; /* remember last \n position (none) */
}
+#ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */
cnt = fp->_cnt; /* get count into register */
str->str_nok = 0; /* invalidate number */
str->str_pok = 1; /* validate pointer */
- if (str->str_len <= cnt) /* make sure we have the room */
- GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
- bp = str->str_ptr; /* move these two too to registers */
+ if (str->str_len <= cnt + 1) { /* make sure we have the room */
+ if (cnt > 80 && str->str_len > 0) {
+ shortbuffered = cnt - str->str_len + 1;
+ cnt = str->str_len - 1;
+ }
+ else {
+ shortbuffered = 0;
+ STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */
+ }
+ }
+ else
+ shortbuffered = 0;
+ bp = str->str_ptr + append; /* move these two too to registers */
ptr = fp->_ptr;
for (;;) {
screamer:
goto thats_all_folks; /* screams */ /* sed :-) */
}
+ if (shortbuffered) { /* oh well, must extend */
+ cnt = shortbuffered;
+ shortbuffered = 0;
+ if (get_paragraph && oldbp)
+ obpx = oldbp - str->str_ptr;
+ bpx = bp - str->str_ptr; /* prepare for possible relocation */
+ STR_GROW(str, str->str_len + append + cnt + 2);
+ bp = str->str_ptr + bpx; /* reconstitute our pointer */
+ if (get_paragraph && oldbp)
+ oldbp = str->str_ptr + obpx;
+ continue;
+ }
+
fp->_cnt = cnt; /* deregisterize cnt and ptr */
fp->_ptr = ptr;
i = _filbuf(fp); /* get more characters */
bpx = bp - str->str_ptr; /* prepare for possible relocation */
if (get_paragraph && oldbp)
obpx = oldbp - str->str_ptr;
- GROWSTR(&(str->str_ptr), &(str->str_len), bpx + cnt + 2);
+ str->str_cur = bpx;
+ STR_GROW(str, bpx + cnt + 2);
bp = str->str_ptr + bpx; /* reconstitute our pointer */
if (get_paragraph && oldbp)
oldbp = str->str_ptr + obpx;
goto screamer; /* and go back to the fray */
}
thats_really_all_folks:
+ if (shortbuffered)
+ cnt += shortbuffered;
fp->_cnt = cnt; /* put these back or we're in trouble */
fp->_ptr = ptr;
*bp = '\0';
#else /* !STDSTDIO */ /* The big, slow, and stupid way */
- static char buf[4192];
+ {
+ static char buf[8192];
+ char * bpe = buf + sizeof(buf) - 3;
- if (fgets(buf, sizeof buf, fp) != Nullch)
- str_set(str, buf);
- else
- str_set(str, No);
+screamer:
+ bp = buf;
+filler:
+ while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe);
+ if (i == newline && get_paragraph &&
+ (i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe)
+ goto filler;
+
+ *bp = '\0';
+ if (append)
+ str_cat(str, buf);
+ else
+ str_set(str, buf);
+ if (i != newline && i != EOF) {
+ append = -1;
+ goto screamer;
+ }
+ }
#endif /* STDSTDIO */
- return str->str_cur ? str->str_ptr : Nullch;
+ return str->str_cur - append ? str->str_ptr : Nullch;
}
+ARG *
+parselist(str)
+STR *str;
+{
+ register CMD *cmd;
+ register ARG *arg;
+ CMD *oldcurcmd = curcmd;
+ int oldperldb = perldb;
+ int retval;
-STR *
-interp(str,s)
-register STR *str;
-register char *s;
+ perldb = 0;
+ str_sset(linestr,str);
+ in_eval++;
+ oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
+ bufend = bufptr + linestr->str_cur;
+ if (++loop_ptr >= loop_max) {
+ loop_max += 128;
+ Renew(loop_stack, loop_max, struct loop);
+ }
+ loop_stack[loop_ptr].loop_label = "_EVAL_";
+ loop_stack[loop_ptr].loop_sp = 0;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
+ }
+#endif
+ if (setjmp(loop_stack[loop_ptr].loop_env)) {
+ in_eval--;
+ loop_ptr--;
+ perldb = oldperldb;
+ fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
+ }
+#ifdef DEBUGGING
+ if (debug & 4) {
+ char *tmps = loop_stack[loop_ptr].loop_label;
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ tmps ? tmps : "" );
+ }
+#endif
+ loop_ptr--;
+ error_count = 0;
+ curcmd = &compiling;
+ curcmd->c_line = oldcurcmd->c_line;
+ retval = yyparse();
+ curcmd = oldcurcmd;
+ perldb = oldperldb;
+ in_eval--;
+ if (retval || error_count)
+ fatal("Invalid component in string or format");
+ cmd = eval_root;
+ arg = cmd->c_expr;
+ if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
+ fatal("panic: error in parselist %d %x %d", cmd->c_type,
+ cmd->c_next, arg ? arg->arg_type : -1);
+ Safefree(cmd);
+ return arg;
+}
+
+void
+intrpcompile(src)
+STR *src;
{
- register char *t = s;
- char *envsave = envname;
- envname = Nullch;
+ register char *s = str_get(src);
+ register char *send = s + src->str_cur;
+ register STR *str;
+ register char *t;
+ STR *toparse;
+ STRLEN len;
+ register int brackets;
+ register char *d;
+ STAB *stab;
+ char *checkpoint;
- str_set(str,"");
- while (*s) {
- if (*s == '\\' && s[1] == '\\') {
- str_ncat(str, t, s++ - t);
- t = s++;
- }
- else if (*s == '\\' && s[1] == '$') {
- str_ncat(str, t, s++ - t);
- t = s++;
+ toparse = Str_new(76,0);
+ str = Str_new(77,0);
+
+ str_nset(str,"",0);
+ str_nset(toparse,"",0);
+ t = s;
+ while (s < send) {
+ if (*s == '\\' && s[1] && index("$@[{\\]}",s[1])) {
+ str_ncat(str, t, s - t);
+ ++s;
+ if (*nointrp && s+1 < send)
+ if (*s != '@' && (*s != '$' || index(nointrp,s[1])))
+ str_ncat(str,s-1,1);
+ str_ncat(str, "$b", 2);
+ str_ncat(str, s, 1);
+ ++s;
+ t = s;
}
- else if (*s == '$' && s[1] && s[1] != '|') {
+ else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) &&
+ s+1 < send) {
str_ncat(str,t,s-t);
- s = scanreg(s,tokenbuf);
- str_cat(str,reg_get(tokenbuf));
t = s;
+ if (*s == '$' && s[1] == '#' && (isalpha(s[2]) || s[2] == '_'))
+ s++;
+ s = scanreg(s,send,tokenbuf);
+ if (*t == '@' &&
+ (!(stab = stabent(tokenbuf,FALSE)) ||
+ (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
+ str_ncat(str,"@",1);
+ s = ++t;
+ continue; /* grandfather @ from old scripts */
+ }
+ str_ncat(str,"$a",2);
+ str_ncat(toparse,",",1);
+ if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) &&
+ (stab = stabent(tokenbuf,FALSE)) &&
+ ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
+ brackets = 0;
+ checkpoint = s;
+ do {
+ switch (*s) {
+ case '[':
+ if (s[-1] != '$')
+ brackets++;
+ break;
+ case '{':
+ brackets++;
+ break;
+ case ']':
+ if (s[-1] != '$')
+ brackets--;
+ break;
+ case '}':
+ brackets--;
+ break;
+ case '\'':
+ case '"':
+ if (s[-1] != '$') {
+ s = cpytill(tokenbuf,s+1,send,*s,&len);
+ if (s >= send)
+ fatal("Unterminated string");
+ }
+ break;
+ }
+ s++;
+ } while (brackets > 0 && s < send);
+ if (s > send)
+ fatal("Unmatched brackets in string");
+ if (*nointrp) { /* we're in a regular expression */
+ d = checkpoint;
+ if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */
+ ++d;
+ if (isdigit(*d)) { /* matches /^{\d,?\d*}$/ */
+ if (*++d == ',')
+ ++d;
+ while (isdigit(*d))
+ d++;
+ if (d == s - 1)
+ s = checkpoint; /* Is {n,m}! Backoff! */
+ }
+ }
+ else if (*d == '[' && s[-1] == ']') { /* char class? */
+ int weight = 2; /* let's weigh the evidence */
+ char seen[256];
+ unsigned char un_char = 0, last_un_char;
+
+ Zero(seen,256,char);
+ *--s = '\0';
+ if (d[1] == '^')
+ weight += 150;
+ else if (d[1] == '$')
+ weight -= 3;
+ if (isdigit(d[1])) {
+ if (d[2]) {
+ if (isdigit(d[2]) && !d[3])
+ weight -= 10;
+ }
+ else
+ weight -= 100;
+ }
+ for (d++; d < s; d++) {
+ last_un_char = un_char;
+ un_char = (unsigned char)*d;
+ switch (*d) {
+ case '&':
+ case '$':
+ weight -= seen[un_char] * 10;
+ if (isalpha(d[1]) || isdigit(d[1]) ||
+ d[1] == '_') {
+ d = scanreg(d,s,tokenbuf);
+ if (stabent(tokenbuf,FALSE))
+ weight -= 100;
+ else
+ weight -= 10;
+ }
+ else if (*d == '$' && d[1] &&
+ index("[#!%*<>()-=",d[1])) {
+ if (!d[2] || /*{*/ index("])} =",d[2]))
+ weight -= 10;
+ else
+ weight -= 1;
+ }
+ break;
+ case '\\':
+ un_char = 254;
+ if (d[1]) {
+ if (index("wds",d[1]))
+ weight += 100;
+ else if (seen['\''] || seen['"'])
+ weight += 1;
+ else if (index("rnftb",d[1]))
+ weight += 40;
+ else if (isdigit(d[1])) {
+ weight += 40;
+ while (d[1] && isdigit(d[1]))
+ d++;
+ }
+ }
+ else
+ weight += 100;
+ break;
+ case '-':
+ if (last_un_char < (unsigned char) d[1]
+ || d[1] == '\\') {
+ if (index("aA01! ",last_un_char))
+ weight += 30;
+ if (index("zZ79~",d[1]))
+ weight += 30;
+ }
+ else
+ weight -= 1;
+ default:
+ if (isalpha(*d) && d[1] && isalpha(d[1])) {
+ bufptr = d;
+ if (yylex() != WORD)
+ weight -= 150;
+ d = bufptr;
+ }
+ if (un_char == last_un_char + 1)
+ weight += 5;
+ weight -= seen[un_char];
+ break;
+ }
+ seen[un_char]++;
+ }
+#ifdef DEBUGGING
+ if (debug & 512)
+ fprintf(stderr,"[%s] weight %d\n",
+ checkpoint+1,weight);
+#endif
+ *s++ = ']';
+ if (weight >= 0) /* probably a character class */
+ s = checkpoint;
+ }
+ }
+ }
+ if (*t == '@')
+ str_ncat(toparse, "join($\",", 8);
+ if (t[1] == '{' && s[-1] == '}') {
+ str_ncat(toparse, t, 1);
+ str_ncat(toparse, t+2, s - t - 3);
+ }
+ else
+ str_ncat(toparse, t, s - t);
+ if (*t == '@')
+ str_ncat(toparse, ")", 1);
+ t = s;
+ }
+ else
+ s++;
+ }
+ str_ncat(str,t,s-t);
+ if (toparse->str_ptr && *toparse->str_ptr == ',') {
+ *toparse->str_ptr = '(';
+ str_ncat(toparse,",$$);",5);
+ str->str_u.str_args = parselist(toparse);
+ str->str_u.str_args->arg_len--; /* ignore $$ reference */
+ }
+ else
+ str->str_u.str_args = Nullarg;
+ str_free(toparse);
+ str->str_pok |= SP_INTRP;
+ str->str_nok = 0;
+ str_replace(src,str);
+}
+
+STR *
+interp(str,src,sp)
+register STR *str;
+STR *src;
+int sp;
+{
+ register char *s;
+ register char *t;
+ register char *send;
+ register STR **elem;
+
+ if (str == &str_undef)
+ return Nullstr;
+ if (!(src->str_pok & SP_INTRP)) {
+ int oldsave = savestack->ary_fill;
+
+ (void)savehptr(&curstash);
+ curstash = curcmd->c_stash; /* so stabent knows right package */
+ intrpcompile(src);
+ restorelist(oldsave);
+ }
+ s = src->str_ptr; /* assumed valid since str_pok set */
+ t = s;
+ send = s + src->str_cur;
+
+ if (src->str_u.str_args) {
+ (void)eval(src->str_u.str_args,G_ARRAY,sp);
+ /* Assuming we have correct # of args */
+ elem = stack->ary_array + sp;
+ }
+
+ str_nset(str,"",0);
+ while (s < send) {
+ if (*s == '$' && s+1 < send) {
+ str_ncat(str,t,s-t);
+ switch(*++s) {
+ case 'a':
+ str_scat(str,*++elem);
+ break;
+ case 'b':
+ str_ncat(str,++s,1);
+ break;
+ }
+ t = ++s;
}
else
s++;
}
- envname = envsave;
str_ncat(str,t,s-t);
return str;
}
{
register char *d;
- if (!str)
+ if (!str || str == &str_undef)
return;
if (str->str_nok) {
- str->str_nval += 1.0;
+ str->str_u.str_nval += 1.0;
str->str_pok = 0;
return;
}
if (!str->str_pok || !*str->str_ptr) {
- str->str_nval = 1.0;
+ str->str_u.str_nval = 1.0;
str->str_nok = 1;
+ str->str_pok = 0;
return;
}
d = str->str_ptr;
}
}
/* oh,oh, the number grew */
- GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
+ STR_GROW(str, str->str_cur + 2);
str->str_cur++;
for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
*d = d[-1];
str_dec(str)
register STR *str;
{
- if (!str)
+ if (!str || str == &str_undef)
return;
if (str->str_nok) {
- str->str_nval -= 1.0;
+ str->str_u.str_nval -= 1.0;
str->str_pok = 0;
return;
}
if (!str->str_pok) {
- str->str_nval = -1.0;
+ str->str_u.str_nval = -1.0;
str->str_nok = 1;
return;
}
str_numset(str,atof(str->str_ptr) - 1.0);
}
-/* make a string that will exist for the duration of the expression eval */
+/* Make a string that will exist for the duration of the expression
+ * evaluation. Actually, it may have to last longer than that, but
+ * hopefully cmd_exec won't free it until it has been assigned to a
+ * permanent location. */
+
+static long tmps_size = -1;
STR *
str_static(oldstr)
STR *oldstr;
{
- register STR *str = str_new(0);
- static long tmps_size = -1;
+ register STR *str = Str_new(78,0);
str_sset(str,oldstr);
if (++tmps_max > tmps_size) {
tmps_size = tmps_max;
if (!(tmps_size & 127)) {
if (tmps_size)
- tmps_list = (STR**)saferealloc((char*)tmps_list,
- (MEM_SIZE)((tmps_size + 128) * sizeof(STR*)) );
+ Renew(tmps_list, tmps_size + 128, STR*);
else
- tmps_list = (STR**)safemalloc(128 * sizeof(char*));
+ New(702,tmps_list, 128, STR*);
}
}
tmps_list[tmps_max] = str;
+ if (str->str_pok)
+ str->str_pok |= SP_TEMP;
return str;
}
+/* same thing without the copying */
+
STR *
-str_make(s)
+str_2static(str)
+register STR *str;
+{
+ if (str == &str_undef)
+ return str;
+ if (++tmps_max > tmps_size) {
+ tmps_size = tmps_max;
+ if (!(tmps_size & 127)) {
+ if (tmps_size)
+ Renew(tmps_list, tmps_size + 128, STR*);
+ else
+ New(704,tmps_list, 128, STR*);
+ }
+ }
+ tmps_list[tmps_max] = str;
+ if (str->str_pok)
+ str->str_pok |= SP_TEMP;
+ return str;
+}
+
+STR *
+str_make(s,len)
char *s;
+STRLEN len;
{
- register STR *str = str_new(0);
+ register STR *str = Str_new(79,0);
- str_set(str,s);
+ if (!len)
+ len = strlen(s);
+ str_nset(str,s,len);
return str;
}
str_nmake(n)
double n;
{
- register STR *str = str_new(0);
+ register STR *str = Str_new(80,0);
str_numset(str,n);
return str;
}
+
+/* make an exact duplicate of old */
+
+STR *
+str_smake(old)
+register STR *old;
+{
+ register STR *new = Str_new(81,0);
+
+ if (!old)
+ return Nullstr;
+ if (old->str_state == SS_FREE) {
+ warn("semi-panic: attempt to dup freed string");
+ return Nullstr;
+ }
+ if (old->str_state == SS_INCR && !(old->str_pok & 2))
+ Str_Grow(old,0);
+ if (new->str_ptr)
+ Safefree(new->str_ptr);
+ Copy(old,new,1,STR);
+ if (old->str_ptr)
+ new->str_ptr = nsavestr(old->str_ptr,old->str_len);
+ return new;
+}
+
+str_reset(s,stash)
+register char *s;
+HASH *stash;
+{
+ register HENT *entry;
+ register STAB *stab;
+ register STR *str;
+ register int i;
+ register SPAT *spat;
+ register int max;
+
+ if (!*s) { /* reset ?? searches */
+ for (spat = stash->tbl_spatroot;
+ spat != Nullspat;
+ spat = spat->spat_next) {
+ spat->spat_flags &= ~SPAT_USED;
+ }
+ return;
+ }
+
+ /* reset variables */
+
+ if (!stash->tbl_array)
+ return;
+ while (*s) {
+ i = *s;
+ if (s[1] == '-') {
+ s += 2;
+ }
+ max = *s++;
+ for ( ; i <= max; i++) {
+ for (entry = stash->tbl_array[i];
+ entry;
+ entry = entry->hent_next) {
+ stab = (STAB*)entry->hent_val;
+ str = stab_val(stab);
+ str->str_cur = 0;
+ str->str_nok = 0;
+#ifdef TAINT
+ str->str_tainted = tainted;
+#endif
+ if (str->str_ptr != Nullch)
+ str->str_ptr[0] = '\0';
+ if (stab_xarray(stab)) {
+ aclear(stab_xarray(stab));
+ }
+ if (stab_xhash(stab)) {
+ hclear(stab_xhash(stab), FALSE);
+ if (stab == envstab)
+ environ[0] = Nullch;
+ }
+ }
+ }
+ }
+}
+
+#ifdef TAINT
+taintproper(s)
+char *s;
+{
+#ifdef DEBUGGING
+ if (debug & 2048)
+ fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
+#endif
+ if (tainted && (!euid || euid != uid || egid != gid)) {
+ if (!unsafe)
+ fatal("%s", s);
+ else if (dowarn)
+ warn("%s", s);
+ }
+}
+
+taintenv()
+{
+ register STR *envstr;
+
+ envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
+ if (envstr == &str_undef || envstr->str_tainted) {
+ tainted = 1;
+ if (envstr->str_tainted == 2)
+ taintproper("Insecure directory in PATH");
+ else
+ taintproper("Insecure PATH");
+ }
+ envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
+ if (envstr != &str_undef && envstr->str_tainted) {
+ tainted = 1;
+ taintproper("Insecure IFS");
+ }
+}
+#endif /* TAINT */