home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mawk.lzh / mawk.3 < prev    next >
Encoding:
Text File  |  1991-05-19  |  60.5 KB  |  2,597 lines

  1.   register FCALL_REC *q = &dummy ; /* trails p */
  2.  
  3.   q->link = p ;
  4.   while ( p )
  5.   {
  6.     if ( ! p->callee->code )
  7.     { /* callee never defined */
  8.       errmsg(0, "line %u: function %s never defined" ,
  9.           p->line_no, p->callee->name) ;
  10.       if ( ++compile_error_count == MAX_COMPILE_ERRORS ) 
  11.               mawk_exit(1) ;
  12.       /* delete p from list */
  13.       q->link = p->link ;
  14.       /* don't worry about freeing memory, we'll exit soon */
  15.     }
  16.     else  /* note p->arg_list starts with last argument */
  17.     if ( ! p->arg_list  /* nothing to do */  ||
  18.          ! p->arg_cnt_checked && 
  19.          ! arg_cnt_ok(p->callee, p->arg_list, p->line_no) )
  20.     {  q->link = p->link ; /* delete p */ 
  21.        /* the ! arg_list case is not an error so free memory */
  22.        zfree(p, sizeof(FCALL_REC)) ;
  23.     }
  24.     else
  25.     { /* keep p and set call_start */
  26.       q = p ;
  27.       switch ( p->call_scope )
  28.       {
  29.         case SCOPE_MAIN  :
  30.                 p->call_start = main_start ;
  31.                 break ;
  32.  
  33.         case SCOPE_BEGIN :
  34.                 p->call_start = begin_start ;
  35.                 break ;
  36.  
  37.         case SCOPE_END :
  38.                 p->call_start = end_start ;
  39.                 break ;
  40.  
  41.         case SCOPE_FUNCT :
  42.                 p->call_start = p->call->code ;
  43.                 break ;
  44.       }
  45.     }
  46.     p = q->link ;
  47.   }
  48.   return  dummy.link ;
  49. }
  50.  
  51. /* continuously walk the resolve_list making type deductions
  52.    until this list goes empty or no more progress can be made
  53.    (An example where no more progress can be made is at end of file
  54. */
  55.  
  56. void  resolve_fcalls()
  57. { register FCALL_REC *p, *old_list , *new_list ;
  58.   int progress ; /* a flag */
  59.  
  60.   old_list = first_pass(resolve_list) ;
  61.   new_list = (FCALL_REC *) 0 ;
  62.   progress = 0 ;
  63.  
  64.   while ( 1 )
  65.   {
  66.     if ( !(p = old_list) )
  67.     { /* flop the lists */
  68.       if ( !(p = old_list = new_list)  /* nothing left */
  69.           || ! progress    /* can't do any more */ )  return ;
  70.  
  71.       /* reset after flop */
  72.       new_list = (FCALL_REC *) 0 ;  progress = 0 ;
  73.     }
  74.  
  75.     old_list = p->link ;
  76.  
  77.     if ( p->arg_list = call_arg_check(p->callee, p->arg_list ,
  78.               p->call_start, p->line_no)  )
  79.     {
  80.        /* still have work to do , put on new_list   */
  81.        progress  |= check_progress ;
  82.        p->link = new_list ;  new_list = p ;
  83.     }
  84.     else  /* done with p */
  85.     {  progress = 1 ;  zfree(p, sizeof(FCALL_REC)) ; }
  86.   }
  87. }
  88.  
  89. /* the parser has just reduced a function call ;
  90.    the info needed to type check is passed in.  If type checking
  91.    can not be done yet (most common reason -- function referenced
  92.    but not defined), a node is added to the resolve list.
  93. */
  94. void check_fcall( callee, call_scope, call, arg_list, line_no )
  95.   FBLOCK *callee ;
  96.   int call_scope ;
  97.   FBLOCK  *call ;
  98.   CA_REC  *arg_list ;
  99.   unsigned line_no ;
  100. {
  101.   FCALL_REC *p ;
  102.   INST *call_start ;
  103.  
  104.   if ( ! callee->code ) 
  105.   { /* forward reference to a function to be defined later */
  106.     p = (FCALL_REC *) zmalloc(sizeof(FCALL_REC)) ;
  107.     p->callee = callee ;
  108.     p->call_scope = call_scope ;
  109.     p->call = call ;
  110.     p->arg_list = arg_list ;
  111.     p->arg_cnt_checked = 0 ;
  112.     p->line_no = line_no ;
  113.     /* add to resolve list */
  114.     p->link = resolve_list ; resolve_list = p ;
  115.   }
  116.   else
  117.   if ( arg_list && arg_cnt_ok( callee, arg_list, line_no ) )
  118.   {
  119.       switch ( call_scope )
  120.       {
  121.         case SCOPE_MAIN  :
  122.                 call_start = main_start ;
  123.                 break ;
  124.  
  125.         case SCOPE_BEGIN :
  126.                 call_start = begin_start ;
  127.                 break ;
  128.  
  129.         case SCOPE_END :
  130.                 call_start = end_start ;
  131.                 break ;
  132.  
  133.         case SCOPE_FUNCT :
  134.                 call_start = call->code ;
  135.                 break ;
  136.       }
  137.  
  138.       /* usually arg_list disappears here and all is well
  139.          otherwise add to resolve list */
  140.  
  141.       if ( arg_list = call_arg_check(callee, arg_list,
  142.                 call_start, line_no) )
  143.       {
  144.             p = (FCALL_REC *) zmalloc(sizeof(FCALL_REC)) ;
  145.             p->callee = callee ;
  146.             p->call_scope = call_scope ;
  147.             p->call = call ;
  148.             p->arg_list = arg_list ;
  149.             p->arg_cnt_checked = 1 ;
  150.             p->line_no = line_no ;
  151.             /* add to resolve list */
  152.             p->link = resolve_list ; resolve_list = p ;
  153.       }
  154.   }
  155. }
  156.  
  157.  
  158.  
  159. /*  example where typing cannot progress
  160.  
  161. { f(z) }
  162.  
  163. function f(x) { print NR }
  164.  
  165. # this is legal, does something useful, but absurdly written
  166. # We have to design so this works
  167. */
  168.  
  169. @//E*O*F mawk0.97/fcall.c//
  170. chmod u=rw,g=r,o=r mawk0.97/fcall.c
  171.  
  172. echo x - mawk0.97/field.c
  173. sed 's/^@//' > "mawk0.97/field.c" <<'@//E*O*F mawk0.97/field.c//'
  174.  
  175. /********************************************
  176. field.c
  177. copyright 1991, Michael D. Brennan
  178.  
  179. This is a source file for mawk, an implementation of
  180. the Awk programming language as defined in
  181. Aho, Kernighan and Weinberger, The AWK Programming Language,
  182. Addison-Wesley, 1988.
  183.  
  184. See the accompaning file, LIMITATIONS, for restrictions
  185. regarding modification and redistribution of this
  186. program in source or binary form.
  187. ********************************************/
  188.  
  189. /* $Log:    field.c,v $
  190.  * Revision 2.2  91/04/09  12:39:00  brennan
  191.  * added static to funct decls to satisfy STARDENT compiler
  192.  * 
  193.  * Revision 2.1  91/04/08  08:23:01  brennan
  194.  * VERSION 0.97
  195.  * 
  196. */
  197.  
  198.  
  199. /* field.c */
  200.  
  201. #include "mawk.h"
  202. #include "field.h"
  203. #include "init.h"
  204. #include "memory.h"
  205. #include "scan.h"
  206. #include "bi_vars.h"
  207. #include "repl.h"
  208. #include "regexp.h"
  209.  
  210. CELL  field[NUM_FIELDS] ;
  211.  
  212. /* statics */
  213. static void PROTO( build_field0, (void) ) ;
  214. static void PROTO( xcast, (CELL *) ) ;
  215. static void PROTO( set_rs_shadow, (void) ) ;
  216.  
  217. /* the order is important here, must be the same as
  218.    postion after field[MAX_FIELD] */
  219.  
  220. static char *biv_field_names[] = {
  221. "NF" , "RS" , "FS", "OFMT" } ;
  222.  
  223. /* a description of how to split based on RS.
  224.    If RS is changed, so is rs_shadow */
  225. SEPARATOR rs_shadow = {SEP_CHAR, '\n'} ;
  226. /* a splitting CELL version of FS */
  227. CELL fs_shadow = {C_SPACE} ;
  228. int   nf ;  
  229.   /* nf holds the true value of NF.  If nf < 0 , then
  230.      NF has not been computed, i.e., $0 has not been split
  231.   */
  232.  
  233. static void set_rs_shadow()
  234. { CELL c ;
  235.   STRING  *sval ;
  236.   char *s ;
  237.   unsigned len ;
  238.  
  239.   if ( rs_shadow.type == SEP_STR )  free_STRING((STRING*) rs_shadow.ptr) ;
  240.  
  241.   cast_for_split( cellcpy(&c, field+RS) ) ;
  242.   switch( c.type )
  243.   {
  244.     case C_RE :
  245.         if ( s = is_string_split(c.ptr, &len) )
  246.             if ( len == 1 )
  247.             { rs_shadow.type = SEP_CHAR ;
  248.               rs_shadow.c = s[0] ;
  249.             }
  250.             else
  251.             { rs_shadow.type = SEP_STR ;
  252.               rs_shadow.ptr = (PTR) new_STRING(s) ;
  253.             }
  254.         else
  255.         { rs_shadow.type = SEP_RE ;
  256.           rs_shadow.ptr = c.ptr ;
  257.         }
  258.         break ;
  259.  
  260.     case C_SPACE :
  261.         rs_shadow.type = SEP_CHAR ;
  262.         rs_shadow.c = ' ' ;
  263.         break ;
  264.  
  265.     case C_SNULL : /* RS becomes one or more blank lines */
  266.         rs_shadow.type = SEP_RE ;
  267.         sval = new_STRING( "\n([ \t]*\n)+" ) ;
  268.         rs_shadow.ptr = re_compile(sval) ;
  269.         free_STRING(sval) ;
  270.         break ;
  271.  
  272.     default : bozo("bad cell in set_rs_shadow") ;
  273.   }
  274. }
  275.  
  276. void  field_init()
  277. { char **p = biv_field_names ;
  278.   SYMTAB *st_p ;
  279.   int i ;
  280.  
  281.   for(i = NF  ; i < NUM_FIELDS ; p++ , i++ )
  282.   {
  283.     st_p = insert( *p ) ;
  284.     st_p->type = ST_FIELD ;
  285.     st_p->stval.cp = &field[i] ;
  286.   }
  287.  
  288.   field[NF].type = C_DOUBLE ;
  289.   field[NF].dval = 0.0 ;
  290.   field[0].type = C_STRING ;
  291.   field[0].ptr = (PTR) & null_str ;
  292.   null_str.ref_cnt++ ;
  293.  
  294.   field[RS].type = C_STRING ;
  295.   field[RS].ptr =  (PTR) new_STRING( "\n" ) ;
  296.   /* rs_shadow already set */
  297.  
  298.   field[FS].type = C_STRING ;
  299.   field[FS].ptr = (PTR) new_STRING( " " ) ;
  300.   /* fs_shadow is already set */
  301.  
  302.   field[OFMT].type = C_STRING ;
  303.   field[OFMT].ptr = (PTR) new_STRING( "%.6g" ) ;
  304. }
  305.  
  306.  
  307.  
  308. void  set_field0( s, len)
  309.   char *s ;
  310.   unsigned len ;
  311.   cell_destroy( & field[0] ) ;
  312.   nf = -1 ;
  313.  
  314.   if ( len )
  315.   {
  316.     field[0].type = C_MBSTRN ;
  317.     field[0].ptr = (PTR) new_STRING( (char *) 0, len) ;
  318.     (void) memcpy( string(&field[0])->str, s, len ) ;
  319.   }
  320.   else
  321.   {
  322.     field[0].type = C_STRING ;
  323.     field[0].ptr = (PTR) &null_str ;
  324.     null_str.ref_cnt++ ;
  325.   }
  326. }
  327.  
  328.  
  329.  
  330. /* split field[0] into $1, $2 ... and set NF  */
  331.  
  332. void  split_field0()
  333. { register int i ;
  334.   CELL  c ;
  335.   int  cast_flag ; /* we had to cast field[0] */
  336.   char *s ;
  337.   unsigned len ;
  338.  
  339.   if ( fs_shadow.type == C_SNULL ) /* FS == "" */
  340.   { cell_destroy(field+1) ;
  341.     (void) cellcpy(field+1, field+0) ;
  342.     cell_destroy(field+NF) ;
  343.     field[NF].type = C_DOUBLE ; field[NF].dval = 1.0 ;
  344.     return ;
  345.   }
  346.  
  347.   if ( field[0].type < C_STRING )
  348.   { cast1_to_s(cellcpy(&c, field+0)) ;
  349.     s = string(&c)->str ;
  350.     len = string(&c)->len ;
  351.     cast_flag = 1 ;
  352.   }
  353.   else  
  354.   { s = string(field)->str ; 
  355.     len = string(field)->len ;
  356.     cast_flag = 0 ; 
  357.   }
  358.  
  359.   nf = len == 0 ? 0 :
  360.        fs_shadow.type == C_SPACE
  361.        ? space_split(s) : re_split(s, fs_shadow.ptr) ;
  362.  
  363.   cell_destroy(field+NF) ;
  364.   field[NF].type = C_DOUBLE ;
  365.   field[NF].dval = (double) nf ;
  366.  
  367.   for( i = 1 ; i <= nf ; i++ )
  368.   {
  369.     cell_destroy(field+i) ;
  370.     field[i].ptr = temp_buff.ptr_buff[i-1] ;
  371.     field[i].type = C_MBSTRN ;
  372.   }
  373.  
  374.   if ( cast_flag )  free_STRING( string(&c) ) ;
  375. }
  376.  
  377. /*
  378.   assign CELL *cp to field[i]
  379.   and take care of all side effects
  380. */
  381.  
  382. void  field_assign( i, cp)
  383.   register int i ;
  384.   CELL *cp ;
  385. { register int j ;
  386.   CELL c ;
  387.  
  388.   /* update fields not up to date */
  389.   if ( nf < 0 )  split_field0() ;
  390.  
  391.   switch( i )
  392.   {
  393.     case 0 :
  394.         cell_destroy(field) ;
  395.         nf = -1 ;
  396.         (void) cellcpy(field, cp) ;
  397.         break ; ;
  398.  
  399.     case  NF :
  400.         cell_destroy(field+NF) ;
  401.         (void) cellcpy(field+NF, cellcpy(&c,cp) ) ;
  402.         if ( c.type != C_DOUBLE )  cast1_to_d(&c) ;
  403.  
  404.         if ( (j = (int) c.dval) < 0 )
  405.             rt_error("negative value assigned to NF") ;
  406.         if ( j > MAX_FIELD )
  407.             rt_overflow("MAX_FIELD", MAX_FIELD) ;
  408.  
  409.         if ( j > nf )
  410.             for ( i = nf+1 ; i <= j ; i++ )
  411.             { cell_destroy(field+i) ;
  412.               field[i].type = C_STRING ;
  413.               field[i].ptr = (PTR) &null_str ;
  414.               null_str.ref_cnt++ ;
  415.             }
  416.  
  417.         nf = j ;
  418.         build_field0() ;
  419.         break ;
  420.  
  421.     case  RS :
  422.         cell_destroy(field+RS) ;
  423.         (void) cellcpy(field+RS, cp) ;
  424.         set_rs_shadow() ;
  425.         break ;
  426.  
  427.     case  FS :
  428.         cell_destroy(field+FS) ;
  429.         cast_for_split( cellcpy(&fs_shadow, cellcpy(field+FS, cp)) ) ;
  430.         break ;
  431.  
  432.     case OFMT : 
  433.         /* If the user does something stupid with OFMT, we could crash.
  434.            We'll make an attempt to protect ourselves here.  This is
  435.            why OFMT is made a field.
  436.  
  437.            The ptr of OFMT always has a valid STRING, even if assigned
  438.            a DOUBLE or NOINIT
  439.         */
  440.  
  441.         free_STRING( string(field+OFMT) ) ;
  442.         (void) cellcpy(field+OFMT, cp) ;
  443.         if ( field[OFMT].type < C_STRING ) /* !! */
  444.              field[OFMT].ptr = (PTR) new_STRING( "%.6g" ) ;
  445.         else
  446.         {
  447.           /* It's a string, but if it's really goofy it could still
  448.              damage us. Test it . */
  449.           temp_buff.string_buff[256] = 0 ;
  450.           (void) sprintf(temp_buff.string_buff, 
  451.              string(field+OFMT)->str, 3.1459) ;
  452.           if ( temp_buff.string_buff[256] )
  453.                 rt_error("OFMT assigned unusable value") ;
  454.         }
  455.         break ;
  456.            
  457.  
  458.     default:
  459.  
  460. #ifdef DEBUG 
  461.         if ( i < 0 )
  462.             bozo("negative field index in field_assign") ;
  463.         if ( i > MAX_FIELD )
  464.             bozo("large field index in field_assign") ;
  465. #endif
  466.  
  467.         cell_destroy(field+i) ;
  468.         (void) cellcpy(field+i, cp) ;
  469.         if ( i > nf )
  470.         { for ( j = nf+1 ; j < i ; j++ )
  471.           { cell_destroy(field+j) ;
  472.             field[j].type = C_STRING ;
  473.             field[j].ptr = (PTR) &null_str ;
  474.             null_str.ref_cnt++ ;
  475.           }
  476.           nf = i ;
  477.           cell_destroy(field+NF) ;
  478.           field[NF].type = C_DOUBLE ;
  479.           field[NF].dval = (double) i ;
  480.         }
  481.  
  482.         build_field0() ;
  483.  
  484.   }
  485. }
  486.  
  487.  
  488. /* get the string rep of a double without changing its
  489.    type */
  490.  
  491. static void  xcast( cp )
  492.   register CELL *cp ;
  493. {
  494.   switch ( cp->type )
  495.   {
  496.     case C_NOINIT :
  497.         cp->ptr = (PTR) &null_str ;
  498.         null_str.ref_cnt++ ;
  499.         break ;
  500.  
  501.     case C_DOUBLE :
  502.         (void) sprintf(temp_buff.string_buff, 
  503.           string(field+OFMT)->str, cp->dval) ;
  504.         cp->ptr = (PTR) new_STRING(temp_buff.string_buff) ;
  505.         break ;
  506.   }
  507. }
  508.  
  509.  
  510. /* construct field[0] from the other fields */
  511.  
  512. static void  build_field0()
  513.  
  514.  
  515. #ifdef DEBUG
  516.   if ( nf < 0 )  
  517.       bozo("nf <0 in build_field0") ;
  518. #endif
  519.  
  520.   cell_destroy( field+0 ) ;
  521.  
  522.   if ( nf == 0 )
  523.   { field[0].type = C_STRING ;
  524.     field[0].ptr = (PTR) &null_str ;
  525.     null_str.ref_cnt++ ;
  526.   }
  527.   else
  528.   if ( nf == 1 )  (void) cellcpy(field, field+1) ;
  529.  
  530.   else
  531.   { CELL  ofs ;
  532.     char *ofs_str ;
  533.     unsigned ofs_len , len0 = 0 ;
  534.     register int i ;
  535.     register char *p, *q ;
  536.  
  537.  
  538.     (void) cellcpy(& ofs , bi_vars + OFS) ;
  539.     if ( ofs.type < C_STRING )  cast1_to_s(&ofs) ;
  540.     ofs_str = string(&ofs)->str ;
  541.     ofs_len = string(&ofs)->len ;
  542.  
  543.  
  544.     for( i = 1 ; i <= nf ; i++ )
  545.     {
  546.       if ( field[i].type < C_STRING )  xcast(field+i) ;
  547.       len0 += string(field+i)->len + ofs_len ;
  548.     }
  549.     len0 -= ofs_len ;
  550.  
  551.     field[0].type = C_STRING ;
  552.     field[0].ptr = (PTR) new_STRING((char *) 0, len0) ;
  553.  
  554.     p = string(field)->str ;
  555.     for( i = 1 ; i < nf ; i++ )
  556.     {
  557.       (void) memcpy(p, string(field+i)->str, string(field+i)->len) ;
  558.       p += string(field+i)->len ;
  559.  
  560.       /* add the separator */
  561.       q = ofs_str ;
  562.       while ( *p++ = *q++ ) ;  p-- ;
  563.  
  564.       /* if not really string undo the xcast */
  565.       if ( field[i].type < C_STRING )
  566.               free_STRING( string(field+i) ) ;
  567.     }
  568.     /* do the last piece */
  569.     (void) memcpy(p, string(field+i)->str, string(field+i)->len) ;
  570.     if ( field[i].type < C_STRING )
  571.               free_STRING( string(field+i) ) ;
  572.     
  573.     free_STRING( string(&ofs) ) ;
  574.   } 
  575. }
  576. @//E*O*F mawk0.97/field.c//
  577. chmod u=rw,g=r,o=r mawk0.97/field.c
  578.  
  579. echo x - mawk0.97/field.h
  580. sed 's/^@//' > "mawk0.97/field.h" <<'@//E*O*F mawk0.97/field.h//'
  581.  
  582. /********************************************
  583. field.h
  584. copyright 1991, Michael D. Brennan
  585.  
  586. This is a source file for mawk, an implementation of
  587. the Awk programming language as defined in
  588. Aho, Kernighan and Weinberger, The AWK Programming Language,
  589. Addison-Wesley, 1988.
  590.  
  591. See the accompaning file, LIMITATIONS, for restrictions
  592. regarding modification and redistribution of this
  593. program in source or binary form.
  594. ********************************************/
  595.  
  596. /* $Log:    field.h,v $
  597.  * Revision 2.1  91/04/08  08:23:03  brennan
  598.  * VERSION 0.97
  599.  * 
  600. */
  601.  
  602. /* field.h */
  603.  
  604.  
  605. #ifndef  FIELD_H
  606. #define  FIELD_H   1
  607.  
  608. void  PROTO( set_field0, (char *, unsigned) ) ;
  609. void  PROTO( split_field0, (void) ) ;
  610. int   PROTO( is_strnum, (char *, unsigned, double *) ) ;
  611. void  PROTO( field_assign, (int, CELL *) ) ;
  612. char *PROTO( is_string_split, (PTR , unsigned *) ) ;
  613.  
  614. #define   NF            (MAX_FIELD+1)
  615. #define   RS            (MAX_FIELD+2)
  616. #define   FS            (MAX_FIELD+3)
  617. #define   OFMT          (MAX_FIELD+4)
  618. #define   NUM_FIELDS    (MAX_FIELD+5)
  619.  
  620.  
  621. extern  CELL  field[NUM_FIELDS] ;
  622.  
  623. extern  int  nf ; /* shadows NF */
  624.  
  625. /* a shadow type for RS and FS */
  626. #define  SEP_SPACE      0
  627. #define  SEP_CHAR       1
  628. #define  SEP_STR        2
  629. #define  SEP_RE         3
  630.  
  631. typedef  struct {
  632. char  type ;
  633. char  c ;
  634. PTR ptr ; /* STRING* or RE machine* */
  635. } SEPARATOR ;
  636.  
  637. extern   SEPARATOR  rs_shadow  ;
  638. extern   CELL  fs_shadow ;
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645. #endif   /* FIELD_H  */
  646. @//E*O*F mawk0.97/field.h//
  647. chmod u=rw,g=r,o=r mawk0.97/field.h
  648.  
  649. echo x - mawk0.97/files.c
  650. sed 's/^@//' > "mawk0.97/files.c" <<'@//E*O*F mawk0.97/files.c//'
  651.  
  652. /********************************************
  653. files.c
  654. copyright 1991, Michael D. Brennan
  655.  
  656. This is a source file for mawk, an implementation of
  657. the Awk programming language as defined in
  658. Aho, Kernighan and Weinberger, The AWK Programming Language,
  659. Addison-Wesley, 1988.
  660.  
  661. See the accompaning file, LIMITATIONS, for restrictions
  662. regarding modification and redistribution of this
  663. program in source or binary form.
  664. ********************************************/
  665.  
  666. /*$Log:    files.c,v $
  667.  * Revision 2.1  91/04/08  08:23:05  brennan
  668.  * VERSION 0.97
  669.  * 
  670. */
  671.  
  672. /* files.c */
  673.  
  674. #include "mawk.h"
  675. #include "files.h"
  676. #include "memory.h"
  677. #include <stdio.h>
  678. #include "fin.h"
  679.  
  680. #if  ! DOS
  681. #include <fcntl.h>
  682. #endif
  683.  
  684. /* We store dynamically created files on a linked linear
  685.    list with move to the front (big surprise)  */
  686.  
  687. typedef struct file {
  688. struct file *link ;
  689. STRING  *name ;
  690. short type ;
  691. #if   ! DOS
  692. int pid ;  /* we need to wait() when we close an out pipe */
  693. #endif
  694. PTR   ptr ;  /* FIN*   or  FILE*   */
  695. }  FILE_NODE ;
  696.  
  697. static FILE_NODE *file_list ;
  698.  
  699. PTR  file_find( sval, type )
  700.   STRING *sval ;
  701.   int type ;
  702. { register FILE_NODE *p = file_list ;
  703.   FILE_NODE *q = (FILE_NODE *) 0 ;
  704.   char *name = sval->str ;
  705.  
  706.   while (1)
  707.   {
  708.     if ( !p )   /* open a new one */
  709.     {
  710.       p = (FILE_NODE*) zmalloc(sizeof(FILE_NODE)) ;
  711.       switch( p->type = type )
  712.       {
  713.         case  F_TRUNC :
  714.             if ( !(p->ptr = (PTR) fopen(name, "w")) )
  715.                 goto out_failure ;
  716.             break ;
  717.  
  718.         case  F_APPEND :
  719.             if ( !(p->ptr = (PTR) fopen(name, "a")) )
  720.                 goto out_failure ;
  721.             break ;
  722.  
  723.         case  F_IN  :
  724.             if ( !(p->ptr = (PTR) FINopen(name, 0)) )
  725.             { zfree(p, sizeof(FILE_NODE)) ; return (PTR) 0 ; }
  726.             break ;
  727.  
  728.         case  PIPE_OUT :
  729.         case  PIPE_IN :
  730. #if   DOS
  731.             rt_error("pipes not supported under MsDOS") ;
  732. #else
  733.             if ( !(p->ptr = get_pipe(name, type, &p->pid)) )
  734.                 if ( type == PIPE_OUT ) goto out_failure ;
  735.                 else
  736.                 { zfree(p, sizeof(FILE_NODE) ) ;
  737.                   return (PTR) 0 ;
  738.                 }
  739. #endif
  740.             break ;
  741.  
  742. #ifdef  DEBUG
  743.         default :
  744.             bozo("bad file type") ;
  745. #endif
  746.       }
  747.       /* successful open */
  748.       p->name = sval ;
  749.       sval->ref_cnt++ ;
  750.       break ;
  751.     }
  752.  
  753.     if ( strcmp(name, p->name->str) == 0 )
  754.     { 
  755.       if ( p->type != type )  goto type_failure ;
  756.       if ( !q )  /*at front of list */
  757.           return  p->ptr ;
  758.       /* delete from list for move to front */
  759.       q->link = p->link ;
  760.       break ;
  761.     }
  762.     q = p ; p = p->link ;
  763.   }
  764.  
  765.   /* put p at the front of the list */
  766.   p->link = file_list ;
  767.   return  (PTR) (file_list = p)->ptr ;
  768.  
  769. out_failure:
  770.   errmsg(errno, "cannot open \"%s\" for output", name) ;
  771.   mawk_exit(1) ;
  772.  
  773. type_failure :
  774.   rt_error("use of file \"%s\"\n\tis inconsistent with previous use",
  775.            name) ;
  776. }
  777.  
  778.  
  779. /* close a file and delete it's node from the file_list */
  780.  
  781. int  file_close( sval )
  782.   STRING *sval ;
  783. { register FILE_NODE *p = file_list ;
  784.   FILE_NODE *q = (FILE_NODE *) 0 ; /* trails p */
  785.   char *name = sval->str ;
  786.  
  787.   while ( p )
  788.         if ( strcmp(name,p->name->str) == 0 ) /* found */
  789.         { 
  790.           switch( p->type )
  791.           {
  792.             case  F_TRUNC :
  793.             case  F_APPEND :    
  794.                 (void) fclose((FILE *) p->ptr) ;
  795.                 break ;
  796.  
  797.             case  PIPE_OUT :
  798.                 (void) fclose((FILE *) p->ptr) ;
  799. #if  ! DOS
  800.                 (void) wait_for(p->pid) ;
  801. #endif
  802.                 break ;
  803.  
  804.             case F_IN  :
  805.             case PIPE_IN :
  806.                 FINclose((FIN *) p->ptr) ;
  807.                 break ;
  808.           }
  809.  
  810.           free_STRING(p->name) ;
  811.           if ( q )  q->link = p->link ;
  812.           else  file_list = p->link ;
  813.  
  814.           zfree(p, sizeof(FILE_NODE)) ;
  815.           return 0 ;
  816.         }
  817.         else { q = p ; p = p->link ; }
  818.  
  819.   /* its not on the list */
  820.   return -1 ;
  821. }
  822.  
  823. /* When we exit, we need to close and wait for all output pipes */
  824.  
  825. #if   !DOS
  826. void close_out_pipes()
  827. { register FILE_NODE *p = file_list ;
  828.  
  829.   while ( p )
  830.   { if ( p->type == PIPE_OUT )
  831.     { (void) fclose((FILE *) p->ptr) ;  (void) wait_for(p->pid) ; }
  832.     p = p->link ;
  833.   }
  834. }
  835. #endif
  836.  
  837.  
  838. char *shell ;
  839.  
  840. #if  !  DOS
  841. PTR get_pipe( name, type, pid_ptr)
  842.   char *name ;
  843.   int type ;
  844.   int *pid_ptr ;
  845. { int the_pipe[2], local_fd, remote_fd ;
  846.  
  847.   if ( ! shell ) shell = (shell = getenv("SHELL")) ? shell :"/bin/sh" ;
  848.   
  849.   if ( pipe(the_pipe) == -1 )  return (PTR) 0 ;
  850.   local_fd = the_pipe[type == PIPE_OUT] ;
  851.   remote_fd = the_pipe[type == PIPE_IN ] ;
  852.  
  853.   switch( *pid_ptr = fork() )
  854.   { case -1 :  
  855.       (void) close(local_fd) ;
  856.       (void) close(remote_fd) ;
  857.       return (PTR) 0 ;
  858.  
  859.     case  0 :
  860.         (void) close(local_fd) ;
  861.         (void) close(type == PIPE_IN) ;
  862.         (void) dup( remote_fd ) ;
  863.         (void) close( remote_fd ) ;
  864.         (void) execl(shell, shell, "-c", name, (char *) 0 ) ;
  865.         errmsg(errno, "failed to exec %s -c %s" , shell, name) ;
  866.     fflush(stderr) ;
  867.         _exit(128) ;
  868.  
  869.     default :
  870.         (void) close(remote_fd) ;
  871.         /* we could deadlock if future child inherit the local fd ,
  872.            set close on exec flag */
  873.         (void) fcntl(local_fd, F_SETFD, 1) ;
  874.         break ;
  875.   }
  876.  
  877.   return  type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) : 
  878.                             (PTR)  fdopen(local_fd, "w")  ;
  879. }
  880.   
  881.  
  882.  
  883. /*------------ children ------------------*/
  884.  
  885. /* we need to wait for children at the end of output pipes to
  886.    complete so we know any files they have created are complete */
  887.  
  888. /* dead children are kept on this list */
  889.  
  890. static struct child {
  891. int pid ;
  892. int exit_status ;
  893. struct child *link ;
  894. }  *child_list ;
  895.  
  896. static  void  add_to_child_list(pid, exit_status)
  897.   int pid, exit_status ;
  898. { register struct child *p = 
  899.           (struct child *) zmalloc(sizeof(struct child)) ;
  900.  
  901.   p->pid = pid ; p->exit_status = exit_status ;
  902.   p->link = child_list ; child_list = p ;
  903. }
  904.  
  905. static struct child *remove_from_child_list(pid)
  906.   int pid ;
  907. { register struct child *p = child_list ;
  908.   struct child *q = (struct child *) 0 ;
  909.  
  910.   while ( p )
  911.     if ( p->pid == pid )
  912.     {
  913.         if ( q ) q->link = p->link ;
  914.         else child_list = p->link ;
  915.         break ;
  916.     }
  917.     else { q = p ; p = p->link ; }
  918.  
  919.   return p ;  /* null return if not in the list */
  920. }
  921.     
  922.  
  923. /* wait for a specific child to complete and return its 
  924.    exit status */
  925.  
  926. int wait_for(pid)
  927.   int pid ;
  928. { int exit_status ;
  929.   struct child *p ;
  930.   int id ;
  931.  
  932.   /* see if an earlier wait() caught our child */
  933.   if ( p = remove_from_child_list(pid) ) 
  934.   { exit_status = p->exit_status ;
  935.     zfree(p, sizeof(struct child)) ;
  936.   }
  937.   else /* need to really wait */
  938.     while ( (id = wait(&exit_status)) != pid )
  939.         if ( id == -1 ) /* can't happen */  bozo("wait_for") ;
  940.         else
  941.         { /* we got the exit status of another child
  942.              put it on the child list and try again */
  943.           add_to_child_list(id, exit_status ) ;
  944.         }
  945.  
  946.   return exit_status ;
  947. }
  948.         
  949. #endif
  950. @//E*O*F mawk0.97/files.c//
  951. chmod u=rw,g=r,o=r mawk0.97/files.c
  952.  
  953. echo x - mawk0.97/files.h
  954. sed 's/^@//' > "mawk0.97/files.h" <<'@//E*O*F mawk0.97/files.h//'
  955.  
  956. /********************************************
  957. files.h
  958. copyright 1991, Michael D. Brennan
  959.  
  960. This is a source file for mawk, an implementation of
  961. the Awk programming language as defined in
  962. Aho, Kernighan and Weinberger, The AWK Programming Language,
  963. Addison-Wesley, 1988.
  964.  
  965. See the accompaning file, LIMITATIONS, for restrictions
  966. regarding modification and redistribution of this
  967. program in source or binary form.
  968. ********************************************/
  969.  
  970. /*$Log:    files.h,v $
  971.  * Revision 2.1  91/04/08  08:23:07  brennan
  972.  * VERSION 0.97
  973.  * 
  974. */
  975.  
  976. #ifndef   FILES_H
  977. #define   FILES_H
  978.  
  979. /* IO redirection types */
  980. #define  F_IN           (-5)
  981. #define  PIPE_IN        (-4)
  982. #define  PIPE_OUT       (-3)
  983. #define  F_APPEND       (-2)
  984. #define  F_TRUNC        (-1)
  985.  
  986. extern char *shell ; /* for pipes and system() */
  987.  
  988. PTR  PROTO(file_find, (STRING *, int)) ;
  989. int  PROTO(file_close, (STRING *)) ;
  990. PTR  PROTO(get_pipe, (char *, int) ) ;
  991. int  PROTO(wait_for, (int) ) ;
  992. void  PROTO( close_out_pipes, (void) ) ;
  993.  
  994.  
  995. #endif
  996. @//E*O*F mawk0.97/files.h//
  997. chmod u=rw,g=r,o=r mawk0.97/files.h
  998.  
  999. echo x - mawk0.97/fin.c
  1000. sed 's/^@//' > "mawk0.97/fin.c" <<'@//E*O*F mawk0.97/fin.c//'
  1001.  
  1002. /********************************************
  1003. fin.c
  1004. copyright 1991, Michael D. Brennan
  1005.  
  1006. This is a source file for mawk, an implementation of
  1007. the Awk programming language as defined in
  1008. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1009. Addison-Wesley, 1988.
  1010.  
  1011. See the accompaning file, LIMITATIONS, for restrictions
  1012. regarding modification and redistribution of this
  1013. program in source or binary form.
  1014. ********************************************/
  1015.  
  1016. /*$Log:    fin.c,v $
  1017.  * Revision 2.1  91/04/08  08:23:09  brennan
  1018.  * VERSION 0.97
  1019.  * 
  1020. */
  1021.  
  1022. /* fin.c */
  1023.  
  1024. #include "mawk.h"
  1025. #include "fin.h"
  1026. #include "memory.h"
  1027. #include "bi_vars.h"
  1028. #include "field.h"
  1029. #include "symtype.h"
  1030. #include "scan.h"
  1031. #include <fcntl.h>
  1032.  
  1033. extern int errno ;
  1034. int PROTO(isatty, (int) ) ;
  1035. FILE *PROTO(fdopen, (int, char*) ) ;
  1036.  
  1037. /* statics */
  1038. int  PROTO( next_main, (void) ) ;
  1039. int  PROTO( is_cmdline_assign, (char *) ) ;
  1040.  
  1041. FIN  *FINdopen( fd, main_flag )
  1042.   int fd , main_flag ;
  1043. { register FIN *fin = (FIN *) zmalloc( sizeof(FIN) ) ;
  1044.  
  1045.   fin->fd = fd ;
  1046.  
  1047.   if ( main_flag )
  1048.   { fin->flags = MAIN_FLAG ;
  1049.     fin->buffp = fin->buff = main_buff ;
  1050.   }
  1051.   else
  1052.   { 
  1053.     fin->flags = 0 ;
  1054.     fin->buffp = fin->buff = (char *) zmalloc(BUFFSZ+1) ;
  1055.   }
  1056.   *fin->buffp = 0 ;
  1057.  
  1058.   if ( isatty(fd) && rs_shadow.type == SEP_CHAR 
  1059.        && rs_shadow.c == '\n' )
  1060.   {
  1061.     /* interactive, i.e., line buffer this file */
  1062.     if ( fd == 0 ) fin->fp = stdin ;
  1063.     else
  1064.     if ( !(fin->fp = fdopen(fd, "r")) )
  1065.     { errmsg(errno, "fdopen failed") ; exit(1) ; }
  1066.   }
  1067.   else  fin->fp = (FILE *) 0 ;
  1068.  
  1069.   return fin ;
  1070. }
  1071.  
  1072. FIN  *FINopen( filename, main_flag )
  1073.   char *filename ;
  1074.   int main_flag ;
  1075. { int fd ;
  1076.  
  1077.   if ( (fd = open( filename , O_RDONLY, 0 )) == -1 )
  1078.   { errmsg( errno, "cannot open %s" , filename ) ;
  1079.     return (FIN *) 0 ; }
  1080.  
  1081.   else  return  FINdopen( fd, main_flag ) ;
  1082. }
  1083.  
  1084. void  FINclose( fin )
  1085.   register FIN *fin ;
  1086. {
  1087.   if ( ! (fin->flags & MAIN_FLAG) )  
  1088.         zfree(fin->buff, BUFFSZ+1) ;
  1089.  
  1090.   if ( fin->fd )  
  1091.         if ( fin->fp )  (void) fclose(fin->fp) ;
  1092.         else  (void) close(fin->fd) ;
  1093.  
  1094.   zfree( fin , sizeof(FIN) ) ;
  1095. }
  1096.  
  1097. /* return one input record as determined by RS,
  1098.    from input file (FIN)  fin
  1099. */
  1100.  
  1101. char *FINgets( fin, len_p )
  1102.   FIN *fin ;
  1103.   unsigned *len_p ;
  1104. { register char *p, *q ;
  1105.   unsigned match_len ;
  1106.   unsigned r ;
  1107.  
  1108. restart :
  1109.  
  1110.   if ( ! (p = fin->buffp)[0] )  /* need a refill */
  1111.   { 
  1112.     if ( fin->flags & EOF_FLAG )
  1113.         if ( (fin->flags & MAIN_FLAG) && next_main() )  goto restart ;
  1114.         else
  1115.         { *len_p = 0 ; return (char *) 0 ; }
  1116.         
  1117.     if ( fin->fp ) /* line buffering */
  1118.       if ( ! fgets(fin->buff, BUFFSZ+1, fin->fp) )
  1119.       {
  1120.         fin->flags |= EOF_FLAG ;
  1121.         fin->buff[0] = 0 ;
  1122.         fin->buffp = fin->buff ;
  1123.         goto restart ;  /* might be main_fin */
  1124.       }
  1125.       else  /* return this line */
  1126.       {
  1127.         if ( !(p = strchr(fin->buff, '\n')) )
  1128.              p = fin->buff + BUFFSZ + 1 ; /* unlikely to occur */
  1129.  
  1130.         *p = 0 ; *len_p = p - fin->buff ;
  1131.         fin->buffp = p ;
  1132.         return  fin->buff ;
  1133.       }
  1134.     else  /* block buffering */
  1135.     {
  1136.       if ( (r = fillbuff(fin->fd, fin->buff, BUFFSZ)) == 0 )
  1137.       {
  1138.         fin->flags |= EOF_FLAG ;
  1139.         fin->buffp = fin->buff ;
  1140.         goto restart ; /* might be main */
  1141.       }
  1142.       else
  1143.       if ( r < BUFFSZ )  fin->flags |= EOF_FLAG ;
  1144.  
  1145.       p = fin->buffp = fin->buff ;
  1146.     }
  1147.   }
  1148.  
  1149. retry: 
  1150.  
  1151.   switch( rs_shadow.type )
  1152.   {
  1153.     case SEP_CHAR :
  1154.             q = strchr(p, rs_shadow.c) ;
  1155.             match_len = 1 ;
  1156.             break ;
  1157.  
  1158.     case SEP_STR  :
  1159.             q = str_str(p, ((STRING *) rs_shadow.ptr)->str,
  1160.                 match_len = ((STRING *) rs_shadow.ptr)->len ) ;
  1161.             break ;
  1162.  
  1163.     case SEP_RE :
  1164.             q = re_pos_match(p, rs_shadow.ptr, &match_len) ;
  1165.             /* if the match is at the end, there might be more
  1166.                still to be read */
  1167.             if ( q && q[match_len] == 0 &&
  1168.                  p != fin->buff )  q = (char *) 0 ;
  1169.             break ;
  1170.             
  1171.     default :
  1172.             bozo("type of rs_shadow") ;
  1173.   }
  1174.   if ( q )
  1175.   {  /* the easy and normal case */
  1176.      *q = 0 ;  *len_p = q - p ;
  1177.      fin->buffp = q + match_len  ;
  1178.      return p ;
  1179.   }
  1180.  
  1181.   if ( p == fin->buff )  /* last line or one huge (truncated) line */
  1182.   { *len_p = r = strlen(p) ;  fin->buffp = p + r ;
  1183.     /* treat truncated case as overflow */
  1184.     if ( r == BUFFSZ ) 
  1185.     { /* overflow, update NR and FNR */
  1186.       cast2_to_d(bi_vars+NR) ;
  1187.       bi_vars[NR].dval += 1.0 ;
  1188.       bi_vars[FNR].dval += 1.0 ;
  1189.       rt_overflow("maximum record length" , BUFFSZ) ;
  1190.     }
  1191.      return p ;
  1192.   }
  1193.  
  1194.   /* move a partial line to front of buffer and try again */
  1195.   p = (char *) memcpy( fin->buff, p, r = strlen(p) ) ;
  1196.   q = p+r ; 
  1197.   if ( fin->flags & EOF_FLAG ) *q = 0 ;
  1198.   else 
  1199.   { unsigned rr = BUFFSZ - r ;
  1200.  
  1201.     if ( (r = fillbuff(fin->fd, q, rr)) < rr ) fin->flags |= EOF_FLAG ;
  1202.   }
  1203.   goto retry ;
  1204. }
  1205.  
  1206. /*--------
  1207.   target is big enough to hold size + 1 chars 
  1208.   on exit the back of the target is zero terminated
  1209.  *--------------*/
  1210. unsigned  fillbuff(fd, target, size)
  1211.   int fd ;
  1212.   register char *target ;
  1213.   unsigned size ;
  1214. { register int r ;
  1215.   unsigned entry_size = size ;
  1216.  
  1217.   while ( size )
  1218.     switch( r = read(fd, target, size) )
  1219.     { case -1 :
  1220.         errmsg(errno, "read error on file") ;
  1221.         exit(1) ;
  1222.  
  1223.       case 0 :
  1224.         goto out ;
  1225.  
  1226.       default :
  1227.         target += r ; size -= r ;
  1228.         break ;
  1229.     }
  1230.  
  1231. out :
  1232.   *target = 0 ;
  1233.   return  entry_size - size ;
  1234. }
  1235.  
  1236. /* main_fin is a handle to the main input stream
  1237.    == -1 if never tried to open 
  1238.    == 0  if end of stream
  1239.       otherwise active    */
  1240. FIN *main_fin = (FIN *) -1 ;
  1241. ARRAY   Argv ;   /* to the user this is ARGV  */
  1242. static int argi = 1 ;  /* index of next ARGV[argi] to try to open */
  1243.  
  1244. int  open_main()  /* boolean return, true if main is open */
  1245.   if ( bi_vars[ARGC].type == C_DOUBLE && bi_vars[ARGC].dval == 1.0 )
  1246.   { cell_destroy( bi_vars + FILENAME ) ;
  1247.     bi_vars[FILENAME].type = C_STRING ;
  1248.     bi_vars[FILENAME].ptr = (PTR) new_STRING( "-") ;
  1249.     main_fin = FINdopen(0, 1) ;
  1250.     return  1 ;
  1251.   }
  1252.   else    return next_main() ;
  1253. }
  1254.  
  1255. static  int  next_main()
  1256. { char xbuff[16] ;
  1257.   register CELL *cp ;
  1258.   STRING *sval ;
  1259.   CELL   argc ;  /* temp copy of ARGC */
  1260.   CELL   tc ;    /* copy of ARGV[argi] */
  1261.   double d_argi ;
  1262.  
  1263. #ifdef  DEBUG
  1264.   if ( ! main_fin ) bozo("call to next_main with dead main") ;
  1265. #endif
  1266.  
  1267.   tc.type = C_NOINIT ;
  1268.  
  1269.   if ( main_fin != (FIN *)-1 )  FINclose(main_fin) ;
  1270.   cell_destroy( bi_vars + FILENAME ) ;
  1271.   cell_destroy( bi_vars + FNR ) ;
  1272.   bi_vars[FNR].type = C_DOUBLE ;
  1273.   bi_vars[FNR].dval = 0.0 ;
  1274.  
  1275.   if ( cellcpy(&argc, &bi_vars[ARGC])->type != C_DOUBLE )
  1276.           cast1_to_d(&argc) ;
  1277.   xbuff[1] = 0 ;
  1278.   d_argi = (double) argi ;
  1279.  
  1280.   while ( d_argi < argc.dval )
  1281.   {
  1282.     if ( argi < 10 )  xbuff[0] = argi + '0' ;
  1283.     else  (void) sprintf(xbuff, "%u", argi) ;
  1284.  
  1285.     argi++ ; d_argi += 1.0 ;
  1286.     sval = new_STRING(xbuff) ;
  1287.  
  1288.     /* the user might have changed ARGC or deleted 
  1289.        ARGV[argi] -- test for existence without side effects */
  1290.     
  1291.     if ( ! array_test(Argv, sval) )
  1292.     { free_STRING(sval) ; continue ; }
  1293.  
  1294.     cp = array_find( Argv, sval, 0) ;
  1295.     free_STRING(sval) ;
  1296.  
  1297.     /* make a copy so we can cast w/o side effect */
  1298.     cell_destroy(&tc) ;
  1299.     cp = cellcpy(&tc, cp) ;
  1300.     if ( cp->type < C_STRING )  cast1_to_s(cp) ;
  1301.     if ( string(cp)->len == 0 )  continue ;
  1302.  
  1303.     if ( string(cp)->len == 1 && string(cp)->str[0] == '-' )
  1304.     { /* input from stdin */
  1305.       main_fin = FINdopen(0,1) ;
  1306.     }
  1307.     else  /* it might be a command line assignment */
  1308.     if ( is_cmdline_assign(string(cp)->str) )  continue ;
  1309.  
  1310.     else /* try to open it */
  1311.     if ( ! (main_fin = FINopen( string(cp)->str, 1 )) ) continue ;
  1312.  
  1313.     /* success */
  1314.     (void) cellcpy( &bi_vars[FILENAME] , cp ) ;
  1315.     free_STRING( string(cp) ) ;
  1316.     return 1 ;
  1317.   }
  1318.   /* failure */
  1319.   bi_vars[FILENAME].type = C_STRING ;
  1320.   bi_vars[FILENAME].ptr = (PTR) new_STRING( "" ) ;
  1321.   main_fin = (FIN *) 0 ;
  1322.   cell_destroy(&tc) ;
  1323.   return 0 ;
  1324. }
  1325.     
  1326.  
  1327. static int is_cmdline_assign(s)
  1328.   char *s ;
  1329. { char *q;
  1330.   unsigned char *p ;
  1331.   int c ;
  1332.   SYMTAB *stp ;
  1333.   CELL *cp ;
  1334.  
  1335.   if ( scan_code[*(unsigned char *)s] != SC_IDCHAR 
  1336.        || !(q = strchr(s,'=')) ) return 0 ;
  1337.  
  1338.   p = (unsigned char *)s+1 ;
  1339.   while ( (c = scan_code[*p]) == SC_IDCHAR || c == SC_DIGIT ) p++ ;
  1340.  
  1341.   if ( (char *)p < q )  return 0 ;
  1342.  
  1343.   *q = 0 ;
  1344.   stp = find(s) ;
  1345.  
  1346.   switch( stp->type )
  1347.   {
  1348.     case  ST_NONE :
  1349.         stp->type = ST_VAR ;
  1350.         stp->stval.cp = cp = new_CELL() ;
  1351.         break ;
  1352.  
  1353.     case  ST_VAR :
  1354.         cp = stp->stval.cp ;
  1355.         break ;
  1356.  
  1357.     default :
  1358.         rt_error(
  1359.           "cannot command line assign to %s\n\t- type clash or keyword" 
  1360.           , s ) ;
  1361.   }
  1362.   
  1363.   *q++ = '=' ;
  1364.   cp->ptr = (PTR) new_STRING(q) ;
  1365.   check_strnum(cp) ;
  1366.   return 1 ;
  1367. }
  1368. @//E*O*F mawk0.97/fin.c//
  1369. chmod u=rw,g=r,o=r mawk0.97/fin.c
  1370.  
  1371. echo x - mawk0.97/fin.h
  1372. sed 's/^@//' > "mawk0.97/fin.h" <<'@//E*O*F mawk0.97/fin.h//'
  1373.  
  1374. /********************************************
  1375. fin.h
  1376. copyright 1991, Michael D. Brennan
  1377.  
  1378. This is a source file for mawk, an implementation of
  1379. the Awk programming language as defined in
  1380. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1381. Addison-Wesley, 1988.
  1382.  
  1383. See the accompaning file, LIMITATIONS, for restrictions
  1384. regarding modification and redistribution of this
  1385. program in source or binary form.
  1386. ********************************************/
  1387.  
  1388. /*$Log:    fin.h,v $
  1389.  * Revision 2.1  91/04/08  08:23:11  brennan
  1390.  * VERSION 0.97
  1391.  * 
  1392. */
  1393.  
  1394. /* fin.h */
  1395.  
  1396. #ifndef  FIN_H
  1397. #define  FIN_H
  1398. /* structure to control input files */
  1399.  
  1400. typedef struct {
  1401. int  fd ;
  1402. FILE *fp ;   /* NULL unless interactive */
  1403. char *buff ;
  1404. char *buffp ;
  1405. short flags ;
  1406. }  FIN ;
  1407.  
  1408. #define  MAIN_FLAG    1   /* part of main input stream if on */
  1409. #define  EOF_FLAG     2
  1410.  
  1411. FIN *  PROTO (FINdopen, (int, int) );
  1412. FIN *  PROTO (FINopen, (char *, int) );
  1413. void   PROTO (FINclose, (FIN *) ) ;
  1414. char*  PROTO (FINgets, (FIN *, unsigned *) ) ;
  1415. unsigned PROTO ( fillbuff, (int, char *, unsigned) ) ;
  1416.  
  1417.  
  1418. extern  FIN  *main_fin ;  /* for the main input stream */
  1419. int   PROTO( open_main, (void) ) ;
  1420. #endif  /* FIN_H */
  1421. @//E*O*F mawk0.97/fin.h//
  1422. chmod u=rw,g=r,o=r mawk0.97/fin.h
  1423.  
  1424. echo x - mawk0.97/hash.c
  1425. sed 's/^@//' > "mawk0.97/hash.c" <<'@//E*O*F mawk0.97/hash.c//'
  1426.  
  1427. /********************************************
  1428. hash.c
  1429. copyright 1991, Michael D. Brennan
  1430.  
  1431. This is a source file for mawk, an implementation of
  1432. the Awk programming language as defined in
  1433. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1434. Addison-Wesley, 1988.
  1435.  
  1436. See the accompaning file, LIMITATIONS, for restrictions
  1437. regarding modification and redistribution of this
  1438. program in source or binary form.
  1439. ********************************************/
  1440.  
  1441.  
  1442. /* $Log:    hash.c,v $
  1443.  * Revision 2.1  91/04/08  08:23:13  brennan
  1444.  * VERSION 0.97
  1445.  * 
  1446. */
  1447.  
  1448.  
  1449. /* hash.c */
  1450.  
  1451. #include "mawk.h"
  1452. #include "memory.h"
  1453. #include "symtype.h"
  1454. #include <string.h>
  1455.  
  1456.  
  1457. unsigned hash(s)
  1458.   register char *s ;
  1459. { register unsigned h = 0 ;
  1460.  
  1461.   while ( *s )  h += h + *s++ ;
  1462.   return  h  ;
  1463. }
  1464.  
  1465. typedef struct hash {
  1466. struct hash *link ;
  1467. SYMTAB  symtab ;
  1468. }  HASHNODE ;
  1469.  
  1470. static  HASHNODE *PROTO( delete, (char *) ) ;
  1471.  
  1472. #define  new_HASHNODE() (HASHNODE *) zmalloc(sizeof(HASHNODE))
  1473.  
  1474. static HASHNODE *hash_table[HASH_PRIME] ;
  1475.  
  1476. /*
  1477.  *   insert -- s is not there and need not be duplicated
  1478.  *   -- used during initialization
  1479.  */
  1480.  
  1481. SYMTAB *insert(s) 
  1482.   char *s ;
  1483. { register HASHNODE *p = new_HASHNODE();
  1484.   register unsigned h ;
  1485.   
  1486.   p->link = hash_table[h = hash(s) % HASH_PRIME ] ;
  1487.   p->symtab.name = s ;
  1488.   hash_table[h] = p ;
  1489.   return &p->symtab ;
  1490. }
  1491.  
  1492. /*
  1493.  *  find --  s might be there, find it else insert and dup
  1494.  *  s 
  1495.  */
  1496.  
  1497. SYMTAB *find(s)
  1498.   char *s ;
  1499. { register HASHNODE *p ;
  1500.   HASHNODE *q ;
  1501.   unsigned h ;
  1502.  
  1503.   p = hash_table[h = hash(s) % HASH_PRIME ] ;
  1504.   q = (HASHNODE *) 0 ;
  1505.   while ( 1 )
  1506.   { if ( !p )
  1507.     { p = new_HASHNODE() ;
  1508.       p->symtab.type = ST_NONE ;
  1509.       p->symtab.name = strcpy(zmalloc( strlen(s)+1 ), s) ;
  1510.       break ;
  1511.     }
  1512.  
  1513.     if ( strcmp(p->symtab.name, s) == 0 ) /* found */
  1514.       if ( !q )  /* already at the front */
  1515.         return  &p->symtab ;
  1516.       else /* delete from the list */
  1517.       { q->link = p->link ;  break ; }
  1518.  
  1519.     q = p ; p = p->link ;
  1520.   }
  1521.   /* put p on front of the list */
  1522.   p->link = hash_table[h] ;
  1523.   hash_table[h] = p ;
  1524.   return & p->symtab ;
  1525. }
  1526.  
  1527.  
  1528. /* remove a node from the hash table
  1529.    return a ptr to the node */
  1530.  
  1531. static unsigned last_hash ;
  1532.  
  1533. static  HASHNODE  *delete( s )
  1534.   char *s ;
  1535. { register HASHNODE *p ;
  1536.   HASHNODE *q = (HASHNODE *) 0 ;
  1537.   unsigned h ;
  1538.  
  1539.   p = hash_table[ last_hash = h = hash(s) % HASH_PRIME ] ;
  1540.   while ( p )
  1541.       if ( strcmp(p->symtab.name, s) == 0 )  /* found */
  1542.       {
  1543.         if ( q )  q->link = p->link ;
  1544.         else  hash_table[h] = p->link ;
  1545.         return p ;
  1546.       }
  1547.       else { q = p ; p = p->link ; }
  1548.  
  1549. #ifdef  DEBUG   /* we should not ever get here */
  1550.   bozo("delete") ;
  1551. #endif
  1552.   return (HASHNODE *) 0 ;
  1553. }
  1554.  
  1555. /* when processing user functions,  global ids which are
  1556.    replaced by local ids are saved on this list */
  1557.  
  1558. static HASHNODE  *save_list ;
  1559.  
  1560. /* store a global id on the save list,
  1561.    return a ptr to the local symtab  */
  1562. SYMTAB *save_id( s )
  1563.   char *s ;
  1564. { HASHNODE *p, *q ;
  1565.   unsigned h ;
  1566.  
  1567.   p = delete(s) ;
  1568.   q = new_HASHNODE() ;
  1569.   q->symtab.type = ST_LOCAL_NONE ;
  1570.   q->symtab.name = p->symtab.name ;
  1571.   /* put q in the hash table */
  1572.   q->link = hash_table[ h = last_hash ] ;
  1573.   hash_table[h] = q ;
  1574.  
  1575.   /* save p */
  1576.   p->link = save_list ; save_list = p ;
  1577.  
  1578.   return & q->symtab ;
  1579. }
  1580.  
  1581. /* restore all global indentifiers */
  1582. void  restore_ids()
  1583. { register HASHNODE *p, *q ;
  1584.   register unsigned h ;
  1585.  
  1586.   q = save_list ; save_list = (HASHNODE *) 0 ;
  1587.   while ( q )
  1588.   {
  1589.     p = q ; q = q->link ;
  1590.     zfree( delete(p->symtab.name) , sizeof(HASHNODE) ) ;
  1591.     p->link = hash_table[h = last_hash ] ; 
  1592.     hash_table[h] = p ;
  1593.   }
  1594. }
  1595. @//E*O*F mawk0.97/hash.c//
  1596. chmod u=rw,g=r,o=r mawk0.97/hash.c
  1597.  
  1598. echo x - mawk0.97/init.c
  1599. sed 's/^@//' > "mawk0.97/init.c" <<'@//E*O*F mawk0.97/init.c//'
  1600.  
  1601. /********************************************
  1602. init.c
  1603. copyright 1991, Michael D. Brennan
  1604.  
  1605. This is a source file for mawk, an implementation of
  1606. the Awk programming language as defined in
  1607. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1608. Addison-Wesley, 1988.
  1609.  
  1610. See the accompaning file, LIMITATIONS, for restrictions
  1611. regarding modification and redistribution of this
  1612. program in source or binary form.
  1613. ********************************************/
  1614.  
  1615.  
  1616. /* $Log:    init.c,v $
  1617.  * Revision 2.2  91/04/09  12:39:08  brennan
  1618.  * added static to funct decls to satisfy STARDENT compiler
  1619.  * 
  1620.  * Revision 2.1  91/04/08  08:23:15  brennan
  1621.  * VERSION 0.97
  1622.  * 
  1623. */
  1624.  
  1625.  
  1626. /* init.c */
  1627. #include "mawk.h"
  1628. #include "code.h"
  1629. #include "init.h"
  1630. #include "memory.h"
  1631. #include "symtype.h"
  1632. #include "bi_vars.h"
  1633. #include "field.h"
  1634.  
  1635. #define PROGRAM_FROM_CMDLINE   1
  1636.  
  1637. /* static protos */
  1638. static void PROTO( no_program, (void) ) ;
  1639. static void PROTO( process_cmdline , (int, char **) ) ;
  1640. static void PROTO( set_FS, (char *) ) ;
  1641. static void PROTO( set_dump, (char *) ) ;
  1642.  
  1643. #if  DOS  &&  ! HAVE_REARGV
  1644. #include <fcntl.h>
  1645. static  void  PROTO(emit_prompt, (void) ) ;
  1646. #endif
  1647.  
  1648. union tbuff  temp_buff ;
  1649. char *main_buff = temp_buff.string_buff + TEMP_BUFF_SZ ;
  1650.  
  1651. void initialize(argc, argv)
  1652.   int argc ; char **argv ;
  1653. {
  1654.   bi_vars_init() ; /* load the builtin variables */
  1655.   bi_funct_init() ; /* load the builtin functions */
  1656.   kw_init() ; /* load the keywords */
  1657.   field_init() ; 
  1658.   process_cmdline(argc, argv)  ;   
  1659.  
  1660.   jmp_stacks_init() ;
  1661.   code_init() ;
  1662.   fpe_init() ;
  1663.  
  1664. #if  NO_STRTOD
  1665.   strtod_init() ;
  1666. #endif
  1667.  
  1668. }
  1669.  
  1670. void  compile_cleanup()
  1671. /* program has parsed OK, free some memory
  1672.    we don't need anymore */
  1673. {
  1674.    scan_cleanup() ;
  1675.    jmp_stacks_cleanup() ;
  1676.    code_cleanup() ;
  1677. }
  1678.  
  1679.  
  1680. static void no_program()
  1681. { errmsg( 0, "no program") ; mawk_exit(1) ; }
  1682.  
  1683. int  dump_code ;  /* if on dump internal code */
  1684. #ifdef   DEBUG
  1685. int  dump_RE   ;  /* if on dump compiled REs  */
  1686. #endif
  1687.  
  1688. static void set_FS(s)
  1689.   char *s ;
  1690. {
  1691.   cell_destroy(field+FS) ;
  1692.   field[FS].type = C_STRING ;
  1693.   field[FS].ptr = (PTR) new_STRING(s) ;
  1694.   cast_for_split( cellcpy(&fs_shadow, field+FS) ) ;
  1695. }
  1696.  
  1697.  
  1698. #ifdef  DEBUG
  1699. static void set_dump(s)
  1700.   char *s ;
  1701. {
  1702.   while ( 1 )
  1703.   { switch ( *s )
  1704.     { case 'p' :
  1705.       case 'P' :  yydebug = 1 ; break ;
  1706.  
  1707.       case  'c' :
  1708.       case  'C' :  dump_code = 1 ; break ;
  1709.  
  1710.       case  'r' :
  1711.       case  'R' :  dump_RE = 1 ; break ;
  1712.  
  1713.       case   0  :  
  1714.              if ( s[-1] == 'D' ) dump_code = 1 ;
  1715.              return ;
  1716.  
  1717.       default :  break ;
  1718.     }
  1719.     s++ ;
  1720.   }
  1721. }
  1722. #else
  1723. static void  set_dump(s)
  1724.   char *s ;
  1725. { dump_code = 1 ; }
  1726. #endif
  1727.  
  1728. static void process_cmdline(argc, argv)
  1729.   int argc ; char **argv ;
  1730. { extern int program_fd ; 
  1731.   int i ;  /* index to walk command line */
  1732.   char *p ;
  1733.   CELL *cp ;
  1734.   SYMTAB *st_p ;
  1735.   char xbuff[20] ;
  1736.  
  1737.  
  1738.   for( i = 1 ; i < argc && argv[i][0] == '-' ; i++ )
  1739.   { p = & argv[i][1] ;
  1740.     if ( *p == 'F' )  set_FS(p+1) ;
  1741.  
  1742.     else if ( *p == 'D' )  set_dump(p+1) ;
  1743.     else if ( *p == 'f' )
  1744.     { if ( i == argc - 1 )  no_program() ;
  1745.       scan_init(! PROGRAM_FROM_CMDLINE, argv[i+1] ) ;
  1746.       i += 2 ;
  1747.       goto  set_ARGV ;
  1748.     }
  1749.   }
  1750.  
  1751. #if  DOS   &&  ! HAVE_REARGV
  1752. /* allows short programs to be typed in without mucking stdin */
  1753.   emit_prompt() ;
  1754.   scan_init(! PROGRAM_FROM_CMDLINE, "CON") ;
  1755. #else   /* the real world */
  1756.  
  1757.   if ( i == argc )  no_program() ;
  1758.   scan_init(PROGRAM_FROM_CMDLINE, argv[i]) ;
  1759.   i++ ;
  1760. #endif
  1761.  
  1762. set_ARGV:
  1763.  
  1764.   /* now set up ARGC and ARGV  */
  1765.   st_p = insert( "ARGV" ) ;
  1766.   st_p->type = ST_ARRAY ;
  1767.   Argv = st_p->stval.array = new_ARRAY() ;
  1768.   xbuff[0] = '0' ; xbuff[1] = 0 ;
  1769.   cp = array_find( st_p->stval.array, xbuff, 1) ;
  1770.   cp->type = C_STRING ;
  1771.   cp->ptr = (PTR) new_STRING( progname ) ;
  1772.  
  1773.   /* ARGV[0] is set, do the rest 
  1774.      The type of ARGV[1] ... should be C_MBSTRN
  1775.      because the user might enter numbers from the command line */
  1776.   { int arg_count = 1 ;
  1777.  
  1778.     for( ; i < argc ; i++, arg_count++ )
  1779.     { 
  1780.       if ( arg_count < 10 )  xbuff[0] = arg_count + '0' ;
  1781.       else (void) sprintf(xbuff, "%u" , arg_count ) ;
  1782.       cp = array_find( st_p->stval.array, xbuff, 1) ;
  1783.       cp->type = C_MBSTRN ;
  1784.       cp->ptr = (PTR) new_STRING( argv[i] ) ;
  1785.     }
  1786.     bi_vars[ARGC].type = C_DOUBLE ;
  1787.     bi_vars[ARGC].dval = (double) arg_count ;
  1788.   }
  1789. }
  1790.  
  1791. #if  DOS  &&  ! HAVE_REARGV
  1792.  
  1793. static void  emit_prompt()
  1794. {  static char prompt[] = DOS_PROMPT ;
  1795.    int fd = open("CON", O_WRONLY, 0) ;
  1796.  
  1797.    (void) write(fd, prompt, strlen(prompt)) ;
  1798.    (void) close(fd) ;
  1799. }
  1800. #endif
  1801.  
  1802. @//E*O*F mawk0.97/init.c//
  1803. chmod u=rw,g=r,o=r mawk0.97/init.c
  1804.  
  1805. echo x - mawk0.97/init.h
  1806. sed 's/^@//' > "mawk0.97/init.h" <<'@//E*O*F mawk0.97/init.h//'
  1807.  
  1808. /********************************************
  1809. init.h
  1810. copyright 1991, Michael D. Brennan
  1811.  
  1812. This is a source file for mawk, an implementation of
  1813. the Awk programming language as defined in
  1814. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1815. Addison-Wesley, 1988.
  1816.  
  1817. See the accompaning file, LIMITATIONS, for restrictions
  1818. regarding modification and redistribution of this
  1819. program in source or binary form.
  1820. ********************************************/
  1821.  
  1822. /* $Log:    init.h,v $
  1823.  * Revision 2.1  91/04/08  08:23:17  brennan
  1824.  * VERSION 0.97
  1825.  * 
  1826. */
  1827.  
  1828. /* init.h  */
  1829.  
  1830.  
  1831. #ifndef  INIT_H
  1832. #define  INIT_H
  1833.  
  1834.  
  1835. void  PROTO( initialize, (int, char **) ) ;
  1836. void  PROTO( code_init, (void) ) ;
  1837. void  PROTO( code_cleanup, (void) ) ;
  1838. void  PROTO( compile_cleanup, (void) ) ;
  1839. void PROTO(scan_init, (int, char *) ) ;
  1840. void PROTO(scan_cleanup, (void) ) ;
  1841. void PROTO(bi_vars_init, (void) ) ;
  1842. void PROTO(bi_funct_init, (void) ) ;
  1843. void PROTO(print_init, (void) ) ;
  1844. void PROTO(kw_init, (void) ) ;
  1845. void PROTO(jmp_stacks_init, (void) ) ;
  1846. void PROTO(jmp_stacks_cleanup, (void) ) ;
  1847. void  PROTO( field_init, (void) ) ;
  1848. void  PROTO( fpe_init, (void) ) ;
  1849.  
  1850. #endif   /* INIT_H  */
  1851. @//E*O*F mawk0.97/init.h//
  1852. chmod u=rw,g=r,o=r mawk0.97/init.h
  1853.  
  1854. echo x - mawk0.97/jmp.c
  1855. sed 's/^@//' > "mawk0.97/jmp.c" <<'@//E*O*F mawk0.97/jmp.c//'
  1856.  
  1857. /********************************************
  1858. jmp.c
  1859. copyright 1991, Michael D. Brennan
  1860.  
  1861. This is a source file for mawk, an implementation of
  1862. the Awk programming language as defined in
  1863. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1864. Addison-Wesley, 1988.
  1865.  
  1866. See the accompaning file, LIMITATIONS, for restrictions
  1867. regarding modification and redistribution of this
  1868. program in source or binary form.
  1869. ********************************************/
  1870.  
  1871. /* $Log:    jmp.c,v $
  1872.  * Revision 2.1  91/04/08  08:23:19  brennan
  1873.  * VERSION 0.97
  1874.  * 
  1875. */
  1876.  
  1877. /* this module deals with back patching jumps, breaks and continues,
  1878.    and with save and restoring code when we move code.
  1879.    There are three stacks.  If we encounter a compile error, the
  1880.    stacks are frozen, i.e., we do not attempt error recovery
  1881.    on the stacks
  1882. */
  1883.  
  1884.  
  1885. #include "mawk.h"
  1886. #include "jmp.h"
  1887. #include "code.h"
  1888. #include "sizes.h"
  1889. #include "init.h"
  1890. #include "memory.h"
  1891.  
  1892. extern unsigned compile_error_count ;
  1893. #define error_state  (compile_error_count>0)
  1894.  
  1895.  
  1896. /* a stack to hold jumps that need to be patched */
  1897.  
  1898. #define JMP_STK_SZ  (2*MAX_LOOP_DEPTH)
  1899.  
  1900. static INST **jmp_stack ; 
  1901. static INST **jmp_sp  ;
  1902.  
  1903. /*-------------------------------------*/
  1904. /* a stack to hold break or continue that need to be
  1905.    patched (which is all of them) */
  1906.  
  1907. #define  BC_SZ    MAX_LOOP_DEPTH
  1908.  
  1909. /* the stack holds a linked list of these */
  1910.  
  1911. struct BC_node { /* struct for the break/continue list */
  1912. char type ;   /*  'B' or 'C' */
  1913. INST *jmp ;   /*  the jump to patch */
  1914. struct BC_node *link ;
  1915. } ;
  1916.  
  1917. static   struct BC_node  **BC_stack ;
  1918. static   struct BC_node  **BC_sp ;
  1919.  
  1920. /*---------------------------------------*/
  1921. /* a stack to hold some pieces of code while 
  1922.    reorganizing loops */
  1923.  
  1924. #define  LOOP_CODE_SZ    (2*MAX_LOOP_DEPTH)
  1925.  
  1926. static struct loop_code {
  1927. INST *code ;
  1928. unsigned short len ;
  1929. }  *loop_code_stack , *lc_sp ;
  1930.  
  1931. /*--------------------------------------*/
  1932. void jmp_stacks_init()
  1933. { jmp_stack = (INST **)  zmalloc(JMP_STK_SZ*sizeof(INST*)) ;
  1934.   jmp_sp = jmp_stack-1 ;
  1935.  
  1936.   BC_stack = (struct BC_node **) 
  1937.               zmalloc(BC_SZ*sizeof(struct BC_node*)) ;
  1938.   BC_sp =  BC_stack-1 ;
  1939.  
  1940.   loop_code_stack = (struct loop_code *)
  1941.                     zmalloc(LOOP_CODE_SZ*sizeof(struct loop_code)) ;
  1942.   lc_sp = loop_code_stack - 1 ;
  1943. }
  1944.  
  1945. void jmp_stacks_cleanup()
  1946. { zfree(jmp_stack, JMP_STK_SZ*sizeof(INST*)) ;
  1947.   zfree(BC_stack, BC_SZ*sizeof(struct BC_node*)) ;
  1948.   zfree(loop_code_stack, LOOP_CODE_SZ*sizeof(struct loop_code)) ;
  1949. }
  1950. /*--------------------------------------*/
  1951. /* operations on the jmp_stack */
  1952.  
  1953. void code_jmp( jtype, target)
  1954.   int jtype ; INST *target ;
  1955.   if (error_state)  return ;
  1956.  
  1957.   /* check if a constant expression will be at top of stack,
  1958.      if so replace conditional jump with jump */
  1959.  
  1960.   if ( code_ptr[-2].op == _PUSHC && jtype != _JMP )
  1961.   { int t = test( (CELL *) code_ptr[-1].ptr ) ;
  1962.     if ( jtype == _JZ && ! t ||
  1963.          jtype == _JNZ && t )
  1964.     { code_ptr -= 2 ; jtype = _JMP ; }
  1965.   }
  1966.    
  1967.   if ( ! target ) /* jump will have to be patched later ,
  1968.                      put it on the jmp_stack */
  1969.   { if ( ++jmp_sp == jmp_stack + JMP_STK_SZ )
  1970.           overflow("jmp stack" , JMP_STK_SZ ) ; 
  1971.     *jmp_sp = code_ptr ;
  1972.     code2(jtype, 0) ;
  1973.   }
  1974.   else
  1975.   { INST *source = code_ptr ;
  1976.   
  1977.     code_ptr++->op = jtype ;
  1978.     code_ptr++->op = target - source ; 
  1979.   }
  1980. }
  1981.  
  1982. void patch_jmp(target)  /* patch a jump on the jmp_stack */
  1983.   INST *target ;
  1984. { register INST *source ;
  1985.  
  1986.   if ( ! error_state )
  1987.   {
  1988.     if ( jmp_sp <= jmp_stack-1 ) bozo("jmp stack underflow") ;
  1989.     source = *jmp_sp-- ;
  1990.     source[1].op = target - source ;
  1991.   }
  1992. }
  1993.  
  1994.  
  1995. /*---------------------------*/
  1996.  
  1997. /* a stack of linked lists of BC_nodes for patching 
  1998.    break and continue statements.  */
  1999.  
  2000.  
  2001. void BC_new()  /* push an empty list on the stack */
  2002.   if ( ! error_state )
  2003.   { if ( ++BC_sp == BC_stack + BC_SZ ) overflow("BC stack", BC_SZ) ;
  2004.     * BC_sp = (struct BC_node *) 0 ;
  2005.   }
  2006. }
  2007.  
  2008. void BC_insert(type, address)
  2009.   int type ; INST *address ;
  2010. { register struct BC_node *p ; 
  2011.  
  2012.   if ( error_state )  return ;
  2013.   if ( BC_sp <= BC_stack - 1 )
  2014.   {  compile_error(  type == 'B' ?
  2015.         "break statement outside of loop" :
  2016.         "continue statement outside of loop" ) ; 
  2017.      return ;
  2018.   }
  2019.   
  2020.   p = (struct BC_node *) zmalloc( sizeof(struct BC_node) ) ;
  2021.   p->type = type ; p->jmp = address ;
  2022.   p->link = *BC_sp ; *BC_sp = p ;
  2023. }
  2024.  
  2025. void BC_clear(B_address, C_address)  
  2026. /* patch all break and continues on list */
  2027. INST *B_address, *C_address ;
  2028. { register struct BC_node *p , *q ;
  2029.  
  2030.   if (error_state) return ;
  2031.   if ( BC_sp <= BC_stack-1) bozo("underflow on BC stack") ;
  2032.   p = *BC_sp-- ;
  2033.   while ( p )
  2034.   { p->jmp[1].op = (p->type=='B' ? B_address : C_address) - p->jmp ;
  2035.     q = p ; p = p->link ; zfree(q, sizeof(struct BC_node)) ;
  2036.   }
  2037. }
  2038.  
  2039. /*---------------------------------------------*/
  2040. /*  save and restore some code for reorganizing
  2041.     loops on a stack */
  2042.  
  2043.  
  2044. void code_push( p, len)
  2045.   INST *p ; unsigned len ;
  2046.   if (error_state) return ;
  2047.   if ( ++lc_sp == loop_code_stack + LOOP_CODE_SZ )
  2048.         overflow("loop_code_stack" , LOOP_CODE_SZ) ;
  2049.  
  2050.   if ( len )
  2051.   { lc_sp->code = (INST *) zmalloc(sizeof(INST) * len) ;
  2052.     (void) memcpy(lc_sp->code, p, sizeof(INST) * len) ; }
  2053.   else  lc_sp->code = (INST *) 0 ;
  2054.   lc_sp->len = (unsigned short) len ;
  2055. }
  2056.  
  2057. /* copy the code at the top of the loop code stack to target.
  2058.    return the number of bytes moved */
  2059.  
  2060. unsigned code_pop(target) 
  2061.   INST *target ;
  2062.   if (error_state)  return 0 ;
  2063.   if ( lc_sp <= loop_code_stack-1 )  bozo("loop code stack underflow") ;
  2064.   if ( lc_sp->len )
  2065.   { (void) memcpy(target, lc_sp->code, lc_sp->len * sizeof(INST)) ;
  2066.     zfree(lc_sp->code, sizeof(INST)*lc_sp->len) ; }
  2067.   return lc_sp-- -> len ;
  2068. }
  2069. @//E*O*F mawk0.97/jmp.c//
  2070. chmod u=rw,g=r,o=r mawk0.97/jmp.c
  2071.  
  2072. echo x - mawk0.97/jmp.h
  2073. sed 's/^@//' > "mawk0.97/jmp.h" <<'@//E*O*F mawk0.97/jmp.h//'
  2074.  
  2075. /********************************************
  2076. jmp.h
  2077. copyright 1991, Michael D. Brennan
  2078.  
  2079. This is a source file for mawk, an implementation of
  2080. the Awk programming language as defined in
  2081. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2082. Addison-Wesley, 1988.
  2083.  
  2084. See the accompaning file, LIMITATIONS, for restrictions
  2085. regarding modification and redistribution of this
  2086. program in source or binary form.
  2087. ********************************************/
  2088.  
  2089. /* $Log:    jmp.h,v $
  2090.  * Revision 2.1  91/04/08  08:23:21  brennan
  2091.  * VERSION 0.97
  2092.  * 
  2093. */
  2094.  
  2095. #ifndef   JMP_H
  2096. #define   JMP_H
  2097.  
  2098. void  PROTO(BC_new, (void) ) ;
  2099. void  PROTO(BC_insert, (int, INST*) ) ;
  2100. void  PROTO(BC_clear, (INST *, INST *) ) ;
  2101. void  PROTO(code_push, (INST *, unsigned) ) ;
  2102. unsigned  PROTO(code_pop, (INST *) ) ;
  2103. void  PROTO(code_jmp, (int, INST *) ) ;
  2104. void  PROTO(patch_jmp, (INST *) ) ;
  2105.  
  2106.  
  2107. #endif  /* JMP_H  */
  2108.  
  2109. @//E*O*F mawk0.97/jmp.h//
  2110. chmod u=rw,g=r,o=r mawk0.97/jmp.h
  2111.  
  2112. echo x - mawk0.97/kw.c
  2113. sed 's/^@//' > "mawk0.97/kw.c" <<'@//E*O*F mawk0.97/kw.c//'
  2114.  
  2115. /********************************************
  2116. kw.c
  2117. copyright 1991, Michael D. Brennan
  2118.  
  2119. This is a source file for mawk, an implementation of
  2120. the Awk programming language as defined in
  2121. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2122. Addison-Wesley, 1988.
  2123.  
  2124. See the accompaning file, LIMITATIONS, for restrictions
  2125. regarding modification and redistribution of this
  2126. program in source or binary form.
  2127. ********************************************/
  2128.  
  2129.  
  2130. /* $Log:    kw.c,v $
  2131.  * Revision 2.1  91/04/08  08:23:23  brennan
  2132.  * VERSION 0.97
  2133.  * 
  2134. */
  2135.  
  2136.  
  2137. /* kw.c */
  2138.  
  2139.  
  2140. #include "mawk.h"
  2141. #include "symtype.h"
  2142. #include "parse.h"
  2143. #include "init.h"
  2144.  
  2145.  
  2146. static struct kw {
  2147. char *text ;
  2148. short kw ;
  2149. }  keywords[] = {
  2150.  
  2151. "print", PRINT,
  2152. "printf", PRINTF,
  2153. "do" , DO ,
  2154. "while" , WHILE ,
  2155. "for" , FOR ,
  2156. "break" , BREAK ,
  2157. "continue" , CONTINUE ,
  2158. "if" , IF ,
  2159. "else", ELSE ,
  2160. "in" , IN ,
  2161. "delete", DELETE ,
  2162. "split" , SPLIT ,
  2163. "match" , MATCH_FUNC ,
  2164. "BEGIN" , BEGIN,
  2165. "END" ,   END ,
  2166. "exit" , EXIT ,
  2167. "next" , NEXT ,
  2168. "return", RETURN,
  2169. "getline", GETLINE,
  2170. "sub" , SUB,
  2171. "gsub", GSUB,
  2172. "function", FUNCTION,
  2173. (char *) 0 , 0 } ;
  2174.  
  2175. /* put keywords in the symbol table */
  2176. void kw_init()
  2177. { register struct kw *p = keywords ;
  2178.   register SYMTAB *q ;
  2179.  
  2180.   while ( p->text )
  2181.   { q = insert( p->text ) ;
  2182.     q->type = ST_KEYWORD ;
  2183.     q->stval.kw = p++ -> kw ;
  2184.   }
  2185. }
  2186.  
  2187. /* find a keyword to emit an error message */
  2188. char *find_kw_str( kw_token )
  2189.   int kw_token ;
  2190. { struct kw *p = keywords ;
  2191.  
  2192.   for( p = keywords ; p->text ; p++ )
  2193.         if ( p->kw == kw_token )  return p->text ;
  2194.   /* search failed */
  2195.   return (char *) 0 ;
  2196. }
  2197. @//E*O*F mawk0.97/kw.c//
  2198. chmod u=rw,g=r,o=r mawk0.97/kw.c
  2199.  
  2200. echo x - mawk0.97/machine.h
  2201. sed 's/^@//' > "mawk0.97/machine.h" <<'@//E*O*F mawk0.97/machine.h//'
  2202.  
  2203. /********************************************
  2204. machine.h
  2205. copyright 1991, Michael D. Brennan
  2206.  
  2207. This is a source file for mawk, an implementation of
  2208. the Awk programming language as defined in
  2209. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2210. Addison-Wesley, 1988.
  2211.  
  2212. See the accompaning file, LIMITATIONS, for restrictions
  2213. regarding modification and redistribution of this
  2214. program in source or binary form.
  2215. ********************************************/
  2216.  
  2217. /*$Log:    machine.h,v $
  2218.  * Revision 2.2  91/04/09  12:39:14  brennan
  2219.  * added static to funct decls to satisfy STARDENT compiler
  2220.  * 
  2221.  * Revision 2.1  91/04/08  08:23:25  brennan
  2222.  * VERSION 0.97
  2223.  * 
  2224. */
  2225.  
  2226.  
  2227. /* I've attempted to isolate machine/system dependencies here.
  2228.  
  2229.    Floating point exceptions are the biggest hassle.
  2230.    If you have IEEE754 floating point, turn off floating point
  2231.    traps and let the INFs and NANs go berserk.  This should be
  2232.    the default (see page 14 of IEEE754), but ANSI C seems to imply
  2233.    they should be on (i.e., one standards committee does not talk to
  2234.    the other).  Anyway, define a macro TURNOFF_FPE_TRAPS() which will
  2235.    probably be a 1 liner.
  2236.  
  2237.    If you cannot turn off floating exceptions, check out
  2238.    fpe_catch() in matherr.c and modify as needed for your machine.
  2239.    Also you may need to define FPE_ZERODIVIDE and FPE_OVERFLOW.
  2240.  
  2241.    If you have SysV like matherr(), use it.
  2242.    If you have SysV compatible math lib , use it.
  2243.    You might need to supply a macro to replace drand48(), otherwise.
  2244.    (See BSD43 for no IEEE754, no matherr(), no fmod(),
  2245.     no strtod(), no drand48())
  2246.  
  2247.    If you have to be conservative with memory (e.g., small model
  2248.    MsDos), a small evaluation stack (16-32) is plenty.
  2249.    Recursive functions calls are the only reason you need a big
  2250.    stack.  The default for MsDos uses 64 which allows some
  2251.    recursion without killing too many memory CELLs.
  2252. */
  2253.  
  2254. /*  MsDOS --
  2255.     If you use command.com as the shell, entering programs on the
  2256.     command line is hopeless.  Command.com will always glom onto
  2257.     | or < or > as redirection.
  2258.  
  2259.     If you use a Unix style shell under DOS, then you need to
  2260.     write 
  2261.  
  2262.         void  reargv(int *argc, char ***argv)
  2263.  
  2264.     which gets the arguments from your shell, and then
  2265.  
  2266.     #define   HAVE_REARGV    1
  2267.  
  2268.     See README in dos directory
  2269.     and MsDos section of manual.
  2270. */
  2271.  
  2272. #ifndef    MACHINE_H
  2273. #define    MACHINE_H
  2274.  
  2275.  
  2276. #ifdef  sun   /* sun3 or sun4 with SUNOS 4.0.3 */
  2277. #define  FPE_TRAPS              0
  2278. #define  TURNOFF_FPE_TRAPS()    /* empty, default is off */      
  2279. #define  HAVE_MATHERR           1
  2280. #endif
  2281.  
  2282. #ifdef    __TURBOC__
  2283. #define   DOS            1
  2284. #define   SMALL_EVAL_STACK      1
  2285. #define  FPE_TRAPS              0
  2286. #define  TURNOFF_FPE_TRAPS()    _control87(0x3f,0x3f)
  2287. #define  HAVE_MATHERR           1
  2288. #endif
  2289.  
  2290. #ifdef   ULTRIX  /* V4.1 on a vax 3600 */
  2291. #define  HAVE_VOID_PTR          1
  2292. #define  HAVE_MATHERR           1
  2293. #define   FPE_ZERODIVIDE   FPE_FLTDIV_FAULT
  2294. #define   FPE_OVERFLOW     FPE_FLTOVF_FAULT
  2295. #endif
  2296.  
  2297. #ifdef    BSD43   /* on a vax */
  2298. #define   NO_STRTOD             1
  2299. #define   NO_FMOD               1
  2300. #define   srand48(x)    srandom(x)
  2301. #define   drand48() (((double)random())/((double)(unsigned)0x80000000))
  2302. #define   vfprintf(s,f,a)  _doprnt(f,a,s)
  2303. #define   FPE_ZERODIVIDE   FPE_FLTDIV_FAULT
  2304. #define   FPE_OVERFLOW     FPE_FLTOVF_FAULT
  2305. #endif
  2306.  
  2307. #ifdef   STARDENT  /* Stardent 3000, SysV R3.0 */
  2308. #define  HAVE_MATHERR    1
  2309. #define  FPE_TRAPS    0
  2310. #define  TURNOFF_FPE_TRAPS()    /* nothing */
  2311. #define  HAVE_VOID_PTR    1
  2312. #endif
  2313.  
  2314. /*  the defaults    */
  2315. #ifndef   HAVE_VOID_PTR
  2316. #define   HAVE_VOID_PTR         0  /* no void * */
  2317. #endif
  2318.  
  2319. #ifndef   FPE_TRAPS
  2320. #define   FPE_TRAPS             1  
  2321.     /* floating point errors generate exceptions  */
  2322. #endif
  2323.  
  2324. #ifndef   HAVE_MATHERR
  2325. #define   HAVE_MATHERR          0
  2326.     /*  SysV style matherr() is not available */
  2327. #endif
  2328.  
  2329. #ifndef  NO_STRTOD
  2330. #define  NO_STRTOD              0 /* default is have */
  2331. #endif
  2332.  
  2333. #ifndef  SMALL_EVAL_STACK
  2334. #define  SMALL_EVAL_STACK       0
  2335. #endif
  2336.  
  2337. #ifndef  NO_FMOD
  2338. #define  NO_FMOD                0 /* default is to have fmod() */
  2339. #endif
  2340.  
  2341. #define   STDC_MATHERR          (FPE_TRAPS && ! HAVE_MATHERR)
  2342.  
  2343. #ifndef   DOS
  2344. #define   DOS    0
  2345. #endif
  2346.  
  2347. #if   DOS 
  2348.  
  2349. #ifndef  HAVE_REARGV
  2350. #define  HAVE_REARGV    0
  2351. #endif
  2352.  
  2353. #define  DOS_PROMPT     "mawk> "
  2354.     /* change to "mawk \01 "  on a good day */
  2355. #endif
  2356.  
  2357.  
  2358.  
  2359.  
  2360.  
  2361. #endif   /* MACHINE_H  */
  2362. @//E*O*F mawk0.97/machine.h//
  2363. chmod u=rw,g=r,o=r mawk0.97/machine.h
  2364.  
  2365. echo x - mawk0.97/main.c
  2366. sed 's/^@//' > "mawk0.97/main.c" <<'@//E*O*F mawk0.97/main.c//'
  2367.  
  2368. /********************************************
  2369. main.c
  2370. copyright 1991, Michael D. Brennan
  2371.  
  2372. This is a source file for mawk, an implementation of
  2373. the Awk programming language as defined in
  2374. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2375. Addison-Wesley, 1988.
  2376.  
  2377. See the accompaning file, LIMITATIONS, for restrictions
  2378. regarding modification and redistribution of this
  2379. program in source or binary form.
  2380. ********************************************/
  2381.  
  2382.  
  2383. /* $Log:    main.c,v $
  2384.  * Revision 2.2  91/04/22  08:08:58  brennan
  2385.  * cannot close(3) or close(4) because of bug in TurboC++ 1.0
  2386.  * 
  2387.  * Revision 2.1  91/04/08  08:23:27  brennan
  2388.  * VERSION 0.97
  2389.  * 
  2390. */
  2391.  
  2392.  
  2393.  
  2394. /*  main.c  */
  2395.  
  2396. #include "mawk.h"
  2397. #include "code.h"
  2398. #include "init.h"
  2399. #include "fin.h"
  2400. #include "bi_vars.h"
  2401. #include "field.h"
  2402. #include "files.h"
  2403. #include <stdio.h>
  2404.  
  2405. #if  DOS 
  2406. void  reargv(int *, char ***) ;
  2407. #endif
  2408.  
  2409.  
  2410. void  PROTO( process, (void) ) ;
  2411. void  PROTO( main_loop, (void) ) ;
  2412.  
  2413. extern int program_fd ;
  2414. char *progname ;
  2415.  
  2416. jmp_buf   exit_jump, next_jump ;
  2417. int  exit_code ;
  2418.  
  2419.  
  2420. main(argc , argv )
  2421.   int argc ; char **argv ;
  2422.  
  2423. #if   DOS
  2424.   progname = "mawk" ;
  2425. #if      HAVE_REARGV
  2426.   reargv(&argc, &argv) ;
  2427. #endif
  2428. #else
  2429.   { char *strrchr() ;
  2430.     char *p = strrchr(argv[0], '/') ;
  2431.     progname = p ? p+1 : argv[0] ; }
  2432. #endif
  2433.  
  2434.   initialize(argc, argv) ;
  2435.  
  2436.   if ( parse() || compile_error_count )  exit(1) ;
  2437.  
  2438.   compile_cleanup() ;
  2439.   process() ;
  2440.  
  2441.   mawk_exit( exit_code ) ;
  2442.   return 0 ;
  2443. }
  2444.  
  2445.  
  2446. static  void  process()
  2447. {
  2448.  
  2449.   if ( setjmp(exit_jump) )
  2450.   { if ( begin_start ) zfree(begin_start, begin_size) ;
  2451.     goto the_exit ;
  2452.   }
  2453.  
  2454.   if ( begin_start )
  2455.   { (void) execute(begin_start, eval_stack-1, 0) ;
  2456.     zfree( begin_start , begin_size ) ;
  2457.     begin_start = (INST *) 0 ;
  2458.   }
  2459.  
  2460.   if ( main_start || end_start )  main_loop() ;
  2461.  
  2462. the_exit:
  2463.  
  2464.   if ( setjmp(exit_jump) )  mawk_exit(exit_code) ;
  2465.  
  2466.   if ( main_start )  zfree(main_start, main_size) ;
  2467.   if ( end_start ) (void) execute(end_start, eval_stack-1, 0) ;
  2468. }
  2469.  
  2470.  
  2471. static void  main_loop()
  2472. { register char *p ;
  2473.   unsigned len ;
  2474.  
  2475.   /* the main file stream might already be open by a call of
  2476.      getline in the BEGIN block */
  2477.  
  2478.   if ( main_fin == (FIN *) -1 && ! open_main()
  2479.        || ! main_fin )  return ;
  2480.  
  2481.   if ( main_start )
  2482.   {
  2483.      (void)  setjmp(next_jump) ;
  2484.  
  2485.      while ( p = FINgets( main_fin, &len ) )
  2486.      { 
  2487.        if ( TEST2(bi_vars + NR) != TWO_DOUBLES )
  2488.                     cast2_to_d(bi_vars + NR) ;
  2489.  
  2490.        bi_vars[NR].dval += 1.0 ;
  2491.        bi_vars[FNR].dval += 1.0 ;
  2492.  
  2493.        set_field0(p, len) ;
  2494.        (void) execute( main_start, eval_stack-1, 0) ;
  2495.      }
  2496.   }
  2497.   else  /* eat main to set NR and FNR before executing END */
  2498.   { long nr ;
  2499.  
  2500.     if ( TEST2(bi_vars+NR) != TWO_DOUBLES ) cast2_to_d(bi_vars+NR) ;
  2501.     nr = (long) bi_vars[NR].dval ;
  2502.     while ( FINgets( main_fin, &len ) )
  2503.     { nr++ ; bi_vars[FNR].dval += 1.0 ; }
  2504.     bi_vars[NR].dval = (double) nr ;
  2505.   }
  2506. }
  2507.  
  2508.  
  2509. void  mawk_exit(x)
  2510.   int x ;
  2511. {
  2512. #if  !  DOS
  2513.   close_out_pipes() ;  /* no effect, if no out pipes */
  2514. #endif
  2515.   exit(x) ;
  2516. }
  2517. @//E*O*F mawk0.97/main.c//
  2518. chmod u=rw,g=r,o=r mawk0.97/main.c
  2519.  
  2520. echo x - mawk0.97/makescan.c
  2521. sed 's/^@//' > "mawk0.97/makescan.c" <<'@//E*O*F mawk0.97/makescan.c//'
  2522.  
  2523. /********************************************
  2524. makescan.c
  2525. copyright 1991, Michael D. Brennan
  2526.  
  2527. This is a source file for mawk, an implementation of
  2528. the Awk programming language as defined in
  2529. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2530. Addison-Wesley, 1988.
  2531.  
  2532. See the accompaning file, LIMITATIONS, for restrictions
  2533. regarding modification and redistribution of this
  2534. program in source or binary form.
  2535. ********************************************/
  2536.  
  2537.  
  2538.  
  2539. /*$Log:    makescan.c,v $
  2540.  * Revision 2.1  91/04/08  08:23:29  brennan
  2541.  * VERSION 0.97
  2542.  * 
  2543. */
  2544.  
  2545. /* source for makescan.exe which builds the scancode[]
  2546.    via:   makescan.exe > scancode.c
  2547. */
  2548.  
  2549. #define  MAKESCAN
  2550.  
  2551. #include  "scan.h"
  2552.  
  2553. char   scan_code[256] ;
  2554.  
  2555. void  scan_init()
  2556.   register char *p ;
  2557.  
  2558.   (void) memset(scan_code, SC_UNEXPECTED, sizeof(scan_code)) ;
  2559.   for( p = scan_code + '0' ; p <= scan_code + '9' ; p++ )
  2560.        *p = SC_DIGIT ;
  2561.   scan_code[0] = 0 ;
  2562.   scan_code[ ' ' ] = scan_code['\t'] = scan_code['\f'] = SC_SPACE ;
  2563.   scan_code[ '\r'] = scan_code['\013'] = SC_SPACE ;
  2564.  
  2565.   scan_code[';'] = SC_SEMI_COLON ;
  2566.   scan_code['\n'] = SC_NL ;
  2567.   scan_code['{'] = SC_LBRACE ;
  2568.   scan_code[ '}'] = SC_RBRACE ;
  2569.   scan_code['+'] = SC_PLUS ;
  2570.   scan_code['-'] = SC_MINUS ;
  2571.   scan_code['*'] = SC_MUL ;
  2572.   scan_code['/'] = SC_DIV ;
  2573.   scan_code['%'] = SC_MOD ;
  2574.   scan_code['^'] = SC_POW ;
  2575.   scan_code['('] = SC_LPAREN ;
  2576.   scan_code[')'] = SC_RPAREN ;
  2577.   scan_code['_'] = SC_IDCHAR ;
  2578.   scan_code['='] = SC_EQUAL ;
  2579.   scan_code['#'] = SC_COMMENT ;
  2580.   scan_code['\"'] = SC_DQUOTE ;
  2581.   scan_code[','] = SC_COMMA ;
  2582.   scan_code['!'] = SC_NOT ;
  2583.   scan_code['<'] = SC_LT ;
  2584.   scan_code['>'] = SC_GT ;
  2585.   scan_code['|'] = SC_OR ;
  2586.  
  2587.  
  2588.