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