home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / mawk11as.zip / ARRAY.C < prev    next >
C/C++ Source or Header  |  1991-12-18  |  9KB  |  402 lines

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