home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PERL4036.ZIP / str.c < prev    next >
C/C++ Source or Header  |  1993-02-26  |  35KB  |  1,597 lines

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