home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perlkt40.zip / STR.C < prev    next >
C/C++ Source or Header  |  1996-06-13  |  10KB  |  465 lines

  1. /* $RCSfile: str.c,v $$Revision: 4.0.1.1 $$Date: 91/06/07 12:20:08 $
  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.1  91/06/07  12:20:08  lwall
  10.  * patch4: new copyright notice
  11.  * 
  12.  * Revision 4.0  91/03/20  01:58:15  lwall
  13.  * 4.0 baseline.
  14.  * 
  15.  */
  16.  
  17. #include "handy.h"
  18. #include "EXTERN.h"
  19. #include "util.h"
  20. #include "a2p.h"
  21.  
  22. str_numset(str,num)
  23. register STR *str;
  24. double num;
  25. {
  26.     str->str_nval = num;
  27.     str->str_pok = 0;        /* invalidate pointer */
  28.     str->str_nok = 1;        /* validate number */
  29. }
  30.  
  31. char *
  32. str_2ptr(str)
  33. register STR *str;
  34. {
  35.     register char *s;
  36.  
  37.     if (!str)
  38.     return "";
  39.     GROWSTR(&(str->str_ptr), &(str->str_len), 24);
  40.     s = str->str_ptr;
  41.     if (str->str_nok) {
  42.     sprintf(s,"%.20g",str->str_nval);
  43.     while (*s) s++;
  44.     }
  45.     *s = '\0';
  46.     str->str_cur = s - str->str_ptr;
  47.     str->str_pok = 1;
  48. #ifdef DEBUGGING
  49.     if (debug & 32)
  50.     fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
  51. #endif
  52.     return str->str_ptr;
  53. }
  54.  
  55. double
  56. str_2num(str)
  57. register STR *str;
  58. {
  59.     if (!str)
  60.     return 0.0;
  61.     if (str->str_len && str->str_pok)
  62.     str->str_nval = atof(str->str_ptr);
  63.     else
  64.     str->str_nval = 0.0;
  65.     str->str_nok = 1;
  66. #ifdef DEBUGGING
  67.     if (debug & 32)
  68.     fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
  69. #endif
  70.     return str->str_nval;
  71. }
  72.  
  73. str_sset(dstr,sstr)
  74. STR *dstr;
  75. register STR *sstr;
  76. {
  77.     if (!sstr)
  78.     str_nset(dstr,No,0);
  79.     else if (sstr->str_nok)
  80.     str_numset(dstr,sstr->str_nval);
  81.     else if (sstr->str_pok)
  82.     str_nset(dstr,sstr->str_ptr,sstr->str_cur);
  83.     else
  84.     str_nset(dstr,"",0);
  85. }
  86.  
  87. str_nset(str,ptr,len)
  88. register STR *str;
  89. register char *ptr;
  90. register int len;
  91. {
  92.     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  93.     bcopy(ptr,str->str_ptr,len);
  94.     str->str_cur = len;
  95.     *(str->str_ptr+str->str_cur) = '\0';
  96.     str->str_nok = 0;        /* invalidate number */
  97.     str->str_pok = 1;        /* validate pointer */
  98. }
  99.  
  100. str_set(str,ptr)
  101. register STR *str;
  102. register char *ptr;
  103. {
  104.     register int len;
  105.  
  106.     if (!ptr)
  107.     ptr = "";
  108.     len = strlen(ptr);
  109.     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  110.     bcopy(ptr,str->str_ptr,len+1);
  111.     str->str_cur = len;
  112.     str->str_nok = 0;        /* invalidate number */
  113.     str->str_pok = 1;        /* validate pointer */
  114. }
  115.  
  116. str_chop(str,ptr)    /* like set but assuming ptr is in str */
  117. register STR *str;
  118. register char *ptr;
  119. {
  120.     if (!(str->str_pok))
  121.     str_2ptr(str);
  122.     str->str_cur -= (ptr - str->str_ptr);
  123.     bcopy(ptr,str->str_ptr, str->str_cur + 1);
  124.     str->str_nok = 0;        /* invalidate number */
  125.     str->str_pok = 1;        /* validate pointer */
  126. }
  127.  
  128. str_ncat(str,ptr,len)
  129. register STR *str;
  130. register char *ptr;
  131. register int len;
  132. {
  133.     if (!(str->str_pok))
  134.     str_2ptr(str);
  135.     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  136.     bcopy(ptr,str->str_ptr+str->str_cur,len);
  137.     str->str_cur += len;
  138.     *(str->str_ptr+str->str_cur) = '\0';
  139.     str->str_nok = 0;        /* invalidate number */
  140.     str->str_pok = 1;        /* validate pointer */
  141. }
  142.  
  143. str_scat(dstr,sstr)
  144. STR *dstr;
  145. register STR *sstr;
  146. {
  147.     if (!(sstr->str_pok))
  148.     str_2ptr(sstr);
  149.     if (sstr)
  150.     str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
  151. }
  152.  
  153. str_cat(str,ptr)
  154. register STR *str;
  155. register char *ptr;
  156. {
  157.     register int len;
  158.  
  159.     if (!ptr)
  160.     return;
  161.     if (!(str->str_pok))
  162.     str_2ptr(str);
  163.     len = strlen(ptr);
  164.     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  165.     bcopy(ptr,str->str_ptr+str->str_cur,len+1);
  166.     str->str_cur += len;
  167.     str->str_nok = 0;        /* invalidate number */
  168.     str->str_pok = 1;        /* validate pointer */
  169. }
  170.  
  171. char *
  172. str_append_till(str,from,delim,keeplist)
  173. register STR *str;
  174. register char *from;
  175. register int delim;
  176. char *keeplist;
  177. {
  178.     register char *to;
  179.     register int len;
  180.  
  181.     if (!from)
  182.     return Nullch;
  183.     len = strlen(from);
  184.     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
  185.     str->str_nok = 0;        /* invalidate number */
  186.     str->str_pok = 1;        /* validate pointer */
  187.     to = str->str_ptr+str->str_cur;
  188.     for (; *from; from++,to++) {
  189.     if (*from == '\\' && from[1] && delim != '\\') {
  190.         if (!keeplist) {
  191.         if (from[1] == delim || from[1] == '\\')
  192.             from++;
  193.         else
  194.             *to++ = *from++;
  195.         }
  196.         else if (index(keeplist,from[1]))
  197.         *to++ = *from++;
  198.         else
  199.         from++;
  200.     }
  201.     else if (*from == delim)
  202.         break;
  203.     *to = *from;
  204.     }
  205.     *to = '\0';
  206.     str->str_cur = to - str->str_ptr;
  207.     return from;
  208. }
  209.  
  210. STR *
  211. str_new(len)
  212. int len;
  213. {
  214.     register STR *str;
  215.     
  216.     if (freestrroot) {
  217.     str = freestrroot;
  218.     freestrroot = str->str_link.str_next;
  219.     }
  220.     else {
  221.     str = (STR *) safemalloc(sizeof(STR));
  222.     bzero((char*)str,sizeof(STR));
  223.     }
  224.     if (len)
  225.     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  226.     return str;
  227. }
  228.  
  229. void
  230. str_grow(str,len)
  231. register STR *str;
  232. int len;
  233. {
  234.     if (len && str)
  235.     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
  236. }
  237.  
  238. /* make str point to what nstr did */
  239.  
  240. void
  241. str_replace(str,nstr)
  242. register STR *str;
  243. register STR *nstr;
  244. {
  245.     safefree(str->str_ptr);
  246.     str->str_ptr = nstr->str_ptr;
  247.     str->str_len = nstr->str_len;
  248.     str->str_cur = nstr->str_cur;
  249.     str->str_pok = nstr->str_pok;
  250.     if (str->str_nok = nstr->str_nok)
  251.     str->str_nval = nstr->str_nval;
  252.     safefree((char*)nstr);
  253. }
  254.  
  255. void
  256. str_free(str)
  257. register STR *str;
  258. {
  259.     if (!str)
  260.     return;
  261.     if (str->str_len)
  262.     str->str_ptr[0] = '\0';
  263.     str->str_cur = 0;
  264.     str->str_nok = 0;
  265.     str->str_pok = 0;
  266.     str->str_link.str_next = freestrroot;
  267.     freestrroot = str;
  268. }
  269.  
  270. str_len(str)
  271. register STR *str;
  272. {
  273.     if (!str)
  274.     return 0;
  275.     if (!(str->str_pok))
  276.     str_2ptr(str);
  277.     if (str->str_len)
  278.     return str->str_cur;
  279.     else
  280.     return 0;
  281. }
  282.  
  283. char *
  284. str_gets(str,fp)
  285. register STR *str;
  286. register FILE *fp;
  287. {
  288. #ifdef STDSTDIO        /* Here is some breathtakingly efficient cheating */
  289.  
  290.     register char *bp;        /* we're going to steal some values */
  291.     register int cnt;        /*  from the stdio struct and put EVERYTHING */
  292.     register STDCHAR *ptr;    /*   in the innermost loop into registers */
  293.     register char newline = '\n';    /* (assuming at least 6 registers) */
  294.     int i;
  295.     int bpx;
  296.  
  297.     cnt = fp->_cnt;            /* get count into register */
  298.     str->str_nok = 0;            /* invalidate number */
  299.     str->str_pok = 1;            /* validate pointer */
  300.     if (str->str_len <= cnt)        /* make sure we have the room */
  301.     GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
  302.     bp = str->str_ptr;            /* move these two too to registers */
  303.     ptr = fp->_ptr;
  304.     for (;;) {
  305.     while (--cnt >= 0) {
  306.         if ((*bp++ = *ptr++) == newline)
  307.         if (bp <= str->str_ptr || bp[-2] != '\\')
  308.             goto thats_all_folks;
  309.         else {
  310.             line++;
  311.             bp -= 2;
  312.         }
  313.     }
  314.     
  315.     fp->_cnt = cnt;            /* deregisterize cnt and ptr */
  316.     fp->_ptr = ptr;
  317.     i = _filbuf(fp);        /* get more characters */
  318.     cnt = fp->_cnt;
  319.     ptr = fp->_ptr;            /* reregisterize cnt and ptr */
  320.  
  321.     bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  322.     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
  323.     bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  324.  
  325.     if (i == newline) {        /* all done for now? */
  326.         *bp++ = i;
  327.         goto thats_all_folks;
  328.     }
  329.     else if (i == EOF)        /* all done for ever? */
  330.         goto thats_all_folks;
  331.     *bp++ = i;            /* now go back to screaming loop */
  332.     }
  333.  
  334. thats_all_folks:
  335.     fp->_cnt = cnt;            /* put these back or we're in trouble */
  336.     fp->_ptr = ptr;
  337.     *bp = '\0';
  338.     str->str_cur = bp - str->str_ptr;    /* set length */
  339.  
  340. #else /* !STDSTDIO */    /* The big, slow, and stupid way */
  341.  
  342.     static char buf[4192];
  343.  
  344.     if (fgets(buf, sizeof buf, fp) != Nullch)
  345.     str_set(str, buf);
  346.     else
  347.     str_set(str, No);
  348.  
  349. #endif /* STDSTDIO */
  350.  
  351.     return str->str_cur ? str->str_ptr : Nullch;
  352. }
  353.  
  354. void
  355. str_inc(str)
  356. register STR *str;
  357. {
  358.     register char *d;
  359.  
  360.     if (!str)
  361.     return;
  362.     if (str->str_nok) {
  363.     str->str_nval += 1.0;
  364.     str->str_pok = 0;
  365.     return;
  366.     }
  367.     if (!str->str_pok) {
  368.     str->str_nval = 1.0;
  369.     str->str_nok = 1;
  370.     return;
  371.     }
  372.     for (d = str->str_ptr; *d && *d != '.'; d++) ;
  373.     d--;
  374.     if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
  375.         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
  376.     return;
  377.     }
  378.     while (d >= str->str_ptr) {
  379.     if (++*d <= '9')
  380.         return;
  381.     *(d--) = '0';
  382.     }
  383.     /* oh,oh, the number grew */
  384.     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
  385.     str->str_cur++;
  386.     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
  387.     *d = d[-1];
  388.     *d = '1';
  389. }
  390.  
  391. void
  392. str_dec(str)
  393. register STR *str;
  394. {
  395.     register char *d;
  396.  
  397.     if (!str)
  398.     return;
  399.     if (str->str_nok) {
  400.     str->str_nval -= 1.0;
  401.     str->str_pok = 0;
  402.     return;
  403.     }
  404.     if (!str->str_pok) {
  405.     str->str_nval = -1.0;
  406.     str->str_nok = 1;
  407.     return;
  408.     }
  409.     for (d = str->str_ptr; *d && *d != '.'; d++) ;
  410.     d--;
  411.     if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
  412.         str_numset(str,atof(str->str_ptr) - 1.0);  /* punt */
  413.     return;
  414.     }
  415.     while (d >= str->str_ptr) {
  416.     if (--*d >= '0')
  417.         return;
  418.     *(d--) = '9';
  419.     }
  420. }
  421.  
  422. /* make a string that will exist for the duration of the expression eval */
  423.  
  424. STR *
  425. str_mortal(oldstr)
  426. STR *oldstr;
  427. {
  428.     register STR *str = str_new(0);
  429.     static long tmps_size = -1;
  430.  
  431.     str_sset(str,oldstr);
  432.     if (++tmps_max > tmps_size) {
  433.     tmps_size = tmps_max;
  434.     if (!(tmps_size & 127)) {
  435.         if (tmps_size)
  436.         tmps_list = (STR**)saferealloc((char*)tmps_list,
  437.             (tmps_size + 128) * sizeof(STR*) );
  438.         else
  439.         tmps_list = (STR**)safemalloc(128 * sizeof(char*));
  440.     }
  441.     }
  442.     tmps_list[tmps_max] = str;
  443.     return str;
  444. }
  445.  
  446. STR *
  447. str_make(s)
  448. char *s;
  449. {
  450.     register STR *str = str_new(0);
  451.  
  452.     str_set(str,s);
  453.     return str;
  454. }
  455.  
  456. STR *
  457. str_nmake(n)
  458. double n;
  459. {
  460.     register STR *str = str_new(0);
  461.  
  462.     str_numset(str,n);
  463.     return str;
  464. }
  465.