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