Main Page | Class List | Directories | File List | Class Members | File Members

array.c File Reference

#include "awk.h"

Go to the source code of this file.

Defines

#define MAX_LEN   0
#define HASHC

Typedefs

typedef enum asort_how ASORT_TYPE

Enumerations

enum  asort_how { VALUE, INDEX }

Functions

static NODE *assoc_find P ((NODE *symbol, NODE *subs, int hash1))
void array_init ()
NODEget_actual (NODE *symbol, int canfatal)
char * array_vname (register const NODE *symbol)
NODEconcat_exp (register NODE *tree)
void assoc_clear (NODE *symbol)
static unsigned long awk_hash (register const char *s, register size_t len, unsigned long hsize)
static NODEassoc_find (NODE *symbol, register NODE *subs, int hash1)
NODEin_array (NODE *symbol, NODE *subs)
NODE ** assoc_lookup (NODE *symbol, NODE *subs, int reference)
void do_delete (NODE *sym, NODE *tree)
void do_delete_loop (NODE *symbol, NODE *tree)
static void grow_table (NODE *symbol)
static void pr_node (NODE *n)
NODEassoc_dump (NODE *symbol)
NODEdo_adump (NODE *tree)
static void dup_table (NODE *symbol, NODE *newsymb)
static NODEmerge (NODE *left, NODE *right)
static NODEmerge_sort (NODE *left, int size)
static void assoc_from_list (NODE *symbol, NODE *list)
static NODEassoc_sort_inplace (NODE *symbol, ASORT_TYPE how)
static NODEasort_actual (NODE *tree, ASORT_TYPE how)
NODEdo_asort (NODE *tree)
NODEdo_asorti (NODE *tree)
static unsigned long gst_hash_string (const char *str, size_t len, unsigned long hsize)
static unsigned long scramble (unsigned long x)

Variables

static int AVG_CHAIN_MAX = 2


Define Documentation

#define HASHC
 

Value:

htmp = (h << 6);  \
                h = *s++ + htmp + (htmp << 10) - h

Referenced by awk_hash().

#define MAX_LEN   0
 

Definition at line 134 of file array.c.

Referenced by array_vname().


Typedef Documentation

typedef enum asort_how ASORT_TYPE
 


Enumeration Type Documentation

enum asort_how
 

Enumerator:
VALUE 
INDEX 

Definition at line 999 of file array.c.

00999 { VALUE, INDEX } ASORT_TYPE;


Function Documentation

void array_init  ) 
 

Definition at line 57 of file array.c.

References AVG_CHAIN_MAX, getenv, gst_hash_string(), ISDIGIT, and NULL.

Referenced by main().

00058 {
00059         const char *val;
00060         int newval;
00061 
00062         if ((val = getenv("AVG_CHAIN_MAX")) != NULL && ISDIGIT(*val)) {
00063                 for (newval = 0; *val && ISDIGIT(*val); val++)
00064                         newval = (newval * 10) + *val - '0';
00065 
00066                 AVG_CHAIN_MAX = newval;
00067         }
00068 
00069         if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
00070                 hash = gst_hash_string; 
00071 }

char* array_vname register const NODE symbol  ) 
 

Definition at line 137 of file array.c.

References _, emalloc, erealloc, len, MAX_LEN, n, Node_array_ref, Node_param_list, Node_var_array, NULL, and stack_ptr.

Referenced by assoc_lookup(), do_delete(), interpret(), r_get_lhs(), and r_tree_eval().

