2 * assoc.c - functions to manipulate associative arrays
4 * Associative arrays are standard shell hash tables.
10 /* Copyright (C) 2008,2009,2011 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;
90 /* Like assoc_insert, but returns b->data instead of freeing it */
92 assoc_replace (hash, key, value)
100 b = hash_search (key, hash, HASH_CREATE);
103 /* If we are overwriting an existing element's value, we're not going to
104 use the key. Nothing in the array assignment code path frees the key
105 string, so we can free it here to avoid a memory leak. */
109 b->data = value ? savestring (value) : (char *)0;
114 assoc_remove (hash, string)
120 b = hash_remove (string, hash, 0);
123 free ((char *)b->data);
130 assoc_reference (hash, string)
139 b = hash_search (string, hash, 0);
140 return (b ? (char *)b->data : 0);
143 /* Quote the data associated with each element of the hash table ASSOC,
144 using quote_string */
150 BUCKET_CONTENTS *tlist;
153 if (h == 0 || assoc_empty (h))
154 return ((HASH_TABLE *)NULL);
156 for (i = 0; i < h->nbuckets; i++)
157 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
159 t = quote_string ((char *)tlist->data);
167 /* Quote escape characters in the data associated with each element
168 of the hash table ASSOC, using quote_escapes */
170 assoc_quote_escapes (h)
174 BUCKET_CONTENTS *tlist;
177 if (h == 0 || assoc_empty (h))
178 return ((HASH_TABLE *)NULL);
180 for (i = 0; i < h->nbuckets; i++)
181 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
183 t = quote_escapes ((char *)tlist->data);
196 BUCKET_CONTENTS *tlist;
199 if (h == 0 || assoc_empty (h))
200 return ((HASH_TABLE *)NULL);
202 for (i = 0; i < h->nbuckets; i++)
203 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
205 t = dequote_string ((char *)tlist->data);
214 assoc_dequote_escapes (h)
218 BUCKET_CONTENTS *tlist;
221 if (h == 0 || assoc_empty (h))
222 return ((HASH_TABLE *)NULL);
224 for (i = 0; i < h->nbuckets; i++)
225 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
227 t = dequote_escapes ((char *)tlist->data);
236 assoc_remove_quoted_nulls (h)
240 BUCKET_CONTENTS *tlist;
243 if (h == 0 || assoc_empty (h))
244 return ((HASH_TABLE *)NULL);
246 for (i = 0; i < h->nbuckets; i++)
247 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
249 t = remove_quoted_nulls ((char *)tlist->data);
257 * Return a string whose elements are the members of array H beginning at
258 * the STARTth element and spanning NELEM members. Null elements are counted.
261 assoc_subrange (hash, start, nelem, starsub, quoted)
263 arrayind_t start, nelem;
266 WORD_LIST *l, *save, *h, *t;
270 if (assoc_empty (hash))
271 return ((char *)NULL);
273 save = l = assoc_to_word_list (hash);
275 return ((char *)NULL);
277 for (i = 1; l && i < start; i++)
280 return ((char *)NULL);
281 for (j = 0,h = t = l; l && j < nelem; j++)
287 t->next = (WORD_LIST *)NULL;
289 ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
294 dispose_words (save);
300 assoc_patsub (h, pat, rep, mflags)
305 BUCKET_CONTENTS *tlist;
308 char *t, *sifs, *ifs;
310 if (h == 0 || assoc_empty (h))
311 return ((char *)NULL);
314 for (i = 0; i < h2->nbuckets; i++)
315 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
317 t = pat_subst ((char *)tlist->data, pat, rep, mflags);
322 if (mflags & MATCH_QUOTED)
325 assoc_quote_escapes (h2);
327 if (mflags & MATCH_STARSUB)
329 assoc_remove_quoted_nulls (h2);
330 sifs = ifs_firstchar ((int *)NULL);
331 t = assoc_to_string (h2, sifs, 0);
334 else if (mflags & MATCH_QUOTED)
337 sifs = ifs_firstchar (&slen);
339 if (ifs == 0 || *ifs == 0)
342 sifs = xrealloc (sifs, 2);
346 t = assoc_to_string (h2, sifs, 0);
350 t = assoc_to_string (h2, " ", 0);
358 assoc_modcase (h, pat, modop, mflags)
364 BUCKET_CONTENTS *tlist;
367 char *t, *sifs, *ifs;
369 if (h == 0 || assoc_empty (h))
370 return ((char *)NULL);
373 for (i = 0; i < h2->nbuckets; i++)
374 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
376 t = sh_modcase ((char *)tlist->data, pat, modop);
381 if (mflags & MATCH_QUOTED)
384 assoc_quote_escapes (h2);
386 if (mflags & MATCH_STARSUB)
388 assoc_remove_quoted_nulls (h2);
389 sifs = ifs_firstchar ((int *)NULL);
390 t = assoc_to_string (h2, sifs, 0);
393 else if (mflags & MATCH_QUOTED)
396 sifs = ifs_firstchar (&slen);
398 if (ifs == 0 || *ifs == 0)
401 sifs = xrealloc (sifs, 2);
405 t = assoc_to_string (h2, sifs, 0);
409 t = assoc_to_string (h2, " ", 0);
417 assoc_to_assign (hash, quoted)
423 int i, rsize, rlen, elen;
424 BUCKET_CONTENTS *tlist;
426 if (hash == 0 || assoc_empty (hash))
429 ret = xmalloc (rsize = 128);
433 for (i = 0; i < hash->nbuckets; i++)
434 for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
437 if (sh_contains_shell_metas (tlist->key))
438 istr = sh_double_quote (tlist->key);
444 vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
446 elen = STRLEN (istr) + 8 + STRLEN (vstr);
447 RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
450 strcpy (ret+rlen, istr);
451 rlen += STRLEN (istr);
456 strcpy (ret + rlen, vstr);
457 rlen += STRLEN (vstr);
462 if (istr != tlist->key)
468 RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
474 vstr = sh_single_quote (ret);
483 assoc_to_word_list_internal (h, t)
489 BUCKET_CONTENTS *tlist;
492 if (h == 0 || assoc_empty (h))
493 return((WORD_LIST *)NULL);
494 list = (WORD_LIST *)NULL;
496 for (i = 0; i < h->nbuckets; i++)
497 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
499 w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
500 list = make_word_list (make_bare_word(w), list);
502 return (REVERSE_LIST(list, WORD_LIST *));
506 assoc_to_word_list (h)
509 return (assoc_to_word_list_internal (h, 0));
513 assoc_keys_to_word_list (h)
516 return (assoc_to_word_list_internal (h, 1));
520 assoc_to_string (h, sep, quoted)
525 BUCKET_CONTENTS *tlist;
527 char *result, *t, *w;
531 return ((char *)NULL);
533 return (savestring (""));
537 /* This might be better implemented directly, but it's simple to implement
538 by converting to a word list first, possibly quoting the data, then
540 for (i = 0; i < h->nbuckets; i++)
541 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
543 w = (char *)tlist->data;
546 t = quoted ? quote_string (w) : savestring (w);
547 list = make_word_list (make_bare_word(t), list);
551 l = REVERSE_LIST(list, WORD_LIST *);
553 result = l ? string_list_internal (l, sep) : savestring ("");
559 #endif /* ARRAY_VARS */