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