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 56static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int)); 57 58ARRAY * 59array_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 74void 75array_flush (a) 76ARRAY *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 92void 93array_dispose(a) 94ARRAY *a; 95{ 96 if (a == 0) 97 return; 98 array_flush (a); 99 array_dispose_element(a->head); 100 free(a); 101} 102 103ARRAY * 104array_copy(a) 105ARRAY *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 */ 127ARRAY * 128array_slice(array, s, e) 129ARRAY *array; 130ARRAY_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 */ 154void 155array_walk(a, func, udata) 156ARRAY *a; 157sh_ae_map_func_t *func; 158void *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 */ 177ARRAY_ELEMENT * 178array_shift(a, n, flags) 179ARRAY *a; 180int 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 */ 236int 237array_rshift (a, n, s) 238ARRAY *a; 239int n; 240char *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 269ARRAY_ELEMENT * 270array_unshift_element(a) 271ARRAY *a; 272{ 273 return (array_shift (a, 1, 0)); 274} 275 276int 277array_shift_element(a, v) 278ARRAY *a; 279char *v; 280{ 281 return (array_rshift (a, 1, v)); 282} 283 284ARRAY * 285array_quote(array) 286ARRAY *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 301ARRAY * 302array_quote_escapes(array) 303ARRAY *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 */ 323char * 324array_subrange (a, start, nelem, starsub, quoted) 325ARRAY *a; 326arrayind_t start, nelem; 327int 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 375char * 376array_patsub (a, pat, rep, mflags) 377ARRAY *a; 378char *pat, *rep; 379int 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 */ 415ARRAY_ELEMENT * 416array_create_element(indx, value) 417arrayind_t indx; 418char *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 430ARRAY_ELEMENT * 431array_copy_element(ae) 432ARRAY_ELEMENT *ae; 433{ 434 return(ae ? array_create_element(element_index(ae), element_value(ae)) 435 : (ARRAY_ELEMENT *) NULL); 436} 437#endif 438 439void 440array_dispose_element(ae) 441ARRAY_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 */ 452int 453array_insert(a, i, v) 454ARRAY *a; 455arrayind_t i; 456char *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 */ 499ARRAY_ELEMENT * 500array_remove(a, i) 501ARRAY *a; 502arrayind_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 */ 523char * 524array_reference(a, i) 525ARRAY *a; 526arrayind_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 541WORD_LIST * 542array_to_word_list(a) 543ARRAY *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 556ARRAY * 557array_from_word_list (list) 558WORD_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 568WORD_LIST * 569array_keys_to_word_list(a) 570ARRAY *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 587ARRAY * 588array_assign_list (array, list) 589ARRAY *array; 590WORD_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 600char ** 601array_to_argv (a) 602ARRAY *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 */ 624static char * 625array_to_string_internal (start, end, sep, quoted) 626ARRAY_ELEMENT *start, *end; 627char *sep; 628int 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 665char * 666array_to_assign (a, quoted) 667ARRAY *a; 668int 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 716char * 717array_to_string (a, sep, quoted) 718ARRAY *a; 719char *sep; 720int 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 */ 733ARRAY * 734array_from_string(s, sep) 735char *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 */ 755int interrupt_immediately = 0; 756 757int 758signal_is_trapped(s) 759int s; 760{ 761 return 0; 762} 763 764void 765fatal_error(const char *s, ...) 766{ 767 fprintf(stderr, "array_test: fatal memory error\n"); 768 abort(); 769} 770 771void 772programming_error(const char *s, ...) 773{ 774 fprintf(stderr, "array_test: fatal programming error\n"); 775 abort(); 776} 777 778WORD_DESC * 779make_bare_word (s) 780const 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 790WORD_LIST * 791make_word_list(x, l) 792WORD_DESC *x; 793WORD_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 803WORD_LIST * 804list_string(s, t, i) 805char *s, *t; 806int 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 823GENERIC_LIST * 824list_reverse (list) 825GENERIC_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 838char * 839pat_subst(s, t, u, i) 840char *s, *t, *u; 841int i; 842{ 843 return ((char *)NULL); 844} 845 846char * 847quote_string(s) 848char *s; 849{ 850 return savestring(s); 851} 852 853print_element(ae) 854ARRAY_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 863print_array(a) 864ARRAY *a; 865{ 866 printf("\n"); 867 array_walk(a, print_element, (void *)NULL); 868} 869 870main() 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 */ 961