Imported from ../bash-2.02.tar.gz.
[platform/upstream/bash.git] / array.c
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)
16 #  ifdef _MINIX
17 #    include <sys/types.h>
18 #  endif
19 #  include <unistd.h>
20 #endif
21
22 #include <stdio.h>
23 #include "bashansi.h"
24
25 #include "shell.h"
26 #include "array.h"
27 #include "builtins/common.h"
28
29 extern 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  */
43 ARRAY_ELEMENT *
44 new_array_element(indx, value)
45 arrayind_t      indx;
46 char    *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
57 void
58 destroy_array_element(ae)
59 ARRAY_ELEMENT   *ae;
60 {
61         FREE(ae->value);
62         free(ae);
63 }
64
65 ARRAY *
66 new_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
81 void
82 empty_array (a)
83 ARRAY   *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
99 void
100 dispose_array(a)
101 ARRAY   *a;
102 {
103         if (a == 0)
104                 return;
105         empty_array (a);
106         destroy_array_element(a->head);
107         free(a);
108 }
109
110 ARRAY *
111 dup_array(a)
112 ARRAY   *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
131 #ifdef INCLUDE_UNUSED
132 /*
133  * Make and return a new array composed of the elements in array A from
134  * S to E, inclusive.
135  */
136 ARRAY *
137 dup_array_subrange(array, s, e)
138 ARRAY           *array;
139 ARRAY_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 }
155 #endif
156
157 #ifdef INCLUDE_UNUSED
158 ARRAY_ELEMENT *
159 copy_array_element(ae)
160 ARRAY_ELEMENT   *ae;
161 {
162         return(ae ? new_array_element(element_index(ae), element_value(ae))
163                   : (ARRAY_ELEMENT *) NULL);
164 }
165 #endif
166
167 /*
168  * Add a new element with index I and value V to array A (a[i] = v).
169  */
170 int
171 array_add_element(a, i, v)
172 ARRAY   *a;
173 arrayind_t      i;
174 char    *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  */
217 ARRAY_ELEMENT *
218 array_delete_element(a, i)
219 ARRAY   *a;
220 arrayind_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  */
241 char *
242 array_reference(a, i)
243 ARRAY   *a;
244 arrayind_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
256 #ifdef TEST_ARRAY
257 /*
258  * Walk the array, calling FUNC once for each element, with the array
259  * element as the argument.
260  */
261 void
262 array_walk(a, func)
263 ARRAY   *a;
264 Function *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 }
273 #endif
274
275 /*
276  * Return a string that is the concatenation of all the elements in A,
277  * separated by SEP.
278  */
279 static char *
280 array_to_string_internal (start, end, sep, quoted)
281 ARRAY_ELEMENT   *start, *end;
282 char    *sep;
283 int     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
318 char *
319 array_to_string (a, sep, quoted)
320 ARRAY   *a;
321 char    *sep;
322 int     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
331 char *
332 array_to_assignment_string (a)
333 ARRAY   *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
375 char *
376 quoted_array_assignment_string (a)
377 ARRAY   *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. */
393 static char *
394 sindex (s1, s2)
395 register 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
406 #if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY)
407 /*
408  * Return an array consisting of elements in S, separated by SEP
409  */
410 ARRAY *
411 string_to_array(s, sep)
412 char    *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 }
425 #endif
426
427 /* Convenience routines for the shell to translate to and from the form used
428    by the rest of the code. */
429 WORD_LIST *
430 array_to_word_list(a)
431 ARRAY   *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
444 ARRAY *
445 assign_word_list (array, list)
446 ARRAY   *array;
447 WORD_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
457 ARRAY *
458 word_list_to_array (list)
459 WORD_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
469 ARRAY   *
470 array_quote(array)
471 ARRAY   *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
486 char *
487 array_subrange (a, start, end, quoted)
488 ARRAY   *a;
489 int     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
508 char *
509 array_pat_subst (a, pat, rep, mflags)
510 ARRAY   *a;
511 char    *pat, *rep;
512 int     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)
538 print_element(ae)
539 ARRAY_ELEMENT   *ae;
540 {
541         printf("array[%d] = %s\n",(int)element_index(ae), element_value(ae));
542 }
543
544 print_array(a)
545 ARRAY   *a;
546 {
547         printf("\n");
548         array_walk(a, print_element);
549 }
550
551 main()
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);
565         s = array_to_string (a, " ", 0);
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);
579         s = array_to_string (a, " ", 0);
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);
592         s = array_to_string (a, ":", 0);
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);
602         s = array_to_string (new_a, ":", 0);
603         printf("s = %s\n", s);
604         copy_of_a = string_to_array(s, ":", 0);
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 */