2 * assoc.c - functions to manipulate associative arrays
4 * Associative arrays are standard shell hash tables.
10 /* Copyright (C) 2008,2009 Free Software Foundation, Inc.
12 This file is part of GNU Bash, the Bourne Again SHell.
14 Bash is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
19 Bash is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with Bash. If not, see <http://www.gnu.org/licenses/>.
30 #if defined (ARRAY_VARS)
32 #if defined (HAVE_UNISTD_H)
34 # include <sys/types.h>
45 #include "builtins/common.h"
47 static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
49 /* assoc_create == hash_create */
70 assoc_insert (hash, key, value)
77 b = hash_search (key, hash, HASH_CREATE);
81 b->data = value ? savestring (value) : (char *)0;
86 assoc_remove (hash, string)
92 b = hash_remove (string, hash, 0);
95 free ((char *)b->data);
102 assoc_reference (hash, string)
111 b = hash_search (string, hash, 0);
112 return (b ? (char *)b->data : 0);
115 /* Quote the data associated with each element of the hash table ASSOC,
116 using quote_string */
122 BUCKET_CONTENTS *tlist;
125 if (h == 0 || assoc_empty (h))
126 return ((HASH_TABLE *)NULL);
128 for (i = 0; i < h->nbuckets; i++)
129 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
131 t = quote_string ((char *)tlist->data);
139 /* Quote escape characters in the data associated with each element
140 of the hash table ASSOC, using quote_escapes */
142 assoc_quote_escapes (h)
146 BUCKET_CONTENTS *tlist;
149 if (h == 0 || assoc_empty (h))
150 return ((HASH_TABLE *)NULL);
152 for (i = 0; i < h->nbuckets; i++)
153 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
155 t = quote_escapes ((char *)tlist->data);
168 BUCKET_CONTENTS *tlist;
171 if (h == 0 || assoc_empty (h))
172 return ((HASH_TABLE *)NULL);
174 for (i = 0; i < h->nbuckets; i++)
175 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
177 t = dequote_string ((char *)tlist->data);
186 assoc_dequote_escapes (h)
190 BUCKET_CONTENTS *tlist;
193 if (h == 0 || assoc_empty (h))
194 return ((HASH_TABLE *)NULL);
196 for (i = 0; i < h->nbuckets; i++)
197 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
199 t = dequote_escapes ((char *)tlist->data);
208 assoc_remove_quoted_nulls (h)
212 BUCKET_CONTENTS *tlist;
215 if (h == 0 || assoc_empty (h))
216 return ((HASH_TABLE *)NULL);
218 for (i = 0; i < h->nbuckets; i++)
219 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
221 t = remove_quoted_nulls ((char *)tlist->data);
229 * Return a string whose elements are the members of array H beginning at
230 * the STARTth element and spanning NELEM members. Null elements are counted.
233 assoc_subrange (hash, start, nelem, starsub, quoted)
235 arrayind_t start, nelem;
238 WORD_LIST *l, *save, *h, *t;
242 if (assoc_empty (hash))
243 return ((char *)NULL);
245 save = l = assoc_to_word_list (hash);
247 return ((char *)NULL);
249 for (i = 1; l && i < start; i++)
252 return ((char *)NULL);
253 for (j = 0,h = t = l; l && j < nelem; j++)
259 t->next = (WORD_LIST *)NULL;
261 ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
266 dispose_words (save);
272 assoc_patsub (h, pat, rep, mflags)
277 BUCKET_CONTENTS *tlist;
280 char *t, *sifs, *ifs;
282 if (h == 0 || assoc_empty (h))
283 return ((char *)NULL);
286 for (i = 0; i < h2->nbuckets; i++)
287 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
289 t = pat_subst ((char *)tlist->data, pat, rep, mflags);
294 if (mflags & MATCH_QUOTED)
297 assoc_quote_escapes (h2);
299 if (mflags & MATCH_STARSUB)
301 assoc_remove_quoted_nulls (h2);
302 sifs = ifs_firstchar ((int *)NULL);
303 t = assoc_to_string (h2, sifs, 0);
306 else if (mflags & MATCH_QUOTED)
309 sifs = ifs_firstchar (&slen);
311 if (ifs == 0 || *ifs == 0)
314 sifs = xrealloc (sifs, 2);
318 t = assoc_to_string (h2, sifs, 0);
322 t = assoc_to_string (h2, " ", 0);
330 assoc_modcase (h, pat, modop, mflags)
336 BUCKET_CONTENTS *tlist;
339 char *t, *sifs, *ifs;
341 if (h == 0 || assoc_empty (h))
342 return ((char *)NULL);
345 for (i = 0; i < h2->nbuckets; i++)
346 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
348 t = sh_modcase ((char *)tlist->data, pat, modop);
353 if (mflags & MATCH_QUOTED)
356 assoc_quote_escapes (h2);
358 if (mflags & MATCH_STARSUB)
360 assoc_remove_quoted_nulls (h2);
361 sifs = ifs_firstchar ((int *)NULL);
362 t = assoc_to_string (h2, sifs, 0);
365 else if (mflags & MATCH_QUOTED)
368 sifs = ifs_firstchar (&slen);
370 if (ifs == 0 || *ifs == 0)
373 sifs = xrealloc (sifs, 2);
377 t = assoc_to_string (h2, sifs, 0);
381 t = assoc_to_string (h2, " ", 0);
389 assoc_to_assign (hash, quoted)
395 int i, rsize, rlen, elen;
396 BUCKET_CONTENTS *tlist;
398 if (hash == 0 || assoc_empty (hash))
401 ret = xmalloc (rsize = 128);
405 for (i = 0; i < hash->nbuckets; i++)
406 for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
409 vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
411 elen = STRLEN (istr) + 8 + STRLEN (vstr);
412 RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
415 strcpy (ret+rlen, istr);
416 rlen += STRLEN (istr);
421 strcpy (ret + rlen, vstr);
422 rlen += STRLEN (vstr);
429 RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
435 vstr = sh_single_quote (ret);
444 assoc_to_word_list_internal (h, t)
450 BUCKET_CONTENTS *tlist;
453 if (h == 0 || assoc_empty (h))
454 return((WORD_LIST *)NULL);
455 list = (WORD_LIST *)NULL;
457 for (i = 0; i < h->nbuckets; i++)
458 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
460 w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
461 list = make_word_list (make_bare_word(w), list);
463 return (REVERSE_LIST(list, WORD_LIST *));
467 assoc_to_word_list (h)
470 return (assoc_to_word_list_internal (h, 0));
474 assoc_keys_to_word_list (h)
477 return (assoc_to_word_list_internal (h, 1));
481 assoc_to_string (h, sep, quoted)
486 BUCKET_CONTENTS *tlist;
488 char *result, *t, *w;
492 return ((char *)NULL);
494 return (savestring (""));
498 /* This might be better implemented directly, but it's simple to implement
499 by converting to a word list first, possibly quoting the data, then
501 for (i = 0; i < h->nbuckets; i++)
502 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
504 w = (char *)tlist->data;
507 t = quoted ? quote_string (w) : savestring (w);
508 list = make_word_list (make_bare_word(t), list);
512 l = REVERSE_LIST(list, WORD_LIST *);
514 result = l ? string_list_internal (l, sep) : savestring ("");
518 #endif /* ARRAY_VARS */