1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * Array processing routines 23 * 24 * David Korn 25 * AT&T Labs 26 * dgk@research.att.com 27 * 28 */ 29 30 #include "defs.h" 31 #include <stak.h> 32 #include "name.h" 33 34 #define NUMSIZE (4+(ARRAY_MAX>999)+(ARRAY_MAX>9999)+(ARRAY_MAX>99999)) 35 #define is_associative(ap) array_assoc((Namarr_t*)(ap)) 36 #define array_setbit(cp, n) (cp[(n)/CHAR_BIT] |= 1<<(((n)&(CHAR_BIT-1)))) 37 #define array_clrbit(cp, n) (cp[(n)/CHAR_BIT] &= ~(1<<(((n)&(CHAR_BIT-1))))) 38 #define array_isbit(cp, n) (cp[(n)/CHAR_BIT] & 1<<(((n)&(CHAR_BIT-1)))) 39 #define NV_CHILD NV_EXPORT 40 41 static char Empty[] = ""; 42 43 struct index_array 44 { 45 Namarr_t header; 46 int cur; /* index of current element */ 47 int maxi; /* maximum index for array */ 48 unsigned char *bits; /* bit array for child subscripts */ 49 union Value val[1]; /* array of value holders */ 50 }; 51 52 struct assoc_array 53 { 54 Namarr_t header; 55 Dt_t *table; 56 Namval_t *pos; 57 Namval_t *nextpos; 58 Namval_t *cur; 59 }; 60 61 /* 62 * replace discipline with new one 63 */ 64 static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new) 65 { 66 register Namfun_t **fp = &np->nvfun; 67 while(*fp && *fp!= &old->header.hdr) 68 fp = &((*fp)->next); 69 if(*fp) 70 { 71 new->header.hdr.next = (*fp)->next; 72 *fp = &new->header.hdr; 73 } 74 else sfprintf(sfstderr,"discipline not replaced\n"); 75 } 76 77 /* 78 * Calculate the amount of space to be allocated to hold an 79 * indexed array into which <maxi> is a legal index. The number of 80 * elements that will actually fit into the array (> <maxi> 81 * but <= ARRAY_MAX) is returned. 82 * 83 */ 84 static int arsize(register int maxi) 85 { 86 register int i = roundof(maxi,ARRAY_INCR); 87 return (i>ARRAY_MAX?ARRAY_MAX:i); 88 } 89 90 static struct index_array *array_grow(Namval_t*, struct index_array*,int); 91 92 /* return index of highest element of an array */ 93 int array_maxindex(Namval_t *np) 94 { 95 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 96 register int i = ap->maxi; 97 if(is_associative(ap)) 98 return(-1); 99 while(i>0 && ap->val[--i].cp==0); 100 return(i+1); 101 } 102 103 static union Value *array_getup(Namval_t *np, Namarr_t *arp) 104 { 105 register struct index_array *ap = (struct index_array*)arp; 106 register union Value *up; 107 if(!nv_isarray(np)) 108 return(&np->nvalue); 109 if(is_associative(ap)) 110 up = (union Value*)((*arp->fun)(np,NIL(char*),0)); 111 else 112 { 113 if(ap->cur >= ap->maxi) 114 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 115 up = &(ap->val[ap->cur]); 116 } 117 return(up); 118 } 119 120 /* 121 * Get the Value pointer for an array. 122 * Delete space as necessary if flag is ARRAY_DELETE 123 * After the lookup is done the last @ or * subscript is incremented 124 */ 125 static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag) 126 { 127 register struct index_array *ap = (struct index_array*)arp; 128 register union Value *up; 129 Namval_t *mp; 130 int wasundef; 131 if(wasundef = ap->header.nelem&ARRAY_UNDEF) 132 { 133 ap->header.nelem &= ~ARRAY_UNDEF; 134 /* delete array is the same as delete array[@] */ 135 if(flag&ARRAY_DELETE) 136 { 137 nv_putsub(np, NIL(char*), ARRAY_SCAN); 138 ap->header.nelem |= ARRAY_SCAN; 139 } 140 else /* same as array[0] */ 141 { 142 if(is_associative(ap)) 143 (*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0); 144 else 145 ap->cur = 0; 146 } 147 } 148 if(is_associative(ap)) 149 { 150 mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT)); 151 if(!mp) 152 up = (union Value*)∓ 153 else if(nv_isattr(mp,NV_CHILD)) 154 { 155 if(wasundef && nv_isarray(mp->nvalue.np)) 156 nv_putsub(mp->nvalue.np,NIL(char*),ARRAY_UNDEF); 157 return(mp->nvalue.np); 158 } 159 else 160 up = &mp->nvalue; 161 } 162 else 163 { 164 if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi) 165 ap = array_grow(np, ap, (int)ap->cur); 166 if(ap->cur>=ap->maxi) 167 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 168 up = &(ap->val[ap->cur]); 169 if(up->np && array_isbit(ap->bits,ap->cur)) 170 { 171 if(wasundef && nv_isarray(up->np)) 172 nv_putsub(up->np,NIL(char*),ARRAY_UNDEF); 173 return(up->np); 174 } 175 } 176 np->nvalue.cp = up->cp; 177 if(!up->cp) 178 { 179 if(flag!=ARRAY_ASSIGN) 180 return(0); 181 ap->header.nelem++; 182 } 183 return(np); 184 } 185 186 static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp) 187 { 188 Namarr_t *ap = (Namarr_t*)fp; 189 Namval_t *nq, *mq; 190 char *name, *sub=0; 191 int nelem = ap->nelem,offset=staktell(); 192 struct index_array *aq, *ar; 193 if(nelem&ARRAY_NOCLONE) 194 return(0); 195 if(array_assoc(ap)) 196 nv_setarray(mp,ap->fun); 197 else 198 { 199 nv_putsub(mp,NIL(char*),ap->nelem); 200 if(aq=(struct index_array*)nv_arrayptr(mp)) 201 aq->bits = (unsigned char*)&aq->val[aq->maxi]; 202 } 203 if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np))) 204 sub = strdup(sub); 205 ar = (struct index_array*)ap; 206 nv_onattr(mp,nv_isattr(np,NV_INTEGER|NV_UTOL|NV_LTOU|NV_LJUST|NV_RJUST|NV_ZFILL|NV_BINARY)); 207 nv_putsub(np,NIL(char*),ARRAY_SCAN); 208 do 209 { 210 if(array_assoc(ap)) 211 name = (char*)((*ap->fun)(np,NIL(char*),NV_ANAME)); 212 else 213 name = nv_getsub(np); 214 nv_putsub(mp,name,ARRAY_ADD); 215 if((!array_assoc(ap) && array_isbit(ar->bits,ar->cur) && (nq=np)) || 216 (array_assoc(ap) && (nq = (Namval_t*)((*ap->fun)(np,NIL(char*),NV_ACURRENT))) && nv_isattr(nq, NV_CHILD))) 217 { 218 sfprintf(stkstd,"%s[%s]",nv_name(mp),name); 219 stakputc(0); 220 mq = nv_search(stakptr(offset), sh.var_tree, NV_ADD); 221 stakseek(offset); 222 if(mq) 223 { 224 nv_clone(nq->nvalue.np,mq,0); 225 if(array_assoc(ap)) 226 { 227 nq = (Namval_t*)((*ap->fun)(mp,NIL(char*),NV_ACURRENT)); 228 nq->nvalue.np = mp; 229 nv_onattr(nq,NV_CHILD); 230 } 231 else if(aq) 232 { 233 array_setbit(aq->bits,aq->cur); 234 aq->val[aq->cur].np = mq; 235 } 236 } 237 } 238 else if(nv_isattr(np,NV_INTEGER)) 239 { 240 Sfdouble_t d= nv_getnum(np); 241 nv_putval(mp,(char*)&d,NV_LDOUBLE); 242 } 243 else 244 nv_putval(mp,nv_getval(np),NV_RDONLY); 245 } 246 while(nv_nextsub(np)); 247 if(sub) 248 { 249 nv_putsub(np,sub,0L); 250 free((void*)sub); 251 } 252 ap->nelem = nelem; 253 ((Namarr_t*)mp->nvfun)->nelem = nelem; 254 return(nv_stack(mp,(Namfun_t*)0)); 255 } 256 257 static char *array_getval(Namval_t *np, Namfun_t *disc) 258 { 259 register Namarr_t *ap = (Namarr_t*)disc; 260 register Namval_t *mp; 261 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 262 return(mp?nv_getval(mp):0); 263 return(nv_getv(np,&ap->hdr)); 264 } 265 266 static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc) 267 { 268 register Namarr_t *ap = (Namarr_t*)disc; 269 register Namval_t *mp; 270 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 271 return(mp?nv_getnum(mp):0); 272 return(nv_getn(np,&ap->hdr)); 273 } 274 275 static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp) 276 { 277 register Namarr_t *ap = (Namarr_t*)dp; 278 register union Value *up; 279 register Namval_t *mp; 280 register struct index_array *aq = (struct index_array*)ap; 281 do 282 { 283 mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE); 284 if(mp && mp!=np) 285 nv_putval(mp, string, flags); 286 if(!string) 287 { 288 if(mp) 289 { 290 if(mp!=np) 291 { 292 dtdelete(sh.var_tree,(void*)mp); 293 free((void*)mp); 294 } 295 if(is_associative(ap)) 296 (*ap->fun)(np,NIL(char*),NV_ADELETE); 297 else if(mp!=np) 298 { 299 array_clrbit(aq->bits,aq->cur); 300 aq->val[aq->cur].cp = 0; 301 } 302 ap->nelem--; 303 } 304 if(array_elem(ap)==0 && ((ap->nelem&ARRAY_SCAN) || !is_associative(ap))) 305 { 306 if(is_associative(ap)) 307 (*ap->fun)(np, NIL(char*), NV_AFREE); 308 nv_offattr(np,NV_ARRAY); 309 } 310 if(!mp || mp!=np) 311 continue; 312 } 313 /* prevent empty string from being deleted */ 314 if(np->nvalue.cp == Empty) 315 np->nvalue.cp = 0; 316 nv_putv(np,string,flags,&ap->hdr); 317 up = array_getup(np,ap); 318 up->cp = np->nvalue.cp; 319 } 320 while(!string && nv_nextsub(np)); 321 if(!string && !nv_isattr(np,NV_ARRAY)) 322 { 323 Namfun_t *nfp; 324 if(nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) 325 free((void*)nfp); 326 } 327 } 328 329 static const Namdisc_t array_disc = 330 { 331 sizeof(Namarr_t), 332 array_putval, 333 array_getval, 334 array_getnum, 335 0, 336 0, 337 array_clone 338 }; 339 340 /* 341 * Increase the size of the indexed array of elements in <arp> 342 * so that <maxi> is a legal index. If <arp> is 0, an array 343 * of the required size is allocated. A pointer to the 344 * allocated Namarr_t structure is returned. 345 * <maxi> becomes the current index of the array. 346 */ 347 static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi) 348 { 349 register struct index_array *ap; 350 register int i=0; 351 register int newsize = arsize(maxi+1); 352 if (maxi >= ARRAY_MAX) 353 errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0)); 354 ap = new_of(struct index_array,(newsize-1)*sizeof(union Value*)+newsize/CHAR_BIT); 355 memset((void*)ap,0,sizeof(*ap)); 356 ap->maxi = newsize; 357 ap->cur = maxi; 358 ap->bits = (unsigned char*)&ap->val[newsize]; 359 memset(ap->bits, 0, newsize/CHAR_BIT); 360 if(arp) 361 { 362 ap->header = arp->header; 363 for(;i < arp->maxi;i++) 364 ap->val[i].cp = arp->val[i].cp; 365 memcpy(ap->bits, arp->bits, (arp->maxi/CHAR_BIT)); 366 array_setptr(np,arp,ap); 367 free((void*)arp); 368 } 369 else 370 { 371 ap->header.fun = 0; 372 if((ap->val[0].cp=np->nvalue.cp)) 373 i++; 374 else if(nv_hasdisc(np,&array_disc)) 375 { 376 Namval_t *mp; 377 int offset = staktell(); 378 sfprintf(stkstd,"%s[0]",nv_name(np)); 379 stakputc(0); 380 mp = nv_search(stakptr(offset), sh.var_tree, NV_ADD); 381 stakseek(offset); 382 if(mp && nv_isnull(mp)) 383 { 384 nv_clone(np,mp,0); 385 ap->val[0].np = mp; 386 array_setbit(ap->bits,0); 387 } 388 i++; 389 } 390 else if(nv_isattr(np,NV_INTEGER)) 391 { 392 Sfdouble_t d= nv_getnum(np); 393 i++; 394 } 395 ap->header.nelem = i; 396 ap->header.hdr.nofree = 1; 397 ap->header.hdr.disc = &array_disc; 398 nv_disc(np,(Namfun_t*)ap, NV_LAST); 399 } 400 for(;i < newsize;i++) 401 ap->val[i].cp = 0; 402 return(ap); 403 } 404 405 Namarr_t *nv_arrayptr(register Namval_t *np) 406 { 407 if(nv_isattr(np,NV_ARRAY)) 408 return((Namarr_t*)nv_hasdisc(np, &array_disc)); 409 return(0); 410 } 411 412 /* 413 * Verify that argument is an indexed array and convert to associative, 414 * freeing relevant storage 415 */ 416 static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 417 { 418 register Namarr_t *ap; 419 char numbuff[NUMSIZE+1]; 420 unsigned dot, digit, n; 421 union Value *up; 422 struct index_array *save_ap; 423 register char *string_index=&numbuff[NUMSIZE]; 424 numbuff[NUMSIZE]='\0'; 425 426 if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap)) 427 return(NIL(Namarr_t*)); 428 429 nv_stack(np,&ap->hdr); 430 save_ap = (struct index_array*)nv_stack(np,0); 431 ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)); 432 ap->nelem = 0; 433 ap->fun = fun; 434 nv_onattr(np,NV_ARRAY); 435 436 for(dot = 0; dot < (unsigned)save_ap->maxi; dot++) 437 { 438 if(save_ap->val[dot].cp) 439 { 440 if ((digit = dot)== 0) 441 *--string_index = '0'; 442 else while( n = digit ) 443 { 444 digit /= 10; 445 *--string_index = '0' + (n-10*digit); 446 } 447 nv_putsub(np, string_index, ARRAY_ADD); 448 up = (union Value*)((*ap->fun)(np,NIL(char*),0)); 449 ap->nelem++; 450 up->cp = save_ap->val[dot].cp; 451 save_ap->val[dot].cp = 0; 452 } 453 string_index = &numbuff[NUMSIZE]; 454 } 455 free((void*)save_ap); 456 return(ap); 457 } 458 459 /* 460 * set the associative array processing method for node <np> to <fun> 461 * The array pointer is returned if sucessful. 462 */ 463 Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 464 { 465 register Namarr_t *ap; 466 char *value; 467 if(fun && (ap = nv_arrayptr(np))) 468 { 469 /* 470 * if it's already an indexed array, convert to 471 * associative structure 472 */ 473 if(!is_associative(ap)) 474 ap = nv_changearray(np, fun); 475 return(ap); 476 } 477 value = nv_getval(np); 478 if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)))) 479 { 480 /* check for preexisting initialization and save */ 481 ap->nelem = 0; 482 ap->fun = fun; 483 nv_onattr(np,NV_ARRAY); 484 if(value) 485 { 486 nv_putsub(np, "0", ARRAY_ADD); 487 nv_putval(np, value, 0); 488 } 489 return(ap); 490 } 491 return(NIL(Namarr_t*)); 492 } 493 494 /* 495 * move parent subscript into child 496 */ 497 Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c) 498 { 499 register Namarr_t *ap = nv_arrayptr(np); 500 union Value *up; 501 if(!(up = array_getup(np,ap))) 502 return((Namval_t*)0); 503 if(!nq) 504 return(array_find(np,ap, ARRAY_LOOKUP)); 505 np->nvalue.cp = up->cp; 506 ap->nelem |= ARRAY_NOCLONE; 507 nv_clone(np, nq, NV_NODISC); 508 nv_offattr(nq,NV_ARRAY); 509 ap->nelem &= ~ARRAY_NOCLONE; 510 if(ap->fun) 511 { 512 up->np = (Namval_t*)((*ap->fun)(np,NIL(char*),NV_ACURRENT)); 513 nv_onattr(up->np, NV_CHILD); 514 (up->np)->nvalue.np = nq; 515 } 516 else 517 { 518 struct index_array *aq = (struct index_array*)ap; 519 array_setbit(aq->bits,aq->cur); 520 up->np = nq; 521 } 522 if(c=='.') 523 nv_setvtree(nq); 524 return(nq); 525 } 526 527 /* 528 * This routine sets subscript of <np> to the next element, if any. 529 * The return value is zero, if there are no more elements 530 * Otherwise, 1 is returned. 531 */ 532 int nv_nextsub(Namval_t *np) 533 { 534 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 535 register unsigned dot; 536 if(!ap || !(ap->header.nelem&ARRAY_SCAN)) 537 return(0); 538 if(is_associative(ap)) 539 { 540 struct assoc_array *aq; 541 if(aq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT)) 542 { 543 if(nv_isattr(aq->cur,NV_CHILD)) 544 nv_putsub(aq->cur->nvalue.np,NIL(char*),ARRAY_UNDEF); 545 return(1); 546 } 547 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 548 return(0); 549 } 550 for(dot=ap->cur+1; dot < (unsigned)ap->maxi; dot++) 551 { 552 if(ap->val[dot].cp) 553 { 554 ap->cur = dot; 555 if(array_isbit(ap->bits, dot)) 556 { 557 558 if(ap->header.nelem&ARRAY_NOCHILD) 559 continue; 560 nv_putsub(ap->val[dot].np,NIL(char*),ARRAY_UNDEF); 561 } 562 return(1); 563 } 564 } 565 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 566 ap->cur = 0; 567 return(0); 568 } 569 570 /* 571 * Set an array subscript for node <np> given the subscript <sp> 572 * An array is created if necessary. 573 * <mode> can be a number, plus or more of symbolic constants 574 * ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD 575 * The node pointer is returned which can be NULL if <np> is 576 * not already array and the ARRAY_ADD bit of <mode> is not set. 577 * ARRAY_FILL sets the specified subscript to the empty string when 578 * ARRAY_ADD is specified and there is no value or sets all 579 * the elements up to the number specified if ARRAY_ADD is not specified 580 */ 581 Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode) 582 { 583 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 584 register int size = (mode&ARRAY_MASK); 585 if(!ap || !ap->header.fun) 586 { 587 if(sp) 588 size = (int)sh_arith((char*)sp); 589 if(size >= ARRAY_MAX || (size < 0)) 590 { 591 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 592 return(NIL(Namval_t*)); 593 } 594 if(!ap || size>=ap->maxi) 595 { 596 if(size==0 && !(mode&ARRAY_FILL)) 597 return(NIL(Namval_t*)); 598 if(sh.subshell) 599 np = sh_assignok(np,1); 600 ap = array_grow(np, ap,size); 601 nv_onattr(np,NV_ARRAY); 602 } 603 ap->header.nelem &= ~ARRAY_UNDEF; 604 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF)); 605 ap->cur = size; 606 if((mode&ARRAY_SCAN) && !ap->val[size].cp && !nv_nextsub(np)) 607 np = 0; 608 if(mode&ARRAY_FILL) 609 { 610 if(!(mode&ARRAY_ADD)) 611 { 612 int n; 613 for(n=0; n < size; n++) 614 { 615 if(!ap->val[n].cp) 616 ap->val[n].cp = Empty; 617 } 618 ap->header.nelem = n|(ap->header.nelem&(ARRAY_SCAN|ARRAY_UNDEF)); 619 if(n=ap->maxi-ap->maxi) 620 memset(&ap->val[size],0,n*sizeof(union Value)); 621 } 622 else if(!ap->val[size].cp) 623 { 624 if(sh.subshell) 625 np = sh_assignok(np,1); 626 ap->val[size].cp = Empty; 627 ap->header.nelem++; 628 } 629 } 630 else if(!(mode&ARRAY_SCAN)) 631 { 632 ap->header.nelem &= ~ARRAY_SCAN; 633 if(array_isbit(ap->bits,size)) 634 nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF); 635 } 636 return((Namval_t*)np); 637 } 638 ap->header.nelem &= ~ARRAY_UNDEF; 639 if(!(mode&ARRAY_FILL)) 640 ap->header.nelem &= ~ARRAY_SCAN; 641 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF)); 642 if(sp) 643 { 644 union Value *up; 645 if(mode&ARRAY_SETSUB) 646 { 647 (*ap->header.fun)(np, sp, NV_ASETSUB); 648 return(np); 649 } 650 up = (union Value*)(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0); 651 if(up && !up->cp && (mode&ARRAY_ADD) && (mode&ARRAY_FILL)) 652 { 653 if(sh.subshell) 654 np = sh_assignok(np,1); 655 up->cp = Empty; 656 ap->header.nelem++; 657 } 658 } 659 else if(mode&ARRAY_SCAN) 660 (*ap->header.fun)(np,(char*)np,0); 661 else if(mode&ARRAY_UNDEF) 662 (*ap->header.fun)(np, "",0); 663 if((mode&ARRAY_SCAN) && !nv_nextsub(np)) 664 np = 0; 665 return(np); 666 } 667 668 /* 669 * process an array subscript for node <np> given the subscript <cp> 670 * returns pointer to character after the subscript 671 */ 672 char *nv_endsubscript(Namval_t *np, register char *cp, int mode) 673 { 674 register int count=1, quoted=0, c; 675 register char *sp = cp+1; 676 /* first find matching ']' */ 677 while(count>0 && (c= *++cp)) 678 { 679 if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@')) 680 { 681 quoted=1; 682 cp++; 683 } 684 else if(c=='[') 685 count++; 686 else if(c==']') 687 count--; 688 } 689 *cp = 0; 690 if(quoted) 691 { 692 /* strip escape characters */ 693 count = staktell(); 694 stakwrite(sp,1+cp-sp); 695 sh_trim(sp=stakptr(count)); 696 } 697 if(mode && np) 698 nv_putsub(np, sp, ARRAY_ADD|(cp[1]?ARRAY_FILL:mode&ARRAY_FILL)); 699 if(quoted) 700 stakseek(count); 701 *cp++ = c; 702 return(cp); 703 } 704 705 706 Namval_t *nv_opensub(Namval_t* np) 707 { 708 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 709 if(ap && is_associative(ap)) 710 return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT))); 711 return(NIL(Namval_t*)); 712 } 713 714 char *nv_getsub(Namval_t* np) 715 { 716 static char numbuff[NUMSIZE]; 717 register struct index_array *ap; 718 register unsigned dot, n; 719 register char *cp = &numbuff[NUMSIZE]; 720 if(!np || !(ap = (struct index_array*)nv_arrayptr(np))) 721 return(NIL(char*)); 722 if(is_associative(ap)) 723 return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME))); 724 if((dot = ap->cur)==0) 725 *--cp = '0'; 726 else while(n=dot) 727 { 728 dot /= 10; 729 *--cp = '0' + (n-10*dot); 730 } 731 return(cp); 732 } 733 734 /* 735 * If <np> is an indexed array node, the current subscript index 736 * returned, otherwise returns -1 737 */ 738 int nv_aindex(register Namval_t* np) 739 { 740 Namarr_t *ap = nv_arrayptr(np); 741 if(!ap || is_associative(ap)) 742 return(-1); 743 return(((struct index_array*)(ap))->cur&ARRAY_MASK); 744 } 745 746 747 /* 748 * This is the default implementation for associate arrays 749 */ 750 void *nv_associative(register Namval_t *np,const char *sp,int mode) 751 { 752 register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np); 753 register int type; 754 switch(mode) 755 { 756 case NV_AINIT: 757 if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array))) 758 { 759 ap->table = dtopen(&_Nvdisc,Dtbag); 760 ap->cur = 0; 761 ap->pos = 0; 762 ap->header.hdr.disc = &array_disc; 763 ap->header.hdr.nofree = 1; 764 nv_disc(np,(Namfun_t*)ap, NV_LAST); 765 } 766 return((void*)ap); 767 case NV_ADELETE: 768 if(ap->cur) 769 { 770 if(nv_isattr(ap->cur,NV_NOFREE)) 771 nv_offattr(ap->cur,NV_NOFREE); 772 else 773 { 774 dtdelete(ap->table,(void*)ap->cur); 775 free((void*)ap->cur); 776 ap->cur = 0; 777 } 778 } 779 return((void*)ap); 780 case NV_AFREE: 781 ap->pos = 0; 782 dtclose(ap->table); 783 return((void*)ap); 784 case NV_ANEXT: 785 if(!ap->pos) 786 { 787 if(!(ap->pos=ap->cur)) 788 ap->pos = (Namval_t*)dtfirst(ap->table); 789 } 790 else 791 ap->pos = ap->nextpos; 792 for(;ap->cur=ap->pos; ap->pos=ap->nextpos) 793 { 794 ap->nextpos = (Namval_t*)dtnext(ap->table,ap->pos); 795 if(ap->cur->nvalue.cp) 796 { 797 if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD)) 798 continue; 799 return((void*)ap); 800 } 801 } 802 return(NIL(void*)); 803 case NV_ASETSUB: 804 ap->cur = (Namval_t*)sp; 805 /* FALL THROUGH*/ 806 case NV_ACURRENT: 807 return((void*)ap->cur); 808 case NV_ANAME: 809 if(ap->cur) 810 return((void*)nv_name(ap->cur)); 811 return(NIL(void*)); 812 default: 813 if(sp) 814 { 815 if(sp==(char*)np) 816 { 817 ap->cur = 0; 818 return(0); 819 } 820 else if(!(ap->header.nelem&ARRAY_SCAN)) 821 ap->pos = 0; 822 type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD)); 823 if((np=nv_search(sp,ap->table,mode?NV_ADD:0)) && nv_isnull(np)) 824 nv_onattr(np,type); 825 ap->cur = np; 826 } 827 if(ap->cur) 828 return((void*)(&ap->cur->nvalue)); 829 else 830 return((void*)(&ap->cur)); 831 } 832 } 833 834 /* 835 * Assign values to an array 836 */ 837 void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[]) 838 { 839 int arg0=0; 840 struct index_array *ap=0; 841 if(nv_isarray(np)) 842 { 843 ap = (struct index_array*)nv_arrayptr(np); 844 if(ap && is_associative(ap)) 845 errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associate array %s",nv_name(np)); 846 } 847 if(append) 848 { 849 if(ap) 850 { 851 arg0 = ap->maxi; 852 while(--arg0>0 && ap->val[arg0].cp==0); 853 arg0++; 854 } 855 else if(!nv_isnull(np)) 856 arg0=1; 857 } 858 while(--argc >= 0) 859 { 860 if((argc+arg0)>0 || nv_isattr(np,NV_ARRAY)) 861 nv_putsub(np,NIL(char*),(long)argc+arg0); 862 nv_putval(np,argv[argc],0); 863 } 864 } 865 866