]> git.ipfire.org Git - thirdparty/bash.git/blame - assoc.c
Bash-4.2 patch 2
[thirdparty/bash.git] / assoc.c
CommitLineData
3185942a
JA
1/*
2 * assoc.c - functions to manipulate associative arrays
3 *
4 * Associative arrays are standard shell hash tables.
5 *
6 * Chet Ramey
7 * chet@ins.cwru.edu
8 */
9
10/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
11
12 This file is part of GNU Bash, the Bourne Again SHell.
13
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.
18
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.
23
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/>.
26*/
27
28#include "config.h"
29
30#if defined (ARRAY_VARS)
31
32#if defined (HAVE_UNISTD_H)
33# ifdef _MINIX
34# include <sys/types.h>
35# endif
36# include <unistd.h>
37#endif
38
39#include <stdio.h>
40#include "bashansi.h"
41
42#include "shell.h"
43#include "array.h"
44#include "assoc.h"
45#include "builtins/common.h"
46
47static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int));
48
49/* assoc_create == hash_create */
50
51void
52assoc_dispose (hash)
53 HASH_TABLE *hash;
54{
55 if (hash)
56 {
57 hash_flush (hash, 0);
58 hash_dispose (hash);
59 }
60}
61
62void
63assoc_flush (hash)
64 HASH_TABLE *hash;
65{
66 hash_flush (hash, 0);
67}
68
69int
70assoc_insert (hash, key, value)
71 HASH_TABLE *hash;
72 char *key;
73 char *value;
74{
75 BUCKET_CONTENTS *b;
76
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);
83}
84
85void
86assoc_remove (hash, string)
87 HASH_TABLE *hash;
88 char *string;
89{
90 BUCKET_CONTENTS *b;
91
92 b = hash_remove (string, hash, 0);
93 if (b)
94 {
95 free ((char *)b->data);
96 free (b->key);
97 free (b);
98 }
99}
100
101char *
102assoc_reference (hash, string)
103 HASH_TABLE *hash;
104 char *string;
105{
106 BUCKET_CONTENTS *b;
107
108 if (hash == 0)
109 return (char *)0;
110
111 b = hash_search (string, hash, 0);
112 return (b ? (char *)b->data : 0);
113}
114
115/* Quote the data associated with each element of the hash table ASSOC,
116 using quote_string */
117HASH_TABLE *
118assoc_quote (h)
119 HASH_TABLE *h;
120{
121 int i;
122 BUCKET_CONTENTS *tlist;
123 char *t;
124
125 if (h == 0 || assoc_empty (h))
126 return ((HASH_TABLE *)NULL);
127
128 for (i = 0; i < h->nbuckets; i++)
129 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
130 {
131 t = quote_string ((char *)tlist->data);
132 FREE (tlist->data);
133 tlist->data = t;
134 }
135
136 return h;
137}
138
139/* Quote escape characters in the data associated with each element
140 of the hash table ASSOC, using quote_escapes */
141HASH_TABLE *
142assoc_quote_escapes (h)
143 HASH_TABLE *h;
144{
145 int i;
146 BUCKET_CONTENTS *tlist;
147 char *t;
148
149 if (h == 0 || assoc_empty (h))
150 return ((HASH_TABLE *)NULL);
151
152 for (i = 0; i < h->nbuckets; i++)
153 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
154 {
155 t = quote_escapes ((char *)tlist->data);
156 FREE (tlist->data);
157 tlist->data = t;
158 }
159
160 return h;
161}
162
163HASH_TABLE *
164assoc_dequote (h)
165 HASH_TABLE *h;
166{
167 int i;
168 BUCKET_CONTENTS *tlist;
169 char *t;
170
171 if (h == 0 || assoc_empty (h))
172 return ((HASH_TABLE *)NULL);
173
174 for (i = 0; i < h->nbuckets; i++)
175 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
176 {
177 t = dequote_string ((char *)tlist->data);
178 FREE (tlist->data);
179 tlist->data = t;
180 }
181
182 return h;
183}
184
185HASH_TABLE *
186assoc_dequote_escapes (h)
187 HASH_TABLE *h;
188{
189 int i;
190 BUCKET_CONTENTS *tlist;
191 char *t;
192
193 if (h == 0 || assoc_empty (h))
194 return ((HASH_TABLE *)NULL);
195
196 for (i = 0; i < h->nbuckets; i++)
197 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
198 {
199 t = dequote_escapes ((char *)tlist->data);
200 FREE (tlist->data);
201 tlist->data = t;
202 }
203
204 return h;
205}
206
207HASH_TABLE *
208assoc_remove_quoted_nulls (h)
209 HASH_TABLE *h;
210{
211 int i;
212 BUCKET_CONTENTS *tlist;
213 char *t;
214
215 if (h == 0 || assoc_empty (h))
216 return ((HASH_TABLE *)NULL);
217
218 for (i = 0; i < h->nbuckets; i++)
219 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
220 {
221 t = remove_quoted_nulls ((char *)tlist->data);
222 tlist->data = t;
223 }
224
225 return h;
226}
227
228/*
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.
231 */
232char *
233assoc_subrange (hash, start, nelem, starsub, quoted)
234HASH_TABLE *hash;
235arrayind_t start, nelem;
236int starsub, quoted;
237{
238 WORD_LIST *l, *save, *h, *t;
239 int i, j;
240 char *ret;
241
242 if (assoc_empty (hash))
243 return ((char *)NULL);
244
245 save = l = assoc_to_word_list (hash);
246 if (save == 0)
247 return ((char *)NULL);
248
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++)
254 {
255 t = l;
256 l = l->next;
257 }
258
259 t->next = (WORD_LIST *)NULL;
260
261 ret = string_list_pos_params (starsub ? '*' : '@', h, quoted);
262
263 if (t != l)
264 t->next = l;
265
266 dispose_words (save);
267 return (ret);
268
269}
270
271char *
272assoc_patsub (h, pat, rep, mflags)
273 HASH_TABLE *h;
274 char *pat, *rep;
275 int mflags;
276{
277 BUCKET_CONTENTS *tlist;
278 int i, slen;
279 HASH_TABLE *h2;
280 char *t, *sifs, *ifs;
281
282 if (h == 0 || assoc_empty (h))
283 return ((char *)NULL);
284
285 h2 = assoc_copy (h);
286 for (i = 0; i < h2->nbuckets; i++)
287 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
288 {
289 t = pat_subst ((char *)tlist->data, pat, rep, mflags);
290 FREE (tlist->data);
291 tlist->data = t;
292 }
293
294 if (mflags & MATCH_QUOTED)
295 assoc_quote (h2);
296 else
297 assoc_quote_escapes (h2);
298
299 if (mflags & MATCH_STARSUB)
300 {
301 assoc_remove_quoted_nulls (h2);
302 sifs = ifs_firstchar ((int *)NULL);
303 t = assoc_to_string (h2, sifs, 0);
304 free (sifs);
305 }
306 else if (mflags & MATCH_QUOTED)
307 {
308 /* ${array[@]} */
309 sifs = ifs_firstchar (&slen);
310 ifs = getifs ();
311 if (ifs == 0 || *ifs == 0)
312 {
313 if (slen < 2)
314 sifs = xrealloc (sifs, 2);
315 sifs[0] = ' ';
316 sifs[1] = '\0';
317 }
318 t = assoc_to_string (h2, sifs, 0);
319 free(sifs);
320 }
321 else
322 t = assoc_to_string (h2, " ", 0);
323
324 assoc_dispose (h2);
325
326 return t;
327}
328
329char *
330assoc_modcase (h, pat, modop, mflags)
331 HASH_TABLE *h;
332 char *pat;
333 int modop;
334 int mflags;
335{
336 BUCKET_CONTENTS *tlist;
337 int i, slen;
338 HASH_TABLE *h2;
339 char *t, *sifs, *ifs;
340
341 if (h == 0 || assoc_empty (h))
342 return ((char *)NULL);
343
344 h2 = assoc_copy (h);
345 for (i = 0; i < h2->nbuckets; i++)
346 for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
347 {
348 t = sh_modcase ((char *)tlist->data, pat, modop);
349 FREE (tlist->data);
350 tlist->data = t;
351 }
352
353 if (mflags & MATCH_QUOTED)
354 assoc_quote (h2);
355 else
356 assoc_quote_escapes (h2);
357
358 if (mflags & MATCH_STARSUB)
359 {
360 assoc_remove_quoted_nulls (h2);
361 sifs = ifs_firstchar ((int *)NULL);
362 t = assoc_to_string (h2, sifs, 0);
363 free (sifs);
364 }
365 else if (mflags & MATCH_QUOTED)
366 {
367 /* ${array[@]} */
368 sifs = ifs_firstchar (&slen);
369 ifs = getifs ();
370 if (ifs == 0 || *ifs == 0)
371 {
372 if (slen < 2)
373 sifs = xrealloc (sifs, 2);
374 sifs[0] = ' ';
375 sifs[1] = '\0';
376 }
377 t = assoc_to_string (h2, sifs, 0);
378 free(sifs);
379 }
380 else
381 t = assoc_to_string (h2, " ", 0);
382
383 assoc_dispose (h2);
384
385 return t;
386}
387
388char *
389assoc_to_assign (hash, quoted)
390 HASH_TABLE *hash;
391 int quoted;
392{
393 char *ret;
394 char *istr, *vstr;
395 int i, rsize, rlen, elen;
396 BUCKET_CONTENTS *tlist;
397
398 if (hash == 0 || assoc_empty (hash))
399 return (char *)0;
400
401 ret = xmalloc (rsize = 128);
402 ret[0] = '(';
403 rlen = 1;
404
405 for (i = 0; i < hash->nbuckets; i++)
406 for (tlist = hash_items (i, hash); tlist; tlist = tlist->next)
407 {
0001803f
CR
408#if 1
409 if (sh_contains_shell_metas (tlist->key))
410 istr = sh_double_quote (tlist->key);
411 else
412 istr = tlist->key;
413#else
3185942a 414 istr = tlist->key;
0001803f 415#endif
3185942a
JA
416 vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0;
417
418 elen = STRLEN (istr) + 8 + STRLEN (vstr);
419 RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize);
420
421 ret[rlen++] = '[';
422 strcpy (ret+rlen, istr);
423 rlen += STRLEN (istr);
424 ret[rlen++] = ']';
425 ret[rlen++] = '=';
426 if (vstr)
427 {
428 strcpy (ret + rlen, vstr);
429 rlen += STRLEN (vstr);
430 }
431 ret[rlen++] = ' ';
432
0001803f
CR
433
434 if (istr != tlist->key)
435 FREE (istr);
436
3185942a
JA
437 FREE (vstr);
438 }
439
440 RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8);
441 ret[rlen++] = ')';
442 ret[rlen] = '\0';
443
444 if (quoted)
445 {
446 vstr = sh_single_quote (ret);
447 free (ret);
448 ret = vstr;
449 }
450
451 return ret;
452}
453
454static WORD_LIST *
455assoc_to_word_list_internal (h, t)
456 HASH_TABLE *h;
457 int t;
458{
459 WORD_LIST *list;
460 int i;
461 BUCKET_CONTENTS *tlist;
462 char *w;
463
464 if (h == 0 || assoc_empty (h))
465 return((WORD_LIST *)NULL);
466 list = (WORD_LIST *)NULL;
467
468 for (i = 0; i < h->nbuckets; i++)
469 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
470 {
471 w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
472 list = make_word_list (make_bare_word(w), list);
473 }
474 return (REVERSE_LIST(list, WORD_LIST *));
475}
476
477WORD_LIST *
478assoc_to_word_list (h)
479 HASH_TABLE *h;
480{
481 return (assoc_to_word_list_internal (h, 0));
482}
483
484WORD_LIST *
485assoc_keys_to_word_list (h)
486 HASH_TABLE *h;
487{
488 return (assoc_to_word_list_internal (h, 1));
489}
490
491char *
492assoc_to_string (h, sep, quoted)
493 HASH_TABLE *h;
494 char *sep;
495 int quoted;
496{
497 BUCKET_CONTENTS *tlist;
498 int i;
499 char *result, *t, *w;
500 WORD_LIST *list, *l;
501
502 if (h == 0)
503 return ((char *)NULL);
504 if (assoc_empty (h))
505 return (savestring (""));
506
507 result = NULL;
508 list = NULL;
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
511 using list_string */
512 for (i = 0; i < h->nbuckets; i++)
513 for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
514 {
515 w = (char *)tlist->data;
516 if (w == 0)
517 continue;
518 t = quoted ? quote_string (w) : savestring (w);
519 list = make_word_list (make_bare_word(t), list);
520 FREE (t);
521 }
522
523 l = REVERSE_LIST(list, WORD_LIST *);
524
525 result = l ? string_list_internal (l, sep) : savestring ("");
526 return result;
527}
528
529#endif /* ARRAY_VARS */