Imported from ../bash-3.1.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 #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 || (array_empty(a) && s == 0))
247                 return 0;
248         else 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                 if (array_num_elements(a) == 1)         /* array was empty */
257                         return 1;
258         }
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         a->max_index = element_index(a->head->prev);
267
268         return (a->num_elements);
269 }
270
271 ARRAY_ELEMENT *
272 array_unshift_element(a)
273 ARRAY   *a;
274 {
275         return (array_shift (a, 1, 0));
276 }
277
278 int
279 array_shift_element(a, v)
280 ARRAY   *a;
281 char    *v;
282 {
283         return (array_rshift (a, 1, v));
284 }
285
286 ARRAY   *
287 array_quote(array)
288 ARRAY   *array;
289 {
290         ARRAY_ELEMENT   *a;
291         char    *t;
292
293         if (array == 0 || array_head(array) == 0 || array_empty(array))
294                 return (ARRAY *)NULL;
295         for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
296                 t = quote_string (a->value);
297                 FREE(a->value);
298                 a->value = t;
299         }
300         return array;
301 }
302
303 /*
304  * Return a string whose elements are the members of array A beginning at
305  * index START and spanning NELEM members.  Null elements are counted.
306  * Since arrays are sparse, unset array elements are not counted.
307  */
308 char *
309 array_subrange (a, start, nelem, starsub, quoted)
310 ARRAY   *a;
311 arrayind_t      start, nelem;
312 int     starsub, quoted;
313 {
314         ARRAY_ELEMENT   *h, *p;
315         arrayind_t      i;
316         char            *ifs, sep[2];
317
318         p = a ? array_head (a) : 0;
319         if (p == 0 || array_empty (a) || start > array_max_index(a))
320                 return ((char *)NULL);
321
322         /*
323          * Find element with index START.  If START corresponds to an unset
324          * element (arrays can be sparse), use the first element whose index
325          * is >= START.  If START is < 0, we count START indices back from
326          * the end of A (not elements, even with sparse arrays -- START is an
327          * index).
328          */
329         for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p))
330                 ;
331
332         if (p == a->head)
333                 return ((char *)NULL);
334
335         /* Starting at P, take NELEM elements, inclusive. */
336         for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p))
337                 ;
338
339         if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
340                 ifs = getifs();
341                 sep[0] = ifs ? *ifs : '\0';
342         } else
343                 sep[0] = ' ';
344         sep[1] = '\0';
345
346         return (array_to_string_internal (h, p, sep, quoted));
347 }
348
349 char *
350 array_patsub (a, pat, rep, mflags)
351 ARRAY   *a;
352 char    *pat, *rep;
353 int     mflags;
354 {
355         ARRAY           *a2;
356         ARRAY_ELEMENT   *e;
357         char    *t, *ifs, sifs[2];
358
359         if (a == 0 || array_head(a) == 0 || array_empty(a))
360                 return ((char *)NULL);
361
362         a2 = array_copy(a);
363         for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
364                 t = pat_subst(element_value(e), pat, rep, mflags);
365                 FREE(element_value(e));
366                 e->value = t;
367         }
368
369         if (mflags & MATCH_QUOTED)
370                 array_quote (a2);
371         if (mflags & MATCH_STARSUB) {
372                 ifs = getifs();
373                 sifs[0] = ifs ? *ifs : '\0';
374                 sifs[1] = '\0';
375                 t = array_to_string (a2, sifs, 0);
376         } else
377                 t = array_to_string (a2, " ", 0);
378         array_dispose (a2);
379
380         return t;
381 }
382
383 /*
384  * Allocate and return a new array element with index INDEX and value
385  * VALUE.
386  */
387 ARRAY_ELEMENT *
388 array_create_element(indx, value)
389 arrayind_t      indx;
390 char    *value;
391 {
392         ARRAY_ELEMENT *r;
393
394         r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT));
395         r->ind = indx;
396         r->value = value ? savestring(value) : (char *)NULL;
397         r->next = r->prev = (ARRAY_ELEMENT *) NULL;
398         return(r);
399 }
400
401 #ifdef INCLUDE_UNUSED
402 ARRAY_ELEMENT *
403 array_copy_element(ae)
404 ARRAY_ELEMENT   *ae;
405 {
406         return(ae ? array_create_element(element_index(ae), element_value(ae))
407                   : (ARRAY_ELEMENT *) NULL);
408 }
409 #endif
410
411 void
412 array_dispose_element(ae)
413 ARRAY_ELEMENT   *ae;
414 {
415         if (ae) {
416                 FREE(ae->value);
417                 free(ae);
418         }
419 }
420
421 /*
422  * Add a new element with index I and value V to array A (a[i] = v).
423  */
424 int
425 array_insert(a, i, v)
426 ARRAY   *a;
427 arrayind_t      i;
428 char    *v;
429 {
430         register ARRAY_ELEMENT *new, *ae;
431
432         if (a == 0)
433                 return(-1);
434         new = array_create_element(i, v);
435         if (i > array_max_index(a)) {
436                 /*
437                  * Hook onto the end.  This also works for an empty array.
438                  * Fast path for the common case of allocating arrays
439                  * sequentially.
440                  */
441                 ADD_BEFORE(a->head, new);
442                 a->max_index = i;
443                 a->num_elements++;
444                 return(0);
445         }
446         /*
447          * Otherwise we search for the spot to insert it.
448          */
449         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
450                 if (element_index(ae) == i) {
451                         /*
452                          * Replacing an existing element.
453                          */
454                         array_dispose_element(new);
455                         free(element_value(ae));
456                         ae->value = v ? savestring(v) : (char *)NULL;
457                         return(0);
458                 } else if (element_index(ae) > i) {
459                         ADD_BEFORE(ae, new);
460                         a->num_elements++;
461                         return(0);
462                 }
463         }
464         return (-1);            /* problem */
465 }
466
467 /*
468  * Delete the element with index I from array A and return it so the
469  * caller can dispose of it.
470  */
471 ARRAY_ELEMENT *
472 array_remove(a, i)
473 ARRAY   *a;
474 arrayind_t      i;
475 {
476         register ARRAY_ELEMENT *ae;
477
478         if (a == 0 || array_empty(a))
479                 return((ARRAY_ELEMENT *) NULL);
480         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
481                 if (element_index(ae) == i) {
482                         ae->next->prev = ae->prev;
483                         ae->prev->next = ae->next;
484                         a->num_elements--;
485                         if (i == array_max_index(a))
486                                 a->max_index = element_index(ae->prev);
487                         return(ae);
488                 }
489         return((ARRAY_ELEMENT *) NULL);
490 }
491
492 /*
493  * Return the value of a[i].
494  */
495 char *
496 array_reference(a, i)
497 ARRAY   *a;
498 arrayind_t      i;
499 {
500         register ARRAY_ELEMENT *ae;
501
502         if (a == 0 || array_empty(a))
503                 return((char *) NULL);
504         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
505                 if (element_index(ae) == i)
506                         return(element_value(ae));
507         return((char *) NULL);
508 }
509
510 /* Convenience routines for the shell to translate to and from the form used
511    by the rest of the code. */
512
513 WORD_LIST *
514 array_to_word_list(a)
515 ARRAY   *a;
516 {
517         WORD_LIST       *list;
518         ARRAY_ELEMENT   *ae;
519
520         if (a == 0 || array_empty(a))
521                 return((WORD_LIST *)NULL);
522         list = (WORD_LIST *)NULL;
523         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae))
524                 list = make_word_list (make_bare_word(element_value(ae)), list);
525         return (REVERSE_LIST(list, WORD_LIST *));
526 }
527
528 ARRAY *
529 array_from_word_list (list)
530 WORD_LIST       *list;
531 {
532         ARRAY   *a;
533
534         if (list == 0)
535                 return((ARRAY *)NULL);
536         a = array_create();
537         return (array_assign_list (a, list));
538 }
539
540 WORD_LIST *
541 array_keys_to_word_list(a)
542 ARRAY   *a;
543 {
544         WORD_LIST       *list;
545         ARRAY_ELEMENT   *ae;
546         char            *t;
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                 t = itos(element_index(ae));
553                 list = make_word_list (make_bare_word(t), list);
554                 free(t);
555         }
556         return (REVERSE_LIST(list, WORD_LIST *));
557 }
558
559 ARRAY *
560 array_assign_list (array, list)
561 ARRAY   *array;
562 WORD_LIST       *list;
563 {
564         register WORD_LIST *l;
565         register arrayind_t i;
566
567         for (l = list, i = 0; l; l = l->next, i++)
568                 array_insert(array, i, l->word->word);
569         return array;
570 }
571
572 char **
573 array_to_argv (a)
574 ARRAY   *a;
575 {
576         char            **ret, *t;
577         int             i;
578         ARRAY_ELEMENT   *ae;
579
580         if (a == 0 || array_empty(a))
581                 return ((char **)NULL);
582         ret = strvec_create (array_num_elements (a) + 1);
583         i = 0;
584         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
585                 t = element_value (ae);
586                 ret[i++] = t ? savestring (t) : (char *)NULL;
587         }
588         ret[i] = (char *)NULL;
589         return (ret);
590 }
591         
592 /*
593  * Return a string that is the concatenation of all the elements in A,
594  * separated by SEP.
595  */
596 static char *
597 array_to_string_internal (start, end, sep, quoted)
598 ARRAY_ELEMENT   *start, *end;
599 char    *sep;
600 int     quoted;
601 {
602         char    *result, *t;
603         ARRAY_ELEMENT *ae;
604         int     slen, rsize, rlen, reg;
605
606         if (start == end)       /* XXX - should not happen */
607                 return ((char *)NULL);
608
609         slen = strlen(sep);
610         result = NULL;
611         for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) {
612                 if (rsize == 0)
613                         result = (char *)xmalloc (rsize = 64);
614                 if (element_value(ae)) {
615                         t = quoted ? quote_string(element_value(ae)) : element_value(ae);
616                         reg = strlen(t);
617                         RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2),
618                                                 rsize, rsize);
619                         strcpy(result + rlen, t);
620                         rlen += reg;
621                         if (quoted && t)
622                                 free(t);
623                         /*
624                          * Add a separator only after non-null elements.
625                          */
626                         if (element_forw(ae) != end) {
627                                 strcpy(result + rlen, sep);
628                                 rlen += slen;
629                         }
630                 }
631         }
632         if (result)
633           result[rlen] = '\0';  /* XXX */
634         return(result);
635 }
636
637 char *
638 array_to_assign (a, quoted)
639 ARRAY   *a;
640 int     quoted;
641 {
642         char    *result, *valstr, *is;
643         char    indstr[INT_STRLEN_BOUND(intmax_t) + 1];
644         ARRAY_ELEMENT *ae;
645         int     rsize, rlen, elen;
646
647         if (a == 0 || array_empty (a))
648                 return((char *)NULL);
649
650         result = (char *)xmalloc (rsize = 128);
651         result[0] = '(';
652         rlen = 1;
653
654         for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
655                 is = inttostr (element_index(ae), indstr, sizeof(indstr));
656                 valstr = element_value (ae) ? sh_double_quote (element_value(ae))
657                                             : (char *)NULL;
658                 elen = STRLEN (indstr) + 8 + STRLEN (valstr);
659                 RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
660
661                 result[rlen++] = '[';
662                 strcpy (result + rlen, is);
663                 rlen += STRLEN (is);
664                 result[rlen++] = ']';
665                 result[rlen++] = '=';
666                 if (valstr) {
667                         strcpy (result + rlen, valstr);
668                         rlen += STRLEN (valstr);
669                 }
670
671                 if (element_forw(ae) != a->head)
672                   result[rlen++] = ' ';
673
674                 FREE (valstr);
675         }
676         RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8);
677         result[rlen++] = ')';
678         result[rlen] = '\0';
679         if (quoted) {
680                 /* This is not as efficient as it could be... */
681                 valstr = sh_single_quote (result);
682                 free (result);
683                 result = valstr;
684         }
685         return(result);
686 }
687
688 char *
689 array_to_string (a, sep, quoted)
690 ARRAY   *a;
691 char    *sep;
692 int     quoted;
693 {
694         if (a == 0)
695                 return((char *)NULL);
696         if (array_empty(a))
697                 return(savestring(""));
698         return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted));
699 }
700
701 #if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY)
702 /*
703  * Return an array consisting of elements in S, separated by SEP
704  */
705 ARRAY *
706 array_from_string(s, sep)
707 char    *s, *sep;
708 {
709         ARRAY   *a;
710         WORD_LIST *w;
711
712         if (s == 0)
713                 return((ARRAY *)NULL);
714         w = list_string (s, sep, 0);
715         if (w == 0)
716                 return((ARRAY *)NULL);
717         a = array_from_word_list (w);
718         return (a);
719 }
720 #endif
721
722 #if defined (TEST_ARRAY)
723 /*
724  * To make a running version, compile -DTEST_ARRAY and link with:
725  *      xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a
726  */
727 int interrupt_immediately = 0;
728
729 int
730 signal_is_trapped(s)
731 int     s;
732 {
733         return 0;
734 }
735
736 void
737 fatal_error(const char *s, ...)
738 {
739         fprintf(stderr, "array_test: fatal memory error\n");
740         abort();
741 }
742
743 void
744 programming_error(const char *s, ...)
745 {
746         fprintf(stderr, "array_test: fatal programming error\n");
747         abort();
748 }
749
750 WORD_DESC *
751 make_bare_word (s)
752 const char      *s;
753 {
754         WORD_DESC *w;
755
756         w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC));
757         w->word = s ? savestring(s) : savestring ("");
758         w->flags = 0;
759         return w;
760 }
761
762 WORD_LIST *
763 make_word_list(x, l)
764 WORD_DESC       *x;
765 WORD_LIST       *l;
766 {
767         WORD_LIST *w;
768
769         w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST));
770         w->word = x;
771         w->next = l;
772         return w;
773 }
774
775 WORD_LIST *
776 list_string(s, t, i)
777 char    *s, *t;
778 int     i;
779 {
780         char    *r, *a;
781         WORD_LIST       *wl;
782
783         if (s == 0)
784                 return (WORD_LIST *)NULL;
785         r = savestring(s);
786         wl = (WORD_LIST *)NULL;
787         a = strtok(r, t);
788         while (a) {
789                 wl = make_word_list (make_bare_word(a), wl);
790                 a = strtok((char *)NULL, t);
791         }
792         return (REVERSE_LIST (wl, WORD_LIST *));
793 }
794
795 GENERIC_LIST *
796 list_reverse (list)
797 GENERIC_LIST    *list;
798 {
799         register GENERIC_LIST *next, *prev;
800
801         for (prev = 0; list; ) {
802                 next = list->next;
803                 list->next = prev;
804                 prev = list;
805                 list = next;
806         }
807         return prev;
808 }
809
810 char *
811 pat_subst(s, t, u, i)
812 char    *s, *t, *u;
813 int     i;
814 {
815         return ((char *)NULL);
816 }
817
818 char *
819 quote_string(s)
820 char    *s;
821 {
822         return savestring(s);
823 }
824
825 print_element(ae)
826 ARRAY_ELEMENT   *ae;
827 {
828         char    lbuf[INT_STRLEN_BOUND (intmax_t) + 1];
829
830         printf("array[%s] = %s\n",
831                 inttostr (element_index(ae), lbuf, sizeof (lbuf)),
832                 element_value(ae));
833 }
834
835 print_array(a)
836 ARRAY   *a;
837 {
838         printf("\n");
839         array_walk(a, print_element, (void *)NULL);
840 }
841
842 main()
843 {
844         ARRAY   *a, *new_a, *copy_of_a;
845         ARRAY_ELEMENT   *ae, *aew;
846         char    *s;
847
848         a = array_create();
849         array_insert(a, 1, "one");
850         array_insert(a, 7, "seven");
851         array_insert(a, 4, "four");
852         array_insert(a, 1029, "one thousand twenty-nine");
853         array_insert(a, 12, "twelve");
854         array_insert(a, 42, "forty-two");
855         print_array(a);
856         s = array_to_string (a, " ", 0);
857         printf("s = %s\n", s);
858         copy_of_a = array_from_string(s, " ");
859         printf("copy_of_a:");
860         print_array(copy_of_a);
861         array_dispose(copy_of_a);
862         printf("\n");
863         free(s);
864         ae = array_remove(a, 4);
865         array_dispose_element(ae);
866         ae = array_remove(a, 1029);
867         array_dispose_element(ae);
868         array_insert(a, 16, "sixteen");
869         print_array(a);
870         s = array_to_string (a, " ", 0);
871         printf("s = %s\n", s);
872         copy_of_a = array_from_string(s, " ");
873         printf("copy_of_a:");
874         print_array(copy_of_a);
875         array_dispose(copy_of_a);
876         printf("\n");
877         free(s);
878         array_insert(a, 2, "two");
879         array_insert(a, 1029, "new one thousand twenty-nine");
880         array_insert(a, 0, "zero");
881         array_insert(a, 134, "");
882         print_array(a);
883         s = array_to_string (a, ":", 0);
884         printf("s = %s\n", s);
885         copy_of_a = array_from_string(s, ":");
886         printf("copy_of_a:");
887         print_array(copy_of_a);
888         array_dispose(copy_of_a);
889         printf("\n");
890         free(s);
891         new_a = array_copy(a);
892         print_array(new_a);
893         s = array_to_string (new_a, ":", 0);
894         printf("s = %s\n", s);
895         copy_of_a = array_from_string(s, ":");
896         free(s);
897         printf("copy_of_a:");
898         print_array(copy_of_a);
899         array_shift(copy_of_a, 2, AS_DISPOSE);
900         printf("copy_of_a shifted by two:");
901         print_array(copy_of_a);
902         ae = array_shift(copy_of_a, 2, 0);
903         printf("copy_of_a shifted by two:");
904         print_array(copy_of_a);
905         for ( ; ae; ) {
906                 aew = element_forw(ae);
907                 array_dispose_element(ae);
908                 ae = aew;
909         }
910         array_rshift(copy_of_a, 1, (char *)0);
911         printf("copy_of_a rshift by 1:");
912         print_array(copy_of_a);
913         array_rshift(copy_of_a, 2, "new element zero");
914         printf("copy_of_a rshift again by 2 with new element zero:");
915         print_array(copy_of_a);
916         s = array_to_assign(copy_of_a, 0);
917         printf("copy_of_a=%s\n", s);
918         free(s);
919         ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0);
920         for ( ; ae; ) {
921                 aew = element_forw(ae);
922                 array_dispose_element(ae);
923                 ae = aew;
924         }
925         array_dispose(copy_of_a);
926         printf("\n");
927         array_dispose(a);
928         array_dispose(new_a);
929 }
930
931 #endif /* TEST_ARRAY */
932 #endif /* ARRAY_VARS */