00138 {
00139         if (symbol->type == Node_param_list)
00140                 symbol = stack_ptr[symbol->param_cnt];
00141 
00142         if (symbol->type != Node_array_ref || symbol->orig_array->type != Node_var_array)
00143                 return symbol->vname;
00144         else {
00145                 static char *message = NULL;
00146                 static size_t msglen = 0;
00147                 char *s;
00148                 size_t len;
00149                 int n;
00150                 const NODE *save_symbol = symbol;
00151                 const char *from = _("from %s");
00152 
00153 #if (MAX_LEN <= 0) || !defined(HAVE_SNPRINTF)
00154                 /* This is the default branch. */
00155 
00156                 /* First, we have to compute the length of the string: */
00157                 len = strlen(symbol->vname) + 2;        /* "%s (" */
00158                 n = 0;
00159                 do {
00160                         symbol = symbol->prev_array;
00161                         len += strlen(symbol->vname);
00162                         n++;
00163                 } while (symbol->type == Node_array_ref);
00164                 /*
00165                  * Each node contributes by strlen(from) minus the length
00166                  * of "%s" in the translation (which is at least 2)
00167                  * plus 2 for ", " or ")\0"; this adds up to strlen(from).
00168                  */
00169                 len += n * strlen(from);
00170 
00171                 /* (Re)allocate memory: */
00172                 if (message == NULL) {
00173                         emalloc(message, char *, len, "array_vname");
00174                         msglen = len;
00175                 } else if (len > msglen) {
00176                         erealloc(message, char *, len, "array_vname");
00177                         msglen = len;
00178                 } /* else
00179                         current buffer can hold new name */
00180 
00181                 /* We're ready to print: */
00182                 symbol = save_symbol;
00183                 s = message;
00184                 /*
00185                  * Ancient systems have sprintf() returning char *, not int.
00186                  * Thus, `s += sprintf(s, from, name);' is a no-no.
00187                  */
00188                 sprintf(s, "%s (", symbol->vname);
00189                 s += strlen(s);
00190                 for (;;) {
00191                         symbol = symbol->prev_array;
00192                         sprintf(s, from, symbol->vname);
00193                         s += strlen(s);
00194                         if (symbol->type != Node_array_ref)
00195                                 break;
00196                         sprintf(s, ", ");
00197                         s += strlen(s);
00198                 }
00199                 sprintf(s, ")");
00200 
00201 #else /* MAX_LEN > 0 */
00202 
00203                 /*
00204                  * The following check fails only on
00205                  * abnormally_long_variable_name.
00206                  */
00207 #define PRINT_CHECK \
00208                 if (n <= 0 || n >= len) \
00209                         return save_symbol->vname; \
00210                 s += n; len -= n
00211 #define PRINT(str) \
00212                 n = snprintf(s, len, str); \
00213                 PRINT_CHECK
00214 #define PRINT_vname(str) \
00215                 n = snprintf(s, len, str, symbol->vname); \
00216                 PRINT_CHECK
00217 
00218                 if (message == NULL)
00219                         emalloc(message, char *, MAX_LEN, "array_vname");
00220 
00221                 s = message;
00222                 len = MAX_LEN;
00223 
00224                 /* First, print the vname of the node. */
00225                 PRINT_vname("%s (");
00226 
00227                 for (;;) {
00228                         symbol = symbol->prev_array;
00229                         /*
00230                          * When we don't have enough space and this is not
00231                          * the last node, shorten the list.
00232                          */
00233                         if (len < 40 && symbol->type == Node_array_ref) {
00234                                 PRINT("..., ");
00235                                 symbol = symbol->orig_array;
00236                         }
00237                         PRINT_vname(from);
00238                         if (symbol->type != Node_array_ref)
00239                                 break;
00240                         PRINT(", ");
00241                 }
00242                 PRINT(")");
00243 
00244 #undef PRINT_CHECK
00245 #undef PRINT
00246 #undef PRINT_vname
00247 #endif /* MAX_LEN <= 0 */
00248 
00249                 return message;
00250         }
00251 }

static NODE* asort_actual NODE tree,
ASORT_TYPE  how
[static]
 

Definition at line 1099 of file array.c.

References assoc_clear(), assoc_sort_inplace(), dup_table(), get_array, and NULL.

Referenced by do_asort(), and do_asorti().

01100 {
01101         NODE *array = get_array(tree->lnode);
01102 
01103         if (tree->rnode != NULL) {  /* 2nd optional arg */
01104                 NODE *dest = get_array(tree->rnode->lnode);
01105 
01106                 assoc_clear(dest);
01107                 dup_table(array, dest);
01108                 array = dest;
01109         }
01110 
01111         return assoc_sort_inplace(array, how);
01112 }

void assoc_clear NODE symbol  ) 
 

Definition at line 303 of file array.c.

References array_size, ARRAYMAXED, exp_node::flags, free(), i, NULL, and unref().

Referenced by asort_actual(), do_delete(), do_delete_loop(), do_match(), do_mkarray(), do_split(), do_stat(), pop_fcall(), and release_all_vars().

00304 {
00305         int i;
00306         NODE *bucket, *next;
00307 
00308         if (symbol->var_array == NULL)
00309                 return;
00310         for (i = 0; i < symbol->array_size; i++) {
00311                 for (bucket = symbol->var_array[i]; bucket != NULL; bucket = next) {
00312                         next = bucket->ahnext;
00313                         unref(bucket->ahvalue);
00314                         unref(bucket);  /* unref() will free the ahname_str */
00315                 }
00316                 symbol->var_array[i] = NULL;
00317         }
00318         free(symbol->var_array);
00319         symbol->var_array = NULL;
00320         symbol->array_size = symbol->table_size = 0;
00321         symbol->flags &= ~ARRAYMAXED;
00322 }

