Patch-ID: bash40-006
[bash.git] / assoc.c
blob476facb340dcd3f429f3669220dea10d6036076a
1 /*
2 * assoc.c - functions to manipulate associative arrays
4 * Associative arrays are standard shell hash tables.
6 * Chet Ramey
7 * chet@ins.cwru.edu
8 */
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/>.
28 #include "config.h"
30 #if defined (ARRAY_VARS)
32 #if defined (HAVE_UNISTD_H)
33 # ifdef _MINIX
34 # include <sys/types.h>
35 # endif
36 # include <unistd.h>
37 #endif
39 #include <stdio.h>
40 #include "bashansi.h"
42 #include "shell.h"
43 #include "array.h"
44 #include "assoc.h"
45 #include "builtins/common.h"
47 static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
49 /* assoc_create == hash_create */
51 void
52 assoc_dispose (hash)
53 HASH_TABLE *hash;
55 if (hash)
57 hash_flush (hash, 0);
58 hash_dispose (hash);
62 void
63 assoc_flush (hash)
64 HASH_TABLE *hash;
66 hash_flush (hash, 0);
69 int
70 assoc_insert (hash, key, value)
71 HASH_TABLE *hash;
72 char *key;
73 char *value;
75 BUCKET_CONTENTS *b;
77 b = hash_search (key, hash, HASH_CREATE);
78 if (b == 0)
79 return -1;
80 FREE (b->data);
81 b->data = value ? savestring (value) : (char *)0;
82 return (0);
85 void
86 assoc_remove (hash, string)
87 HASH_TABLE *hash;
88 char *string;
90 BUCKET_CONTENTS *b;
92 b = hash_remove (string, hash, 0);
93 if (b)
95 free ((char *)b->data);
96 free (b->key);
97 free (b);
101 char *
102 assoc_reference (hash, string)
103 HASH_TABLE *hash;
104 char *string;
106 BUCKET_CONTENTS *b;
108 if (hash == 0)
109 return (char *)0;
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 */
117 HASH_TABLE *
118 assoc_quote (h)
119 HASH_TABLE *h;
121 int i;
122 BUCKET_CONTENTS *tlist;
123 char *t;
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);
132 FREE (tlist->data);
133 tlist->data = t;
136 return h;
139 /* Quote escape characters in the data associated with each element
140 of the hash table ASSOC, using quote_escapes */
141 HASH_TABLE *
142 assoc_quote_escapes (h)
143 HASH_TABLE *h;
145 int i;
146 BUCKET_CONTENTS *tlist;
147 char *t;
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);
156 FREE (tlist->data);
157 tlist->data = t;
160 return h;
163 HASH_TABLE *
164 assoc_dequote (h)
165 HASH_TABLE *h;
167 int i;
168 BUCKET_CONTENTS *tlist;
169 char *t;
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);
178 FREE (tlist->data);
179 tlist->data = t;
182 return h;
185 HASH_TABLE *
186 assoc_dequote_escapes (h)
187 HASH_TABLE *h;
189 int i;
190 BUCKET_CONTENTS *tlist;
191 char *t;
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);
200 FREE (tlist->data);
201 tlist->data = t;
204 return h;
207 HASH_TABLE *
208 assoc_remove_quoted_nulls (h)
209 HASH_TABLE *h;
211 int i;
212 BUCKET_CONTENTS *tlist;
213 char *t;
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);
222 tlist->data = t;
225 return h;
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.
232 char *
233 assoc_subrange (hash, start, nelem, starsub, quoted)
234 HASH_TABLE *hash;
235 arrayind_t start, nelem;
236 int starsub, quoted;
238 WORD_LIST *l, *save, *h, *t;
239 int i, j;
240 char *ret;
242 if (assoc_empty (hash))
243 return ((char *)NULL);
245 save = l = assoc_to_word_list (hash);
246 if (save == 0)
247 return ((char *)NULL);
249 for (i = 1; l && i < start; i++)
250 l = l->next;
251 if (l == 0)
252 return ((char *)NULL);
253 for (j = 0,h = t = l; l && j < nelem; j++)
255 t = l;
256 l = l->next;
259 t->next = (WORD_LIST *)NULL;
261 ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
263 if (t != l)
264 t->next = l;
266 dispose_words (save);
267 return (ret);
271 char *
272 assoc_patsub (h, pat, rep, mflags)
273 HASH_TABLE *h;
274 char *pat, *rep;
275 int mflags;
277 BUCKET_CONTENTS *tlist;
278 int i, slen;
279 HASH_TABLE *h2;
280 char *t, *sifs, *ifs;
282 if (h == 0 || assoc_empty (h))
283 return ((char *)NULL);
285 h2 = assoc_copy (h);
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);
290 FREE (tlist->data);
291 tlist->data = t;
294 if (mflags & MATCH_QUOTED)
295 assoc_quote (h2);
296 else
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);
304 free (sifs);
306 else if (mflags & MATCH_QUOTED)
308 /* ${array[@]} */
309 sifs = ifs_firstchar (&slen);
310 ifs = getifs ();
311 if (ifs == 0 || *ifs == 0)
313 if (slen < 2)
314 sifs = xrealloc (sifs, 2);
315 sifs[0] = ' ';
316 sifs[1] = '\0';
318 t = assoc_to_string (h2, sifs, 0);
319 free(sifs);
321 else
322 t = assoc_to_string (h2, " ", 0);
324 assoc_dispose (h2);
326 return t;
329 char *
330 assoc_modcase (h, pat, modop, mflags)
331 HASH_TABLE *h;
332 char *pat;
333 int modop;
334 int mflags;
336 BUCKET_CONTENTS *tlist;
337 int i, slen;
338 HASH_TABLE *h2;
339 char *t, *sifs, *ifs;
341 if (h == 0 || assoc_empty (h))
342 return ((char *)NULL);
344 h2 = assoc_copy (h);
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);
349 FREE (tlist->data);
350 tlist->data = t;
353 if (mflags & MATCH_QUOTED)
354 assoc_quote (h2);
355 else
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);
363 free (sifs);
365 else if (mflags & MATCH_QUOTED)
367 /* ${array[@]} */
368 sifs = ifs_firstchar (&slen);
369 ifs = getifs ();
370 if (ifs == 0 || *ifs == 0)
372 if (slen < 2)
373 sifs = xrealloc (sifs, 2);
374 sifs[0] = ' ';
375 sifs[1] = '\0';
377 t = assoc_to_string (h2, sifs, 0);
378 free(sifs);
380 else
381 t = assoc_to_string (h2, " ", 0);
383 assoc_dispose (h2);
385 return t;
388 char *
389 assoc_to_assign (hash, quoted)
390 HASH_TABLE *hash;
391 int quoted;
393 char *ret;
394 char *istr, *vstr;
395 int i, rsize, rlen, elen;
396 BUCKET_CONTENTS *tlist;
398 if (hash == 0 || assoc_empty (hash))
399 return (char *)0;
401 ret = xmalloc (rsize = 128);
402 ret[0] = '(';
403 rlen = 1;
405 for (i = 0; i < hash->nbuckets; i++)
406 for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
408 istr = tlist->key;
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);
414 ret[rlen++] = '[';
415 strcpy (ret+rlen, istr);
416 rlen += STRLEN (istr);
417 ret[rlen++] = ']';
418 ret[rlen++] = '=';
419 if (vstr)
421 strcpy (ret + rlen, vstr);
422 rlen += STRLEN (vstr);
424 ret[rlen++] = ' ';
426 FREE (vstr);
429 RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
430 ret[rlen++] = ')';
431 ret[rlen] = '\0';
433 if (quoted)
435 vstr = sh_single_quote (ret);
436 free (ret);
437 ret = vstr;
440 return ret;
443 static WORD_LIST *
444 assoc_to_word_list_internal (h, t)
445 HASH_TABLE *h;
446 int t;
448 WORD_LIST *list;
449 int i;
450 BUCKET_CONTENTS *tlist;
451 char *w;
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 *));
466 WORD_LIST *
467 assoc_to_word_list (h)
468 HASH_TABLE *h;
470 return (assoc_to_word_list_internal (h, 0));
473 WORD_LIST *
474 assoc_keys_to_word_list (h)
475 HASH_TABLE *h;
477 return (assoc_to_word_list_internal (h, 1));
480 char *
481 assoc_to_string (h, sep, quoted)
482 HASH_TABLE *h;
483 char *sep;
484 int quoted;
486 BUCKET_CONTENTS *tlist;
487 int i;
488 char *result, *t, *w;
489 WORD_LIST *list, *l;
491 if (h == 0)
492 return ((char *)NULL);
493 if (assoc_empty (h))
494 return (savestring (""));
496 result = NULL;
497 list = NULL;
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
500 using list_string */
501 for (i = 0; i < h->nbuckets; i++)
502 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
504 w = (char *)tlist->data;
505 if (w == 0)
506 continue;
507 t = quoted ? quote_string (w) : savestring (w);
508 list = make_word_list (make_bare_word(t), list);
509 FREE (t);
512 l = REVERSE_LIST(list, WORD_LIST *);
514 result = l ? string_list_internal (l, sep) : savestring ("");
515 return result;
518 #endif /* ARRAY_VARS */