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 if (sh_contains_shell_metas (tlist
->key
))
410 istr
= sh_double_quote (tlist
->key
);
416 vstr
= tlist
->data
? sh_double_quote ((char *)tlist
->data
) : (char *)0;
418 elen
= STRLEN (istr
) + 8 + STRLEN (vstr
);
419 RESIZE_MALLOCED_BUFFER (ret
, rlen
, (elen
+1), rsize
, rsize
);
422 strcpy (ret
+rlen
, istr
);
423 rlen
+= STRLEN (istr
);
428 strcpy (ret
+ rlen
, vstr
);
429 rlen
+= STRLEN (vstr
);
434 if (istr
!= tlist
->key
)
440 RESIZE_MALLOCED_BUFFER (ret
, rlen
, 1, rsize
, 8);
446 vstr
= sh_single_quote (ret
);
455 assoc_to_word_list_internal (h
, t
)
461 BUCKET_CONTENTS
*tlist
;
464 if (h
== 0 || assoc_empty (h
))
465 return((WORD_LIST
*)NULL
);
466 list
= (WORD_LIST
*)NULL
;
468 for (i
= 0; i
< h
->nbuckets
; i
++)
469 for (tlist
= hash_items (i
, h
); tlist
; tlist
= tlist
->next
)
471 w
= (t
== 0) ? (char *)tlist
->data
: (char *)tlist
->key
;
472 list
= make_word_list (make_bare_word(w
), list
);
474 return (REVERSE_LIST(list
, WORD_LIST
*));
478 assoc_to_word_list (h
)
481 return (assoc_to_word_list_internal (h
, 0));
485 assoc_keys_to_word_list (h
)
488 return (assoc_to_word_list_internal (h
, 1));
492 assoc_to_string (h
, sep
, quoted
)
497 BUCKET_CONTENTS
*tlist
;
499 char *result
, *t
, *w
;
503 return ((char *)NULL
);
505 return (savestring (""));
509 /* This might be better implemented directly, but it's simple to implement
510 by converting to a word list first, possibly quoting the data, then
512 for (i
= 0; i
< h
->nbuckets
; i
++)
513 for (tlist
= hash_items (i
, h
); tlist
; tlist
= tlist
->next
)
515 w
= (char *)tlist
->data
;
518 t
= quoted
? quote_string (w
) : savestring (w
);
519 list
= make_word_list (make_bare_word(t
), list
);
523 l
= REVERSE_LIST(list
, WORD_LIST
*);
525 result
= l
? string_list_internal (l
, sep
) : savestring ("");
529 #endif /* ARRAY_VARS */