NODE* assoc_dump NODE symbol  ) 
 

Definition at line 763 of file array.c.

References _, array_size, AWKNUM, i, NULL, pr_node(), and tmp_number.

Referenced by do_adump().

00764 {
00765         int i;
00766         NODE *bucket;
00767 
00768         if (symbol->var_array == NULL) {
00769                 printf(_("%s: empty (null)\n"), symbol->vname);
00770                 return tmp_number((AWKNUM) 0);
00771         }
00772 
00773         if (symbol->table_size == 0) {
00774                 printf(_("%s: empty (zero)\n"), symbol->vname);
00775                 return tmp_number((AWKNUM) 0);
00776         }
00777 
00778         printf(_("%s: table_size = %d, array_size = %d\n"), symbol->vname,
00779                         (int) symbol->table_size, (int) symbol->array_size);
00780 
00781         for (i = 0; i < symbol->array_size; i++) {
00782                 for (bucket = symbol->var_array[i]; bucket != NULL;
00783                                 bucket = bucket->ahnext) {
00784                         printf("%s: I: [len %d <%.*s>] V: [",
00785                                 symbol->vname,
00786                                 (int) bucket->ahname_len,
00787                                 (int) bucket->ahname_len,
00788                                 bucket->ahname_str);
00789                         pr_node(bucket->ahvalue);
00790                         printf("]\n");
00791                 }
00792         }
00793 
00794         return tmp_number((AWKNUM) 0);
00795 }

static NODE* assoc_find NODE symbol,
register NODE subs,
int  hash1
[static]
 

Definition at line 414 of file array.c.

References NULL, and STREQN.

Referenced by assoc_lookup(), and in_array().

00415 {
00416         register NODE *bucket;
00417         const char *s1_str;
00418         size_t s1_len;
00419         NODE *s2;
00420 
00421         for (bucket = symbol->var_array[hash1]; bucket != NULL;
00422                         bucket = bucket->ahnext) {
00423                 /*
00424                  * This used to use cmp_nodes() here.  That's wrong.
00425                  * Array indexes are strings; compare as such, always!
00426                  */
00427                 s1_str = bucket->ahname_str;
00428                 s1_len = bucket->ahname_len;
00429                 s2 = subs;
00430 
00431                 if (s1_len == s2->stlen) {
00432                         if (s1_len == 0         /* "" is a valid index */
00433                             || STREQN(s1_str, s2->stptr, s1_len))
00434                                 return bucket;
00435                 }
00436         }
00437         return NULL;
00438 }

static void assoc_from_list NODE symbol,
NODE list
[static]
 

Definition at line 965 of file array.c.

References emalloc, i, and NULL.

Referenced by assoc_sort_inplace().

00966 {
00967         NODE *next;
00968         unsigned long i = 0;
00969         register int hash1;
00970         char buf[100];
00971 
00972         for (; list != NULL; list = next) {
00973                 next = list->ahnext;
00974 
00975                 /* make an int out of i++ */
00976                 i++;
00977                 sprintf(buf, "%lu", i);
00978                 assert(list->ahname_str == NULL);
00979                 assert(list->ahname_ref == 1);
00980                 emalloc(list->ahname_str, char *, strlen(buf) + 2, "assoc_from_list");
00981                 list->ahname_len = strlen(buf);
00982                 strcpy(list->ahname_str, buf);
00983 
00984                 /* find the bucket where it belongs */
00985                 hash1 = hash(list->ahname_str, list->ahname_len,
00986                                 symbol->array_size);
00987 
00988                 /* link the node into the chain at that bucket */
00989                 list->ahnext = symbol->var_array[hash1];
00990                 symbol->var_array[hash1] = list;
00991         }
00992 }

NODE** assoc_lookup NODE symbol,
NODE subs,
int  reference
 

Definition at line 479 of file array.c.

References _, array_vname(), ARRAYMAXED, assoc_find(), AVG_CHAIN_MAX, do_lint, emalloc, exp_node::flags, force_string, free_temp, getnode, grow_table(), lintwarn, MALLOC, memcpy, Nnull_string, Node_ahash, Node_var_array, NULL, and exp_node::type.

Referenced by do_fork(), do_match(), do_mkarray(), do_stat(), init_args(), load_environ(), load_procinfo(), nextfile(), r_get_lhs(), set_element(), and update_PROCINFO().

