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