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);
80 /* If we are overwriting an existing element's value, we're not going to
81 use the key. Nothing in the array assignment code path frees the key
82 string, so we can free it here to avoid a memory leak. */
86 b->data = value ? savestring (value) : (char *)0;
91 assoc_remove (hash, string)
97 b = hash_remove (string, hash, 0);
100 free ((char *)b->data);
107 assoc_reference (hash, string)
116 b = hash_search (string, hash, 0);
117 return (b ? (char *)b->data : 0);
120 /* Quote the data associated with each element of the hash table ASSOC,
121 using quote_string */
127 BUCKET_CONTENTS *tlist;
130 if (h == 0 || assoc_empty (h))
131 return ((HASH_TABLE *)NULL);
133 for (i = 0; i < h->nbuckets; i++)
134 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
136 t = quote_string ((char *)tlist->data);
144 /* Quote escape characters in the data associated with each element
145 of the hash table ASSOC, using quote_escapes */
147 assoc_quote_escapes (h)
151 BUCKET_CONTENTS *tlist;
154 if (h == 0 || assoc_empty (h))
155 return ((HASH_TABLE *)NULL);
157 for (i = 0; i < h->nbuckets; i++)
158 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
160 t = quote_escapes ((char *)tlist->data);
173 BUCKET_CONTENTS *tlist;
176 if (h == 0 || assoc_empty (h))
177 return ((HASH_TABLE *)NULL);
179 for (i = 0; i < h->nbuckets; i++)
180 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
182 t = dequote_string ((char *)tlist->data);
191 assoc_dequote_escapes (h)
195 BUCKET_CONTENTS *tlist;
198 if (h == 0 || assoc_empty (h))
199 return ((HASH_TABLE *)NULL);
201 for (i = 0; i < h->nbuckets; i++)
202 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
204 t = dequote_escapes ((char *)tlist->data);
213 assoc_remove_quoted_nulls (h)
217 BUCKET_CONTENTS *tlist;
220 if (h == 0 || assoc_empty (h))
221 return ((HASH_TABLE *)NULL);
223 for (i = 0; i < h->nbuckets; i++)
224 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
226 t = remove_quoted_nulls ((char *)tlist->data);
234 * Return a string whose elements are the members of array H beginning at
235 * the STARTth element and spanning NELEM members. Null elements are counted.
238 assoc_subrange (hash, start, nelem, starsub, quoted)
240 arrayind_t start, nelem;
243 WORD_LIST *l, *save, *h, *t;
247 if (assoc_empty (hash))
248 return ((char *)NULL);
250 save = l = assoc_to_word_list (hash);
252 return ((char *)NULL);
254 for (i = 1; l && i < start; i++)
257 return ((char *)NULL);
258 for (j = 0,h = t = l; l && j < nelem; j++)
264 t->next = (WORD_LIST *)NULL;
266 ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
271 dispose_words (save);
277 assoc_patsub (h, pat, rep, mflags)
282 BUCKET_CONTENTS *tlist;
285 char *t, *sifs, *ifs;
287 if (h == 0 || assoc_empty (h))
288 return ((char *)NULL);
291 for (i = 0; i < h2->nbuckets; i++)
292 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
294 t = pat_subst ((char *)tlist->data, pat, rep, mflags);
299 if (mflags & MATCH_QUOTED)
302 assoc_quote_escapes (h2);
304 if (mflags & MATCH_STARSUB)
306 assoc_remove_quoted_nulls (h2);
307 sifs = ifs_firstchar ((int *)NULL);
308 t = assoc_to_string (h2, sifs, 0);
311 else if (mflags & MATCH_QUOTED)
314 sifs = ifs_firstchar (&slen);
316 if (ifs == 0 || *ifs == 0)
319 sifs = xrealloc (sifs, 2);
323 t = assoc_to_string (h2, sifs, 0);
327 t = assoc_to_string (h2, " ", 0);
335 assoc_modcase (h, pat, modop, mflags)
341 BUCKET_CONTENTS *tlist;
344 char *t, *sifs, *ifs;
346 if (h == 0 || assoc_empty (h))
347 return ((char *)NULL);
350 for (i = 0; i < h2->nbuckets; i++)
351 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
353 t = sh_modcase ((char *)tlist->data, pat, modop);
358 if (mflags & MATCH_QUOTED)
361 assoc_quote_escapes (h2);
363 if (mflags & MATCH_STARSUB)
365 assoc_remove_quoted_nulls (h2);
366 sifs = ifs_firstchar ((int *)NULL);
367 t = assoc_to_string (h2, sifs, 0);
370 else if (mflags & MATCH_QUOTED)
373 sifs = ifs_firstchar (&slen);
375 if (ifs == 0 || *ifs == 0)
378 sifs = xrealloc (sifs, 2);
382 t = assoc_to_string (h2, sifs, 0);
386 t = assoc_to_string (h2, " ", 0);
394 assoc_to_assign (hash, quoted)
400 int i, rsize, rlen, elen;
401 BUCKET_CONTENTS *tlist;
403 if (hash == 0 || assoc_empty (hash))
406 ret = xmalloc (rsize = 128);
410 for (i = 0; i < hash->nbuckets; i++)
411 for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
414 if (sh_contains_shell_metas (tlist->key))
415 istr = sh_double_quote (tlist->key);
421 vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
423 elen = STRLEN (istr) + 8 + STRLEN (vstr);
424 RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
427 strcpy (ret+rlen, istr);
428 rlen += STRLEN (istr);
433 strcpy (ret + rlen, vstr);
434 rlen += STRLEN (vstr);
439 if (istr != tlist->key)
445 RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
451 vstr = sh_single_quote (ret);
460 assoc_to_word_list_internal (h, t)
466 BUCKET_CONTENTS *tlist;
469 if (h == 0 || assoc_empty (h))
470 return((WORD_LIST *)NULL);
471 list = (WORD_LIST *)NULL;
473 for (i = 0; i < h->nbuckets; i++)
474 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
476 w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
477 list = make_word_list (make_bare_word(w), list);
479 return (REVERSE_LIST(list, WORD_LIST *));
483 assoc_to_word_list (h)
486 return (assoc_to_word_list_internal (h, 0));
490 assoc_keys_to_word_list (h)
493 return (assoc_to_word_list_internal (h, 1));
497 assoc_to_string (h, sep, quoted)
502 BUCKET_CONTENTS *tlist;
504 char *result, *t, *w;
508 return ((char *)NULL);
510 return (savestring (""));
514 /* This might be better implemented directly, but it's simple to implement
515 by converting to a word list first, possibly quoting the data, then
517 for (i = 0; i < h->nbuckets; i++)
518 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
520 w = (char *)tlist->data;
523 t = quoted ? quote_string (w) : savestring (w);
524 list = make_word_list (make_bare_word(t), list);
528 l = REVERSE_LIST(list, WORD_LIST *);
530 result = l ? string_list_internal (l, sep) : savestring ("");
534 #endif /* ARRAY_VARS */