00480 {
00481         register int hash1;
00482         register NODE *bucket;
00483 
00484         assert(symbol->type == Node_var_array);
00485 
00486         (void) force_string(subs);
00487 
00488         if (symbol->var_array == NULL) {
00489                 symbol->array_size = symbol->table_size = 0;    /* sanity */
00490                 symbol->flags &= ~ARRAYMAXED;
00491                 grow_table(symbol);
00492                 hash1 = hash(subs->stptr, subs->stlen,
00493                                 (unsigned long) symbol->array_size);
00494         } else {
00495                 hash1 = hash(subs->stptr, subs->stlen,
00496                                 (unsigned long) symbol->array_size);
00497                 bucket = assoc_find(symbol, subs, hash1);
00498                 if (bucket != NULL) {
00499                         free_temp(subs);
00500                         return &(bucket->ahvalue);
00501                 }
00502         }
00503 
00504         if (do_lint && reference) {
00505                 subs->stptr[subs->stlen] = '\0';
00506                 lintwarn(_("reference to uninitialized element `%s[\"%s\"]'"),
00507                       array_vname(symbol), subs->stptr);
00508         }
00509 
00510         /* It's not there, install it. */
00511         if (do_lint && subs->stlen == 0)
00512                 lintwarn(_("subscript of array `%s' is null string"),
00513                         array_vname(symbol));
00514 
00515         /* first see if we would need to grow the array, before installing */
00516         symbol->table_size++;
00517         if ((symbol->flags & ARRAYMAXED) == 0
00518             && (symbol->table_size / symbol->array_size) > AVG_CHAIN_MAX) {
00519                 grow_table(symbol);
00520                 /* have to recompute hash value for new size */
00521                 hash1 = hash(subs->stptr, subs->stlen,
00522                                 (unsigned long) symbol->array_size);
00523         }
00524 
00525         getnode(bucket);
00526         bucket->type = Node_ahash;
00527 
00528         /*
00529          * Freeze this string value --- it must never
00530          * change, no matter what happens to the value
00531          * that created it or to CONVFMT, etc.
00532          *
00533          * One day: Use an atom table to track array indices,
00534          * and avoid the extra memory overhead.
00535          */
00536         bucket->flags |= MALLOC;
00537         bucket->ahname_ref = 1;
00538         emalloc(bucket->ahname_str, char *, subs->stlen + 2, "assoc_lookup");
00539         bucket->ahname_len = subs->stlen;
00540 
00541         memcpy(bucket->ahname_str, subs->stptr, subs->stlen);
00542         bucket->ahname_str[bucket->ahname_len] = '\0';
00543 
00544         free_temp(subs);
00545 
00546         bucket->ahvalue = Nnull_string;
00547         bucket->ahnext = symbol->var_array[hash1];
00548         symbol->var_array[hash1] = bucket;
00549         return &(bucket->ahvalue);
00550 }

static NODE* assoc_sort_inplace NODE symbol,
ASORT_TYPE  how
[static]
 

Definition at line 1002 of file array.c.

References ALREADY_MALLOCED, array_size, assoc_from_list(), AWKNUM, exp_node::flags, free(), getnode, i, make_str_node(), make_string, MALLOC, merge_sort(), NULL, tmp_number, unref(), and VALUE.

Referenced by asort_actual().

