home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / lang / perl4.035.V010.lzh / perl4.035 / src / str.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-25  |  34.1 KB  |  1,595 lines

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