/********************************************
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
* Revision 5.1 91/12/05 07:55:32 brennan
/* convert doubles to string for array indexing */
static ANODE
*PROTO(find_by_sval
, (ARRAY
, STRING
*, int) ) ;
static ANODE
*PROTO(find_by_index
, (ARRAY
, int,int,int) ) ;
static ANODE
*PROTO(find_by_dval
, (ARRAY
, double, int)) ;
static void PROTO(load_array_ov
, (ARRAY
) ) ;
/* An array A is a pointer to an array of struct array,
which is two hash tables in one. One for strings
and one for non-negative integers (this is much simplier
and works just as well as previous versions)
Each array is of size A_HASH_PRIME.
When an index is deleted via delete A[i], the
ANODE is not removed from the hash chain. A[i].cp
and A[i].sval are both freed and sval is set NULL.
This method of deletion simplifies for( i in A ) loops.
static ANODE
*find_by_sval(A
, sval
, cflag
)
int cflag
; /* create if on */
unsigned h
= hash(s
) % A_HASH_PRIME
;
register ANODE
*p
= A
[h
].link
;
ANODE
*q
= 0 ; /* holds first deleted ANODE */
{ if ( strcmp(s
,p
->sval
->str
) == 0 ) return p
; }
else /* its deleted, mark with q */
if ( q
) p
= q
; /* reuse the deleted node q */
{ p
= (ANODE
*)zmalloc(sizeof(ANODE
)) ;
p
->link
= A
[h
].link
; A
[h
].link
= p
;
p
->cp
= (CELL
*) zmalloc(sizeof(CELL
)) ;
static ANODE
*find_by_index(A
, index
, ival
, flag
)
register ANODE
*p
= A
[index
].ilink
;
ANODE
*q
= 0 ; /* trails p */
if ( p
->ival
== ival
) /* found */
if ( !q
|| flag
== NO_MOVE
) return p
;
else /* delete to put at front */
{ q
->ilink
= p
->ilink
; goto found
; }
{ q
= p
; p
= p
->ilink
; }
/* not there, still need to look by sval */
do { *s
-- = x
%10 + '0' ; x
/= 10 ; } while(x
) ;
p
= find_by_sval(A
, sval
, flag
) ;
if ( ! p
) return (ANODE
*) 0 ;
found
: /* put p at front */
p
->ilink
= A
[index
].ilink
; A
[index
].ilink
= p
;
static ANODE
*find_by_dval(A
, d
, flag
)
if ( (double)(ival
= (int)d
) == d
) /* integer valued */
return find_by_index(A
, ival
%A_HASH_PRIME
, ival
, flag
) ;
(void) sprintf(xbuff
, "%d", ival
) ;
else (void) sprintf(xbuff
, string(CONVFMT
)->str
, d
) ;
sval
= new_STRING(xbuff
) ;
p
= find_by_sval(A
, sval
, flag
) ;
CELL
*array_find(A
, cp
, create_flag
)
ap
= find_by_dval(A
, cp
->dval
, create_flag
) ;
ap
= find_by_sval(A
, &null_str
, create_flag
) ;
ap
= find_by_sval(A
, string(cp
), create_flag
) ;
return ap
? ap
->cp
: (CELL
*) 0 ;
ap
= find_by_dval(A
, cp
->dval
, NO_CREATE
) ;
if ( ap
&& ap
->ival
>= 0 ) /* must be at front */
A
[ap
->ival
%A_HASH_PRIME
].ilink
= ap
->ilink
;
ap
= find_by_sval(A
, &null_str
, NO_CREATE
) ;
ap
= find_by_sval(A
, string(cp
), NO_CREATE
) ;
if ( ap
&& ap
->ival
>= 0 )
int index
= ap
->ival
% A_HASH_PRIME
;
ap
= find_by_index(A
, index
, ap
->ival
, NO_CREATE
) ;
A
[index
].ilink
= ap
->ilink
;
{ free_STRING(ap
->sval
) ; ap
->sval
= (STRING
*) 0 ;
cell_destroy(ap
->cp
) ; zfree(ap
->cp
, sizeof(CELL
)) ;
/* load into an array from the split_ov_list */
static void load_array_ov(A
)
int cnt
= MAX_SPLIT
+ 1 ;
int index
= (MAX_SPLIT
+1) % A_HASH_PRIME
;
p
= split_ov_list
; split_ov_list
= (SPLIT_OV
*) 0 ;
if ( !p
) bozo("array_ov") ;
cp
= find_by_index(A
, index
, cnt
, NO_MOVE
) ->cp
;
cp
->ptr
= (PTR
) p
->sval
;
q
= p
; p
= p
->link
; zfree(q
, sizeof(SPLIT_OV
)) ;
if ( ++index
== A_HASH_PRIME
) index
= 0 ;
/* this is called by bi_split()
to load strings into an array
index
= cnt
% A_HASH_PRIME
;
cp
= find_by_index(A
, index
, cnt
, NO_MOVE
) ->cp
;
cp
->ptr
= (PTR
) split_buff
[--cnt
] ;
if ( --index
< 0 ) index
= A_HASH_PRIME
- 1 ;
/* cat together cnt elements on the eval stack to form
an array index using SUBSEP */
CELL
*array_cat( sp
, cnt
)
{ register CELL
*p
; /* walks the stack */
CELL subsep
; /* a copy of SUBSEP */
unsigned total_len
; /* length of cat'ed expression */
CELL
*top
; /* sp at entry */
char *t
; /* target ptr when catting */
STRING
*sval
; /* build new STRING here */
/* get a copy of subsep, we may need to cast */
(void) cellcpy(&subsep
, SUBSEP
) ;
if ( subsep
.type
< C_STRING
) cast1_to_s(&subsep
) ;
subsep_len
= string(&subsep
)->len
;
subsep_str
= string(&subsep
)->str
;
total_len
= --cnt
* subsep_len
;
for( p
= sp
; p
<= top
; p
++ )
if ( p
->type
< C_STRING
) cast1_to_s(p
) ;
total_len
+= string(p
)->len
;
sval
= new_STRING((char *)0, total_len
) ;
/* put the pieces together */
for( p
= sp
; p
< top
; p
++ )
{ (void) memcpy(t
, string(p
)->str
, SIZE_T(string(p
)->len
)) ;
(void) memcpy( t
+= string(p
)->len
, subsep_str
, SIZE_T(subsep_len
)) ;
(void) memcpy(t
, string(p
)->str
, SIZE_T(string(p
)->len
)) ;
free_STRING(string(&subsep
)) ;
while ( p
>= sp
) { free_STRING(string(p
)) ; p
-- ; }
/* free all memory used by an array,
only used for arrays local to a function call
for( i
= 0 ; i
< A_HASH_PRIME
; i
++ )
{ /* check its not a deleted node */
zfree( q
, sizeof(ANODE
)) ;
zfree(A
, sizeof(A
[0]) * A_HASH_PRIME
) ;
int inc_aloop_state( ap
)
if ( (i
= ap
->index
) == -1 ) p
= A
[++i
].link
;
if ( ++i
== A_HASH_PRIME
) return 0 ;
{ p
= A
[i
].link
; continue ; }
if ( p
->sval
) /* found one */
cp
->ptr
= (PTR
) p
->sval
;