]> git.ipfire.org Git - thirdparty/bash.git/blame - array.c
Imported from ../bash-2.03.tar.gz.
[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 */
11#include "config.h"
12
13#if defined (ARRAY_VARS)
14
15#if defined (HAVE_UNISTD_H)
cce855bc
JA
16# ifdef _MINIX
17# include <sys/types.h>
18# endif
ccc6cda3
JA
19# include <unistd.h>
20#endif
21
22#include <stdio.h>
d166f048
JA
23#include "bashansi.h"
24
ccc6cda3
JA
25#include "shell.h"
26#include "array.h"
27#include "builtins/common.h"
28
29extern char *quote_string (); /* XXX */
30
31#define ADD_BEFORE(ae, new) \
32 do { \
33 ae->prev->next = new; \
34 new->prev = ae->prev; \
35 ae->prev = new; \
36 new->next = ae; \
37 } while(0)
38
39/*
40 * Allocate and return a new array element with index INDEX and value
41 * VALUE.
42 */
43ARRAY_ELEMENT *
44new_array_element(indx, value)
45arrayind_t indx;
46char *value;
47{
48 ARRAY_ELEMENT *r;
49
50 r = (ARRAY_ELEMENT *) xmalloc(sizeof(ARRAY_ELEMENT));
51 r->ind = indx;
52 r->value = value ? savestring(value) : (char *)NULL;
53 r->next = r->prev = (ARRAY_ELEMENT *) NULL;
54 return(r);
55}
56
57void
58destroy_array_element(ae)
59ARRAY_ELEMENT *ae;
60{
61 FREE(ae->value);
62 free(ae);
63}
64
65ARRAY *
66new_array()
67{
68 ARRAY *r;
69 ARRAY_ELEMENT *head;
70
71 r =(ARRAY *) xmalloc(sizeof(ARRAY));
72 r->type = array_indexed;
73 r->max_index = r->max_size = -1;
74 r->num_elements = 0;
75 head = new_array_element(-1, (char *)NULL); /* dummy head */
76 head->prev = head->next = head;
77 r->head = head;
78 return(r);
79}
80
81void
82empty_array (a)
83ARRAY *a;
84{
85 register ARRAY_ELEMENT *r, *r1;
86
87 if (a == 0)
88 return;
89 for (r = element_forw(a->head); r != a->head; ) {
90 r1 = element_forw(r);
91 destroy_array_element(r);
92 r = r1;
93 }
94 a->head->next = a->head->prev = a->head;
95 a->max_index = a->max_size = -1;
96 a->num_elements = a->max_size = 0;
97}
98
99void
100dispose_array(a)
101ARRAY *a;
102{
103 if (a == 0)
104 return;
105 empty_array (a);
106 destroy_array_element(a->head);
107 free(a);
108}
109
110ARRAY *
111dup_array(a)
112ARRAY *a;
113{
114 ARRAY *a1;
115 ARRAY_ELEMENT *ae, *new;
116
117 if (!a)
118 return((ARRAY *) NULL);
119 a1 = new_array();
120 a1->type = a->type;
121 a1->max_index = a->max_index;
122 a1->num_elements = a->num_elements;
123 a1->max_size = a->max_size;
124 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
125 new = new_array_element(element_index(ae), element_value(ae));
126 ADD_BEFORE(a1->head, new);
127 }
128 return(a1);
129}
130
d166f048 131#ifdef INCLUDE_UNUSED
ccc6cda3
JA
132/*
133 * Make and return a new array composed of the elements in array A from
134 * S to E, inclusive.
135 */
136ARRAY *
137dup_array_subrange(array, s, e)
138ARRAY *array;
139ARRAY_ELEMENT *s, *e;
140{
141 ARRAY *a;
142 ARRAY_ELEMENT *p, *n;
143 int i;
144
145 a = new_array ();
146 a->type = array->type;
147
148 for (p = s, i = 0; p != e; p = element_forw(p), i++) {
149 n = new_array_element (i, element_value(p));
150 ADD_BEFORE(a->head, n);
151 }
152 a->num_elements = a->max_index = i;
153 return a;
154}
d166f048 155#endif
ccc6cda3 156
cce855bc 157#ifdef INCLUDE_UNUSED
ccc6cda3
JA
158ARRAY_ELEMENT *
159copy_array_element(ae)
160ARRAY_ELEMENT *ae;
161{
162 return(ae ? new_array_element(element_index(ae), element_value(ae))
163 : (ARRAY_ELEMENT *) NULL);
164}
cce855bc 165#endif
ccc6cda3
JA
166
167/*
168 * Add a new element with index I and value V to array A (a[i] = v).
169 */
170int
171array_add_element(a, i, v)
172ARRAY *a;
173arrayind_t i;
174char *v;
175{
176 register ARRAY_ELEMENT *new, *ae;
177
178 if (!a)
179 return(-1);
180 new = new_array_element(i, v);
181 if (i > array_max_index(a)) {
182 /*
183 * Hook onto the end. This also works for an empty array.
184 * Fast path for the common case of allocating arrays
185 * sequentially.
186 */
187 ADD_BEFORE(a->head, new);
188 a->max_index = i;
189 a->num_elements++;
190 return(0);
191 }
192 /*
193 * Otherwise we search for the spot to insert it.
194 */
195 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
196 if (element_index(ae) == i) {
197 /*
198 * Replacing an existing element.
199 */
200 destroy_array_element(new);
201 free(element_value(ae));
202 ae->value = savestring(v);
203 return(0);
204 } else if (element_index(ae) > i) {
205 ADD_BEFORE(ae, new);
206 a->num_elements++;
207 return(0);
208 }
209 }
210 return (-1); /* problem */
211}
212
213/*
214 * Delete the element with index I from array A and return it so the
215 * caller can dispose of it.
216 */
217ARRAY_ELEMENT *
218array_delete_element(a, i)
219ARRAY *a;
220arrayind_t i;
221{
222 register ARRAY_ELEMENT *ae;
223
224 if (!a || array_empty(a))
225 return((ARRAY_ELEMENT *) NULL);
226 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
227 if (element_index(ae) == i) {
228 ae->next->prev = ae->prev;
229 ae->prev->next = ae->next;
230 a->num_elements--;
231 if (i == array_max_index(a))
232 a->max_index = element_index(ae->prev);
233 return(ae);
234 }
235 return((ARRAY_ELEMENT *) NULL);
236}
237
238/*
239 * Return the value of a[i].
240 */
241char *
242array_reference(a, i)
243ARRAY *a;
244arrayind_t i;
245{
246 register ARRAY_ELEMENT *ae;
247
248 if (a == 0 || array_empty(a))
249 return((char *) NULL);
250 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
251 if (element_index(ae) == i)
252 return(element_value(ae));
253 return((char *) NULL);
254}
255
cce855bc 256#ifdef TEST_ARRAY
ccc6cda3
JA
257/*
258 * Walk the array, calling FUNC once for each element, with the array
259 * element as the argument.
260 */
261void
262array_walk(a, func)
263ARRAY *a;
264Function *func;
265{
266 register ARRAY_ELEMENT *ae;
267
268 if (a == 0 || array_empty(a))
269 return;
270 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
271 (*func)(ae);
272}
cce855bc 273#endif
ccc6cda3
JA
274
275/*
276 * Return a string that is the concatenation of all the elements in A,
277 * separated by SEP.
278 */
279static char *
280array_to_string_internal (start, end, sep, quoted)
281ARRAY_ELEMENT *start, *end;
282char *sep;
283int quoted;
284{
285 char *result, *t;
286 ARRAY_ELEMENT *ae;
287 int slen, rsize, rlen, reg;
288
289 if (start == end) /* XXX - should not happen */
290 return ((char *)NULL);
291
292 slen = strlen(sep);
293 for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) {
294 if (rsize == 0)
295 result = xmalloc (rsize = 64);
296 if (element_value(ae)) {
297 t = quoted ? quote_string(element_value(ae)) : element_value(ae);
298 reg = strlen(t);
299 RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2),
300 rsize, rsize);
301 strcpy(result + rlen, t);
302 rlen += reg;
303 if (quoted && t)
304 free(t);
305 /*
306 * Add a separator only after non-null elements.
307 */
308 if (element_forw(ae) != end) {
309 strcpy(result + rlen, sep);
310 rlen += slen;
311 }
312 }
313 }
314 result[rlen] = '\0'; /* XXX */
315 return(result);
316}
317
318char *
319array_to_string (a, sep, quoted)
320ARRAY *a;
321char *sep;
322int quoted;
323{
324 if (a == 0)
325 return((char *)NULL);
326 if (array_empty(a))
327 return(savestring(""));
328 return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted));
329}
330
331char *
332array_to_assignment_string (a)
333ARRAY *a;
334{
335 char *result, *indstr, *valstr;
336 ARRAY_ELEMENT *ae;
337 int rsize, rlen, elen;
338
339 if (a == 0 || array_empty (a))
340 return((char *)NULL);
341
342 result = xmalloc (rsize = 128);
343 result[0] = '(';
344 rlen = 1;
345
346 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
347 indstr = itos (element_index(ae));
348 valstr = element_value (ae) ? double_quote (element_value(ae))
349 : (char *)NULL;
350 elen = STRLEN (indstr) + 8 + STRLEN (valstr);
351 RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
352
353 result[rlen++] = '[';
354 strcpy (result + rlen, indstr);
355 rlen += STRLEN (indstr);
356 result[rlen++] = ']';
357 result[rlen++] = '=';
358 if (valstr) {
359 strcpy (result + rlen, valstr);
360 rlen += STRLEN (valstr);
361 }
362
363 if (element_forw(ae) != a->head)
364 result[rlen++] = ' ';
365
366 FREE (indstr);
367 FREE (valstr);
368 }
369 RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8);
370 result[rlen++] = ')';
371 result[rlen] = '\0';
372 return(result);
373}
374
375char *
376quoted_array_assignment_string (a)
377ARRAY *a;
378{
379 char *vstr, *sv;
380
381 sv = array_to_assignment_string (a);
382 if (sv == 0)
383 return ((char *)NULL);
384
385 vstr = single_quote (sv);
386 free (sv);
387 return (vstr);
388}
389
390#if 0
391/* Determine if s2 occurs in s1. If so, return a pointer to the
392 match in s1. The compare is case sensitive. */
393static char *
394sindex (s1, s2)
395register char *s1, *s2;
396{
397 register int i, l, len;
398
399 for (i = 0, l = strlen(s2), len = strlen(s1); (len - i) >= l; i++)
400 if (strncmp (s1 + i, s2, l) == 0)
401 return (s1 + i);
402 return ((char *)NULL);
403}
404#endif
405
d166f048 406#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY)
ccc6cda3
JA
407/*
408 * Return an array consisting of elements in S, separated by SEP
409 */
410ARRAY *
411string_to_array(s, sep)
412char *s, *sep;
413{
414 ARRAY *a;
415 WORD_LIST *w;
416
417 if (s == 0)
418 return((ARRAY *)NULL);
419 w = list_string (s, sep, 0);
420 if (w == 0)
421 return((ARRAY *)NULL);
422 a = word_list_to_array (w);
423 return (a);
424}
d166f048 425#endif
ccc6cda3
JA
426
427/* Convenience routines for the shell to translate to and from the form used
428 by the rest of the code. */
429WORD_LIST *
430array_to_word_list(a)
431ARRAY *a;
432{
433 WORD_LIST *list;
434 ARRAY_ELEMENT *ae;
435
436 if (a == 0 || array_empty(a))
437 return((WORD_LIST *)NULL);
438 list = (WORD_LIST *)NULL;
439 for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
440 list = make_word_list (make_bare_word(element_value(ae)), list);
441 return (REVERSE_LIST(list, WORD_LIST *));
442}
443
444ARRAY *
445assign_word_list (array, list)
446ARRAY *array;
447WORD_LIST *list;
448{
449 register WORD_LIST *l;
450 register arrayind_t i;
451
452 for (l = list, i = 0; l; l = l->next, i++)
453 array_add_element(array, i, l->word->word);
454 return array;
455}
456
457ARRAY *
458word_list_to_array (list)
459WORD_LIST *list;
460{
461 ARRAY *a;
462
463 if (list == 0)
464 return((ARRAY *)NULL);
465 a = new_array();
466 return (assign_word_list (a, list));
467}
468
469ARRAY *
470array_quote(array)
471ARRAY *array;
472{
473 ARRAY_ELEMENT *a;
474 char *t;
475
476 if (array == 0 || array->head == 0 || array_empty (array))
477 return (ARRAY *)NULL;
478 for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
479 t = quote_string (a->value);
480 FREE(a->value);
481 a->value = t;
482 }
483 return array;
484}
485
486char *
487array_subrange (a, start, end, quoted)
488ARRAY *a;
489int start, end, quoted;
490{
491 ARRAY_ELEMENT *h, *p;
492 int i;
493
494 p = array_head (a);
495 if (p == 0 || array_empty (a) || start > array_num_elements (a))
496 return ((char *)NULL);
497
498 for (i = 0, p = element_forw(p); p != a->head && i < start; i++, p = element_forw(p))
499 ;
500 if (p == a->head)
501 return ((char *)NULL);
502 for (h = p; p != a->head && i < end; i++, p = element_forw(p))
503 ;
504
505 return (array_to_string_internal (h, p, " ", quoted));
506}
507
508char *
509array_pat_subst (a, pat, rep, mflags)
510ARRAY *a;
511char *pat, *rep;
512int mflags;
513{
514 ARRAY *a2;
515 ARRAY_ELEMENT *e;
516 char *t;
517
518 if (array_head (a) == 0 || array_empty (a))
519 return ((char *)NULL);
520
521 a2 = dup_array (a);
522 for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
523 t = pat_subst(element_value(e), pat, rep, mflags);
524 FREE(element_value(e));
525 e->value = t;
526 }
527
528 if (mflags & MATCH_QUOTED)
529 array_quote (a2);
530 t = array_to_string (a2, " ", 0);
531 dispose_array (a2);
532
533 return t;
534}
535
536
537#if defined (TEST_ARRAY)
538print_element(ae)
539ARRAY_ELEMENT *ae;
540{
541 printf("array[%d] = %s\n",(int)element_index(ae), element_value(ae));
542}
543
544print_array(a)
545ARRAY *a;
546{
547 printf("\n");
548 array_walk(a, print_element);
549}
550
551main()
552{
553 ARRAY *a, *new_a, *copy_of_a;
554 ARRAY_ELEMENT *ae;
555 char *s;
556
557 a = new_array();
558 array_add_element(a, 1, "one");
559 array_add_element(a, 7, "seven");
560 array_add_element(a, 4, "four");
561 array_add_element(a, 1029, "one thousand twenty-nine");
562 array_add_element(a, 12, "twelve");
563 array_add_element(a, 42, "forty-two");
564 print_array(a);
d166f048 565 s = array_to_string (a, " ", 0);
ccc6cda3
JA
566 printf("s = %s\n", s);
567 copy_of_a = string_to_array(s, " ");
568 printf("copy_of_a:");
569 print_array(copy_of_a);
570 dispose_array(copy_of_a);
571 printf("\n");
572 free(s);
573 ae = array_delete_element(a, 4);
574 destroy_array_element(ae);
575 ae = array_delete_element(a, 1029);
576 destroy_array_element(ae);
577 array_add_element(a, 16, "sixteen");
578 print_array(a);
d166f048 579 s = array_to_string (a, " ", 0);
ccc6cda3
JA
580 printf("s = %s\n", s);
581 copy_of_a = string_to_array(s, " ");
582 printf("copy_of_a:");
583 print_array(copy_of_a);
584 dispose_array(copy_of_a);
585 printf("\n");
586 free(s);
587 array_add_element(a, 2, "two");
588 array_add_element(a, 1029, "new one thousand twenty-nine");
589 array_add_element(a, 0, "zero");
590 array_add_element(a, 134, "");
591 print_array(a);
d166f048 592 s = array_to_string (a, ":", 0);
ccc6cda3
JA
593 printf("s = %s\n", s);
594 copy_of_a = string_to_array(s, ":");
595 printf("copy_of_a:");
596 print_array(copy_of_a);
597 dispose_array(copy_of_a);
598 printf("\n");
599 free(s);
600 new_a = copy_array(a);
601 print_array(new_a);
d166f048 602 s = array_to_string (new_a, ":", 0);
ccc6cda3 603 printf("s = %s\n", s);
d166f048 604 copy_of_a = string_to_array(s, ":", 0);
ccc6cda3
JA
605 printf("copy_of_a:");
606 print_array(copy_of_a);
607 dispose_array(copy_of_a);
608 printf("\n");
609 free(s);
610 dispose_array(a);
611 dispose_array(new_a);
612}
613
614#endif /* TEST_ARRAY */
615#endif /* ARRAY_VARS */