home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3351 < prev    next >
Encoding:
Internet Message Format  |  1991-05-17  |  60.8 KB

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