home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / perl / Source / C / Str < prev    next >
Encoding:
Text File  |  1991-02-09  |  32.9 KB  |  1,413 lines

  1. /* $Header: str.c,v 3.0.1.12 91/01/11 18:26:54 lwall Locked $
  2.  *
  3.  *    Copyright (c) 1989, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of the GNU General Public License
  6.  *    as specified in the README file that comes with the perl 3.0 kit.
  7.  *
  8.  * $Log:    str.c,v $
  9. +  * Revision 3.0.1.12  91/01/11  18:26:54  lwall
  10.  * patch42: s/^foo/bar/ occasionally brought on core dumps
  11.  * patch42: undid unwarranted assumptions about memcmp() return value
  12.  * patch42: ('a' .. 'z') could lose its value in a loop
  13.  * 
  14.  * Revision 3.0.1.11  90/11/13  15:27:14  lwall
  15.  * patch41: fixed a couple of malloc/free problems
  16.  * 
  17.  * Revision 3.0.1.10  90/11/10  02:06:29  lwall
  18.  * patch38: temp string values are now copied less often
  19.  * patch38: array slurps are now faster and take less memory
  20.  * patch38: fixed a memory leakage on local(*foo)
  21.  * 
  22.  * Revision 3.0.1.9  90/10/16  10:41:21  lwall
  23.  * patch29: the undefined value could get defined by devious means
  24.  * patch29: undefined values compared inconsistently 
  25.  * patch29: taintperl now checks for world writable PATH components
  26.  * 
  27.  * Revision 3.0.1.8  90/08/09  05:22:18  lwall
  28.  * patch19: the number to string converter wasn't allocating enough space
  29.  * patch19: tainting didn't work on setgid scripts
  30.  * 
  31.  * Revision 3.0.1.7  90/03/27  16:24:11  lwall
  32.  * patch16: strings with prefix chopped off sometimes freed wrong
  33.  * patch16: taint check blows up on undefined array element
  34.  * 
  35.  * Revision 3.0.1.6  90/03/12  17:02:14  lwall
  36.  * patch13: substr as lvalue didn't invalidate old numeric value
  37.  * 
  38.  * Revision 3.0.1.5  90/02/28  18:30:38  lwall
  39.  * patch9: you may now undef $/ to have no input record separator
  40.  * patch9: nested evals clobbered their longjmp environment
  41.  * patch9: sometimes perl thought ordinary data was a symbol table entry
  42.  * patch9: insufficient space allocated for numeric string on sun4
  43.  * patch9: underscore in an array name in a double-quoted string not recognized
  44.  * patch9: "@foo{}" not recognized unless %foo defined
  45.  * patch9: "$foo[$[]" gives error
  46.  * 
  47.  * Revision 3.0.1.4  89/12/21  20:21:35  lwall
  48.  * patch7: errno may now be a macro with an lvalue
  49.  * patch7: made nested or recursive foreach work right
  50.  * 
  51.  * Revision 3.0.1.3  89/11/17  15:38:23  lwall
  52.  * patch5: some machines typedef unchar too
  53.  * patch5: substitution on leading components occasionally caused <> corruption
  54.  * 
  55.  * Revision 3.0.1.2  89/11/11  04:56:22  lwall
  56.  * patch2: uchar gives Crays fits
  57.  * 
  58.  * Revision 3.0.1.1  89/10/26  23:23:41  lwall
  59.  * patch1: string ordering tests were wrong
  60.  * patch1: $/ now works even when STDSTDIO undefined
  61.  * 
  62.  * Revision 3.0  89/10/18  15:23:38  lwall
  63.  * 3.0 baseline
  64.  * 
  65.  */
  66.  
  67. #include "EXTERN.h"
  68. #include "perl.h"
  69. #include "perly.h"
  70.  
  71. #ifndef ARM
  72. extern char **environ;
  73. #endif
  74.  
  75. #ifndef str_get
  76. char *str_get(STR *str)
  77. {
  78. #ifdef TAINT
  79.     tainted |= str->str_tainted;
  80. #endif
  81.     return str->str_pok ? str->str_ptr : str_2ptr(str);
  82. }
  83. #endif
  84.  
  85. /* dlb ... guess we have a "crippled cc".
  86.  * dlb the following functions are usually macros.
  87.  */
  88. #ifndef str_true
  89. int str_true(STR *Str)
  90. {
  91.     if (Str->str_pok) {
  92.         if (*Str->str_ptr > '0' ||
  93.           Str->str_cur > 1 ||
  94.           (Str->str_cur && *Str->str_ptr != '0'))
  95.         return 1;
  96.         return 0;
  97.     }
  98.     if (Str->str_nok)
  99.         return (Str->str_u.str_nval != 0.0);
  100.     return 0;
  101. }
  102. #endif /* str_true */
  103.  
  104. #ifndef str_gnum
  105. double str_gnum(STR *Str)
  106. {
  107. #ifdef TAINT
  108.     tainted |= Str->str_tainted;
  109. #endif /* TAINT*/
  110.     if (Str->str_nok)
  111.         return Str->str_u.str_nval;
  112.     return str_2num(Str);
  113. }
  114. #endif /* str_gnum */
  115. /* dlb ... end of crutch */
  116.  
  117. char *str_grow (register STR *str, register int newlen)
  118. {
  119.     register char *s = str->str_ptr;
  120.  
  121. #ifdef MSDOS
  122.     if (newlen >= 0x10000) {
  123.     fprintf(stderr, "Allocation too large: %lx\n", newlen);
  124.     exit(1);
  125.     }
  126. #endif /* MSDOS */
  127.     if (str->str_state == SS_INCR) {        /* data before str_ptr? */
  128.     str->str_len += (int)str->str_u.str_useful;
  129.     str->str_ptr -= (int)str->str_u.str_useful;
  130.     str->str_u.str_useful = 0L;
  131.     bcopy(s, str->str_ptr, str->str_cur+1);
  132.     s = str->str_ptr;
  133.     str->str_state = SS_NORM;            /* normal again */
  134.     if (newlen > str->str_len)
  135.         newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
  136.     }
  137.     if (newlen > str->str_len) {        /* need more room? */
  138.         if (str->str_len)
  139.         Renew(s,newlen,char);
  140.         else
  141.         New(703,s,newlen,char);
  142.     str->str_ptr = s;
  143.         str->str_len = newlen;
  144.     }
  145.     return s;
  146. }
  147.  
  148. void str_numset (register STR *str, double num)
  149. {
  150.     if (str->str_pok) {
  151.     str->str_pok = 0;    /* invalidate pointer */
  152.     if (str->str_state == SS_INCR)
  153.         Str_Grow(str,0);
  154.     }
  155.     str->str_u.str_nval = num;
  156.     str->str_state = SS_NORM;
  157.     str->str_nok = 1;            /* validate number */
  158. #ifdef TAINT
  159.     str->str_tainted = tainted;
  160. #endif
  161. }
  162.  
  163. char *str_2ptr (register STR *str)
  164. {
  165.     register char *s;
  166.     int olderrno;
  167.  
  168.     if (!str)
  169.     return "";
  170.     if (str->str_nok) {
  171.     STR_GROW(str, 30);
  172.     s = str->str_ptr;
  173.     olderrno = errno;    /* some Xenix systems wipe out errno here */
  174. #if defined(scs) && defined(ns32000)
  175.     gcvt(str->str_u.str_nval,20,s);
  176. #else
  177. #ifdef apollo
  178.     if (str->str_u.str_nval == 0.0)
  179.         (void)strcpy(s,"0");
  180.     else
  181. #endif /*apollo*/
  182.     (void)sprintf(s,"%.20g",str->str_u.str_nval);
  183. #endif /*scs*/
  184.     errno = olderrno;
  185.     while (*s) s++;
  186. #ifdef hcx
  187.     if (s[-1] == '.')
  188.         s--;
  189. #endif
  190.     }
  191.     else {
  192.     if (str == &str_undef)
  193.         return No;
  194.     if (dowarn)
  195.         warn("Use of uninitialized variable");
  196.     STR_GROW(str, 30);
  197.     s = str->str_ptr;
  198.     }
  199.     *s = '\0';
  200.     str->str_cur = s - str->str_ptr;
  201.     str->str_pok = 1;
  202. #ifdef DEBUGGING
  203.     if (debug & 32)
  204.     fprintf(stderr,"%p ptr(%s)\n",str,str->str_ptr);
  205. #endif
  206.     return str->str_ptr;
  207. }
  208.  
  209. double str_2num (register STR *str)
  210. {
  211.     if (!str)
  212.     return 0.0;
  213.     if (str->str_state == SS_INCR)
  214.     Str_Grow(str,0);       /* just force copy down */
  215.     str->str_state = SS_NORM;
  216.     if (str->str_len && str->str_pok)
  217.     str->str_u.str_nval = atof(str->str_ptr);
  218.     else  {
  219.     if (str == &str_undef)
  220.         return 0.0;
  221.     if (dowarn)
  222.         warn("Use of uninitialized variable");
  223.     str->str_u.str_nval = 0.0;
  224.     }
  225.     str->str_nok = 1;
  226. #ifdef DEBUGGING
  227.     if (debug & 32)
  228.     fprintf(stderr,"%p num(%g)\n",str,str->str_u.str_nval);
  229. #endif
  230.     return str->str_u.str_nval;
  231. }
  232.  
  233. /* Note: str_sset() should not be called with a source string that needs
  234.  * be reused, since it may destroy the source string if it is marked
  235.  * as temporary.
  236.  */
  237.  
  238. void str_sset (STR *dstr, register STR *sstr)
  239. {
  240. #ifdef TAINT
  241.     if (sstr)
  242.     tainted |= sstr->str_tainted;
  243. #endif
  244.     if (sstr == dstr || dstr == &str_undef)
  245.     return;
  246.     if (!sstr)
  247.     dstr->str_pok = dstr->str_nok = 0;
  248.     else if (sstr->str_pok) {
  249.  
  250.     /*
  251.      * Check to see if we can just swipe the string.  If so, it's a
  252.      * possible small lose on short strings, but a big win on long ones.
  253.      * It might even be a win on short strings if dstr->str_ptr
  254.      * has to be allocated and sstr->str_ptr has to be freed.
  255.      */
  256.  
  257.     if (sstr->str_pok & SP_TEMP) {        /* slated for free anyway? */
  258.         if (dstr->str_ptr) {
  259.         if (dstr->str_state == SS_INCR)
  260.             dstr->str_ptr -= dstr->str_u.str_useful;
  261.         Safefree(dstr->str_ptr);
  262.         }
  263.         dstr->str_ptr = sstr->str_ptr;
  264.         dstr->str_len = sstr->str_len;
  265.         dstr->str_cur = sstr->str_cur;
  266.         dstr->str_state = sstr->str_state;
  267.         dstr->str_pok = sstr->str_pok & ~SP_TEMP;
  268. #ifdef TAINT
  269.         dstr->str_tainted = sstr->str_tainted;
  270. #endif
  271.         sstr->str_ptr = Nullch;
  272.         sstr->str_len = 0;
  273.         sstr->str_pok = 0;            /* wipe out any weird flags */
  274.         sstr->str_state = 0;        /* so sstr frees uneventfully */
  275.     }
  276.     else {                    /* have to copy actual string */
  277.         if (dstr->str_ptr) {
  278.         if (dstr->str_state == SS_INCR) {
  279.             Str_Grow(dstr,0);
  280.         }
  281.         }
  282.         str_nset(dstr,sstr->str_ptr,sstr->str_cur);
  283.     }
  284.     if ((dstr->str_nok = sstr->str_nok) != 0)
  285.         dstr->str_u.str_nval = sstr->str_u.str_nval;
  286.     else {
  287. #ifdef STRUCTCOPY
  288.         dstr->str_u = sstr->str_u;
  289. #else
  290.         dstr->str_u.str_nval = sstr->str_u.str_nval;
  291. #endif
  292.         if (dstr->str_cur == sizeof(STBP)) {
  293.         char *tmps = dstr->str_ptr;
  294.  
  295.         if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
  296.             if (!dstr->str_magic) {
  297.             dstr->str_magic = str_smake(sstr->str_magic);
  298.             dstr->str_magic->str_rare = 'X';
  299.             }
  300.         }
  301.         }
  302.     }
  303.     }
  304.     else if (sstr->str_nok)
  305.     str_numset(dstr,sstr->str_u.str_nval);
  306.     else {
  307.     if (dstr->str_state == SS_INCR)
  308.         Str_Grow(dstr,0);       /* just force copy down */
  309.  
  310. #ifdef STRUCTCOPY
  311.     dstr->str_u = sstr->str_u;
  312. #else
  313.     dstr->str_u.str_nval = sstr->str_u.str_nval;
  314. #endif
  315.     dstr->str_pok = dstr->str_nok = 0;
  316.     }
  317. }
  318.  
  319. void str_nset (register STR *str, register char *ptr, register STRLEN len)
  320. {
  321.     if (str == &str_undef)
  322.     return;
  323.     STR_GROW(str, len + 1);
  324.     if (ptr)
  325.     (void)bcopy(ptr,str->str_ptr,len);
  326.     str->str_cur = len;
  327.     *(str->str_ptr+str->str_cur) = '\0';
  328.     str->str_nok = 0;        /* invalidate number */
  329.     str->str_pok = 1;        /* validate pointer */
  330. #ifdef TAINT
  331.     str->str_tainted = tainted;
  332. #endif
  333. }
  334.  
  335. void str_set (register STR *str, register char *ptr)
  336. {
  337.     register STRLEN len;
  338.  
  339.     if (str == &str_undef)
  340.     return;
  341.     if (!ptr)
  342.     ptr = "";
  343.     len = strlen(ptr);
  344.     STR_GROW(str, len + 1);
  345.     (void)bcopy(ptr,str->str_ptr,len+1);
  346.     str->str_cur = len;
  347.     str->str_nok = 0;        /* invalidate number */
  348.     str->str_pok = 1;        /* validate pointer */
  349. #ifdef TAINT
  350.     str->str_tainted = tainted;
  351. #endif
  352. }
  353.  
  354. /* like set but assuming ptr is in str */
  355. void str_chop (register STR *str, register char *ptr)
  356. {
  357.     register STRLEN delta;
  358.  
  359.     if (!(str->str_pok))
  360.     fatal("str_chop: internal inconsistency");
  361.     delta = ptr - str->str_ptr;
  362.     str->str_len -= delta;
  363.     str->str_cur -= delta;
  364.     str->str_ptr += delta;
  365.     if (str->str_state == SS_INCR)
  366.     str->str_u.str_useful += delta;
  367.     else {
  368.     str->str_u.str_useful = delta;
  369.     str->str_state = SS_INCR;
  370.     }
  371.     str->str_nok = 0;        /* invalidate number */
  372.     str->str_pok = 1;        /* validate pointer (and unstudy str) */
  373. }
  374.  
  375. void str_ncat (register STR *str, register char *ptr, register STRLEN len)
  376. {
  377.     if (str == &str_undef)
  378.     return;
  379.     if (!(str->str_pok))
  380.     (void)str_2ptr(str);
  381.     STR_GROW(str, str->str_cur + len + 1);
  382.     (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
  383.     str->str_cur += len;
  384.     *(str->str_ptr+str->str_cur) = '\0';
  385.     str->str_nok = 0;        /* invalidate number */
  386.     str->str_pok = 1;        /* validate pointer */
  387. #ifdef TAINT
  388.     str->str_tainted |= tainted;
  389. #endif
  390. }
  391.  
  392. void str_scat (STR *dstr, register STR *sstr)
  393. {
  394. #ifdef TAINT
  395.     tainted |= sstr->str_tainted;
  396. #endif
  397.     if (!sstr)
  398.     return;
  399.     if (!(sstr->str_pok))
  400.     (void)str_2ptr(sstr);
  401.     if (sstr)
  402.     str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
  403. }
  404.  
  405. void str_cat (register STR *str, register char *ptr)
  406. {
  407.     register STRLEN len;
  408.  
  409.     if (str == &str_undef)
  410.     return;
  411.     if (!ptr)
  412.     return;
  413.     if (!(str->str_pok))
  414.     (void)str_2ptr(str);
  415.     len = strlen(ptr);
  416.     STR_GROW(str, str->str_cur + len + 1);
  417.     (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
  418.     str->str_cur += len;
  419.     str->str_nok = 0;        /* invalidate number */
  420.     str->str_pok = 1;        /* validate pointer */
  421. #ifdef TAINT
  422.     str->str_tainted |= tainted;
  423. #endif
  424. }
  425.  
  426. char *str_append_till (register STR *str, register char *from,
  427.         register char *fromend, register int delim, char *keeplist)
  428. {
  429.     register char *to;
  430.     register STRLEN len;
  431.  
  432.     if (str == &str_undef)
  433.     return Nullch;
  434.     if (!from)
  435.     return Nullch;
  436.     len = fromend - from;
  437.     STR_GROW(str, str->str_cur + len + 1);
  438.     str->str_nok = 0;        /* invalidate number */
  439.     str->str_pok = 1;        /* validate pointer */
  440.     to = str->str_ptr+str->str_cur;
  441.     for (; from < fromend; from++,to++) {
  442.     if (*from == '\\' && from+1 < fromend && delim != '\\') {
  443.         if (!keeplist) {
  444.         if (from[1] == delim || from[1] == '\\')
  445.             from++;
  446.         else
  447.             *to++ = *from++;
  448.         }
  449.         else if (from[1] && index(keeplist,from[1]))
  450.         *to++ = *from++;
  451.         else
  452.         from++;
  453.     }
  454.     else if (*from == delim)
  455.         break;
  456.     *to = *from;
  457.     }
  458.     *to = '\0';
  459.     str->str_cur = to - str->str_ptr;
  460.     return from;
  461. }
  462.  
  463. #ifdef LEAKTEST
  464. STR *str_new (int x, STRLEN len)
  465. #else
  466. STR *str_new (STRLEN len)
  467. #endif
  468. {
  469.     register STR *str;
  470.     
  471.     if (freestrroot) {
  472.     str = freestrroot;
  473.     freestrroot = str->str_magic;
  474.     str->str_magic = Nullstr;
  475.     str->str_state = SS_NORM;
  476.     }
  477.     else {
  478.     Newz(700+x,str,1,STR);
  479.     }
  480.     if (len)
  481.     STR_GROW(str, len + 1);
  482.     return str;
  483. }
  484.  
  485. void str_magic (register STR *str, STAB *stab, int how, char *name, STRLEN namlen)
  486. {
  487.     if (str == &str_undef || str->str_magic)
  488.     return;
  489.     str->str_magic = Str_new(75,namlen);
  490.     str = str->str_magic;
  491.     str->str_u.str_stab = stab;
  492.     str->str_rare = how;
  493.     if (name)
  494.     str_nset(str,name,namlen);
  495. }
  496.  
  497. void str_insert (STR *bigstr, STRLEN offset, STRLEN len, char *little, STRLEN littlelen)
  498. {
  499.     register char *big;
  500.     register char *mid;
  501.     register char *midend;
  502.     register char *bigend;
  503.     register int i;
  504.  
  505.     if (bigstr == &str_undef)
  506.     return;
  507.     bigstr->str_nok = 0;
  508.     bigstr->str_pok = SP_VALID;    /* disable possible screamer */
  509.  
  510.     i = littlelen - len;
  511.     if (i > 0) {            /* string might grow */
  512.     STR_GROW(bigstr, bigstr->str_cur + i + 1);
  513.     big = bigstr->str_ptr;
  514.     mid = big + offset + len;
  515.     midend = bigend = big + bigstr->str_cur;
  516.     bigend += i;
  517.     *bigend = '\0';
  518.     while (midend > mid)        /* shove everything down */
  519.         *--bigend = *--midend;
  520.     (void)bcopy(little,big+offset,littlelen);
  521.     bigstr->str_cur += i;
  522.     return;
  523.     }
  524.     else if (i == 0) {
  525.     (void)bcopy(little,bigstr->str_ptr+offset,len);
  526.     return;
  527.     }
  528.  
  529.     big = bigstr->str_ptr;
  530.     mid = big + offset;
  531.     midend = mid + len;
  532.     bigend = big + bigstr->str_cur;
  533.  
  534.     if (midend > bigend)
  535.     fatal("panic: str_insert");
  536.  
  537.     if (mid - big > bigend - midend) {    /* faster to shorten from end */
  538.     if (littlelen) {
  539.         (void)bcopy(little, mid, littlelen);
  540.         mid += littlelen;
  541.     }
  542.     i = bigend - midend;
  543.     if (i > 0) {
  544.         (void)bcopy(midend, mid, i);
  545.         mid += i;
  546.     }
  547.     *mid = '\0';
  548.     bigstr->str_cur = mid - big;
  549.     }
  550.     else if ((i = mid - big) != 0) {    /* faster from front */
  551.     midend -= littlelen;
  552.     mid = midend;
  553.     str_chop(bigstr,midend-i);
  554.     big += i;
  555.     while (i--)
  556.         *--midend = *--big;
  557.     if (littlelen)
  558.         (void)bcopy(little, mid, littlelen);
  559.     }
  560.     else if (littlelen) {
  561.     midend -= littlelen;
  562.     str_chop(bigstr,midend);
  563.     (void)bcopy(little,midend,littlelen);
  564.     }
  565.     else {
  566.     str_chop(bigstr,midend);
  567.     }
  568.     STABSET(bigstr);
  569. }
  570.  
  571. /* make str point to what nstr did */
  572.  
  573. void str_replace (register STR *str, register STR *nstr)
  574. {
  575.     if (str == &str_undef)
  576.     return;
  577.     if (str->str_state == SS_INCR)
  578.     Str_Grow(str,0);    /* just force copy down */
  579.     if (nstr->str_state == SS_INCR)
  580.     Str_Grow(nstr,0);
  581.     if (str->str_ptr)
  582.     Safefree(str->str_ptr);
  583.     str->str_ptr = nstr->str_ptr;
  584.     str->str_len = nstr->str_len;
  585.     str->str_cur = nstr->str_cur;
  586.     str->str_pok = nstr->str_pok;
  587.     str->str_nok = nstr->str_nok;
  588. #ifdef STRUCTCOPY
  589.     str->str_u = nstr->str_u;
  590. #else
  591.     str->str_u.str_nval = nstr->str_u.str_nval;
  592. #endif
  593. #ifdef TAINT
  594.     str->str_tainted = nstr->str_tainted;
  595. #endif
  596.     if (nstr->str_magic)
  597.     str_free(nstr->str_magic);
  598.     Safefree(nstr);
  599. }
  600.  
  601. void str_free (register STR *str)
  602. {
  603.     if (!str || str == &str_undef)
  604.     return;
  605.     if (str->str_state) {
  606.     if (str->str_state == SS_FREE)    /* already freed */
  607.         return;
  608.     if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
  609.         str->str_ptr -= (int)str->str_u.str_useful;
  610.         str->str_len += (int)str->str_u.str_useful;
  611.     }
  612.     }
  613.     if (str->str_magic)
  614.     str_free(str->str_magic);
  615. #ifdef LEAKTEST
  616.     if (str->str_len)
  617.     Safefree(str->str_ptr);
  618.     if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  619.     arg_free(str->str_u.str_args);
  620.     Safefree(str);
  621. #else /* LEAKTEST */
  622.     if (str->str_len) {
  623.     if (str->str_len > 127) {    /* next user not likely to want more */
  624.         Safefree(str->str_ptr);    /* so give it back to malloc */
  625.         str->str_ptr = Nullch;
  626.         str->str_len = 0;
  627.     }
  628.     else
  629.         str->str_ptr[0] = '\0';
  630.     }
  631.     if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  632.     arg_free(str->str_u.str_args);
  633.     str->str_cur = 0;
  634.     str->str_nok = 0;
  635.     str->str_pok = 0;
  636.     str->str_state = SS_FREE;
  637. #ifdef TAINT
  638.     str->str_tainted = 0;
  639. #endif
  640.     str->str_magic = freestrroot;
  641.     freestrroot = str;
  642. #endif /* LEAKTEST */
  643. }
  644.  
  645. STRLEN str_len (register STR *str)
  646. {
  647.     if (!str)
  648.     return 0;
  649.     if (!(str->str_pok))
  650.     (void)str_2ptr(str);
  651.     if (str->str_ptr)
  652.     return str->str_cur;
  653.     else
  654.     return 0;
  655. }
  656.  
  657. int str_eq (register STR *str1, register STR *str2)
  658. {
  659.     if (!str1 || str1 == &str_undef)
  660.     return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur);
  661.     if (!str2 || str2 == &str_undef)
  662.     return !str1->str_cur;
  663.  
  664.     if (!str1->str_pok)
  665.     (void)str_2ptr(str1);
  666.     if (!str2->str_pok)
  667.     (void)str_2ptr(str2);
  668.  
  669.     if (str1->str_cur != str2->str_cur)
  670.     return 0;
  671.  
  672.     return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
  673. }
  674.  
  675. int str_cmp (register STR *str1, register STR *str2)
  676. {
  677.     int retval;
  678.  
  679.     if (!str1 || str1 == &str_undef)
  680.     return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1;
  681.     if (!str2 || str2 == &str_undef)
  682.     return str1->str_cur != 0;
  683.  
  684.     if (!str1->str_pok)
  685.     (void)str_2ptr(str1);
  686.     if (!str2->str_pok)
  687.     (void)str_2ptr(str2);
  688.  
  689.     if (str1->str_cur < str2->str_cur) {
  690.     if ((retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur)) != 0)
  691.         return retval < 0 ? -1 : 1;
  692.     else
  693.         return -1;
  694.     }
  695.     else if ((retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur)) != 0)
  696.     return retval < 0 ? -1 : 1;
  697.     else if (str1->str_cur == str2->str_cur)
  698.     return 0;
  699.     else
  700.     return 1;
  701. }
  702.  
  703. char *str_gets (register STR *str, register FILE *fp, int append)
  704. {
  705.     register char *bp;
  706.  
  707. #ifdef STDSTDIO
  708.  
  709. /* We're going to steal some values from the stdio struct
  710.  * and put EVERYTHING in the innermost loop into registers
  711.  */
  712.     register int cnt;
  713.     register STDCHAR *ptr;
  714.     STRLEN bpx;
  715.     STRLEN obpx;
  716. #endif
  717.  
  718.     register int newline = record_separator;
  719.     register int get_paragraph;
  720.     register char *oldbp;
  721.     int i;
  722.  
  723. #ifdef STDSTDIO
  724.     int shortbuffered;
  725. #endif
  726.  
  727.     if (str == &str_undef)
  728.     return Nullch;
  729.     if ((get_paragraph = !rslen) != 0) {/* yes, that's an assignment */
  730.     newline = '\n';
  731.     oldbp = Nullch;            /* remember last \n position (none) */
  732.     }
  733.  
  734. #ifdef STDSTDIO
  735.  
  736. /* Here is some breathtakingly efficient cheating */
  737.     cnt = fp->_cnt;            /* get count into register */
  738.     str->str_nok = 0;            /* invalidate number */
  739.     str->str_pok = 1;            /* validate pointer */
  740.     if (str->str_len <= cnt + 1) {    /* make sure we have the room */
  741.     if (cnt > 80 && str->str_len > 0) {
  742.         shortbuffered = cnt - str->str_len + 1;
  743.         cnt = str->str_len - 1;
  744.     }
  745.     else {
  746.         shortbuffered = 0;
  747.         STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */
  748.     }
  749.     }
  750.     else
  751.     shortbuffered = 0;
  752.     bp = str->str_ptr + append;        /* move these two too to registers */
  753.     ptr = fp->_ptr;
  754.     for (;;) {
  755.       screamer:
  756.     while (--cnt >= 0) {            /* this */    /* eat */
  757.         if ((*bp++ = *ptr++) == newline)    /* really */    /* dust */
  758.         goto thats_all_folks;        /* screams */    /* sed :-) */ 
  759.     }
  760.     
  761.     if (shortbuffered) {            /* oh well, must extend */
  762.         cnt = shortbuffered;
  763.         shortbuffered = 0;
  764.         if (get_paragraph && oldbp)
  765.         obpx = oldbp - str->str_ptr;
  766.         bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  767.         str->str_cur = bpx;
  768.         STR_GROW(str, str->str_len + append + cnt + 2);
  769.         bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  770.         if (get_paragraph && oldbp)
  771.         oldbp = str->str_ptr + obpx;
  772.         continue;
  773.     }
  774.  
  775.     fp->_cnt = cnt;            /* deregisterize cnt and ptr */
  776.     fp->_ptr = ptr;
  777.     i = _filbuf(fp);        /* get more characters */
  778.     cnt = fp->_cnt;
  779.     ptr = fp->_ptr;            /* reregisterize cnt and ptr */
  780.  
  781.     bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  782.     if (get_paragraph && oldbp)
  783.         obpx = oldbp - str->str_ptr;
  784.     str->str_cur = bpx;
  785.     STR_GROW(str, bpx + cnt + 2);
  786.     bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  787.     if (get_paragraph && oldbp)
  788.         oldbp = str->str_ptr + obpx;
  789.  
  790.     if (i == newline) {        /* all done for now? */
  791.         *bp++ = i;
  792.         goto thats_all_folks;
  793.     }
  794.     else if (i == EOF)        /* all done for ever? */
  795.         goto thats_really_all_folks;
  796.     *bp++ = i;            /* now go back to screaming loop */
  797.     }
  798.  
  799. thats_all_folks:
  800.     if (get_paragraph && bp - 1 != oldbp) {
  801.     oldbp = bp;    /* remember where this newline was */
  802.     goto screamer;    /* and go back to the fray */
  803.     }
  804. thats_really_all_folks:
  805.     if (shortbuffered)
  806.     cnt += shortbuffered;
  807.     fp->_cnt = cnt;            /* put these back or we're in trouble */
  808.     fp->_ptr = ptr;
  809.     *bp = '\0';
  810.     str->str_cur = bp - str->str_ptr;    /* set length */
  811.  
  812. #else /* !STDSTDIO */
  813.  
  814. /* The big, slow, and stupid way */
  815.  
  816.     {
  817.     static char buf[8192];
  818.     char *bpe = buf + sizeof(buf) - 3;
  819.  
  820. screamer:
  821.     bp = buf;
  822. filler:
  823.     while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe);
  824.     if (i == newline && get_paragraph &&
  825.         (i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe)
  826.         goto filler;
  827.  
  828.     *bp = '\0';
  829.     if (append)
  830.         str_cat(str, buf);
  831.     else
  832.         str_set(str, buf);
  833.     if (i != newline && i != EOF) {
  834.         append = -1;
  835.         goto screamer;
  836.     }
  837.     }
  838.  
  839. #endif /* STDSTDIO */
  840.  
  841.     return str->str_cur - append ? str->str_ptr : Nullch;
  842. }
  843.  
  844. ARG *parselist (STR *str)
  845. {
  846.     register CMD *cmd;
  847.     register ARG *arg;
  848.     CMD *oldcurcmd = curcmd;
  849.     int oldperldb = perldb;
  850.     int retval;
  851.  
  852.     perldb = 0;
  853.     str_sset(linestr,str);
  854.     in_eval++;
  855.     oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
  856.     bufend = bufptr + linestr->str_cur;
  857.     if (++loop_ptr >= loop_max) {
  858.         loop_max += 128;
  859.         Renew(loop_stack, loop_max, struct loop);
  860.     }
  861.     loop_stack[loop_ptr].loop_label = "_EVAL_";
  862.     loop_stack[loop_ptr].loop_sp = 0;
  863. #ifdef DEBUGGING
  864.     if (debug & 4) {
  865.         deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
  866.     }
  867. #endif
  868.     if (setjmp(loop_stack[loop_ptr].loop_env)) {
  869.     in_eval--;
  870.     loop_ptr--;
  871.     perldb = oldperldb;
  872.     fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
  873.     }
  874. #ifdef DEBUGGING
  875.     if (debug & 4) {
  876.     char *tmps = loop_stack[loop_ptr].loop_label;
  877.     deb("(Popping label #%d %s)\n",loop_ptr,
  878.         tmps ? tmps : "" );
  879.     }
  880. #endif
  881.     loop_ptr--;
  882.     error_count = 0;
  883.     curcmd = &compiling;
  884.     curcmd->c_line = oldcurcmd->c_line;
  885.     retval = yyparse();
  886.     curcmd = oldcurcmd;
  887.     perldb = oldperldb;
  888.     in_eval--;
  889.     if (retval || error_count)
  890.     fatal("Invalid component in string or format");
  891.     cmd = eval_root;
  892.     arg = cmd->c_expr;
  893.     if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
  894.     fatal("panic: error in parselist %d %x %d", cmd->c_type,
  895.       cmd->c_next, arg ? arg->arg_type : -1);
  896.     Safefree(cmd);
  897.     return arg;
  898. }
  899.  
  900. void intrpcompile (STR *src)
  901. {
  902.     register char *s = str_get(src);
  903.     register char *send = s + src->str_cur;
  904.     register STR *str;
  905.     register char *t;
  906.     STR *toparse;
  907.     STRLEN len;
  908.     register int brackets;
  909.     register char *d;
  910.     STAB *stab;
  911.     char *checkpoint;
  912.  
  913.     toparse = Str_new(76,0);
  914.     str = Str_new(77,0);
  915.  
  916.     str_nset(str,"",0);
  917.     str_nset(toparse,"",0);
  918.     t = s;
  919.     while (s < send) {
  920.     if (*s == '\\' && s[1] && index("$@[{\\]}",s[1])) {
  921.         str_ncat(str, t, s - t);
  922.         ++s;
  923.         if (*nointrp && s+1 < send)
  924.         if (*s != '@' && (*s != '$' || index(nointrp,s[1])))
  925.             str_ncat(str,s-1,1);
  926.         str_ncat(str, "$b", 2);
  927.         str_ncat(str, s, 1);
  928.         ++s;
  929.         t = s;
  930.     }
  931.     else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) &&
  932.       s+1 < send) {
  933.         str_ncat(str,t,s-t);
  934.         t = s;
  935.         if (*s == '$' && s[1] == '#' && (isalpha(s[2]) || s[2] == '_'))
  936.         s++;
  937.         s = scanreg(s,send,tokenbuf);
  938.         if (*t == '@' &&
  939.           ((stab = stabent(tokenbuf,FALSE)) == Nullstab ||
  940.          (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
  941.         str_ncat(str,"@",1);
  942.         s = ++t;
  943.         continue;    /* grandfather @ from old scripts */
  944.         }
  945.         str_ncat(str,"$a",2);
  946.         str_ncat(toparse,",",1);
  947.         if (t[1] != '{' && (*s == '['  || *s == '{' /* }} */ ) &&
  948.           (stab = stabent(tokenbuf,FALSE)) != Nullstab &&
  949.           ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
  950.         brackets = 0;
  951.         checkpoint = s;
  952.         do {
  953.             switch (*s) {
  954.             case '[':
  955.             if (s[-1] != '$')
  956.                 brackets++;
  957.             break;
  958.             case '{':
  959.             brackets++;
  960.             break;
  961.             case ']':
  962.             if (s[-1] != '$')
  963.                 brackets--;
  964.             break;
  965.             case '}':
  966.             brackets--;
  967.             break;
  968.             case '\'':
  969.             case '"':
  970.             if (s[-1] != '$') {
  971.                 s = cpytill(tokenbuf,s+1,send,*s,(int *)&len);
  972.                 if (s >= send)
  973.                 fatal("Unterminated string");
  974.             }
  975.             break;
  976.             }
  977.             s++;
  978.         } while (brackets > 0 && s < send);
  979.         if (s > send)
  980.             fatal("Unmatched brackets in string");
  981.         if (*nointrp) {        /* we're in a regular expression */
  982.             d = checkpoint;
  983.             if (*d == '{' && s[-1] == '}') {    /* maybe {n,m} */
  984.             ++d;
  985.             if (isdigit(*d)) {    /* matches /^{\d,?\d*}$/ */
  986.                 if (*++d == ',')
  987.                 ++d;
  988.                 while (isdigit(*d))
  989.                 d++;
  990.                 if (d == s - 1)
  991.                 s = checkpoint;        /* Is {n,m}! Backoff! */
  992.             }
  993.             }
  994.             else if (*d == '[' && s[-1] == ']') { /* char class? */
  995.             int weight = 2;        /* let's weigh the evidence */
  996.             char seen[256];
  997.             unsigned char un_char = 0, last_un_char;
  998.  
  999.             Zero(seen,256,char);
  1000.             *--s = '\0';
  1001.             if (d[1] == '^')
  1002.                 weight += 150;
  1003.             else if (d[1] == '$')
  1004.                 weight -= 3;
  1005.             if (isdigit(d[1])) {
  1006.                 if (d[2]) {
  1007.                 if (isdigit(d[2]) && !d[3])
  1008.                     weight -= 10;
  1009.                 }
  1010.                 else
  1011.                 weight -= 100;
  1012.             }
  1013.             for (d++; d < s; d++) {
  1014.                 last_un_char = un_char;
  1015.                 un_char = (unsigned char)*d;
  1016.                 switch (*d) {
  1017.                 case '&':
  1018.                 case '$':
  1019.                 weight -= seen[un_char] * 10;
  1020.                 if (isalpha(d[1]) || isdigit(d[1]) ||
  1021.                   d[1] == '_') {
  1022.                     d = scanreg(d,s,tokenbuf);
  1023.                     if (stabent(tokenbuf,FALSE))
  1024.                     weight -= 100;
  1025.                     else
  1026.                     weight -= 10;
  1027.                 }
  1028.                 else if (*d == '$' && d[1] &&
  1029.                   index("[#!%*<>()-=",d[1])) {
  1030.                     if (!d[2] || /*{*/ index("])} =",d[2]))
  1031.                     weight -= 10;
  1032.                     else
  1033.                     weight -= 1;
  1034.                 }
  1035.                 break;
  1036.                 case '\\':
  1037.                 un_char = 254;
  1038.                 if (d[1]) {
  1039.                     if (index("wds",d[1]))
  1040.                     weight += 100;
  1041.                     else if (seen['\''] || seen['"'])
  1042.                     weight += 1;
  1043.                     else if (index("rnftb",d[1]))
  1044.                     weight += 40;
  1045.                     else if (isdigit(d[1])) {
  1046.                     weight += 40;
  1047.                     while (d[1] && isdigit(d[1]))
  1048.                         d++;
  1049.                     }
  1050.                 }
  1051.                 else
  1052.                     weight += 100;
  1053.                 break;
  1054.                 case '-':
  1055.                 if (last_un_char < (unsigned char) d[1]
  1056.                   || d[1] == '\\') {
  1057.                     if (index("aA01! ",last_un_char))
  1058.                     weight += 30;
  1059.                     if (index("zZ79~",d[1]))
  1060.                     weight += 30;
  1061.                 }
  1062.                 else
  1063.                     weight -= 1;
  1064.                 default:
  1065.                 if (isalpha(*d) && d[1] && isalpha(d[1])) {
  1066.                     bufptr = d;
  1067.                     if (yylex() != WORD)
  1068.                     weight -= 150;
  1069.                     d = bufptr;
  1070.                 }
  1071.                 if (un_char == last_un_char + 1)
  1072.                     weight += 5;
  1073.                 weight -= seen[un_char];
  1074.                 break;
  1075.                 }
  1076.                 seen[un_char]++;
  1077.             }
  1078. #ifdef DEBUGGING
  1079.             if (debug & 512)
  1080.                 fprintf(stderr,"[%s] weight %d\n",
  1081.                   checkpoint+1,weight);
  1082. #endif
  1083.             *s++ = ']';
  1084.             if (weight >= 0)    /* probably a character class */
  1085.                 s = checkpoint;
  1086.             }
  1087.         }
  1088.         }
  1089.         if (*t == '@')
  1090.         str_ncat(toparse, "join($\",", 8);
  1091.         if (t[1] == '{' && s[-1] == '}') {
  1092.         str_ncat(toparse, t, 1);
  1093.         str_ncat(toparse, t+2, s - t - 3);
  1094.         }
  1095.         else
  1096.         str_ncat(toparse, t, s - t);
  1097.         if (*t == '@')
  1098.         str_ncat(toparse, ")", 1);
  1099.         t = s;
  1100.     }
  1101.     else
  1102.         s++;
  1103.     }
  1104.     str_ncat(str,t,s-t);
  1105.     if (toparse->str_ptr && *toparse->str_ptr == ',') {
  1106.     *toparse->str_ptr = '(';
  1107.     str_ncat(toparse,",$$);",5);
  1108.     str->str_u.str_args = parselist(toparse);
  1109.     str->str_u.str_args->arg_len--;        /* ignore $$ reference */
  1110.     }
  1111.     else
  1112.     str->str_u.str_args = Nullarg;
  1113.     str_free(toparse);
  1114.     str->str_pok |= SP_INTRP;
  1115.     str->str_nok = 0;
  1116.     str_replace(src,str);
  1117. }
  1118.  
  1119. STR *interp (register STR *str, STR *src, int sp)
  1120. {
  1121.     register char *s;
  1122.     register char *t;
  1123.     register char *send;
  1124.     register STR **elem;
  1125.  
  1126.     if (str == &str_undef)
  1127.     return Nullstr;
  1128.     if (!(src->str_pok & SP_INTRP)) {
  1129.     int oldsave = savestack->ary_fill;
  1130.  
  1131.     (void)savehptr(&curstash);
  1132.     curstash = curcmd->c_stash;    /* so stabent knows right package */
  1133.     intrpcompile(src);
  1134.     restorelist(oldsave);
  1135.     }
  1136.     s = src->str_ptr;        /* assumed valid since str_pok set */
  1137.     t = s;
  1138.     send = s + src->str_cur;
  1139.  
  1140.     if (src->str_u.str_args) {
  1141.     (void)eval(src->str_u.str_args,G_ARRAY,sp);
  1142.     /* Assuming we have correct # of args */
  1143.     elem = stack->ary_array + sp;
  1144.     }
  1145.  
  1146.     str_nset(str,"",0);
  1147.     while (s < send) {
  1148.     if (*s == '$' && s+1 < send) {
  1149.         str_ncat(str,t,s-t);
  1150.         switch(*++s) {
  1151.         case 'a':
  1152.         str_scat(str,*++elem);
  1153.         break;
  1154.         case 'b':
  1155.         str_ncat(str,++s,1);
  1156.         break;
  1157.         }
  1158.         t = ++s;
  1159.     }
  1160.     else
  1161.         s++;
  1162.     }
  1163.     str_ncat(str,t,s-t);
  1164.     return str;
  1165. }
  1166.  
  1167. void str_inc (register STR *str)
  1168. {
  1169.     register char *d;
  1170.  
  1171.     if (!str || str == &str_undef)
  1172.     return;
  1173.     if (str->str_nok) {
  1174.     str->str_u.str_nval += 1.0;
  1175.     str->str_pok = 0;
  1176.     return;
  1177.     }
  1178.     if (!str->str_pok || !*str->str_ptr) {
  1179.     str->str_u.str_nval = 1.0;
  1180.     str->str_nok = 1;
  1181.     str->str_pok = 0;
  1182.     return;
  1183.     }
  1184.     d = str->str_ptr;
  1185.     while (isalpha(*d)) d++;
  1186.     while (isdigit(*d)) d++;
  1187.     if (*d) {
  1188.         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
  1189.     return;
  1190.     }
  1191.     d--;
  1192.     while (d >= str->str_ptr) {
  1193.     if (isdigit(*d)) {
  1194.         if (++*d <= '9')
  1195.         return;
  1196.         *(d--) = '0';
  1197.     }
  1198.     else {
  1199.         ++*d;
  1200.         if (isalpha(*d))
  1201.         return;
  1202.         *(d--) -= 'z' - 'a' + 1;
  1203.     }
  1204.     }
  1205.     /* oh,oh, the number grew */
  1206.     STR_GROW(str, str->str_cur + 2);
  1207.     str->str_cur++;
  1208.     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
  1209.     *d = d[-1];
  1210.     if (isdigit(d[1]))
  1211.     *d = '1';
  1212.     else
  1213.     *d = d[1];
  1214. }
  1215.  
  1216. void str_dec (register STR *str)
  1217. {
  1218.     if (!str || str == &str_undef)
  1219.     return;
  1220.     if (str->str_nok) {
  1221.     str->str_u.str_nval -= 1.0;
  1222.     str->str_pok = 0;
  1223.     return;
  1224.     }
  1225.     if (!str->str_pok) {
  1226.     str->str_u.str_nval = -1.0;
  1227.     str->str_nok = 1;
  1228.     return;
  1229.     }
  1230.     str_numset(str,atof(str->str_ptr) - 1.0);
  1231. }
  1232.  
  1233. /* Make a string that will exist for the duration of the expression
  1234.  * evaluation.  Actually, it may have to last longer than that, but
  1235.  * hopefully cmd_exec won't free it until it has been assigned to a
  1236.  * permanent location. */
  1237.  
  1238. static long tmps_size = -1;
  1239.  
  1240. STR *str_static (STR *oldstr)
  1241. {
  1242.     register STR *str = Str_new(78,0);
  1243.  
  1244.     str_sset(str,oldstr);
  1245.     if (++tmps_max > tmps_size) {
  1246.     tmps_size = tmps_max;
  1247.     if (!(tmps_size & 127)) {
  1248.         if (tmps_size)
  1249.         Renew(tmps_list, tmps_size + 128, STR*);
  1250.         else
  1251.         New(702,tmps_list, 128, STR*);
  1252.     }
  1253.     }
  1254.     tmps_list[tmps_max] = str;
  1255.     if (str->str_pok)
  1256.     str->str_pok |= SP_TEMP;
  1257.     return str;
  1258. }
  1259.  
  1260. /* same thing without the copying */
  1261.  
  1262. STR *str_2static (register STR *str)
  1263. {
  1264.     if (str == &str_undef)
  1265.     return str;
  1266.     if (++tmps_max > tmps_size) {
  1267.     tmps_size = tmps_max;
  1268.     if (!(tmps_size & 127)) {
  1269.         if (tmps_size)
  1270.         Renew(tmps_list, tmps_size + 128, STR*);
  1271.         else
  1272.         New(704,tmps_list, 128, STR*);
  1273.     }
  1274.     }
  1275.     tmps_list[tmps_max] = str;
  1276.     if (str->str_pok)
  1277.     str->str_pok |= SP_TEMP;
  1278.     return str;
  1279. }
  1280.  
  1281. STR *str_make (char *s, STRLEN len)
  1282. {
  1283.     register STR *str = Str_new(79,0);
  1284.  
  1285.     if (!len)
  1286.     len = strlen(s);
  1287.     str_nset(str,s,len);
  1288.     return str;
  1289. }
  1290.  
  1291. STR *str_nmake (double n)
  1292. {
  1293.     register STR *str = Str_new(80,0);
  1294.  
  1295.     str_numset(str,n);
  1296.     return str;
  1297. }
  1298.  
  1299. /* make an exact duplicate of old */
  1300.  
  1301. STR *str_smake (register STR *old)
  1302. {
  1303.     register STR *new = Str_new(81,0);
  1304.  
  1305.     if (!old)
  1306.     return Nullstr;
  1307.     if (old->str_state == SS_FREE) {
  1308.     warn("semi-panic: attempt to dup freed string");
  1309.     return Nullstr;
  1310.     }
  1311.     if (old->str_state == SS_INCR && !(old->str_pok & 2))
  1312.     Str_Grow(old,0);
  1313.     if (new->str_ptr)
  1314.     Safefree(new->str_ptr);
  1315.     Copy(old,new,1,STR);
  1316.     if (old->str_ptr) {
  1317.     new->str_ptr = nsavestr(old->str_ptr,old->str_len);
  1318.     new->str_pok &= ~SP_TEMP;
  1319.     }
  1320.     return new;
  1321. }
  1322.  
  1323. void str_reset (register char *s, HASH *stash)
  1324. {
  1325.     register HENT *entry;
  1326.     register STAB *stab;
  1327.     register STR *str;
  1328.     register int i;
  1329.     register SPAT *spat;
  1330.     register int max;
  1331.  
  1332.     if (!*s) {        /* reset ?? searches */
  1333.     for (spat = stash->tbl_spatroot;
  1334.       spat != Nullspat;
  1335.       spat = spat->spat_next) {
  1336.         spat->spat_flags &= ~SPAT_USED;
  1337.     }
  1338.     return;
  1339.     }
  1340.  
  1341.     /* reset variables */
  1342.  
  1343.     if (!stash->tbl_array)
  1344.     return;
  1345.     while (*s) {
  1346.     i = *s;
  1347.     if (s[1] == '-') {
  1348.         s += 2;
  1349.     }
  1350.     max = *s++;
  1351.     for ( ; i <= max; i++) {
  1352.         for (entry = stash->tbl_array[i];
  1353.           entry;
  1354.           entry = entry->hent_next) {
  1355.         stab = (STAB*)entry->hent_val;
  1356.         str = stab_val(stab);
  1357.         str->str_cur = 0;
  1358.         str->str_nok = 0;
  1359. #ifdef TAINT
  1360.         str->str_tainted = tainted;
  1361. #endif
  1362.         if (str->str_ptr != Nullch)
  1363.             str->str_ptr[0] = '\0';
  1364.         if (stab_xarray(stab)) {
  1365.             aclear(stab_xarray(stab));
  1366.         }
  1367.         if (stab_xhash(stab)) {
  1368.             hclear(stab_xhash(stab), FALSE);
  1369. #ifndef ARM
  1370.             if (stab == envstab)
  1371.             environ[0] = Nullch;
  1372. #endif
  1373.         }
  1374.         }
  1375.     }
  1376.     }
  1377. }
  1378.  
  1379. #ifdef TAINT
  1380. void taintproper (char *s)
  1381. {
  1382. #ifdef DEBUGGING
  1383.     if (debug & 2048)
  1384.     fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
  1385. #endif
  1386.     if (tainted && (!euid || euid != uid || egid != gid)) {
  1387.     if (!unsafe)
  1388.         fatal("%s", s);
  1389.     else if (dowarn)
  1390.         warn("%s", s);
  1391.     }
  1392. }
  1393.  
  1394. void taintenv (void)
  1395. {
  1396.     register STR *envstr;
  1397.  
  1398.     envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
  1399.     if (envstr == &str_undef || envstr->str_tainted) {
  1400.     tainted = 1;
  1401.     if (envstr->str_tainted == 2)
  1402.         taintproper("Insecure directory in PATH");
  1403.     else
  1404.         taintproper("Insecure PATH");
  1405.     }
  1406.     envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
  1407.     if (envstr != &str_undef && envstr->str_tainted) {
  1408.     tainted = 1;
  1409.     taintproper("Insecure IFS");
  1410.     }
  1411. }
  1412. #endif /* TAINT */
  1413.