01003 {
01004         int i, num;
01005         NODE *bucket, *next, *list;
01006 
01007         if (symbol->var_array == NULL
01008             || symbol->array_size <= 0
01009             || symbol->table_size <= 0)
01010                 return tmp_number((AWKNUM) 0);
01011 
01012         /* build a linked list out of all the entries in the table */
01013         if (how == VALUE) {
01014                 list = NULL;
01015                 num = 0;
01016                 for (i = 0; i < symbol->array_size; i++) {
01017                         for (bucket = symbol->var_array[i]; bucket != NULL; bucket = next) {
01018                                 next = bucket->ahnext;
01019                                 if (bucket->ahname_ref == 1) {
01020                                         free(bucket->ahname_str);
01021                                         bucket->ahname_str = NULL;
01022                                         bucket->ahname_len = 0;
01023                                 } else {
01024                                         NODE *r;
01025 
01026                                         getnode(r);
01027                                         *r = *bucket;
01028                                         unref(bucket);
01029                                         bucket = r;
01030                                         bucket->flags |= MALLOC;
01031                                         bucket->ahname_ref = 1;
01032                                         bucket->ahname_str = NULL;
01033                                         bucket->ahname_len = 0;
01034                                 }
01035                                 bucket->ahnext = list;
01036                                 list = bucket;
01037                                 num++;
01038                         }
01039                         symbol->var_array[i] = NULL;
01040                 }
01041         } else {        /* how == INDEX */
01042                 list = NULL;
01043                 num = 0;
01044                 for (i = 0; i < symbol->array_size; i++) {
01045                         for (bucket = symbol->var_array[i]; bucket != NULL; bucket = next) {
01046                                 next = bucket->ahnext;
01047 
01048                                 /* toss old value */
01049                                 unref(bucket->ahvalue);
01050 
01051                                 /* move index into value */
01052                                 if (bucket->ahname_ref == 1) {
01053                                         bucket->ahvalue = make_str_node(bucket->ahname_str,
01054                                                                 bucket->ahname_len, ALREADY_MALLOCED);
01055                                         bucket->ahname_str = NULL;
01056                                         bucket->ahname_len = 0;
01057                                 } else {
01058                                         NODE *r;
01059 
01060                                         bucket->ahvalue = make_string(bucket->ahname_str, bucket->ahname_len);
01061                                         getnode(r);
01062                                         *r = *bucket;
01063                                         unref(bucket);
01064                                         bucket = r;
01065                                         bucket->flags |= MALLOC;
01066                                         bucket->ahname_ref = 1;
01067                                         bucket->ahname_str = NULL;
01068                                         bucket->ahname_len = 0;
01069                                 }
01070 
01071                                 bucket->ahnext = list;
01072                                 list = bucket;
01073                                 num++;
01074                         }
01075                         symbol->var_array[i] = NULL;
01076                 }
01077         }
01078 
01079         /*
01080          * Sort the linked list of NODEs.
01081          * (The especially nice thing about using a merge sort here is that
01082          * we require absolutely no additional storage. This is handy if the
01083          * array has grown to be very large.)
01084          */
01085         list = merge_sort(list, num);
01086 
01087         /*
01088          * now repopulate the original array, using increasing
01089          * integers as the key
01090          */
01091         assoc_from_list(symbol, list);
01092 
01093         return tmp_number((AWKNUM) num);
01094 }

static unsigned long awk_hash register const char *  s,
register size_t  len,
unsigned long  hsize
[static]
 

Definition at line 327 of file array.c.

References HASHC.

00328 {
00329         register unsigned long h = 0;
00330 
00331         /*
00332          * This is INCREDIBLY ugly, but fast.  We break the string up into
00333          * 8 byte units.  On the first time through the loop we get the
00334          * "leftover bytes" (strlen % 8).  On every other iteration, we
00335          * perform 8 HASHC's so we handle all 8 bytes.  Essentially, this
00336          * saves us 7 cmp & branch instructions.  If this routine is
00337          * heavily used enough, it's worth the ugly coding.
00338          *
00339          * OZ's original sdbm hash, copied from Margo Seltzers db package.
00340          */
00341 
00342         /*
00343          * Even more speed:
00344          * #define HASHC   h = *s++ + 65599 * h
00345          * Because 65599 = pow(2, 6) + pow(2, 16) - 1 we multiply by shifts
00346          */
00347 #define HASHC   htmp = (h << 6);  \
00348                 h = *s++ + htmp + (htmp << 10) - h
00349 
00350         unsigned long htmp;
00351 
00352         h = 0;
00353 
00354 #if defined(VAXC)
00355         /*      
00356          * This was an implementation of "Duff's Device", but it has been
00357          * redone, separating the switch for extra iterations from the
00358          * loop. This is necessary because the DEC VAX-C compiler is
00359          * STOOPID.
00360          */
00361         switch (len & (8 - 1)) {
00362         case 7:         HASHC;
00363         case 6:         HASHC;
00364         case 5:         HASHC;
00365         case 4:         HASHC;
00366         case 3:         HASHC;
00367         case 2:         HASHC;
00368         case 1:         HASHC;
00369         default:        break;
00370         }
00371 
00372         if (len > (8 - 1)) {
00373                 register size_t loop = len >> 3;
00374                 do {
00375                         HASHC;
00376                         HASHC;
00377                         HASHC;
00378                         HASHC;
00379                         HASHC;
00380                         HASHC;
00381                         HASHC;
00382                         HASHC;
00383                 } while (--loop);
00384         }
00385 #else /* ! VAXC */
00386         /* "Duff's Device" for those who can handle it */
00387         if (len > 0) {
00388                 register size_t loop = (len + 8 - 1) >> 3;
00389 
00390                 switch (len & (8 - 1)) {
00391                 case 0:
00392                         do {    /* All fall throughs */
00393                                 HASHC;
00394                 case 7:         HASHC;
00395                 case 6:         HASHC;
00396                 case 5:         HASHC;
00397                 case 4:         HASHC;
00398                 case 3:         HASHC;
00399                 case 2:         HASHC;
00400                 case 1:         HASHC;
00401                         } while (--loop);
00402                 }
00403         }
00404 #endif /* ! VAXC */
00405 
00406         if (h >= hsize)
00407                 h %= hsize;
00408         return h;
00409 }

