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