home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / MAWK113.ZIP / mawk113 / bi_funct.c < prev    next >
C/C++ Source or Header  |  1993-01-26  |  20KB  |  890 lines

  1.  
  2. /********************************************
  3. bi_funct.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /* $Log: bi_funct.c,v $
  14.  * Revision 5.3.1.2  1993/01/27  01:04:06  mike
  15.  * minor tuning to str_str()
  16.  *
  17.  * Revision 5.3.1.1  1993/01/15  03:33:35  mike
  18.  * patch3: safer double to int conversion
  19.  *
  20.  * Revision 5.3  1992/12/17  02:48:01  mike
  21.  * 1.1.2d changes for DOS
  22.  *
  23.  * Revision 5.2  1992/07/08  15:43:41  brennan
  24.  * patch2: length returns.  I am a wimp
  25.  *
  26.  * Revision 5.1  1991/12/05  07:55:35  brennan
  27.  * 1.1 pre-release
  28.  *
  29. */
  30.  
  31.  
  32. #include "mawk.h"
  33. #include "bi_funct.h"
  34. #include "bi_vars.h"
  35. #include "memory.h"
  36. #include "init.h"
  37. #include "files.h"
  38. #include "fin.h"
  39. #include "field.h"
  40. #include "regexp.h"
  41. #include "repl.h"
  42. #include <math.h>
  43.  
  44.  
  45. /* statics */
  46. static STRING *PROTO(gsub, (PTR, CELL *, char *, int) ) ;
  47. static void  PROTO( fplib_err, (char *, double, char *) ) ;
  48.  
  49.  
  50. /* global for the disassembler */
  51. BI_REC  bi_funct[] = { /* info to load builtins */
  52.  
  53. "length" , bi_length, 0, 1, /* special must come first */
  54. "index" , bi_index , 2, 2 ,
  55. "substr" , bi_substr, 2, 3,
  56. "sprintf" , bi_sprintf, 1, 255,
  57. "sin", bi_sin , 1, 1 ,
  58. "cos", bi_cos , 1, 1 ,
  59. "atan2", bi_atan2, 2,2,
  60. "exp", bi_exp, 1, 1,
  61. "log", bi_log , 1, 1 ,
  62. "int", bi_int, 1, 1,
  63. "sqrt", bi_sqrt, 1, 1,
  64. "rand" , bi_rand, 0, 0,
  65. "srand", bi_srand, 0, 1,
  66. "close", bi_close, 1, 1,
  67. "system", bi_system, 1, 1,
  68. "toupper", bi_toupper, 1, 1,
  69. "tolower", bi_tolower, 1, 1,
  70.  
  71. (char *) 0, (PF_CP) 0, 0, 0 } ;
  72.  
  73.  
  74. /* load built-in functions in symbol table */
  75. void bi_funct_init()
  76. { register BI_REC *p ; 
  77.   register SYMTAB *stp ;
  78.  
  79.   /* length is special (posix bozo) */
  80.   stp = insert(bi_funct->name) ;
  81.   stp->type = ST_LENGTH ;
  82.   stp->stval.bip = bi_funct ;
  83.  
  84.   for( p = bi_funct + 1 ; p->name ; p++ )
  85.   { stp = insert( p->name ) ;
  86.     stp->type = ST_BUILTIN ;
  87.     stp->stval.bip = p ;
  88.   }
  89.  
  90.   /* seed rand() off the clock */
  91.   { CELL c ;
  92.  
  93.     c.type = 0 ; (void) bi_srand(&c) ;
  94.   }
  95.  
  96. }
  97.  
  98. /**************************************************
  99.  string builtins (except split (in split.c) and [g]sub (at end))
  100.  **************************************************/
  101.  
  102. CELL *bi_length(sp)
  103.   register  CELL *sp ;
  104. { unsigned len ;
  105.  
  106.   if ( sp->type == 0 )  cellcpy(sp, field) ;
  107.   else sp-- ;
  108.  
  109.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  110.   len = string(sp)->len ;
  111.  
  112.   free_STRING( string(sp) ) ;
  113.   sp->type = C_DOUBLE ;
  114.   sp->dval = (double) len ;
  115.  
  116.   return sp ;
  117. }
  118.  
  119. char *str_str(target, key , key_len)
  120.   register char *target;
  121.   char *key ;
  122.   unsigned key_len ;
  123.   register int k = key[0] ;
  124.  
  125.   switch( key_len )
  126.   {
  127.     case 0 :  return (char *) 0 ;
  128.     case 1 :  return strchr( target, k) ;
  129.     case 2 :
  130.     { int k1 = key[1] ;
  131.         while ( target = strchr(target, k) )
  132.           if ( target[1] == k1 )  return  target ;
  133.           else target++ ;
  134.         /*failed*/
  135.         return (char *) 0 ;
  136.     }
  137.   }
  138.  
  139.   key_len-- ;
  140.   while ( target = strchr(target, k) )
  141.   {
  142.         if ( memcmp(target+1, key+1, SIZE_T(key_len)) == 0 )
  143.          return target ;
  144.         else target++ ;
  145.   }
  146.   /*failed*/
  147.   return (char *) 0 ;
  148. }
  149.  
  150.  
  151.  
  152. CELL *bi_index(sp)
  153.   register CELL *sp ;
  154. { register int idx ;
  155.   unsigned len ;
  156.   char *p ;
  157.  
  158.   sp-- ;
  159.   if ( TEST2(sp) != TWO_STRINGS )
  160.         cast2_to_s(sp) ;
  161.  
  162.   if ( len = string(sp+1)->len )
  163.     idx = (p = str_str(string(sp)->str,string(sp+1)->str,len))
  164.           ? p - string(sp)->str + 1 : 0 ;
  165.  
  166.   else  /* index of the empty string */
  167.     idx = 1 ;
  168.   
  169.   free_STRING( string(sp) ) ;
  170.   free_STRING( string(sp+1) ) ;
  171.   sp->type = C_DOUBLE ;
  172.   sp->dval = (double) idx ;
  173.   return sp ;
  174. }
  175.  
  176. /*  substr(s, i, n)
  177.     if l = length(s)
  178.     then get the characters
  179.     from  max(1,i) to min(l,n-i-1) inclusive */
  180.  
  181. CELL *bi_substr(sp)
  182.   CELL *sp ;
  183. { int n_args, len ;
  184.   register int i, n ;
  185.   STRING *sval ;  /* substr(sval->str, i, n) */
  186.  
  187.   n_args = sp->type ;
  188.   sp -= n_args ;
  189.   if ( sp->type != C_STRING )  cast1_to_s(sp) ;
  190.       /* don't use < C_STRING shortcut */
  191.   sval = string(sp) ;
  192.  
  193.   if ( (len = sval->len) == 0 )  /* substr on null string */
  194.   {  if ( n_args == 3 )  cell_destroy(sp+2) ;
  195.      cell_destroy(sp+1) ;
  196.      return sp ;
  197.   }
  198.  
  199.   if ( n_args == 2 )  
  200.   { n = MAX__INT  ;  
  201.     if ( sp[1].type != C_DOUBLE ) cast1_to_d(sp+1) ; 
  202.   }
  203.   else
  204.   { if ( TEST2(sp+1) != TWO_DOUBLES ) cast2_to_d(sp+1) ;
  205.     n = d_to_i(sp[2].dval) ;
  206.   }
  207.   i = d_to_i(sp[1].dval) - 1 ; /* i now indexes into string */
  208.  
  209.   if ( i < 0 ) { n += i ; i = 0 ; }
  210.   if ( n > len - i )  n = len - i ;
  211.  
  212.   if ( n <= 0 )  /* the null string */
  213.   { 
  214.     sp->ptr = (PTR) &null_str ;
  215.     null_str.ref_cnt++ ;
  216.   }
  217.   else  /* got something */
  218.   { 
  219.     sp->ptr = (PTR) new_STRING((char *)0, n) ;
  220.     (void) memcpy(string(sp)->str, sval->str + i, SIZE_T(n)) ;
  221.   }
  222.  
  223.   free_STRING(sval) ;
  224.   return sp ;
  225.  
  226. /*
  227.   match(s,r)
  228.   sp[0] holds r, sp[-1] holds s
  229. */
  230.  
  231. CELL *bi_match(sp)
  232.   register CELL *sp ;
  233.   char *p ;
  234.   unsigned length ;
  235.  
  236.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  237.   if ( (--sp)->type < C_STRING )  cast1_to_s(sp) ;
  238.  
  239.   cell_destroy(RSTART) ;
  240.   cell_destroy(RLENGTH) ;
  241.   RSTART->type = C_DOUBLE ;
  242.   RLENGTH->type = C_DOUBLE ;
  243.  
  244.   p = REmatch(string(sp)->str, (sp+1)->ptr, &length) ;
  245.  
  246.   if ( p )
  247.   { sp->dval = (double) ( p - string(sp)->str + 1 ) ;
  248.     RLENGTH->dval = (double) length ;
  249.   }
  250.   else
  251.   { sp->dval = 0.0 ;
  252.     RLENGTH->dval = -1.0 ; /* posix */
  253.   }
  254.  
  255.   free_STRING(string(sp)) ;
  256.   sp->type = C_DOUBLE ;
  257.  
  258.   RSTART->dval = sp->dval ;
  259.  
  260.   return sp ;
  261. }
  262.  
  263. CELL *bi_toupper(sp)
  264.   CELL *sp ;
  265. { STRING *old ;
  266.   register char *p, *q ;
  267.  
  268.   if ( sp->type != C_STRING )  cast1_to_s(sp) ;
  269.   old = string(sp) ;
  270.   sp->ptr = (PTR) new_STRING((char *) 0, old->len) ;
  271.  
  272.   q = string(sp)->str ; p = old->str ;
  273.  
  274.   while ( *p )
  275.   {
  276.     *q = *p++ ;
  277.     if ( *q >= 'a' && *q <= 'z' )  *q += 'A' - 'a' ;
  278.     q++ ;
  279.   }
  280.   free_STRING(old) ;
  281.   return sp ;
  282. }
  283.  
  284. CELL *bi_tolower(sp)
  285.   CELL *sp ;
  286. { STRING *old ;
  287.   register char *p, *q ;
  288.  
  289.   if ( sp->type != C_STRING )  cast1_to_s(sp) ;
  290.   old = string(sp) ;
  291.   sp->ptr = (PTR) new_STRING((char *) 0, old->len) ;
  292.  
  293.   q = string(sp)->str ; p = old->str ;
  294.  
  295.   while ( *p )
  296.   {
  297.     *q = *p++ ;
  298.     if ( *q >= 'A' && *q <= 'Z' )  *q += 'a' - 'A' ;
  299.     q++ ;
  300.   }
  301.   free_STRING(old) ;
  302.   return sp ;
  303. }
  304.  
  305.  
  306. /************************************************
  307.   arithemetic builtins
  308.  ************************************************/
  309.  
  310. static void fplib_err( fname, val, error)
  311.   char *fname ;
  312.   double val ;
  313.   char *error ;
  314. {
  315.   rt_error("%s(%g) : %s" , fname, val, error) ;
  316. }
  317.  
  318.  
  319. CELL *bi_sin(sp)
  320.   register CELL *sp ;
  321. #if ! STDC_MATHERR
  322.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  323.   sp->dval = sin( sp->dval ) ;
  324.   return sp ;
  325. #else
  326.   double x ;
  327.  
  328.   errno = 0 ;
  329.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  330.   x = sp->dval ;
  331.   sp->dval = sin( sp->dval ) ;
  332.   if ( errno )  fplib_err("sin", x, "loss of precision") ;
  333.   return sp ;
  334. #endif
  335. }
  336.  
  337. CELL *bi_cos(sp)
  338.   register CELL *sp ;
  339. #if ! STDC_MATHERR
  340.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  341.   sp->dval = cos( sp->dval ) ;
  342.   return sp ;
  343. #else
  344.   double x ;
  345.  
  346.   errno = 0 ;
  347.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  348.   x = sp->dval ;
  349.   sp->dval = cos( sp->dval ) ;
  350.   if ( errno )  fplib_err("cos", x, "loss of precision") ;
  351.   return sp ;
  352. #endif
  353. }
  354.  
  355. CELL *bi_atan2(sp)
  356.   register CELL *sp ;
  357. #if  !  STDC_MATHERR
  358.   sp-- ;
  359.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  360.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  361.   return sp ;
  362. #else
  363.  
  364.   errno = 0 ;
  365.   sp-- ;
  366.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  367.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  368.   if ( errno ) rt_error("atan2(0,0) : domain error") ;
  369.   return sp ;
  370. #endif
  371. }
  372.  
  373. CELL *bi_log(sp)
  374.   register CELL *sp ;
  375. #if ! STDC_MATHERR
  376.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  377.   sp->dval = log( sp->dval ) ;
  378.   return sp ;
  379. #else
  380.   double  x ;
  381.  
  382.   errno = 0 ;
  383.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  384.   x = sp->dval ;
  385.   sp->dval = log( sp->dval ) ;
  386.   if ( errno )  fplib_err("log", x, "domain error") ;
  387.   return sp ;
  388. #endif
  389. }
  390.  
  391. CELL *bi_exp(sp)
  392.   register CELL *sp ;
  393. #if  ! STDC_MATHERR
  394.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  395.   sp->dval = exp(sp->dval) ;
  396.   return sp ;
  397. #else
  398.   double  x ;
  399.  
  400.   errno = 0 ;
  401.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  402.   x = sp->dval ;
  403.   sp->dval = exp(sp->dval) ;
  404.   if ( errno && sp->dval)  fplib_err("exp", x, "overflow") ;
  405.      /* on underflow sp->dval==0, ignore */
  406.   return sp ;
  407. #endif
  408. }
  409.  
  410. CELL *bi_int(sp)
  411.   register CELL *sp ;
  412. { if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  413.   sp->dval = sp->dval >= 0.0 ? floor( sp->dval ) : ceil(sp->dval)  ;
  414.   return sp ;
  415. }
  416.  
  417. CELL *bi_sqrt(sp)
  418.   register CELL *sp ;
  419. #if  ! STDC_MATHERR
  420.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  421.   sp->dval = sqrt( sp->dval ) ;
  422.   return sp ;
  423. #else
  424.   double x ;
  425.  
  426.   errno = 0 ;
  427.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  428.   x = sp->dval ;
  429.   sp->dval = sqrt( sp->dval ) ;
  430.   if ( errno )  fplib_err("sqrt", x, "domain error") ;
  431.   return sp ;
  432. #endif
  433. }
  434.  
  435. #ifdef  HAVE_TIME_H
  436. #include <time.h>
  437. #else
  438. #include <sys/types.h>
  439. #endif
  440.  
  441.  
  442. /* For portability, we'll use our own random number generator , taken
  443.    from:  Park, SK and Miller KW, "Random Number Generators:
  444.    Good Ones are Hard to Find", CACM, 31, 1192-1201, 1988.
  445. */
  446.  
  447. static long seed ;  /* must be >=1 and <= 2^31-1 */
  448. static CELL cseed ; /* argument of last call to srand() */
  449.  
  450. #define         M       0x7fffffff   /* 2^31-1 */
  451.  
  452. CELL *bi_srand(sp)
  453.   register CELL *sp ;
  454. { CELL c ;
  455.  
  456.   if ( sp->type == 0 ) /* seed off clock */
  457.   { (void) cellcpy(sp, &cseed) ;
  458.     cell_destroy(&cseed) ;
  459.     cseed.type = C_DOUBLE ;
  460.     cseed.dval = (double) time((time_t*) 0) ;
  461.   }
  462.   else /* user seed */
  463.   { sp-- ;
  464.     /* swap cseed and *sp ; don't need to adjust ref_cnts */
  465.     c = *sp ; *sp = cseed ; cseed = c ;
  466.   }
  467.  
  468.   /* The old seed is now in *sp ; move the value in cseed to
  469.      seed in range 1 to M */
  470.  
  471.   (void) cellcpy(&c, &cseed) ;
  472.   if ( c.type == C_NOINIT )  cast1_to_d(&c) ;
  473.  
  474.   seed =  c.type == C_DOUBLE ? (d_to_i(c.dval) & M) % M + 1 :
  475.                         hash(string(&c)->str) % M + 1 ;
  476.  
  477.   cell_destroy(&c) ;
  478.  
  479.   /* crank it once so close seeds don't give a close 
  480.        first result  */
  481. #define   A     16807
  482. #define   Q     127773   /* M/A */
  483. #define   R     2836     /* M%A */
  484.   seed = A * (seed%Q) - R * (seed/Q) ;
  485.   if ( seed <= 0 )  seed += M ;
  486.  
  487.   return sp ;
  488. }
  489.     
  490. CELL *bi_rand(sp)
  491.   register CELL *sp ;
  492.   register long test ;
  493.  
  494.   test = A * (seed%Q) - R * (seed/Q) ;
  495.   if ( test <= 0 )  test += M ;
  496.  
  497.   (++sp)->type = C_DOUBLE ;
  498.   sp->dval = (double)( seed = test ) / (double) M ;
  499.   return sp ;
  500.  
  501. #undef   A
  502. #undef   M
  503. #undef   Q
  504. #undef   R
  505. }
  506.  
  507. /*************************************************
  508.  miscellaneous builtins
  509.  close, system and getline
  510.  *************************************************/
  511.  
  512. CELL *bi_close(sp)
  513.   register CELL *sp ;
  514. { int x ;
  515.  
  516.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  517.   x = file_close( (STRING *) sp->ptr) ;
  518.   free_STRING( string(sp) ) ;
  519.   sp->type = C_DOUBLE ;
  520.   sp->dval = (double) x ;
  521.   return sp ;
  522. }
  523.  
  524. #if   HAVE_REAL_PIPES
  525.  
  526. CELL *bi_system(sp)
  527.   CELL *sp ;
  528. { int pid ;
  529.   unsigned ret_val ;
  530.  
  531.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  532.  
  533.   fflush(stdout) ; fflush(stderr) ;
  534.  
  535.   switch( pid = fork() )
  536.   { case -1 :  /* fork failed */
  537.  
  538.        errmsg(errno, "could not create a new process") ;
  539.        ret_val = 127 ;
  540.        break ;
  541.  
  542.     case  0  :  /* the child */
  543.        (void) execl(shell, shell, "-c", string(sp)->str, (char *) 0) ;
  544.        /* if get here, execl() failed */
  545.        errmsg(errno, "execute of %s failed", shell) ;
  546.        fflush(stderr) ;
  547.        _exit(127) ;
  548.  
  549.     default   :  /* wait for the child */
  550.        ret_val = wait_for(pid) ;
  551.        break ;
  552.   }
  553.  
  554.   cell_destroy(sp) ;
  555.   sp->type = C_DOUBLE ;
  556.   sp->dval = (double) ret_val ;
  557.   return sp ;
  558. }
  559.  
  560. #endif /* HAVE_REAL_PIPES */
  561.  
  562. #ifdef  THINK_C
  563.  
  564. CELL *bi_system( sp )
  565.   register CELL *sp ;
  566. { rt_error("no system call for the Macintosh Toy Operating System!!!") ;
  567.   return sp ;
  568. }
  569.  
  570. #endif
  571.  
  572.  
  573. #if   MSDOS
  574.  
  575.  
  576. CELL *bi_system( sp )
  577.   register CELL *sp ;
  578. { int retval ;
  579.  
  580.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  581.   retval = DOSexec(string(sp)->str) ;
  582.   free_STRING(string(sp)) ;
  583.   sp->type = C_DOUBLE ;
  584.   sp->dval = (double) retval ;
  585.   return sp ;
  586. }
  587.  
  588. #endif
  589.  
  590.  
  591. /*  getline()  */
  592.  
  593. /*  if type == 0 :  stack is 0 , target address
  594.  
  595.     if type == F_IN : stack is F_IN, expr(filename), target address
  596.  
  597.     if type == PIPE_IN : stack is PIPE_IN, target address, expr(pipename)
  598. */
  599.  
  600. CELL *bi_getline(sp)
  601.   register CELL *sp ;
  602.   CELL tc , *cp ;
  603.   char *p ;
  604.   unsigned len ;
  605.   FIN *fin_p ;
  606.  
  607.  
  608.   switch( sp->type )
  609.   { 
  610.     case 0 :
  611.         sp-- ;
  612.         if ( ! main_fin )  open_main() ;
  613.     
  614.         if ( ! (p = FINgets(main_fin, &len)) )
  615.                 goto  eof ;
  616.  
  617.         cp = (CELL *) sp->ptr ;
  618.         if ( TEST2(NR) != TWO_DOUBLES ) cast2_to_d(NR) ;
  619.         NR->dval += 1.0 ;
  620.         FNR->dval += 1.0 ;
  621.         break ;
  622.  
  623.     case  F_IN :
  624.         sp-- ;
  625.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  626.         fin_p = (FIN *) file_find(sp->ptr, F_IN) ;
  627.         free_STRING(string(sp) ) ;
  628.         sp-- ;
  629.  
  630.         if ( ! fin_p )   goto open_failure ;
  631.         if ( ! (p = FINgets(fin_p, &len)) )  
  632.         {
  633.           FINsemi_close(fin_p) ;
  634.           goto eof ; 
  635.         }
  636.         cp = (CELL *) sp->ptr ;
  637.         break ;
  638.  
  639.     case PIPE_IN :
  640.         sp -= 2 ;
  641.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  642.         fin_p = (FIN *) file_find(sp->ptr, PIPE_IN) ;
  643.         free_STRING(string(sp)) ;
  644.  
  645.         if ( ! fin_p )   goto open_failure ;
  646.         if ( ! (p = FINgets(fin_p, &len)) ) 
  647.         { 
  648.           FINsemi_close(fin_p) ;
  649. #if  HAVE_REAL_PIPES
  650.           /* reclaim process slot */
  651.           (void) wait_for(0) ;
  652. #endif
  653.           goto eof ; 
  654.         }
  655.         cp = (CELL *) (sp+1)->ptr ;
  656.         break ;
  657.  
  658.     default : bozo("type in bi_getline") ;
  659.  
  660.   }
  661.  
  662.   /* we've read a line , store it */
  663.  
  664.     if ( len == 0 )
  665.     { tc.type = C_STRING ; 
  666.       tc.ptr = (PTR) &null_str ; 
  667.       null_str.ref_cnt++ ;
  668.     }
  669.     else
  670.     { tc.type = C_MBSTRN ;
  671.       tc.ptr = (PTR) new_STRING((char *) 0, len) ;
  672.       (void) memcpy( string(&tc)->str, p, SIZE_T(len)) ;
  673.     }
  674.  
  675.     slow_cell_assign(cp, &tc) ;
  676.  
  677.     cell_destroy(&tc) ;
  678.  
  679.   sp->dval = 1.0  ;  goto done ;
  680.  
  681. open_failure :
  682.   sp->dval = -1.0  ; goto done ;
  683.  
  684. eof :
  685.   sp->dval = 0.0  ;  /* fall thru to done  */
  686.  
  687. done :
  688.   sp->type = C_DOUBLE  ;
  689.   return sp ;
  690. }
  691.  
  692. /**********************************************
  693.  sub() and gsub()
  694.  **********************************************/
  695.  
  696. /* entry:  sp[0] = address of CELL to sub on
  697.            sp[-1] = substitution CELL
  698.            sp[-2] = regular expression to match
  699. */
  700.  
  701. CELL *bi_sub( sp )
  702.   register CELL *sp ;
  703. { CELL *cp ; /* pointer to the replacement target */
  704.   CELL tc ;  /* build the new string here */
  705.   CELL sc ;  /* copy of the target CELL */
  706.   char *front, *middle, *back ; /* pieces */
  707.   unsigned front_len, middle_len, back_len ;
  708.  
  709.   sp -= 2 ;
  710.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  711.   if ( sp[1].type != C_REPL && sp[1].type != C_REPLV )
  712.               cast_to_REPL(sp+1) ;
  713.   cp = (CELL *) (sp+2)->ptr ;
  714.   /* make a copy of the target, because we won't change anything
  715.      including type unless the match works */
  716.   (void) cellcpy(&sc, cp) ;
  717.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  718.   front = string(&sc)->str ;
  719.  
  720.   if ( middle = REmatch(front, sp->ptr, &middle_len) )
  721.   { 
  722.     front_len = middle - front ;
  723.     back = middle + middle_len ; 
  724.     back_len = string(&sc)->len - front_len - middle_len ;
  725.  
  726.     if ( (sp+1)->type == C_REPLV ) 
  727.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  728.  
  729.       (void) memcpy(sval->str, middle, SIZE_T(middle_len)) ;
  730.       (void) replv_to_repl(sp+1, sval) ;
  731.       free_STRING(sval) ;
  732.     }
  733.  
  734.     tc.type = C_STRING ;
  735.     tc.ptr = (PTR) new_STRING((char *) 0, 
  736.              front_len + string(sp+1)->len + back_len ) ;
  737.  
  738.     { char *p = string(&tc)->str ;
  739.  
  740.       if ( front_len )
  741.       { (void) memcpy(p, front, SIZE_T(front_len)) ;
  742.         p += front_len ;
  743.       }
  744.       if ( string(sp+1)->len )
  745.       { (void) memcpy(p, string(sp+1)->str, SIZE_T(string(sp+1)->len)) ;
  746.         p += string(sp+1)->len ;
  747.       }
  748.       if ( back_len )  (void) memcpy(p, back, SIZE_T(back_len)) ;
  749.     }
  750.  
  751.     slow_cell_assign(cp, &tc) ;
  752.  
  753.     free_STRING(string(&tc)) ;
  754.   }
  755.  
  756.   free_STRING(string(&sc)) ;
  757.   repl_destroy(sp+1) ;
  758.   sp->type = C_DOUBLE ;
  759.   sp->dval = middle != (char *) 0 ? 1.0 : 0.0 ;
  760.   return sp ;
  761. }
  762.  
  763. static  unsigned repl_cnt ;  /* number of global replacements */
  764.  
  765. /* recursive global subsitution 
  766.    dealing with empty matches makes this mildly painful
  767. */
  768.  
  769. static STRING *gsub( re, repl, target, flag)
  770.   PTR  re ;
  771.   CELL *repl ;  /* always of type REPL or REPLV, 
  772.        destroyed by caller */
  773.   char *target ;
  774.   int flag ; /* if on, match of empty string at front is OK */
  775. { char *front, *middle ;
  776.   STRING *back ;
  777.   unsigned front_len, middle_len ;
  778.   STRING  *ret_val ;
  779.   CELL xrepl ; /* a copy of repl so we can change repl */
  780.  
  781.   if ( ! (middle = REmatch(target, re, &middle_len)) )
  782.       return  new_STRING(target) ; /* no match */
  783.  
  784.   (void) cellcpy(&xrepl, repl) ;
  785.  
  786.   if ( !flag && middle_len == 0 && middle == target ) 
  787.   { /* match at front that's not allowed */
  788.  
  789.     if ( *target == 0 )  /* target is empty string */
  790.     { repl_destroy(&xrepl) ;
  791.       null_str.ref_cnt++ ;
  792.       return & null_str ;
  793.     }
  794.     else
  795.     { char xbuff[2] ;
  796.  
  797.       front_len = 0 ;
  798.       /* make new repl with target[0] */
  799.       repl_destroy(repl) ;
  800.       xbuff[0] = *target++ ;  xbuff[1] = 0 ;
  801.       repl->type = C_REPL ;
  802.       repl->ptr = (PTR) new_STRING( xbuff ) ;
  803.       back = gsub(re, &xrepl, target, 1) ;
  804.     }
  805.   }
  806.   else  /* a match that counts */
  807.   { repl_cnt++ ;
  808.  
  809.     front = target ;
  810.     front_len = middle - target ;
  811.  
  812.     if ( *middle == 0 )  /* matched back of target */
  813.     { back = &null_str ; null_str.ref_cnt++ ; }
  814.     else back = gsub(re, &xrepl, middle + middle_len, 0) ;
  815.       
  816.     /* patch the &'s if needed */
  817.     if ( repl->type == C_REPLV )
  818.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  819.  
  820.       (void) memcpy(sval->str, middle, SIZE_T(middle_len)) ;
  821.       (void) replv_to_repl(repl, sval) ;
  822.       free_STRING(sval) ;
  823.     }
  824.   }
  825.  
  826.   /* put the three pieces together */
  827.   ret_val = new_STRING((char *)0,
  828.               front_len + string(repl)->len + back->len); 
  829.   { char *p = ret_val->str ;
  830.  
  831.     if ( front_len )
  832.     { (void) memcpy(p, front, SIZE_T(front_len)) ; p += front_len ; }
  833.     if ( string(repl)->len )
  834.     { (void) memcpy(p, string(repl)->str, SIZE_T(string(repl)->len)) ;
  835.       p += string(repl)->len ;
  836.     }
  837.     if ( back->len ) (void) memcpy(p, back->str, SIZE_T(back->len)) ;
  838.   }
  839.  
  840.   /* cleanup, repl is freed by the caller */
  841.   repl_destroy(&xrepl) ;
  842.   free_STRING(back) ;
  843.  
  844.   return ret_val ;
  845. }
  846.  
  847. /* set up for call to gsub() */
  848. CELL *bi_gsub( sp )
  849.   register CELL *sp ;
  850. { CELL *cp ;  /* pts at the replacement target */
  851.   CELL sc  ;  /* copy of replacement target */
  852.   CELL tc  ;  /* build the result here */
  853.  
  854.   sp -= 2 ;
  855.   if ( sp->type != C_RE ) cast_to_RE(sp) ;
  856.   if ( (sp+1)->type != C_REPL && (sp+1)->type != C_REPLV )
  857.           cast_to_REPL(sp+1) ;
  858.  
  859.   (void) cellcpy(&sc, cp = (CELL *)(sp+2)->ptr) ;
  860.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  861.  
  862.   repl_cnt = 0 ;
  863.   tc.ptr = (PTR) gsub(sp->ptr, sp+1, string(&sc)->str, 1) ;
  864.  
  865.   if ( repl_cnt )
  866.   { 
  867.     tc.type = C_STRING ;
  868.     slow_cell_assign(cp, &tc) ;
  869.   }
  870.  
  871.   /* cleanup */
  872.   free_STRING(string(&sc)) ; free_STRING(string(&tc)) ;
  873.   repl_destroy(sp+1) ;
  874.  
  875.   sp->type = C_DOUBLE ;
  876.   sp->dval = (double) repl_cnt ;
  877.   return sp ;
  878. }
  879.