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

  1.  
  2. /********************************************
  3. array.c
  4. copyright 1991, 1992.  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: array.c,v $
  14.  * Revision 5.3.1.1  1993/01/20  12:24:25  mike
  15.  * patch3: safer double to int conversions
  16.  *
  17.  * Revision 5.3  1992/11/28  23:48:42  mike
  18.  * For internal conversion numeric->string, when testing
  19.  * if integer, use longs instead of ints so 16 and 32 bit
  20.  * systems behave the same
  21.  *
  22.  * Revision 5.2  1992/04/07  17:17:31  brennan
  23.  * patch 2
  24.  * n = split(s,A,r)
  25.  * delete A[i] if i not in 1..n
  26.  * This is consistent with [ng]?awk
  27.  *
  28.  * Revision 5.1  91/12/05  07:55:32  brennan
  29.  * 1.1 pre-release
  30.  * 
  31. */
  32.  
  33. #include "mawk.h"
  34. #include "symtype.h"
  35. #include "memory.h"
  36. #include "field.h"
  37. #include "bi_vars.h"
  38.  
  39. /* convert doubles to string for array indexing */
  40. #define   NO_MOVE       2
  41. #define   NO_IVAL       (-1)
  42.  
  43. static ANODE *PROTO(find_by_sval, (ARRAY, STRING *, int) ) ;
  44. static ANODE *PROTO(find_by_index, (ARRAY, int,long,int) ) ;
  45. static ANODE *PROTO(find_by_dval, (ARRAY, double, int)) ;
  46. static void PROTO(load_array_ov, (ARRAY) ) ;
  47. static void PROTO(ilist_delete, (ARRAY, ANODE*)) ;
  48.  
  49.  
  50. extern unsigned hash() ;
  51.  
  52. /* An array A is a pointer to an array of struct array,
  53.    which is two hash tables in one.  One for strings
  54.    and one for non-negative integers (this is much simplier
  55.    and works just as well as previous versions)
  56.  
  57.    Each array is of size A_HASH_PRIME.
  58.  
  59.    When an index is deleted via  delete A[i], the
  60.    ANODE is not removed from the hash chain.  A[i].cp
  61.    and A[i].sval are both freed and sval is set NULL.
  62.    This method of deletion simplifies for( i in A ) loops.
  63.  
  64. */
  65.  
  66.  
  67. static  ANODE *find_by_sval(A, sval, cflag)
  68.   ARRAY  A ;
  69.   STRING *sval ;
  70.   int  cflag ; /* create if on */
  71.    char *s = sval->str ;
  72.    unsigned h = hash(s) % A_HASH_PRIME ;
  73.    register ANODE *p = A[h].link ;
  74.    ANODE *q = 0 ; /* holds first deleted ANODE */
  75.  
  76.    while ( 1 )
  77.      if ( !p )  goto not_there ;
  78.      else 
  79.      if ( p->sval )
  80.     if ( strcmp(s,p->sval->str) == 0 )  return p ;
  81.     else  p = p->link ;
  82.      else { q = p ; p = p->link ; break ; }
  83.     
  84.    while ( p )  /* q is now set */
  85.      if ( p->sval && strcmp(s,p->sval->str) == 0 )  return p ; 
  86.      else  p = p->link ;
  87.  
  88. not_there :
  89.    if ( cflag )
  90.    {
  91.        if ( q )  p = q ; /* reuse the deleted node q */
  92.        else
  93.        { p = (ANODE *)zmalloc(sizeof(ANODE)) ;
  94.          p->link = A[h].link ; A[h].link = p ;
  95.        }
  96.  
  97.        p->ival = NO_IVAL ;
  98.        p->sval = sval ;
  99.        sval->ref_cnt++ ;
  100.        p->cp = (CELL *) zmalloc(sizeof(CELL)) ;
  101.        p->cp->type = C_NOINIT ;
  102.    }
  103.    return p ;
  104. }
  105.  
  106.  
  107. /* find an array by (long) integer ival.
  108.    Caller has already computed the hash value index.
  109.    (This allows fast insertion for split())
  110. */
  111.  
  112. static ANODE  *find_by_index(A, index, ival, flag)
  113.   ARRAY  A ;
  114.   int index; 
  115.   long ival; 
  116.   int flag ;
  117. {
  118.   register ANODE *p = A[index].ilink ;
  119.   ANODE *q = 0 ; /* trails p */
  120.  
  121.   while ( p )
  122.        if ( p->ival == ival )  /* found */
  123.          if ( !q || flag == NO_MOVE )  return  p ;
  124.          else /* delete to put at front */
  125.          { q->ilink = p->ilink ; goto found ; }
  126.         
  127.        else
  128.        { q = p ; p = p->ilink ; }
  129.  
  130.    /* not there, still need to look by sval */
  131.    
  132.    { /* convert to string */
  133.      char xbuff[16] ;
  134.      STRING *sval ;
  135.      char *s = xbuff+14 ;
  136.      long x = ival ;
  137.  
  138.      xbuff[15] = 0 ;
  139.  
  140.      do { *s-- = x%10 + '0' ; x /= 10 ; } while(x) ;
  141.      sval = new_STRING(s+1) ;
  142.      p = find_by_sval(A, sval, flag) ;
  143.      free_STRING(sval) ;
  144.    }
  145.  
  146.  
  147.    if ( ! p )  return (ANODE *) 0 ;
  148.  
  149.    p->ival = ival ;
  150.  
  151. found : /* put p at front */
  152.    p->ilink = A[index].ilink ; A[index].ilink = p ;
  153.    return p ;
  154. }
  155.  
  156.  
  157. static ANODE *find_by_dval(A, d, flag)
  158.   ARRAY A ;
  159.   double d ;
  160.   int flag ;
  161. {
  162.   long lval ;
  163.   ANODE *p ;
  164.   char xbuff[260] ;
  165.   STRING *sval ;
  166.   
  167.  
  168.   lval = d_to_l(d) ;
  169.   if ( (double)lval == d ) /* integer valued */
  170.   {
  171.     if ( lval >= 0 )  
  172.     {
  173.             return 
  174.         find_by_index(A, (int)(lval%A_HASH_PRIME), lval, flag) ;
  175.     }
  176.     else
  177.     (void) sprintf(xbuff, INT_FMT, lval) ;
  178.   } 
  179.   else (void) sprintf(xbuff, string(CONVFMT)->str, d) ;
  180.  
  181.   sval = new_STRING(xbuff) ;
  182.   p = find_by_sval(A, sval, flag) ;
  183.   free_STRING(sval) ;
  184.   return p ;
  185. }
  186.  
  187.   
  188.  
  189. CELL *array_find(A, cp, create_flag)
  190.   ARRAY A ;
  191.   CELL *cp ;
  192.   int create_flag ;
  193. {
  194.   ANODE *ap ;
  195.  
  196.   switch( cp->type )
  197.   {
  198.     case C_DOUBLE :
  199.         ap = find_by_dval(A, cp->dval, create_flag) ;
  200.         break ;
  201.  
  202.     case  C_NOINIT :
  203.         ap = find_by_sval(A, &null_str, create_flag) ;
  204.         break ;
  205.  
  206.     default :
  207.         ap = find_by_sval(A, string(cp), create_flag) ;
  208.         break ;
  209.   }
  210.  
  211.   return  ap ? ap->cp : (CELL *) 0 ;
  212. }
  213.  
  214.  
  215. void  array_delete(A, cp)
  216.   ARRAY A ; CELL *cp ;
  217. {
  218.   ANODE *ap ;
  219.  
  220.   switch( cp->type )
  221.   {
  222.     case C_DOUBLE :
  223.         ap = find_by_dval(A, cp->dval, NO_CREATE) ;
  224.     /* cut the ilink */
  225.         if ( ap && ap->ival >= 0 ) /* must be at front */
  226.                 A[(int)(ap->ival%A_HASH_PRIME)].ilink = ap->ilink ;
  227.         break ;
  228.  
  229.     case  C_NOINIT :
  230.         ap = find_by_sval(A, &null_str, NO_CREATE) ;
  231.         break ;
  232.  
  233.     default :
  234.         ap = find_by_sval(A, string(cp), NO_CREATE) ;
  235.         if ( ap && ap->ival >= 0 ) ilist_delete(A, ap) ;
  236.         break ;
  237.   }
  238.  
  239.   
  240.   /* delete -- leave the empty ANODE so for(i in A)
  241.      works */
  242.   if ( ap )
  243.   { free_STRING(ap->sval) ; ap->sval = (STRING *) 0 ;
  244.     cell_destroy(ap->cp)  ; zfree(ap->cp, sizeof(CELL)) ;
  245.   }
  246. }
  247.  
  248. /* load into an array from the split_ov_list */
  249.  
  250. static void  load_array_ov(A)
  251.   ARRAY A ;
  252. {
  253.   register SPLIT_OV *p ;
  254.   register CELL *cp ;
  255.   SPLIT_OV *q ;
  256.  
  257.   int cnt = MAX_SPLIT + 1 ;
  258.   int index = (MAX_SPLIT+1) % A_HASH_PRIME ;
  259.  
  260.   p = split_ov_list ; split_ov_list = (SPLIT_OV*) 0 ;
  261.  
  262. #ifdef  DEBUG
  263.   if ( !p ) bozo("array_ov") ;
  264. #endif
  265.  
  266.   while( 1 )
  267.   {
  268.     cp = find_by_index(A, index, (long)cnt, NO_MOVE) ->cp ;
  269.     cell_destroy(cp) ;
  270.     cp->type = C_MBSTRN ;
  271.     cp->ptr = (PTR) p->sval ;
  272.  
  273.     q = p ; p = p->link ; zfree(q, sizeof(SPLIT_OV)) ;
  274.     if ( !p )  break ;
  275.  
  276.     cnt++ ;
  277.     if ( ++index == A_HASH_PRIME )  index = 0 ;
  278.   }
  279. }
  280.  
  281. /* delete an ANODE from the ilist that is known
  282.    to be there */
  283.  
  284. static  void  ilist_delete(A, d) 
  285.   ARRAY A ;
  286.   ANODE *d ;
  287. {
  288.   int index = d->ival % A_HASH_PRIME ;
  289.   register ANODE *p = A[index].ilink ;
  290.   register ANODE *q = (ANODE *) 0 ;
  291.  
  292.   while ( p != d ) { q = p ; p = p->ilink ; }
  293.  
  294.   if ( q )  q->ilink = p->ilink ;
  295.   else  A[index].ilink = p->ilink ;
  296. }
  297.  
  298.  
  299. /* this is called by bi_split()
  300.    to load strings into an array
  301. */
  302.  
  303. void  load_array( A, cnt)
  304.   ARRAY  A ;
  305.   register int cnt ;
  306. {
  307.   register CELL *cp ;
  308.   register int index ;
  309.  
  310.   { /* clear A , leaving only A[1]..A[cnt] (if exist) */
  311.     int i ;
  312.     ANODE *p ;
  313.  
  314.     for( i = 0 ; i < A_HASH_PRIME ; i++ )
  315.     {
  316.       p = A[i].link ;
  317.       while ( p )
  318.       {
  319.     if ( p->sval && (p->ival <= 0 || p->ival > cnt) )
  320.     {
  321.       if (p->ival >= 0) ilist_delete(A, p) ;
  322.  
  323.       free_STRING(p->sval) ;
  324.       p->sval = (STRING *) 0 ;
  325.       cell_destroy(p->cp) ;
  326.       ZFREE(p->cp) ;
  327.     }
  328.     p = p->link ;
  329.       }
  330.     }
  331.   }
  332.   if ( cnt > MAX_SPLIT )
  333.   {
  334.     load_array_ov(A) ;
  335.     cnt = MAX_SPLIT ;
  336.   }
  337.  
  338.   index = cnt % A_HASH_PRIME ;
  339.  
  340.   while ( cnt )
  341.   {
  342.     cp = find_by_index(A, index, (long) cnt, NO_MOVE) ->cp  ;
  343.     cell_destroy(cp) ;
  344.     cp->type = C_MBSTRN ;
  345.     cp->ptr = (PTR) split_buff[--cnt] ;
  346.  
  347.     if ( --index < 0 )  index = A_HASH_PRIME - 1 ;
  348.   }
  349. }
  350.  
  351.  
  352. /* cat together cnt elements on the eval stack to form
  353.    an array index using SUBSEP */
  354.  
  355. CELL *array_cat( sp, cnt)
  356.   register CELL *sp ;
  357.   int cnt ;
  358. { register CELL *p ;  /* walks the stack */
  359.   CELL subsep ;  /* a copy of SUBSEP */
  360.   unsigned subsep_len ;
  361.   char *subsep_str ;
  362.   unsigned total_len ; /* length of cat'ed expression */
  363.   CELL *top ;  /* sp at entry */
  364.   char *t ; /* target ptr when catting */
  365.   STRING *sval ;  /* build new STRING here */
  366.  
  367.   /* get a copy of subsep, we may need to cast */
  368.   (void) cellcpy(&subsep, SUBSEP) ;
  369.   if ( subsep.type < C_STRING ) cast1_to_s(&subsep) ;
  370.   subsep_len = string(&subsep)->len ;
  371.   subsep_str = string(&subsep)->str ;
  372.   total_len = --cnt * subsep_len ;
  373.  
  374.   top = sp ;
  375.   sp -= cnt ;
  376.   for( p = sp ; p <= top ; p++ )
  377.   {
  378.     if ( p->type < C_STRING ) cast1_to_s(p) ;
  379.     total_len += string(p)->len ;
  380.   }
  381.  
  382.   sval = new_STRING((char *)0, total_len) ;
  383.   t = sval->str ;
  384.  
  385.   /* put the pieces together */
  386.   for( p = sp ; p < top ; p++ )
  387.   { (void) memcpy(t, string(p)->str, SIZE_T(string(p)->len)) ;
  388.     (void) memcpy( t += string(p)->len, subsep_str, SIZE_T(subsep_len)) ;
  389.     t += subsep_len ;
  390.   }
  391.   /* p == top */
  392.   (void) memcpy(t, string(p)->str, SIZE_T(string(p)->len)) ;
  393.  
  394.   /* done, now cleanup */
  395.   free_STRING(string(&subsep)) ;
  396.   while ( p >= sp )  { free_STRING(string(p)) ; p-- ; }
  397.   sp->type = C_STRING ;
  398.   sp->ptr = (PTR) sval ;
  399.   return sp ;
  400. }
  401.  
  402.  
  403. /* free all memory used by an array,
  404.    only used for arrays local to a function call
  405. */
  406.  
  407. void  array_free(A)
  408.   ARRAY  A ;
  409. { register ANODE *p ;
  410.   register int i ;
  411.   ANODE *q ;
  412.  
  413.   for( i = 0 ; i < A_HASH_PRIME ; i++ )
  414.   { p = A[i].link ;
  415.     while ( p )
  416.     { /* check its not a deleted node */
  417.       if ( p->sval )
  418.       { free_STRING(p->sval) ;
  419.         cell_destroy(p->cp) ;
  420.         free_CELL(p->cp) ;
  421.       }
  422.  
  423.       q = p ; p = p->link ;
  424.       zfree( q, sizeof(ANODE)) ;
  425.     }
  426.   }
  427.  
  428.   zfree(A, sizeof(A[0]) * A_HASH_PRIME ) ;
  429. }
  430.  
  431.  
  432. int  inc_aloop_state( ap )
  433.   ALOOP_STATE *ap ;
  434. {
  435.   register ANODE *p ;
  436.   register int i ;
  437.   ARRAY  A = ap->A ;
  438.   CELL *cp ;
  439.  
  440.   if ( (i = ap->index) == -1 )  p = A[++i].link ;
  441.   else  p = ap->ptr->link ;
  442.  
  443.   while ( 1 )
  444.   {
  445.     if ( !p )
  446.     if ( ++i == A_HASH_PRIME )  return 0 ;
  447.     else
  448.     { p = A[i].link ; continue ; }
  449.  
  450.     if ( p->sval )  /* found one */
  451.     {
  452.       cp = ap->var ;
  453.       cell_destroy(cp) ;
  454.       cp->type = C_STRING ;
  455.       cp->ptr = (PTR) p->sval ;
  456.       p->sval->ref_cnt++ ;
  457.  
  458.       /* save the state */
  459.       ap->index = i ;
  460.       ap->ptr = p ;
  461.       return 1 ;
  462.     }
  463.     else /* its deleted */
  464.     p = p->link ;
  465.   }
  466. }
  467.