NODE* concat_exp register NODE tree  ) 
 

Definition at line 257 of file array.c.

References ALREADY_MALLOCED, emalloc, erealloc, exp_node::flags, force_string, free_temp, len, make_str_node(), memcpy, Node_expression_list, NULL, SUBSEP_node, TEMP, and tree_eval.

Referenced by do_delete(), in_array(), and r_get_lhs().

00258 {
00259         register NODE *r;
00260         char *str;
00261         char *s;
00262         size_t len;
00263         int offset;
00264         size_t subseplen;
00265         const char *subsep;
00266 
00267         if (tree->type != Node_expression_list)
00268                 return force_string(tree_eval(tree));
00269         r = force_string(tree_eval(tree->lnode));
00270         if (tree->rnode == NULL)
00271                 return r;
00272         subseplen = SUBSEP_node->var_value->stlen;
00273         subsep = SUBSEP_node->var_value->stptr;
00274         len = r->stlen + subseplen + 2;
00275         emalloc(str, char *, len, "concat_exp");
00276         memcpy(str, r->stptr, r->stlen+1);
00277         s = str + r->stlen;
00278         free_temp(r);
00279         for (tree = tree->rnode; tree != NULL; tree = tree->rnode) {
00280                 if (subseplen == 1)
00281                         *s++ = *subsep;
00282                 else {
00283                         memcpy(s, subsep, subseplen+1);
00284                         s += subseplen;
00285                 }
00286                 r = force_string(tree_eval(tree->lnode));
00287                 len += r->stlen + subseplen;
00288                 offset = s - str;
00289                 erealloc(str, char *, len, "concat_exp");
00290                 s = str + offset;
00291                 memcpy(s, r->stptr, r->stlen+1);
00292                 s += r->stlen;
00293                 free_temp(r);
00294         }
00295         r = make_str_node(str, s - str, ALREADY_MALLOCED);
00296         r->flags |= TEMP;
00297         return r;
00298 }

NODE* do_adump NODE tree  ) 
 

Definition at line 800 of file array.c.

References _, assoc_dump(), Node_array_ref, Node_param_list, stack_ptr, and exp_node::type.

00801 {
00802         NODE *r, *a;
00803 
00804         a = tree->lnode;
00805 
00806         if (a->type == Node_param_list) {
00807                 printf(_("%s: is parameter\n"), a->vname);
00808                 a = stack_ptr[a->param_cnt];
00809         }
00810 
00811         if (a->type == Node_array_ref) {
00812                 printf(_("%s: array_ref to %s\n"), a->vname,
00813                                         a->orig_array->vname);
00814                 a = a->orig_array;
00815         }
00816 
00817         r = assoc_dump(a);
00818 
00819         return r;
00820 }

NODE* do_asort NODE tree  ) 
 

Definition at line 1117 of file array.c.

References asort_actual(), and VALUE.

01118 {
01119         return asort_actual(tree, VALUE);
01120 }

NODE* do_asorti NODE tree  ) 
 

Definition at line 1125 of file array.c.

References asort_actual(), and INDEX.

01126 {
01127         return asort_actual(tree, INDEX);
01128 }

void do_delete NODE sym,
NODE tree
 

Definition at line 560 of file array.c.

References _, array_vname(), ARRAYMAXED, assoc_clear(), concat_exp(), do_lint, exp_node::flags, free(), free_temp, get_array, lintwarn, memset(), NULL, STREQN, and unref().

Referenced by interpret().

