]> git.ipfire.org Git - thirdparty/bash.git/blame - array.c
fix for SIGINT in sourced script
[thirdparty/bash.git] / array.c
CommitLineData
ccc6cda3
JA
1/*
2 * array.c - functions to create, destroy, access, and manipulate arrays
3 * of strings.
4 *
5 * Arrays are sparse doubly-linked lists. An element's index is stored
6 * with it.
7 *
8 * Chet Ramey
9 * chet@ins.cwru.edu
10 */
bb70624e 11
3185942a 12/* Copyright (C) 1997-2009 Free Software Foundation, Inc.
bb70624e
JA
13
14 This file is part of GNU Bash, the Bourne Again SHell.
15
3185942a
JA
16 Bash is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
bb70624e 20
3185942a
JA
21 Bash is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
bb70624e 25
3185942a
JA
26 You should have received a copy of the GNU General Public License
27 along with Bash. If not, see <http://www.gnu.org/licenses/>.
28*/
bb70624e 29
ccc6cda3
JA
30#include "config.h"
31
32#if defined (ARRAY_VARS)
33
34#if defined (HAVE_UNISTD_H)
cce855bc
JA
35# ifdef _MINIX
36# include <sys/types.h>
37# endif
ccc6cda3
JA
38# include <unistd.h>
39#endif
40
41#include <stdio.h>
d166f048
JA
42#include "bashansi.h"
43
ccc6cda3
JA
44#include "shell.h"
45#include "array.h"
46#include "builtins/common.h"
47
ccc6cda3
JA
48#define ADD_BEFORE(ae, new) \
49 do { \
50 ae->prev->next = new; \
51 new->prev = ae->prev; \
52 ae->prev = new; \
53 new->next = ae; \
54 } while(0)
55
7117c2d2 56static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int));
ccc6cda3 57
a0c0a00f
CR
58/* lastref should be moved into the array structure so each array can be
59 optimized separately */
60
0001803f
CR
61static ARRAY *lastarray = 0;
62static ARRAY_ELEMENT *lastref = 0;
63
ac50fbac
CR
64#define IS_LASTREF(a) (lastarray && (a) == lastarray)
65
66#define LASTREF_START(a, i) \
67 (IS_LASTREF(a) && i >= element_index(lastref)) ? lastref \
68 : element_forw(a->head)
0001803f
CR
69
70#define INVALIDATE_LASTREF(a) \
71do { \
72 if ((a) == lastarray) { \
73 lastarray = 0; \
74 lastref = 0; \
75 } \
76} while (0)
77
78#define SET_LASTREF(a, e) \
79do { \
80 lastarray = (a); \
81 lastref = (e); \
82} while (0)
83
84#define UNSET_LASTREF() \
85do { \
86 lastarray = 0; \
87 lastref = 0; \
88} while (0)
89
ccc6cda3 90ARRAY *
7117c2d2 91array_create()
ccc6cda3
JA
92{
93 ARRAY *r;
94 ARRAY_ELEMENT *head;
95
f73dda09 96 r =(ARRAY *)xmalloc(sizeof(ARRAY));
ccc6cda3 97 r->type = array_indexed;
7117c2d2 98 r->max_index = -1;
ccc6cda3 99 r->num_elements = 0;
7117c2d2 100 head = array_create_element(-1, (char *)NULL); /* dummy head */
ccc6cda3
JA
101 head->prev = head->next = head;
102 r->head = head;
103 return(r);
104}
105
106void
7117c2d2 107array_flush (a)
ccc6cda3
JA
108ARRAY *a;
109{
110 register ARRAY_ELEMENT *r, *r1;
111
112 if (a == 0)
113 return;
114 for (r = element_forw(a->head); r != a->head; ) {
115 r1 = element_forw(r);
7117c2d2 116 array_dispose_element(r);
ccc6cda3
JA
117 r = r1;
118 }
119 a->head->next = a->head->prev = a->head;
7117c2d2
JA
120 a->max_index = -1;
121 a->num_elements = 0;
0001803f 122 INVALIDATE_LASTREF(a);
ccc6cda3
JA
123}
124
125void
7117c2d2 126array_dispose(a)
ccc6cda3
JA
127ARRAY *a;
128{
129 if (a == 0)
130 return;
7117c2d2
JA
131 array_flush (a);
132 array_dispose_element(a->head);
ccc6cda3
JA
133 free(a);
134}
135
136ARRAY *
7117c2d2 137array_copy(a)
ccc6cda3
JA
138ARRAY *a;
139{
140 ARRAY *a1;
141 ARRAY_ELEMENT *ae, *new;
142
95732b49 143 if (a == 0)
ccc6cda3 144 return((ARRAY *) NULL);
7117c2d2 145 a1 = array_create();
ccc6cda3
JA
146 a1->type = a->type;
147 a1->max_index = a->max_index;
148 a1->num_elements = a->num_elements;
ccc6cda3 149 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
7117c2d2 150 new = array_create_element(element_index(ae), element_value(ae));
ccc6cda3
JA
151 ADD_BEFORE(a1->head, new);
152 }
153 return(a1);
154}
155
156/*
157 * Make and return a new array composed of the elements in array A from
158 * S to E, inclusive.
159 */
160ARRAY *
7117c2d2 161array_slice(array, s, e)
ccc6cda3
JA
162ARRAY *array;
163ARRAY_ELEMENT *s, *e;
164{
165 ARRAY *a;
166 ARRAY_ELEMENT *p, *n;
7117c2d2
JA
167 int i;
168 arrayind_t mi;
ccc6cda3 169
7117c2d2 170 a = array_create ();
ccc6cda3
JA
171 a->type = array->type;
172
3185942a 173 for (mi = 0, p = s, i = 0; p != e; p = element_forw(p), i++) {
7117c2d2 174 n = array_create_element (element_index(p), element_value(p));
ccc6cda3 175 ADD_BEFORE(a->head, n);
f1be666c 176 mi = element_index(n);
ccc6cda3 177 }
7117c2d2
JA
178 a->num_elements = i;
179 a->max_index = mi;
ccc6cda3
JA
180 return a;
181}
182
7117c2d2
JA
183/*
184 * Walk the array, calling FUNC once for each element, with the array
185 * element as the argument.
186 */
187void
b80f6443 188array_walk(a, func, udata)
7117c2d2
JA
189ARRAY *a;
190sh_ae_map_func_t *func;
b80f6443 191void *udata;
7117c2d2
JA
192{
193 register ARRAY_ELEMENT *ae;
194
195 if (a == 0 || array_empty(a))
196 return;
197 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
b80f6443 198 if ((*func)(ae, udata) < 0)
7117c2d2
JA
199 return;
200}
201
202/*
203 * Shift the array A N elements to the left. Delete the first N elements
204 * and subtract N from the indices of the remaining elements. If FLAGS
205 * does not include AS_DISPOSE, this returns a singly-linked null-terminated
206 * list of elements so the caller can dispose of the chain. If FLAGS
207 * includes AS_DISPOSE, this function disposes of the shifted-out elements
208 * and returns NULL.
209 */
210ARRAY_ELEMENT *
211array_shift(a, n, flags)
212ARRAY *a;
213int n, flags;
214{
215 register ARRAY_ELEMENT *ae, *ret;
216 register int i;
217
218 if (a == 0 || array_empty(a) || n <= 0)
219 return ((ARRAY_ELEMENT *)NULL);
220
0001803f 221 INVALIDATE_LASTREF(a);
7117c2d2
JA
222 for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++)
223 ;
224 if (ae == a->head) {
225 /* Easy case; shifting out all of the elements */
226 if (flags & AS_DISPOSE) {
227 array_flush (a);
228 return ((ARRAY_ELEMENT *)NULL);
229 }
230 for (ae = ret; element_forw(ae) != a->head; ae = element_forw(ae))
231 ;
232 element_forw(ae) = (ARRAY_ELEMENT *)NULL;
233 a->head->next = a->head->prev = a->head;
234 a->max_index = -1;
235 a->num_elements = 0;
236 return ret;
237 }
238 /*
239 * ae now points to the list of elements we want to retain.
240 * ret points to the list we want to either destroy or return.
241 */
242 ae->prev->next = (ARRAY_ELEMENT *)NULL; /* null-terminate RET */
243
244 a->head->next = ae; /* slice RET out of the array */
245 ae->prev = a->head;
246
247 for ( ; ae != a->head; ae = element_forw(ae))
248 element_index(ae) -= n; /* renumber retained indices */
249
250 a->num_elements -= n; /* modify bookkeeping information */
0001803f 251 a->max_index = element_index(a->head->prev);
7117c2d2
JA
252
253 if (flags & AS_DISPOSE) {
254 for (ae = ret; ae; ) {
255 ret = element_forw(ae);
256 array_dispose_element(ae);
257 ae = ret;
258 }
259 return ((ARRAY_ELEMENT *)NULL);
260 }
261
262 return ret;
263}
264
265/*
266 * Shift array A right N indices. If S is non-null, it becomes the value of
267 * the new element 0. Returns the number of elements in the array after the
268 * shift.
269 */
270int
271array_rshift (a, n, s)
272ARRAY *a;
273int n;
274char *s;
275{
276 register ARRAY_ELEMENT *ae, *new;
277
95732b49 278 if (a == 0 || (array_empty(a) && s == 0))
7117c2d2 279 return 0;
95732b49 280 else if (n <= 0)
7117c2d2
JA
281 return (a->num_elements);
282
283 ae = element_forw(a->head);
284 if (s) {
285 new = array_create_element(0, s);
286 ADD_BEFORE(ae, new);
287 a->num_elements++;
0001803f
CR
288 if (array_num_elements(a) == 1) { /* array was empty */
289 a->max_index = 0;
95732b49 290 return 1;
0001803f 291 }
7117c2d2
JA
292 }
293
7117c2d2
JA
294 /*
295 * Renumber all elements in the array except the one we just added.
296 */
297 for ( ; ae != a->head; ae = element_forw(ae))
298 element_index(ae) += n;
299
95732b49
JA
300 a->max_index = element_index(a->head->prev);
301
0001803f 302 INVALIDATE_LASTREF(a);
7117c2d2
JA
303 return (a->num_elements);
304}
305
b80f6443
JA
306ARRAY_ELEMENT *
307array_unshift_element(a)
308ARRAY *a;
309{
310 return (array_shift (a, 1, 0));
311}
312
313int
314array_shift_element(a, v)
315ARRAY *a;
316char *v;
317{
318 return (array_rshift (a, 1, v));
319}
320
3185942a 321ARRAY *
7117c2d2
JA
322array_quote(array)
323ARRAY *array;
324{
325 ARRAY_ELEMENT *a;
326 char *t;
327
95732b49 328 if (array == 0 || array_head(array) == 0 || array_empty(array))
7117c2d2
JA
329 return (ARRAY *)NULL;
330 for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
331 t = quote_string (a->value);
332 FREE(a->value);
333 a->value = t;
334 }
335 return array;
336}
337
3185942a 338ARRAY *
f1be666c
JA
339array_quote_escapes(array)
340ARRAY *array;
341{
342 ARRAY_ELEMENT *a;
343 char *t;
344
345 if (array == 0 || array_head(array) == 0 || array_empty(array))
346 return (ARRAY *)NULL;
347 for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
348 t = quote_escapes (a->value);
349 FREE(a->value);
350 a->value = t;
351 }
352 return array;
353}
354
3185942a
JA
355ARRAY *
356array_dequote(array)
357ARRAY *array;
358{
359 ARRAY_ELEMENT *a;
360 char *t;
361
362 if (array == 0 || array_head(array) == 0 || array_empty(array))
363 return (ARRAY *)NULL;
364 for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
365 t = dequote_string (a->value);
366 FREE(a->value);
367 a->value = t;
368 }
369 return array;
370}
371
372ARRAY *
373array_dequote_escapes(array)
374ARRAY *array;
375{
376 ARRAY_ELEMENT *a;
377 char *t;
378
379 if (array == 0 || array_head(array) == 0 || array_empty(array))
380 return (ARRAY *)NULL;
381 for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
382 t = dequote_escapes (a->value);
383 FREE(a->value);
384 a->value = t;
385 }
386 return array;
387}
388
389ARRAY *
390array_remove_quoted_nulls(array)
391ARRAY *array;
392{
393 ARRAY_ELEMENT *a;
394 char *t;
395
396 if (array == 0 || array_head(array) == 0 || array_empty(array))
397 return (ARRAY *)NULL;
398 for (a = element_forw(array->head); a != array->head; a = element_forw(a))
399 a->value = remove_quoted_nulls (a->value);
400 return array;
401}
402
b80f6443
JA
403/*
404 * Return a string whose elements are the members of array A beginning at
405 * index START and spanning NELEM members. Null elements are counted.
406 * Since arrays are sparse, unset array elements are not counted.
407 */
7117c2d2 408char *
b80f6443 409array_subrange (a, start, nelem, starsub, quoted)
7117c2d2 410ARRAY *a;
b80f6443
JA
411arrayind_t start, nelem;
412int starsub, quoted;
7117c2d2 413{
f1be666c 414 ARRAY *a2;
7117c2d2
JA
415 ARRAY_ELEMENT *h, *p;
416 arrayind_t i;
3185942a
JA
417 char *ifs, *sifs, *t;
418 int slen;
7117c2d2 419
95732b49 420 p = a ? array_head (a) : 0;
b80f6443 421 if (p == 0 || array_empty (a) || start > array_max_index(a))
7117c2d2
JA
422 return ((char *)NULL);
423
b80f6443
JA
424 /*
425 * Find element with index START. If START corresponds to an unset
426 * element (arrays can be sparse), use the first element whose index
427 * is >= START. If START is < 0, we count START indices back from
428 * the end of A (not elements, even with sparse arrays -- START is an
429 * index).
430 */
431 for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p))
7117c2d2 432 ;
b80f6443 433
7117c2d2
JA
434 if (p == a->head)
435 return ((char *)NULL);
b80f6443
JA
436
437 /* Starting at P, take NELEM elements, inclusive. */
438 for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p))
7117c2d2
JA
439 ;
440
f1be666c
JA
441 a2 = array_slice(a, h, p);
442
443 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
444 array_quote(a2);
445 else
446 array_quote_escapes(a2);
447
b80f6443 448 if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
3185942a
JA
449 /* ${array[*]} */
450 array_remove_quoted_nulls (a2);
451 sifs = ifs_firstchar ((int *)NULL);
452 t = array_to_string (a2, sifs, 0);
453 free (sifs);
454 } else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) {
455 /* ${array[@]} */
456 sifs = ifs_firstchar (&slen);
457 ifs = getifs ();
458 if (ifs == 0 || *ifs == 0) {
459 if (slen < 2)
460 sifs = xrealloc(sifs, 2);
461 sifs[0] = ' ';
462 sifs[1] = '\0';
463 }
464 t = array_to_string (a2, sifs, 0);
465 free (sifs);
b80f6443 466 } else
3185942a 467 t = array_to_string (a2, " ", 0);
f1be666c
JA
468 array_dispose(a2);
469
470 return t;
7117c2d2
JA
471}
472
473char *
474array_patsub (a, pat, rep, mflags)
475ARRAY *a;
476char *pat, *rep;
477int mflags;
478{
479 ARRAY *a2;
480 ARRAY_ELEMENT *e;
3185942a
JA
481 char *t, *sifs, *ifs;
482 int slen;
7117c2d2 483
95732b49 484 if (a == 0 || array_head(a) == 0 || array_empty(a))
7117c2d2
JA
485 return ((char *)NULL);
486
95732b49 487 a2 = array_copy(a);
7117c2d2
JA
488 for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
489 t = pat_subst(element_value(e), pat, rep, mflags);
490 FREE(element_value(e));
491 e->value = t;
492 }
493
494 if (mflags & MATCH_QUOTED)
f1be666c
JA
495 array_quote(a2);
496 else
497 array_quote_escapes(a2);
3185942a 498
b80f6443 499 if (mflags & MATCH_STARSUB) {
3185942a
JA
500 array_remove_quoted_nulls (a2);
501 sifs = ifs_firstchar((int *)NULL);
b80f6443 502 t = array_to_string (a2, sifs, 0);
3185942a
JA
503 free(sifs);
504 } else if (mflags & MATCH_QUOTED) {
505 /* ${array[@]} */
506 sifs = ifs_firstchar (&slen);
507 ifs = getifs ();
508 if (ifs == 0 || *ifs == 0) {
509 if (slen < 2)
510 sifs = xrealloc (sifs, 2);
511 sifs[0] = ' ';
512 sifs[1] = '\0';
513 }
514 t = array_to_string (a2, sifs, 0);
515 free(sifs);
b80f6443
JA
516 } else
517 t = array_to_string (a2, " ", 0);
7117c2d2
JA
518 array_dispose (a2);
519
520 return t;
521}
522
3185942a
JA
523char *
524array_modcase (a, pat, modop, mflags)
525ARRAY *a;
526char *pat;
527int modop;
528int mflags;
529{
530 ARRAY *a2;
531 ARRAY_ELEMENT *e;
532 char *t, *sifs, *ifs;
533 int slen;
534
535 if (a == 0 || array_head(a) == 0 || array_empty(a))
536 return ((char *)NULL);
537
538 a2 = array_copy(a);
539 for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
540 t = sh_modcase(element_value(e), pat, modop);
541 FREE(element_value(e));
542 e->value = t;
543 }
544
545 if (mflags & MATCH_QUOTED)
546 array_quote(a2);
547 else
548 array_quote_escapes(a2);
549
550 if (mflags & MATCH_STARSUB) {
551 array_remove_quoted_nulls (a2);
552 sifs = ifs_firstchar((int *)NULL);
553 t = array_to_string (a2, sifs, 0);
554 free(sifs);
555 } else if (mflags & MATCH_QUOTED) {
556 /* ${array[@]} */
557 sifs = ifs_firstchar (&slen);
558 ifs = getifs ();
559 if (ifs == 0 || *ifs == 0) {
560 if (slen < 2)
561 sifs = xrealloc (sifs, 2);
562 sifs[0] = ' ';
563 sifs[1] = '\0';
564 }
565 t = array_to_string (a2, sifs, 0);
566 free(sifs);
567 } else
568 t = array_to_string (a2, " ", 0);
569 array_dispose (a2);
570
571 return t;
572}
7117c2d2
JA
573/*
574 * Allocate and return a new array element with index INDEX and value
575 * VALUE.
576 */
577ARRAY_ELEMENT *
578array_create_element(indx, value)
579arrayind_t indx;
580char *value;
581{
582 ARRAY_ELEMENT *r;
583
584 r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT));
585 r->ind = indx;
586 r->value = value ? savestring(value) : (char *)NULL;
587 r->next = r->prev = (ARRAY_ELEMENT *) NULL;
588 return(r);
589}
590
cce855bc 591#ifdef INCLUDE_UNUSED
ccc6cda3 592ARRAY_ELEMENT *
7117c2d2 593array_copy_element(ae)
ccc6cda3
JA
594ARRAY_ELEMENT *ae;
595{
7117c2d2 596 return(ae ? array_create_element(element_index(ae), element_value(ae))
ccc6cda3
JA
597 : (ARRAY_ELEMENT *) NULL);
598}
cce855bc 599#endif
ccc6cda3 600
7117c2d2
JA
601void
602array_dispose_element(ae)
603ARRAY_ELEMENT *ae;
604{
b80f6443
JA
605 if (ae) {
606 FREE(ae->value);
607 free(ae);
608 }
7117c2d2
JA
609}
610
ccc6cda3
JA
611/*
612 * Add a new element with index I and value V to array A (a[i] = v).
613 */
614int
7117c2d2 615array_insert(a, i, v)
ccc6cda3
JA
616ARRAY *a;
617arrayind_t i;
618char *v;
619{
ac50fbac 620 register ARRAY_ELEMENT *new, *ae, *start;
ccc6cda3 621
95732b49 622 if (a == 0)
ccc6cda3 623 return(-1);
7117c2d2 624 new = array_create_element(i, v);
ccc6cda3
JA
625 if (i > array_max_index(a)) {
626 /*
627 * Hook onto the end. This also works for an empty array.
628 * Fast path for the common case of allocating arrays
629 * sequentially.
630 */
631 ADD_BEFORE(a->head, new);
632 a->max_index = i;
633 a->num_elements++;
0001803f 634 SET_LASTREF(a, new);
ccc6cda3
JA
635 return(0);
636 }
ac50fbac 637#if OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT
ccc6cda3 638 /*
ac50fbac
CR
639 * Otherwise we search for the spot to insert it. The lastref
640 * handle optimizes the case of sequential or almost-sequential
641 * assignments that are not at the end of the array.
ccc6cda3 642 */
ac50fbac
CR
643 start = LASTREF_START(a, i);
644#else
645 start = element_forw(ae->head);
646#endif
647 for (ae = start; ae != a->head; ae = element_forw(ae)) {
ccc6cda3
JA
648 if (element_index(ae) == i) {
649 /*
650 * Replacing an existing element.
651 */
7117c2d2 652 array_dispose_element(new);
ccc6cda3 653 free(element_value(ae));
eb873671 654 ae->value = v ? savestring(v) : (char *)NULL;
0001803f 655 SET_LASTREF(a, ae);
ccc6cda3
JA
656 return(0);
657 } else if (element_index(ae) > i) {
658 ADD_BEFORE(ae, new);
659 a->num_elements++;
0001803f 660 SET_LASTREF(a, new);
ccc6cda3
JA
661 return(0);
662 }
663 }
ac50fbac 664 array_dispose_element(new);
0001803f 665 INVALIDATE_LASTREF(a);
ccc6cda3
JA
666 return (-1); /* problem */
667}
668
669/*
670 * Delete the element with index I from array A and return it so the
671 * caller can dispose of it.
672 */
673ARRAY_ELEMENT *
7117c2d2 674array_remove(a, i)
ccc6cda3
JA
675ARRAY *a;
676arrayind_t i;
677{
ac50fbac 678 register ARRAY_ELEMENT *ae, *start;
ccc6cda3 679
95732b49 680 if (a == 0 || array_empty(a))
ccc6cda3 681 return((ARRAY_ELEMENT *) NULL);
ac50fbac
CR
682 start = LASTREF_START(a, i);
683 for (ae = start; ae != a->head; ae = element_forw(ae))
ccc6cda3
JA
684 if (element_index(ae) == i) {
685 ae->next->prev = ae->prev;
686 ae->prev->next = ae->next;
687 a->num_elements--;
688 if (i == array_max_index(a))
689 a->max_index = element_index(ae->prev);
ac50fbac 690#if 0
0001803f 691 INVALIDATE_LASTREF(a);
ac50fbac
CR
692#else
693 if (ae->next != a->head)
694 SET_LASTREF(a, ae->next);
695 else if (ae->prev != a->head)
696 SET_LASTREF(a, ae->prev);
697 else
698 INVALIDATE_LASTREF(a);
699#endif
ccc6cda3
JA
700 return(ae);
701 }
702 return((ARRAY_ELEMENT *) NULL);
703}
704
705/*
706 * Return the value of a[i].
707 */
708char *
709array_reference(a, i)
710ARRAY *a;
711arrayind_t i;
712{
ac50fbac 713 register ARRAY_ELEMENT *ae, *start;
ccc6cda3
JA
714
715 if (a == 0 || array_empty(a))
716 return((char *) NULL);
0001803f 717 if (i > array_max_index(a))
ac50fbac
CR
718 return((char *)NULL); /* Keep roving pointer into array to optimize sequential access */
719 start = LASTREF_START(a, i);
720 for (ae = start; ae != a->head; ae = element_forw(ae))
0001803f
CR
721 if (element_index(ae) == i) {
722 SET_LASTREF(a, ae);
ccc6cda3 723 return(element_value(ae));
0001803f 724 }
a0c0a00f 725 UNSET_LASTREF(); /* XXX SET_LASTREF(a, start) ? */
ccc6cda3
JA
726 return((char *) NULL);
727}
728
7117c2d2
JA
729/* Convenience routines for the shell to translate to and from the form used
730 by the rest of the code. */
b80f6443 731
7117c2d2
JA
732WORD_LIST *
733array_to_word_list(a)
ccc6cda3 734ARRAY *a;
ccc6cda3 735{
7117c2d2
JA
736 WORD_LIST *list;
737 ARRAY_ELEMENT *ae;
ccc6cda3
JA
738
739 if (a == 0 || array_empty(a))
7117c2d2
JA
740 return((WORD_LIST *)NULL);
741 list = (WORD_LIST *)NULL;
ccc6cda3 742 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
7117c2d2
JA
743 list = make_word_list (make_bare_word(element_value(ae)), list);
744 return (REVERSE_LIST(list, WORD_LIST *));
ccc6cda3
JA
745}
746
7117c2d2
JA
747ARRAY *
748array_from_word_list (list)
749WORD_LIST *list;
750{
751 ARRAY *a;
752
753 if (list == 0)
754 return((ARRAY *)NULL);
755 a = array_create();
756 return (array_assign_list (a, list));
757}
758
b80f6443
JA
759WORD_LIST *
760array_keys_to_word_list(a)
761ARRAY *a;
762{
763 WORD_LIST *list;
764 ARRAY_ELEMENT *ae;
765 char *t;
766
767 if (a == 0 || array_empty(a))
768 return((WORD_LIST *)NULL);
769 list = (WORD_LIST *)NULL;
770 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
771 t = itos(element_index(ae));
772 list = make_word_list (make_bare_word(t), list);
773 free(t);
774 }
775 return (REVERSE_LIST(list, WORD_LIST *));
776}
777
7117c2d2
JA
778ARRAY *
779array_assign_list (array, list)
780ARRAY *array;
781WORD_LIST *list;
782{
783 register WORD_LIST *l;
784 register arrayind_t i;
785
786 for (l = list, i = 0; l; l = l->next, i++)
787 array_insert(array, i, l->word->word);
788 return array;
789}
790
791char **
792array_to_argv (a)
793ARRAY *a;
794{
795 char **ret, *t;
796 int i;
797 ARRAY_ELEMENT *ae;
798
799 if (a == 0 || array_empty(a))
800 return ((char **)NULL);
801 ret = strvec_create (array_num_elements (a) + 1);
802 i = 0;
803 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
804 t = element_value (ae);
805 ret[i++] = t ? savestring (t) : (char *)NULL;
806 }
807 ret[i] = (char *)NULL;
808 return (ret);
809}
810
ccc6cda3 811/*
3185942a
JA
812 * Return a string that is the concatenation of the elements in A from START
813 * to END, separated by SEP.
ccc6cda3
JA
814 */
815static char *
816array_to_string_internal (start, end, sep, quoted)
817ARRAY_ELEMENT *start, *end;
818char *sep;
819int quoted;
820{
821 char *result, *t;
822 ARRAY_ELEMENT *ae;
823 int slen, rsize, rlen, reg;
824
825 if (start == end) /* XXX - should not happen */
826 return ((char *)NULL);
827
828 slen = strlen(sep);
f73dda09 829 result = NULL;
ccc6cda3
JA
830 for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) {
831 if (rsize == 0)
f73dda09 832 result = (char *)xmalloc (rsize = 64);
ccc6cda3
JA
833 if (element_value(ae)) {
834 t = quoted ? quote_string(element_value(ae)) : element_value(ae);
835 reg = strlen(t);
836 RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2),
837 rsize, rsize);
838 strcpy(result + rlen, t);
839 rlen += reg;
a0c0a00f 840 if (quoted)
ccc6cda3
JA
841 free(t);
842 /*
843 * Add a separator only after non-null elements.
844 */
845 if (element_forw(ae) != end) {
846 strcpy(result + rlen, sep);
847 rlen += slen;
848 }
849 }
850 }
f73dda09
JA
851 if (result)
852 result[rlen] = '\0'; /* XXX */
ccc6cda3
JA
853 return(result);
854}
855
856char *
7117c2d2 857array_to_assign (a, quoted)
ccc6cda3 858ARRAY *a;
ccc6cda3
JA
859int quoted;
860{
7117c2d2
JA
861 char *result, *valstr, *is;
862 char indstr[INT_STRLEN_BOUND(intmax_t) + 1];
ccc6cda3
JA
863 ARRAY_ELEMENT *ae;
864 int rsize, rlen, elen;
865
866 if (a == 0 || array_empty (a))
867 return((char *)NULL);
868
f73dda09 869 result = (char *)xmalloc (rsize = 128);
ccc6cda3
JA
870 result[0] = '(';
871 rlen = 1;
872
873 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
7117c2d2 874 is = inttostr (element_index(ae), indstr, sizeof(indstr));
a0c0a00f
CR
875 valstr = element_value (ae) ?
876 (ansic_shouldquote (element_value (ae)) ?
877 ansic_quote (element_value(ae), 0, (int *)0) :
878 sh_double_quote (element_value (ae)))
ccc6cda3 879 : (char *)NULL;
f1be666c 880 elen = STRLEN (is) + 8 + STRLEN (valstr);
ccc6cda3
JA
881 RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
882
883 result[rlen++] = '[';
7117c2d2
JA
884 strcpy (result + rlen, is);
885 rlen += STRLEN (is);
ccc6cda3
JA
886 result[rlen++] = ']';
887 result[rlen++] = '=';
888 if (valstr) {
889 strcpy (result + rlen, valstr);
890 rlen += STRLEN (valstr);
891 }
892
893 if (element_forw(ae) != a->head)
894 result[rlen++] = ' ';
895
ccc6cda3
JA
896 FREE (valstr);
897 }
898 RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8);
899 result[rlen++] = ')';
900 result[rlen] = '\0';
7117c2d2
JA
901 if (quoted) {
902 /* This is not as efficient as it could be... */
903 valstr = sh_single_quote (result);
904 free (result);
905 result = valstr;
906 }
ccc6cda3
JA
907 return(result);
908}
909
910char *
7117c2d2 911array_to_string (a, sep, quoted)
ccc6cda3 912ARRAY *a;
7117c2d2
JA
913char *sep;
914int quoted;
ccc6cda3 915{
7117c2d2
JA
916 if (a == 0)
917 return((char *)NULL);
918 if (array_empty(a))
919 return(savestring(""));
920 return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted));
ccc6cda3 921}
ccc6cda3 922
d166f048 923#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY)
ccc6cda3
JA
924/*
925 * Return an array consisting of elements in S, separated by SEP
926 */
927ARRAY *
7117c2d2 928array_from_string(s, sep)
ccc6cda3
JA
929char *s, *sep;
930{
931 ARRAY *a;
932 WORD_LIST *w;
933
934 if (s == 0)
935 return((ARRAY *)NULL);
936 w = list_string (s, sep, 0);
937 if (w == 0)
938 return((ARRAY *)NULL);
7117c2d2 939 a = array_from_word_list (w);
ccc6cda3
JA
940 return (a);
941}
d166f048 942#endif
ccc6cda3 943
7117c2d2
JA
944#if defined (TEST_ARRAY)
945/*
946 * To make a running version, compile -DTEST_ARRAY and link with:
947 * xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a
948 */
949int interrupt_immediately = 0;
ccc6cda3 950
7117c2d2
JA
951int
952signal_is_trapped(s)
953int s;
954{
955 return 0;
ccc6cda3
JA
956}
957
7117c2d2
JA
958void
959fatal_error(const char *s, ...)
bb70624e 960{
7117c2d2
JA
961 fprintf(stderr, "array_test: fatal memory error\n");
962 abort();
963}
bb70624e 964
7117c2d2
JA
965void
966programming_error(const char *s, ...)
967{
968 fprintf(stderr, "array_test: fatal programming error\n");
969 abort();
bb70624e 970}
7117c2d2
JA
971
972WORD_DESC *
973make_bare_word (s)
974const char *s;
ccc6cda3 975{
7117c2d2 976 WORD_DESC *w;
ccc6cda3 977
7117c2d2
JA
978 w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC));
979 w->word = s ? savestring(s) : savestring ("");
980 w->flags = 0;
981 return w;
ccc6cda3
JA
982}
983
7117c2d2
JA
984WORD_LIST *
985make_word_list(x, l)
986WORD_DESC *x;
987WORD_LIST *l;
ccc6cda3 988{
7117c2d2 989 WORD_LIST *w;
ccc6cda3 990
7117c2d2
JA
991 w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST));
992 w->word = x;
993 w->next = l;
994 return w;
ccc6cda3
JA
995}
996
7117c2d2
JA
997WORD_LIST *
998list_string(s, t, i)
999char *s, *t;
1000int i;
ccc6cda3 1001{
7117c2d2
JA
1002 char *r, *a;
1003 WORD_LIST *wl;
ccc6cda3 1004
7117c2d2
JA
1005 if (s == 0)
1006 return (WORD_LIST *)NULL;
1007 r = savestring(s);
1008 wl = (WORD_LIST *)NULL;
1009 a = strtok(r, t);
1010 while (a) {
1011 wl = make_word_list (make_bare_word(a), wl);
1012 a = strtok((char *)NULL, t);
ccc6cda3 1013 }
7117c2d2 1014 return (REVERSE_LIST (wl, WORD_LIST *));
ccc6cda3
JA
1015}
1016
7117c2d2
JA
1017GENERIC_LIST *
1018list_reverse (list)
1019GENERIC_LIST *list;
ccc6cda3 1020{
7117c2d2 1021 register GENERIC_LIST *next, *prev;
ccc6cda3 1022
7117c2d2
JA
1023 for (prev = 0; list; ) {
1024 next = list->next;
1025 list->next = prev;
1026 prev = list;
1027 list = next;
1028 }
1029 return prev;
ccc6cda3
JA
1030}
1031
1032char *
7117c2d2
JA
1033pat_subst(s, t, u, i)
1034char *s, *t, *u;
1035int i;
ccc6cda3 1036{
7117c2d2 1037 return ((char *)NULL);
ccc6cda3
JA
1038}
1039
7117c2d2
JA
1040char *
1041quote_string(s)
1042char *s;
1043{
1044 return savestring(s);
1045}
ccc6cda3 1046
ccc6cda3
JA
1047print_element(ae)
1048ARRAY_ELEMENT *ae;
1049{
7117c2d2
JA
1050 char lbuf[INT_STRLEN_BOUND (intmax_t) + 1];
1051
1052 printf("array[%s] = %s\n",
1053 inttostr (element_index(ae), lbuf, sizeof (lbuf)),
1054 element_value(ae));
ccc6cda3
JA
1055}
1056
1057print_array(a)
1058ARRAY *a;
1059{
1060 printf("\n");
b80f6443 1061 array_walk(a, print_element, (void *)NULL);
ccc6cda3
JA
1062}
1063
1064main()
1065{
1066 ARRAY *a, *new_a, *copy_of_a;
7117c2d2 1067 ARRAY_ELEMENT *ae, *aew;
ccc6cda3
JA
1068 char *s;
1069
7117c2d2
JA
1070 a = array_create();
1071 array_insert(a, 1, "one");
1072 array_insert(a, 7, "seven");
1073 array_insert(a, 4, "four");
1074 array_insert(a, 1029, "one thousand twenty-nine");
1075 array_insert(a, 12, "twelve");
1076 array_insert(a, 42, "forty-two");
ccc6cda3 1077 print_array(a);
d166f048 1078 s = array_to_string (a, " ", 0);
ccc6cda3 1079 printf("s = %s\n", s);
7117c2d2 1080 copy_of_a = array_from_string(s, " ");
ccc6cda3
JA
1081 printf("copy_of_a:");
1082 print_array(copy_of_a);
7117c2d2 1083 array_dispose(copy_of_a);
ccc6cda3
JA
1084 printf("\n");
1085 free(s);
7117c2d2
JA
1086 ae = array_remove(a, 4);
1087 array_dispose_element(ae);
1088 ae = array_remove(a, 1029);
1089 array_dispose_element(ae);
1090 array_insert(a, 16, "sixteen");
ccc6cda3 1091 print_array(a);
d166f048 1092 s = array_to_string (a, " ", 0);
ccc6cda3 1093 printf("s = %s\n", s);
7117c2d2 1094 copy_of_a = array_from_string(s, " ");
ccc6cda3
JA
1095 printf("copy_of_a:");
1096 print_array(copy_of_a);
7117c2d2 1097 array_dispose(copy_of_a);
ccc6cda3
JA
1098 printf("\n");
1099 free(s);
7117c2d2
JA
1100 array_insert(a, 2, "two");
1101 array_insert(a, 1029, "new one thousand twenty-nine");
1102 array_insert(a, 0, "zero");
1103 array_insert(a, 134, "");
ccc6cda3 1104 print_array(a);
d166f048 1105 s = array_to_string (a, ":", 0);
ccc6cda3 1106 printf("s = %s\n", s);
7117c2d2 1107 copy_of_a = array_from_string(s, ":");
ccc6cda3
JA
1108 printf("copy_of_a:");
1109 print_array(copy_of_a);
7117c2d2 1110 array_dispose(copy_of_a);
ccc6cda3
JA
1111 printf("\n");
1112 free(s);
7117c2d2 1113 new_a = array_copy(a);
ccc6cda3 1114 print_array(new_a);
d166f048 1115 s = array_to_string (new_a, ":", 0);
ccc6cda3 1116 printf("s = %s\n", s);
7117c2d2
JA
1117 copy_of_a = array_from_string(s, ":");
1118 free(s);
ccc6cda3
JA
1119 printf("copy_of_a:");
1120 print_array(copy_of_a);
7117c2d2
JA
1121 array_shift(copy_of_a, 2, AS_DISPOSE);
1122 printf("copy_of_a shifted by two:");
1123 print_array(copy_of_a);
1124 ae = array_shift(copy_of_a, 2, 0);
1125 printf("copy_of_a shifted by two:");
1126 print_array(copy_of_a);
1127 for ( ; ae; ) {
1128 aew = element_forw(ae);
1129 array_dispose_element(ae);
1130 ae = aew;
1131 }
1132 array_rshift(copy_of_a, 1, (char *)0);
1133 printf("copy_of_a rshift by 1:");
1134 print_array(copy_of_a);
1135 array_rshift(copy_of_a, 2, "new element zero");
1136 printf("copy_of_a rshift again by 2 with new element zero:");
1137 print_array(copy_of_a);
1138 s = array_to_assign(copy_of_a, 0);
1139 printf("copy_of_a=%s\n", s);
ccc6cda3 1140 free(s);
7117c2d2
JA
1141 ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0);
1142 for ( ; ae; ) {
1143 aew = element_forw(ae);
1144 array_dispose_element(ae);
1145 ae = aew;
1146 }
1147 array_dispose(copy_of_a);
1148 printf("\n");
1149 array_dispose(a);
1150 array_dispose(new_a);
ccc6cda3
JA
1151}
1152
1153#endif /* TEST_ARRAY */
1154#endif /* ARRAY_VARS */