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

  1.  
  2. /********************************************
  3. field.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /* $Log: field.c,v $
  14.  * Revision 5.4.1.2  1993/01/20  12:53:08  mike
  15.  * d_to_l()
  16.  *
  17.  * Revision 5.4.1.1  1993/01/15  03:33:42  mike
  18.  * patch3: safer double to int conversion
  19.  *
  20.  * Revision 5.4  1992/11/29  22:52:11  mike
  21.  * double->string conversions uses long ints for 16/32 bit
  22.  * compatibility.
  23.  * Fixed small LM_DOS bozo.
  24.  *
  25.  * Revision 5.3  1992/08/17  14:21:10  brennan
  26.  * patch2: After parsing, only bi_sprintf() uses string_buff.
  27.  *
  28.  * Revision 5.2  1992/07/10  16:17:10  brennan
  29.  * MsDOS: remove NO_BINMODE macro
  30.  *
  31.  * Revision 5.1  1991/12/05  07:55:57  brennan
  32.  * 1.1 pre-release
  33.  *
  34. */
  35.  
  36.  
  37. /* field.c */
  38.  
  39. #include "mawk.h"
  40. #include "field.h"
  41. #include "init.h"
  42. #include "memory.h"
  43. #include "scan.h"
  44. #include "bi_vars.h"
  45. #include "repl.h"
  46. #include "regexp.h"
  47.  
  48. CELL  field[FBANK_SZ+NUM_PFIELDS] ;
  49.  
  50. CELL  *fbank[NUM_FBANK] = {field} ;
  51.  
  52. static int max_field = MAX_SPLIT ; /* maximum field actually created*/
  53.  
  54. static void PROTO( build_field0, (void) ) ;
  55. static void PROTO( set_rs_shadow, (void) ) ;
  56. static void PROTO( load_pfield, (char*, CELL*)) ;
  57. static void PROTO( load_field_ov, (void)) ;
  58.  
  59.  
  60.  
  61. /* a description of how to split based on RS.
  62.    If RS is changed, so is rs_shadow */
  63. SEPARATOR rs_shadow = {SEP_CHAR, '\n'} ;
  64. /* a splitting CELL version of FS */
  65. CELL fs_shadow = {C_SPACE} ;
  66. int   nf ;  
  67.   /* nf holds the true value of NF.  If nf < 0 , then
  68.      NF has not been computed, i.e., $0 has not been split
  69.   */
  70.  
  71. static void set_rs_shadow()
  72. { CELL c ;
  73.   STRING  *sval ;
  74.   char *s ;
  75.   unsigned len ;
  76.  
  77.   if ( posix_space_flag && mawk_state == EXECUTION ) 
  78.           scan_code['\n'] = SC_UNEXPECTED ;
  79.  
  80.   if ( rs_shadow.type == SEP_STR )  free_STRING((STRING*) rs_shadow.ptr) ;
  81.  
  82.   cast_for_split( cellcpy(&c, RS) ) ;
  83.   switch( c.type )
  84.   {
  85.     case C_RE :
  86.         if ( s = is_string_split(c.ptr, &len) )
  87.             if ( len == 1 )
  88.             { rs_shadow.type = SEP_CHAR ;
  89.               rs_shadow.c = s[0] ;
  90.             }
  91.             else
  92.             { rs_shadow.type = SEP_STR ;
  93.               rs_shadow.ptr = (PTR) new_STRING(s) ;
  94.             }
  95.         else
  96.         { rs_shadow.type = SEP_RE ;
  97.           rs_shadow.ptr = c.ptr ;
  98.         }
  99.         break ;
  100.  
  101.     case C_SPACE :
  102.         rs_shadow.type = SEP_CHAR ;
  103.         rs_shadow.c = ' ' ;
  104.         break ;
  105.  
  106.     case C_SNULL : /* RS becomes one or more blank lines */
  107.     if ( mawk_state == EXECUTION ) scan_code['\n'] = SC_SPACE ;
  108.         rs_shadow.type = SEP_MLR ;
  109.         sval = new_STRING( "\n\n+" ) ;
  110.         rs_shadow.ptr = re_compile(sval) ;
  111.         free_STRING(sval) ;
  112.         break ;
  113.  
  114.     default : bozo("bad cell in set_rs_shadow") ;
  115.   }
  116. }
  117.  
  118. static  void load_pfield(name, cp)
  119.   char *name ;
  120.   CELL *cp ;
  121. { SYMTAB *stp ;
  122.  
  123.   stp = insert(name) ; stp->type = ST_FIELD ;
  124.   stp->stval.cp = cp ;
  125. }
  126.  
  127. /* initialize $0 and the pseudo fields */
  128. void  field_init()
  129.   field[0].type = C_STRING ;
  130.   field[0].ptr = (PTR) & null_str ;
  131.   null_str.ref_cnt++ ;
  132.  
  133.   load_pfield("NF",NF) ;
  134.   NF->type = C_DOUBLE ;
  135.   NF->dval = 0.0 ;
  136.  
  137.   load_pfield("RS", RS) ;
  138.   RS->type = C_STRING ;
  139.   RS->ptr =  (PTR) new_STRING( "\n" ) ;
  140.   /* rs_shadow already set */
  141.  
  142.   load_pfield("FS", FS) ;
  143.   FS->type = C_STRING ;
  144.   FS->ptr = (PTR) new_STRING( " " ) ;
  145.   /* fs_shadow is already set */
  146.  
  147.   load_pfield("OFMT", OFMT) ;
  148.   OFMT->type = C_STRING ;
  149.   OFMT->ptr = (PTR) new_STRING( "%.6g" ) ;
  150.  
  151.   load_pfield("CONVFMT", CONVFMT) ;
  152.   CONVFMT->type = C_STRING ;
  153.   CONVFMT->ptr = OFMT->ptr ;
  154.   string(OFMT)->ref_cnt++ ;
  155. }
  156.  
  157.  
  158.  
  159. void  set_field0( s, len)
  160.   char *s ;
  161.   unsigned len ;
  162.   cell_destroy( & field[0] ) ;
  163.   nf = -1 ;
  164.  
  165.   if ( len )
  166.   {
  167.     field[0].type = C_MBSTRN ;
  168.     field[0].ptr = (PTR) new_STRING( (char *) 0, len) ;
  169.     (void) memcpy( string(&field[0])->str, s, SIZE_T(len) ) ;
  170.   }
  171.   else
  172.   {
  173.     field[0].type = C_STRING ;
  174.     field[0].ptr = (PTR) &null_str ;
  175.     null_str.ref_cnt++ ;
  176.   }
  177. }
  178.  
  179.  
  180.  
  181. /* split field[0] into $1, $2 ... and set NF  */
  182.  
  183. void  split_field0()
  184. { register CELL *cp ;
  185.   register int cnt ;
  186.   CELL  c ;  /* copy field[0] here if not string */
  187.  
  188.  
  189.   if ( field[0].type < C_STRING )
  190.   { cast1_to_s(cellcpy(&c, field+0)) ;
  191.     cp = &c ;
  192.   }
  193.   else   cp = &field[0] ;
  194.  
  195.   if ( string(cp)->len == 0 )  nf = 0 ;
  196.   else
  197.   {
  198.     switch( fs_shadow.type )
  199.     {
  200.       case   C_SNULL :  /* FS == "" */
  201.           nf = 1 ;
  202.           cell_destroy(NF) ;
  203.           NF->type = C_DOUBLE ;
  204.           NF->dval = 1.0 ;
  205.           field[1].type = C_MBSTRN ;
  206.           field[1].ptr = cp->ptr ;
  207.  
  208.           if ( cp == field )  string(cp)->ref_cnt++ ;
  209.           /* else we gain one ref_cnt and lose one for a wash */
  210.  
  211.           return ;
  212.  
  213.       case  C_SPACE :
  214.           nf = space_split(string(cp)->str, string(cp)->len) ;
  215.           break ;
  216.  
  217.       default :
  218.           nf = re_split(string(cp)->str, fs_shadow.ptr) ;
  219.           break ;
  220.     }
  221.         
  222.   }
  223.   
  224.   cell_destroy(NF) ;
  225.   NF->type = C_DOUBLE ;
  226.   NF->dval = (double) nf ;
  227.  
  228.   if ( nf > MAX_SPLIT )  
  229.   {
  230.     cnt = MAX_SPLIT ; load_field_ov() ;
  231.   }
  232.   else cnt = nf ;
  233.  
  234.   while ( cnt > 0 )
  235.   {
  236.     cell_destroy(field+cnt) ;
  237.     field[cnt].ptr = (PTR) split_buff[cnt-1] ;
  238.     field[cnt--].type = C_MBSTRN ;
  239.   }
  240.  
  241.   if ( cp == &c )  free_STRING( string(cp) ) ;
  242. }
  243.  
  244. /*
  245.   assign CELL *cp to field or pseudo field
  246.   and take care of all side effects
  247. */
  248.  
  249. void  field_assign( fp, cp)
  250.   register CELL *fp ;
  251.   CELL *cp ;
  252.   CELL c ;
  253.   int i , j ;
  254.  
  255.   /* the most common case first */
  256.   if ( fp == field )
  257.   { cell_destroy(field) ;
  258.     (void) cellcpy(fp, cp) ;
  259.     nf = -1 ;
  260.     return ;
  261.   }
  262.  
  263.   /* its not important to do any of this fast */
  264.  
  265.   if ( nf < 0 )  split_field0() ;
  266.  
  267. #if  LM_DOS
  268.   if ( !SAMESEG(fp,field) )
  269.   { 
  270.     i = -1 ;
  271.     goto lm_dos_label ;
  272.   }
  273. #endif
  274.  
  275.   switch( i = (fp - field) )
  276.   {
  277.  
  278.     case  NF_field :
  279.  
  280.         cell_destroy(NF) ;
  281.         (void) cellcpy(NF, cellcpy(&c,cp) ) ;
  282.         if ( c.type != C_DOUBLE )  cast1_to_d(&c) ;
  283.  
  284.         if ( (j = d_to_i(c.dval)) < 0 )
  285.             rt_error("negative value assigned to NF") ;
  286.  
  287.         if ( j > nf )
  288.             for ( i = nf+1 ; i <= j ; i++ )
  289.             { 
  290.           cp = field_ptr(i) ;
  291.           cell_destroy(cp) ;
  292.           cp->type = C_STRING ;
  293.               cp->ptr = (PTR) &null_str ;
  294.               null_str.ref_cnt++ ;
  295.             }
  296.  
  297.         nf = j ;
  298.         build_field0() ;
  299.         break ;
  300.  
  301.     case  RS_field :
  302.         cell_destroy(RS) ;
  303.         (void) cellcpy(RS, cp) ;
  304.         set_rs_shadow() ;
  305.         break ;
  306.  
  307.     case  FS_field :
  308.         cell_destroy(FS) ;
  309.         cast_for_split( cellcpy(&fs_shadow, cellcpy(FS, cp)) ) ;
  310.         break ;
  311.  
  312.     case OFMT_field : 
  313.     case CONVFMT_field:
  314.         /* If the user does something stupid with OFMT or CONVFMT,
  315.        we could crash.
  316.            We'll make an attempt to protect ourselves here.  This is
  317.            why OFMT and CONVFMT are pseudo fields.
  318.  
  319.            The ptrs of OFMT and CONVFMT always have a valid STRING,
  320.        even if assigned a DOUBLE or NOINIT
  321.         */
  322.  
  323.         free_STRING( string(fp) ) ;
  324.         (void) cellcpy(fp, cp) ;
  325.         if ( fp->type < C_STRING ) /* !! */
  326.              fp->ptr = (PTR) new_STRING( "%.6g" ) ;
  327.         else
  328.     if ( fp == CONVFMT )
  329.         {
  330.           /* It's a string, but if it's really goofy and CONVFMT,
  331.          it could still damage us. Test it .
  332.       */
  333.           char xbuff[512] ;
  334.  
  335.       xbuff[256] = 0 ;
  336.           (void) sprintf( xbuff, string(fp)->str, 3.1459) ;
  337.           if ( xbuff[256] ) 
  338.           rt_error("CONVFMT assigned unusable value") ;
  339.         }
  340.         break ;
  341.  
  342. #if LM_DOS
  343. lm_dos_label :
  344. #endif
  345.  
  346.     default:  /* $1 or $2 or ... */
  347.  
  348.  
  349.         cell_destroy(fp) ;
  350.         (void) cellcpy(fp, cp) ;
  351.  
  352.     if ( i < 0 || i > MAX_SPLIT ) i = field_addr_to_index(fp) ;    
  353.  
  354.         if ( i > nf )
  355.         { for ( j = nf+1 ; j < i ; j++ )
  356.           { 
  357.         cp = field_ptr(j) ;
  358.         cell_destroy(cp) ;
  359.             cp->type = C_STRING ;
  360.         cp->ptr = (PTR) &null_str ;
  361.             null_str.ref_cnt++ ;
  362.           }
  363.           nf = i ;
  364.           cell_destroy(NF) ;
  365.           NF->type = C_DOUBLE ;
  366.           NF->dval = (double) i ;
  367.         }
  368.  
  369.         build_field0() ;
  370.  
  371.   }
  372. }
  373.  
  374.  
  375. /* construct field[0] from the other fields */
  376.  
  377. static void  build_field0()
  378.  
  379.  
  380. #ifdef DEBUG
  381.   if ( nf < 0 )  
  382.       bozo("nf <0 in build_field0") ;
  383. #endif
  384.  
  385.   cell_destroy( field+0 ) ;
  386.  
  387.   if ( nf == 0 )
  388.   { field[0].type = C_STRING ;
  389.     field[0].ptr = (PTR) &null_str ;
  390.     null_str.ref_cnt++ ;
  391.   }
  392.   else
  393.   if ( nf == 1 )  (void) cellcpy(field, field+1) ;
  394.  
  395.   else
  396.   { CELL  c ;
  397.     STRING *ofs, *tail ;
  398.     unsigned len ;
  399.     register CELL *cp ;
  400.     register char *p, *q ;
  401.     int cnt ;
  402.     CELL **fbp, *cp_limit ;
  403.  
  404.  
  405.     cast1_to_s(cellcpy(&c,OFS)) ;
  406.     ofs = (STRING *) c.ptr ;
  407.     cast1_to_s(cellcpy(&c, field_ptr(nf))) ;
  408.     tail = (STRING *) c.ptr ;
  409.     cnt = nf-1 ;
  410.  
  411.     len = cnt*ofs->len + tail->len ;
  412.  
  413.     fbp = fbank ; cp_limit = field + FBANK_SZ ;
  414.     cp = field + 1 ;
  415.  
  416.     while ( cnt-- > 0 )
  417.     {
  418.       if ( cp->type < C_STRING ) 
  419.       { /* use the string field temporarily */
  420.         if ( cp->type == C_NOINIT )
  421.     { 
  422.       cp->ptr = (PTR) &null_str ;
  423.       null_str.ref_cnt++ ;
  424.         }
  425.     else /* its a double */
  426.     { 
  427.       long ival ;
  428.       char xbuff[260] ;
  429.  
  430.       ival = d_to_l(cp->dval) ;
  431.       if ( ival == cp->dval )
  432.         (void) sprintf(xbuff, INT_FMT, ival) ;
  433.       else
  434.         (void) sprintf(xbuff, string(CONVFMT)->str, cp->dval) ;
  435.  
  436.       cp->ptr = (PTR) new_STRING(xbuff) ;
  437.         }
  438.       }
  439.  
  440.       len += string(cp)->len ;
  441.  
  442.       if ( ++cp == cp_limit )
  443.       { cp = * ++fbp ; cp_limit = cp + FBANK_SZ ; }
  444.     }
  445.  
  446.     field[0].type = C_STRING ;
  447.     field[0].ptr = (PTR) new_STRING((char *) 0, len) ;
  448.  
  449.     p = string(field)->str ;
  450.  
  451.     /* walk it again , putting things together */
  452.     cnt = nf-1 ; fbp = fbank ;
  453.     cp = field+1 ; cp_limit = field + FBANK_SZ ;
  454.  
  455.     while ( cnt-- > 0 )
  456.     {
  457.       (void) memcpy(p, string(cp)->str,SIZE_T(string(cp)->len)) ;
  458.       p += string(cp)->len ;
  459.       /* if not really string, free temp use of ptr */
  460.       if ( cp->type < C_STRING ) free_STRING(string(cp)) ;
  461.       if ( ++cp == cp_limit )
  462.       { cp = * ++fbp ; cp_limit = cp + FBANK_SZ ; }
  463.  
  464.       /* add the separator */
  465.       q = ofs->str ;  while( *q )  *p++ = *q++ ;
  466.     }
  467.     /* tack tail on the end */
  468.     (void) memcpy(p, tail->str, SIZE_T(tail->len)) ;
  469.  
  470.     /* cleanup */
  471.     free_STRING(tail) ; free_STRING(ofs) ;
  472.   }
  473. }
  474.  
  475. /* We are assigning to a CELL and we aren't sure if its
  476.    a field */
  477.  
  478. void slow_cell_assign(target, source)
  479.   register CELL *target ;
  480.   CELL *source ;
  481.   if ( 
  482.  
  483. #if  LM_DOS  /* the dreaded segment nonsense */
  484.   SAMESEG(target,field) &&
  485. #endif
  486.        target >= field && target <= LAST_PFIELD )
  487.        field_assign(target, source) ;
  488.   else
  489.   { CELL **p = fbank + 1 ;
  490.  
  491.     while ( *p )
  492.     {
  493.       if ( 
  494. #if  LM_DOS
  495.       SAMESEG(target, *p) &&
  496. #endif
  497.        target >= *p && target < *p + FBANK_SZ )
  498.       {
  499.         field_assign(target, source) ;
  500.     return ;
  501.       }
  502.       p++ ;
  503.     }
  504.     /* its not a field */
  505.     cell_destroy(target) ;
  506.     (void) cellcpy(target, source) ;
  507.   }
  508. }
  509.  
  510. int field_addr_to_index(cp)
  511.   CELL *cp ;
  512. { CELL **p = fbank ;
  513.  
  514.   while(
  515.  
  516. #if  LM_DOS
  517.     ! SAMESEG(cp,*p) ||
  518. #endif
  519.  
  520.      cp < *p || cp >= *p + FBANK_SZ )  p++ ;
  521.  
  522.   return  ((p-fbank)<<FB_SHIFT) + (cp - *p) ;
  523. }
  524.  
  525. /*------- more than 1 fbank needed  ------------*/
  526.  
  527. /*
  528.   compute the address of a field with index
  529.   > MAX_SPLIT
  530. */
  531.  
  532. CELL *slow_field_ptr(i)
  533.   register int i ;
  534. {
  535.  
  536.   if ( i > max_field )
  537.   { int j ;
  538.  
  539.     if ( i > MAX_FIELD )
  540.         rt_overflow("maximum number of fields", MAX_FIELD) ;
  541.  
  542.     j = 1 ; while( fbank[j] )  j++ ;
  543.     do
  544.     {
  545.       fbank[j] = (CELL*)zmalloc(sizeof(CELL)*FBANK_SZ) ;
  546.       (void) memset(fbank[j], 0, SIZE_T(sizeof(CELL)*FBANK_SZ)) ;
  547.       j++ ;  
  548.       max_field += FBANK_SZ ;
  549.     }
  550.     while ( i > max_field ) ;
  551.   }
  552.  
  553.   return  & fbank[i>>FB_SHIFT][i & (FBANK_SZ-1)] ;
  554. }
  555.  
  556. /*
  557.   $0 split into more than MAX_SPLIT fields, 
  558.   $(MAX_FIELD+1) ... are on the split_ov_list.
  559.   Copy into fields which start at fbank[1]
  560. */
  561.  
  562. static void  load_field_ov()
  563. {
  564.   register SPLIT_OV *p ;  /* walks split_ov_list */
  565.   register CELL *cp ;  /* target of copy */
  566.   int j ;  /* current fbank[] */
  567.   CELL *cp_limit ;  /* change fbank[] */
  568.   SPLIT_OV *q ;    /* trails p */
  569.  
  570.   /* make sure the fields are allocated */
  571.   (void) slow_field_ptr(nf) ;
  572.  
  573.   p = split_ov_list ; split_ov_list = (SPLIT_OV*) 0 ;
  574.   j = 1 ; cp = fbank[j] ; cp_limit = cp + FBANK_SZ ;
  575.  
  576.   while ( p )
  577.   {
  578.     cell_destroy(cp) ;
  579.     cp->type = C_MBSTRN ;
  580.     cp->ptr = (PTR) p->sval ;
  581.  
  582.     if ( ++cp == cp_limit )
  583.     {
  584.       cp = fbank[++j] ; cp_limit = cp + FBANK_SZ ;
  585.     }
  586.  
  587.     q = p ; p = p->link ; ZFREE(q) ;
  588.   }
  589. }
  590.  
  591.  
  592. #if  MSDOS 
  593.  
  594. int binmode()  /* read current value of BINMODE */
  595. { CELL c ;
  596.   
  597.   cast1_to_d(cellcpy(&c, BINMODE)) ;
  598.   return  d_to_i(c.dval) ;
  599. }
  600.  
  601. /* set BINMODE and RS and ORS 
  602.    from environment or -W binmode=   */
  603.  
  604. void  set_binmode(x)
  605.   int x ;
  606. {
  607.   CELL c ;
  608.  
  609.   /* set RS */
  610.   c.type = C_STRING ;
  611.   c.ptr = (PTR) new_STRING ( (x&1) ? "\r\n" : "\n" ) ;
  612.   field_assign(RS, &c) ;
  613.   free_STRING(string(&c)) ;
  614.  
  615.   /* set ORS */
  616.   cell_destroy(ORS) ;
  617.   ORS->type = C_STRING ;
  618.   ORS->ptr = (PTR) new_STRING( (x&2) ? "\r\n" : "\n") ;
  619.  
  620.   cell_destroy(BINMODE) ;
  621.   BINMODE->type = C_DOUBLE ;
  622.   BINMODE->dval = (double) x ;
  623. }
  624.  
  625. #endif /* MSDOS */
  626.  
  627.  
  628.