00561 {
00562         register int hash1;
00563         register NODE *bucket, *last;
00564         NODE *subs;
00565         register NODE *symbol = get_array(sym);
00566 
00567         if (tree == NULL) {     /* delete array */
00568                 assoc_clear(symbol);
00569                 return;
00570         }
00571 
00572         last = NULL;    /* shut up gcc -Wall */
00573         hash1 = 0;      /* ditto */
00574 
00575         /*
00576          * Always evaluate subscript, it could have side effects.
00577          */
00578         subs = concat_exp(tree);        /* concat_exp returns string node */
00579 
00580         if (symbol->var_array != NULL) {
00581                 hash1 = hash(subs->stptr, subs->stlen,
00582                                 (unsigned long) symbol->array_size);
00583                 last = NULL;
00584                 for (bucket = symbol->var_array[hash1]; bucket != NULL;
00585                                 last = bucket, bucket = bucket->ahnext) {
00586                         /*
00587                          * This used to use cmp_nodes() here.  That's wrong.
00588                          * Array indexes are strings; compare as such, always!
00589                          */
00590                         const char *s1_str;
00591                         size_t s1_len;
00592                         NODE *s2;
00593 
00594                         s1_str = bucket->ahname_str;
00595                         s1_len = bucket->ahname_len;
00596                         s2 = subs;
00597         
00598                         if (s1_len == s2->stlen) {
00599                                 if (s1_len == 0         /* "" is a valid index */
00600                                     || STREQN(s1_str, s2->stptr, s1_len))
00601                                         break;
00602                         }
00603                 }
00604         } else
00605                 bucket = NULL;  /* The array is empty.  */
00606 
00607         if (bucket == NULL) {
00608                 if (do_lint)
00609                         lintwarn(_("delete: index `%s' not in array `%s'"),
00610                                 subs->stptr, array_vname(sym));
00611                 free_temp(subs);
00612                 return;
00613         }
00614 
00615         free_temp(subs);
00616 
00617         if (last != NULL)
00618                 last->ahnext = bucket->ahnext;
00619         else
00620                 symbol->var_array[hash1] = bucket->ahnext;
00621         unref(bucket->ahvalue);
00622         unref(bucket);  /* unref() will free the ahname_str */
00623         symbol->table_size--;
00624         if (symbol->table_size <= 0) {
00625                 memset(symbol->var_array, '\0',
00626                         sizeof(NODE *) * symbol->array_size);
00627                 symbol->table_size = symbol->array_size = 0;
00628                 symbol->flags &= ~ARRAYMAXED;
00629                 free((char *) symbol->var_array);
00630                 symbol->var_array = NULL;
00631         }
00632 }

void do_delete_loop NODE symbol,
NODE tree
 

Definition at line 643 of file array.c.

References array_size, assoc_clear(), FALSE, get_array, get_lhs, i, make_string, NULL, and unref().

Referenced by interpret().

00644 {
00645         size_t i;
00646         NODE **lhs;
00647         Func_ptr after_assign = NULL;
00648 
00649         symbol = get_array(symbol);
00650 
00651         if (symbol->var_array == NULL)
00652                 return;
00653 
00654         /* get first index value */
00655         for (i = 0; i < symbol->array_size; i++) {
00656                 if (symbol->var_array[i] != NULL) {
00657                         lhs = get_lhs(tree->lnode, & after_assign, FALSE);
00658                         unref(*lhs);
00659                         *lhs = make_string(symbol->var_array[i]->ahname_str,
00660                                         symbol->var_array[i]->ahname_len);
00661                         if (after_assign)
00662                                 (*after_assign)();
00663                         break;
00664                 }
00665         }
00666 
00667         /* blast the array in one shot */
00668         assoc_clear(symbol);
00669 }

static void dup_table NODE symbol,
NODE newsymb
[static]
 

Definition at line 831 of file array.c.

References dupnode, emalloc, exp_node::flags, getnode, i, MALLOC, memcpy, memset(), Node_ahash, NULL, and exp_node::type.

Referenced by asort_actual().

00832 {
00833         NODE **old, **new, *chain, *bucket;
00834         int i;
00835         unsigned long cursize;
00836 
00837         /* find the current hash size */
00838         cursize = symbol->array_size;
00839 
00840         new = NULL;
00841 
00842         /* input is a brand new hash table, so there's nothing to copy */
00843         if (symbol->var_array == NULL)
00844                 newsymb->table_size = 0;
00845         else {
00846                 /* old hash table there, dupnode stuff into a new table */
00847 
00848                 /* allocate new table */
00849                 emalloc(new, NODE **, cursize * sizeof(NODE *), "dup_table");
00850                 memset(new, '\0', cursize * sizeof(NODE *));
00851 
00852                 /* do the copying/dupnode'ing */
00853                 old = symbol->var_array;
00854                 for (i = 0; i < cursize; i++) {
00855                         if (old[i] != NULL) {
00856                                 for (chain = old[i]; chain != NULL;
00857                                                 chain = chain->ahnext) {
00858                                         /* get a node for the linked list */
00859                                         getnode(bucket);
00860                                         bucket->type = Node_ahash;
00861                                         bucket->flags |= MALLOC;
00862                                         bucket->ahname_ref = 1;
00863 
00864                                         /*
00865                                          * copy the corresponding name and
00866                                          * value from the original input list
00867                                          */
00868                                         emalloc(bucket->ahname_str, char *, chain->ahname_len + 2, "dup_table");
00869                                         bucket->ahname_len = chain->ahname_len;
00870 
00871                                         memcpy(bucket->ahname_str, chain->ahname_str, chain->ahname_len);
00872                                         bucket->ahname_str[bucket->ahname_len] = '\0';
00873 
00874                                         bucket->ahvalue = dupnode(chain->ahvalue);
00875 
00876                                         /*
00877                                          * put the node on the corresponding
00878                                          * linked list in the new table
00879                                          */
00880                                         bucket->ahnext = new[i];
00881                                         new[i] = bucket;
00882                                 }
00883                         }
00884                 }
00885                 newsymb->table_size = symbol->table_size;
00886         }
00887 
00888         newsymb->var_array = new;
00889         newsymb->array_size = cursize;
00890 }

NODE* get_actual NODE symbol,
int  canfatal
 

Definition at line 81 of file array.c.

References _, cant_happen, fatal, exp_node::flags, FUNC, Node_array_ref, Node_param_list, Node_var_array, Node_var_new, NULL, stack_ptr, and exp_node::type.

00082 {
00083         int isparam = (symbol->type == Node_param_list
00084                         && (symbol->flags & FUNC) == 0);
00085         NODE *save_symbol = symbol;
00086 
00087         if (isparam) {
00088                 save_symbol = symbol = stack_ptr[symbol->param_cnt];
00089                 if (symbol->type == Node_array_ref)
00090                         symbol = symbol->orig_array;
00091         }
00092 
00093         switch (symbol->type) {
00094         case Node_var_new:
00095                 symbol->type = Node_var_array;
00096                 symbol->var_array = NULL;
00097                 /* fall through */
00098         case Node_var_array:
00099                 break;
00100 
00101         case Node_array_ref:
00102         case Node_param_list:
00103                 if (canfatal)
00104                         cant_happen();
00105                 /* else
00106                         fall through */
00107 
00108         default:
00109                 /* notably Node_var but catches also e.g. FS[1] = "x" */
00110                 if (canfatal)
00111                         fatal(isparam ?
00112                                 _("attempt to use scalar parameter `%s' as an array") :
00113                                 _("attempt to use scalar `%s' as array"),
00114                                                                 save_symbol->vname);
00115                 else
00116                         break;
00117         }
00118 
00119         return symbol;
00120 }

static void grow_table NODE symbol  )  [static]
 

Definition at line 674 of file array.c.

References ARRAYMAXED, emalloc, exp_node::flags, free(), i, memset(), and NULL.

Referenced by assoc_lookup().

00675 {
00676         NODE **old, **new, *chain, *next;
00677         int i, j;
00678         unsigned long hash1;
00679         unsigned long oldsize, newsize;
00680         /*
00681          * This is an array of primes. We grow the table by an order of
00682          * magnitude each time (not just doubling) so that growing is a
00683          * rare operation. We expect, on average, that it won't happen
00684          * more than twice.  The final size is also chosen to be small
00685          * enough so that MS-DOG mallocs can handle it. When things are
00686          * very large (> 8K), we just double more or less, instead of
00687          * just jumping from 8K to 64K.
00688          */
00689         static const long sizes[] = { 13, 127, 1021, 8191, 16381, 32749, 65497,
00690 #if ! defined(MSDOS) && ! defined(OS2) && ! defined(atarist)
00691                                 131101, 262147, 524309, 1048583, 2097169,
00692                                 4194319, 8388617, 16777259, 33554467, 
00693                                 67108879, 134217757, 268435459, 536870923,
00694                                 1073741827
00695 #endif
00696         };
00697 
00698         /* find next biggest hash size */
00699         newsize = oldsize = symbol->array_size;
00700         for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
00701                 if (oldsize < sizes[i]) {
00702                         newsize = sizes[i];
00703                         break;
00704                 }
00705         }
00706 
00707         if (newsize == oldsize) {       /* table already at max (!) */
00708                 symbol->flags |=