1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 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, b) (cp[n] |= (b)) 37 #define array_clrbit(cp, n, b) (cp[n] &= ~(b)) 38 #define array_isbit(cp, n, b) (cp[n] & (b)) 39 #define NV_CHILD NV_EXPORT 40 #define ARRAY_CHILD 1 41 #define ARRAY_NOFREE 2 42 43 struct index_array 44 { 45 Namarr_t header; 46 void *xp; /* if set, subscripts will be converted */ 47 int cur; /* index of current element */ 48 int maxi; /* maximum index for array */ 49 unsigned char *bits; /* bit array for child subscripts */ 50 union Value val[1]; /* array of value holders */ 51 }; 52 53 struct assoc_array 54 { 55 Namarr_t header; 56 Namval_t *pos; 57 Namval_t *nextpos; 58 Namval_t *cur; 59 }; 60 61 static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags) 62 { 63 Namarr_t *aq; 64 struct index_array *ar; 65 size_t size = ap->hdr.dsize; 66 if(size==0) 67 size = ap->hdr.disc->dsize; 68 if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t)))) 69 return(0); 70 memcpy(aq,ap,size); 71 aq->hdr.nofree &= ~1; 72 aq->hdr.nofree |= (flags&NV_RDONLY)?1:0; 73 if(is_associative(aq)) 74 { 75 aq->scope = (void*)dtopen(&_Nvdisc,Dtoset); 76 dtview((Dt_t*)aq->scope,aq->table); 77 aq->table = (Dt_t*)aq->scope; 78 return(aq); 79 } 80 aq->scope = (void*)ap; 81 ar = (struct index_array*)aq; 82 memset(ar->val, 0, ar->maxi*sizeof(char*)); 83 return(aq); 84 } 85 86 static int array_unscope(Namval_t *np,Namarr_t *ap) 87 { 88 Namfun_t *fp; 89 if(!ap->scope) 90 return(0); 91 if(is_associative(ap)) 92 (*ap->fun)(np, NIL(char*), NV_AFREE); 93 if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1)) 94 free((void*)fp); 95 nv_delete(np,(Dt_t*)0,0); 96 return(1); 97 } 98 99 static void array_syncsub(Namarr_t *ap, Namarr_t *aq) 100 { 101 ((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur; 102 } 103 104 static int array_covered(Namval_t *np, struct index_array *ap) 105 { 106 struct index_array *aq = (struct index_array*)ap->header.scope; 107 if(!ap->header.fun && aq) 108 return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp); 109 return(0); 110 } 111 112 /* 113 * replace discipline with new one 114 */ 115 static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new) 116 { 117 register Namfun_t **fp = &np->nvfun; 118 while(*fp && *fp!= &old->header.hdr) 119 fp = &((*fp)->next); 120 if(*fp) 121 { 122 new->header.hdr.next = (*fp)->next; 123 *fp = &new->header.hdr; 124 } 125 else sfprintf(sfstderr,"discipline not replaced\n"); 126 } 127 128 /* 129 * Calculate the amount of space to be allocated to hold an 130 * indexed array into which <maxi> is a legal index. The number of 131 * elements that will actually fit into the array (> <maxi> 132 * but <= ARRAY_MAX) is returned. 133 * 134 */ 135 static int arsize(struct index_array *ap, register int maxi) 136 { 137 if(ap && maxi < 2*ap->maxi) 138 maxi = 2*ap->maxi; 139 maxi = roundof(maxi,ARRAY_INCR); 140 return (maxi>ARRAY_MAX?ARRAY_MAX:maxi); 141 } 142 143 static struct index_array *array_grow(Namval_t*, struct index_array*,int); 144 145 /* return index of highest element of an array */ 146 int array_maxindex(Namval_t *np) 147 { 148 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 149 register int i = ap->maxi; 150 if(is_associative(ap)) 151 return(-1); 152 while(i>0 && ap->val[--i].cp==0); 153 return(i+1); 154 } 155 156 static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update) 157 { 158 register struct index_array *ap = (struct index_array*)arp; 159 register union Value *up; 160 int nofree; 161 if(!arp) 162 return(&np->nvalue); 163 if(is_associative(ap)) 164 { 165 Namval_t *mp; 166 mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT)); 167 if(mp) 168 { 169 nofree = nv_isattr(mp,NV_NOFREE); 170 up = &mp->nvalue; 171 } 172 else 173 return((union Value*)((*arp->fun)(np,NIL(char*),0))); 174 } 175 else 176 { 177 if(ap->cur >= ap->maxi) 178 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 179 up = &(ap->val[ap->cur]); 180 nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE); 181 } 182 if(update) 183 { 184 if(nofree) 185 nv_onattr(np,NV_NOFREE); 186 else 187 nv_offattr(np,NV_NOFREE); 188 } 189 return(up); 190 } 191 192 int nv_arrayisset(Namval_t *np, Namarr_t *arp) 193 { 194 register struct index_array *ap = (struct index_array*)arp; 195 union Value *up; 196 if(is_associative(ap)) 197 return((np = nv_opensub(np)) && !nv_isnull(np)); 198 if(ap->cur >= ap->maxi) 199 return(0); 200 up = &(ap->val[ap->cur]); 201 return(up->cp && up->cp!=Empty); 202 } 203 204 /* 205 * Get the Value pointer for an array. 206 * Delete space as necessary if flag is ARRAY_DELETE 207 * After the lookup is done the last @ or * subscript is incremented 208 */ 209 static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag) 210 { 211 register struct index_array *ap = (struct index_array*)arp; 212 register union Value *up; 213 Namval_t *mp; 214 int wasundef; 215 if(flag&ARRAY_LOOKUP) 216 ap->header.nelem &= ~ARRAY_NOSCOPE; 217 else 218 ap->header.nelem |= ARRAY_NOSCOPE; 219 if(wasundef = ap->header.nelem&ARRAY_UNDEF) 220 { 221 ap->header.nelem &= ~ARRAY_UNDEF; 222 /* delete array is the same as delete array[@] */ 223 if(flag&ARRAY_DELETE) 224 { 225 nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE); 226 ap->header.nelem |= ARRAY_SCAN; 227 } 228 else /* same as array[0] */ 229 { 230 if(is_associative(ap)) 231 (*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0); 232 else 233 ap->cur = 0; 234 } 235 } 236 if(is_associative(ap)) 237 { 238 mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT)); 239 if(!mp) 240 up = (union Value*)∓ 241 else if(nv_isarray(mp)) 242 { 243 if(wasundef) 244 nv_putsub(mp,NIL(char*),ARRAY_UNDEF); 245 return(mp); 246 } 247 else 248 { 249 up = &mp->nvalue; 250 if(nv_isvtree(mp)) 251 { 252 if(!up->cp && flag==ARRAY_ASSIGN) 253 { 254 nv_arraychild(np,mp,0); 255 ap->header.nelem++; 256 } 257 return(mp); 258 } 259 } 260 } 261 else 262 { 263 if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi) 264 ap = array_grow(np, ap, (int)ap->cur); 265 if(ap->cur>=ap->maxi) 266 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 267 up = &(ap->val[ap->cur]); 268 if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np)) 269 { 270 char *cp; 271 if(!ap->header.table) 272 ap->header.table = dtopen(&_Nvdisc,Dtoset); 273 sfprintf(sh.strbuf,"%d",ap->cur); 274 cp = sfstruse(sh.strbuf); 275 mp = nv_search(cp, ap->header.table, NV_ADD); 276 mp->nvenv = (char*)np; 277 nv_arraychild(np,mp,0); 278 } 279 if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD)) 280 { 281 if(wasundef && nv_isarray(up->np)) 282 nv_putsub(up->np,NIL(char*),ARRAY_UNDEF); 283 return(up->np); 284 } 285 } 286 np->nvalue.cp = up->cp; 287 if(!up->cp) 288 { 289 char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np); 290 if(flag!=ARRAY_ASSIGN) 291 return(xp && xp!=(char*)np?np:0); 292 if(!array_covered(np,ap)) 293 ap->header.nelem++; 294 } 295 return(np); 296 } 297 298 #if SHOPT_TYPEDEF 299 int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags) 300 { 301 Namval_t *nq; 302 char *av[2]; 303 int rdonly = nv_isattr(np,NV_RDONLY); 304 int xtrace = sh_isoption(SH_XTRACE); 305 Namarr_t *ap = nv_arrayptr(np); 306 av[1] = 0; 307 sh.last_table = 0; 308 if(!ap->table) 309 ap->table = dtopen(&_Nvdisc,Dtoset); 310 if(nq = nv_search(sub, ap->table, NV_ADD)) 311 { 312 if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0) 313 _nv_unset(nq,NV_RDONLY); 314 nv_arraychild(np,nq,0); 315 if(!nv_isattr(tp,NV_BINARY)) 316 { 317 sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np)); 318 av[0] = strdup(sfstruse(sh.strbuf)); 319 } 320 if(!nv_clone(tp,nq,flags|NV_NOFREE)) 321 return(0); 322 ap->nelem |= ARRAY_SCAN; 323 if(!rdonly) 324 nv_offattr(nq,NV_RDONLY); 325 if(!nv_isattr(tp,NV_BINARY)) 326 { 327 if(xtrace) 328 sh_offoption(SH_XTRACE); 329 ap->nelem &= ~ARRAY_SCAN; 330 sh_eval(sh_sfeval(av),0); 331 ap->nelem |= ARRAY_SCAN; 332 free((void*)av[0]); 333 if(xtrace) 334 sh_onoption(SH_XTRACE); 335 } 336 return(1); 337 } 338 return(0); 339 } 340 #endif /* SHOPT_TYPEDEF */ 341 342 343 static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp) 344 { 345 Namarr_t *ap = (Namarr_t*)fp; 346 Namval_t *nq, *mq; 347 char *name, *sub=0; 348 int nelem, skipped=0; 349 Dt_t *otable=ap->table; 350 struct index_array *aq = (struct index_array*)ap, *ar; 351 Shell_t *shp = sh_getinterp(); 352 if(flags&NV_MOVE) 353 { 354 if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN)) 355 { 356 do 357 { 358 if(nq=nv_opensub(np)) 359 nq->nvenv = (void*)mp; 360 } 361 while(nv_nextsub(np)); 362 } 363 return(fp); 364 } 365 nelem = ap->nelem; 366 if(nelem&ARRAY_NOCLONE) 367 return(0); 368 if((flags&NV_TYPE) && !ap->scope) 369 { 370 ap = array_scope(np,ap,flags); 371 return(&ap->hdr); 372 } 373 ap = (Namarr_t*)nv_clone_disc(fp,0); 374 if(flags&NV_COMVAR) 375 { 376 ap->scope = 0; 377 ap->nelem = 0; 378 sh.prev_table = sh.last_table; 379 sh.prev_root = sh.last_root; 380 } 381 if(ap->table) 382 { 383 ap->table = dtopen(&_Nvdisc,Dtoset); 384 if(ap->scope && !(flags&NV_COMVAR)) 385 { 386 ap->scope = ap->table; 387 dtview(ap->table, otable->view); 388 } 389 } 390 mp->nvfun = (Namfun_t*)ap; 391 mp->nvflag &= NV_MINIMAL; 392 mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE)); 393 if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np))) 394 sub = strdup(sub); 395 ar = (struct index_array*)ap; 396 if(!is_associative(ap)) 397 ar->bits = (unsigned char*)&ar->val[ar->maxi]; 398 if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE))) 399 { 400 if(ap->fun) 401 (*ap->fun)(np,(char*)np,0); 402 skipped=1; 403 goto skip; 404 } 405 do 406 { 407 name = nv_getsub(np); 408 nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE); 409 mq = 0; 410 if(nq=nv_opensub(np)) 411 mq = nv_search(name,ap->table,NV_ADD); 412 if(nq && (flags&NV_COMVAR) && nv_isvtree(nq)) 413 { 414 mq->nvalue.cp = 0; 415 if(!is_associative(ap)) 416 ar->val[ar->cur].np = mq; 417 nv_clone(nq,mq,flags); 418 } 419 else if(flags&NV_ARRAY) 420 { 421 if((flags&NV_NOFREE) && !is_associative(ap)) 422 array_setbit(aq->bits,aq->cur,ARRAY_NOFREE); 423 else if(nq && (flags&NV_NOFREE)) 424 { 425 mq->nvalue = nq->nvalue; 426 nv_onattr(nq,NV_NOFREE); 427 } 428 } 429 else if(nv_isattr(np,NV_INTEGER)) 430 { 431 Sfdouble_t d= nv_getnum(np); 432 if(!is_associative(ap)) 433 ar->val[ar->cur].cp = 0; 434 nv_putval(mp,(char*)&d,NV_LDOUBLE); 435 } 436 else 437 { 438 if(!is_associative(ap)) 439 ar->val[ar->cur].cp = 0; 440 nv_putval(mp,nv_getval(np),NV_RDONLY); 441 } 442 aq->header.nelem |= ARRAY_NOSCOPE; 443 } 444 while(nv_nextsub(np)); 445 skip: 446 if(sub) 447 { 448 if(!skipped) 449 nv_putsub(np,sub,0L); 450 free((void*)sub); 451 } 452 aq->header.nelem = ap->nelem = nelem; 453 return(&ap->hdr); 454 } 455 456 static char *array_getval(Namval_t *np, Namfun_t *disc) 457 { 458 register Namarr_t *aq,*ap = (Namarr_t*)disc; 459 register Namval_t *mp; 460 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 461 { 462 if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope)) 463 { 464 array_syncsub(aq,ap); 465 if((mp=array_find(np,aq,ARRAY_LOOKUP))==np) 466 return(nv_getv(np,&aq->hdr)); 467 } 468 return(mp?nv_getval(mp):0); 469 } 470 return(nv_getv(np,&ap->hdr)); 471 } 472 473 static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc) 474 { 475 register Namarr_t *aq,*ap = (Namarr_t*)disc; 476 register Namval_t *mp; 477 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 478 { 479 if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope)) 480 { 481 array_syncsub(aq,ap); 482 if((mp=array_find(np,aq,ARRAY_LOOKUP))==np) 483 return(nv_getn(np,&aq->hdr)); 484 } 485 return(mp?nv_getnum(mp):0); 486 } 487 return(nv_getn(np,&ap->hdr)); 488 } 489 490 static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp) 491 { 492 register Namarr_t *ap = (Namarr_t*)dp; 493 register union Value *up; 494 register Namval_t *mp; 495 register struct index_array *aq = (struct index_array*)ap; 496 int scan,nofree = nv_isattr(np,NV_NOFREE); 497 do 498 { 499 mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE); 500 scan = ap->nelem&ARRAY_SCAN; 501 if(mp && mp!=np) 502 { 503 if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp)) 504 { 505 if(!nv_isattr(np,NV_NOFREE)) 506 _nv_unset(mp,flags&NV_RDONLY); 507 array_clrbit(aq->bits,aq->cur,ARRAY_CHILD); 508 aq->val[aq->cur].cp = 0; 509 if(!nv_isattr(mp,NV_NOFREE)) 510 nv_delete(mp,ap->table,0); 511 goto skip; 512 } 513 nv_putval(mp, string, flags); 514 if(string) 515 { 516 #if SHOPT_TYPEDEF 517 if(ap->hdr.type && ap->hdr.type!=nv_type(mp)) 518 nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0); 519 #endif /* SHOPT_TYPEDEF */ 520 continue; 521 } 522 ap->nelem |= scan; 523 } 524 if(!string) 525 { 526 if(mp) 527 { 528 if(is_associative(ap)) 529 { 530 (*ap->fun)(np,NIL(char*),NV_ADELETE); 531 np->nvalue.cp = 0; 532 } 533 else 534 { 535 if(mp!=np) 536 { 537 array_clrbit(aq->bits,aq->cur,ARRAY_CHILD); 538 aq->val[aq->cur].cp = 0; 539 nv_delete(mp,ap->table,0); 540 } 541 if(!array_covered(np,(struct index_array*)ap)) 542 ap->nelem--; 543 } 544 } 545 if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN)) 546 { 547 if(is_associative(ap)) 548 (*ap->fun)(np, NIL(char*), NV_AFREE); 549 else if(ap->table) 550 dtclose(ap->table); 551 nv_offattr(np,NV_ARRAY); 552 } 553 if(!mp || mp!=np || is_associative(ap)) 554 continue; 555 } 556 skip: 557 /* prevent empty string from being deleted */ 558 up = array_getup(np,ap,!nofree); 559 if(up->cp == Empty) 560 up->cp = 0; 561 if(nv_isarray(np)) 562 np->nvalue.up = up; 563 nv_putv(np,string,flags,&ap->hdr); 564 if(!is_associative(ap)) 565 { 566 if(string) 567 array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE); 568 else if(mp==np) 569 aq->val[aq->cur].cp = 0; 570 } 571 #if SHOPT_TYPEDEF 572 if(string && ap->hdr.type && nv_isvtree(np)) 573 nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0); 574 #endif /* SHOPT_TYPEDEF */ 575 } 576 while(!string && nv_nextsub(np)); 577 if(ap) 578 ap->nelem &= ~ARRAY_NOSCOPE; 579 if(nofree) 580 nv_onattr(np,NV_NOFREE); 581 else 582 nv_offattr(np,NV_NOFREE); 583 if(!string && !nv_isattr(np,NV_ARRAY)) 584 { 585 Namfun_t *nfp; 586 if(!is_associative(ap) && aq->xp) 587 { 588 _nv_unset(nv_namptr(aq->xp,0),NV_RDONLY); 589 free((void*)aq->xp); 590 } 591 if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1)) 592 free((void*)nfp); 593 if(!nv_isnull(np)) 594 { 595 nv_onattr(np,NV_NOFREE); 596 _nv_unset(np,flags); 597 } 598 if(np->nvalue.cp==Empty) 599 np->nvalue.cp = 0; 600 } 601 if(!string && (flags&NV_TYPE)) 602 array_unscope(np,ap); 603 } 604 605 static const Namdisc_t array_disc = 606 { 607 sizeof(Namarr_t), 608 array_putval, 609 array_getval, 610 array_getnum, 611 0, 612 0, 613 array_clone 614 }; 615 616 static void array_copytree(Namval_t *np, Namval_t *mp) 617 { 618 Namfun_t *fp = nv_disc(np,NULL,NV_POP); 619 nv_offattr(np,NV_ARRAY); 620 nv_clone(np,mp,0); 621 if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE)) 622 free((void*)np->nvalue.cp); 623 np->nvalue.cp = 0; 624 np->nvalue.up = &mp->nvalue; 625 fp->nofree &= ~1; 626 nv_disc(np,(Namfun_t*)fp, NV_FIRST); 627 fp->nofree |= 1; 628 nv_onattr(np,NV_ARRAY); 629 mp->nvenv = (char*)np; 630 } 631 632 /* 633 * Increase the size of the indexed array of elements in <arp> 634 * so that <maxi> is a legal index. If <arp> is 0, an array 635 * of the required size is allocated. A pointer to the 636 * allocated Namarr_t structure is returned. 637 * <maxi> becomes the current index of the array. 638 */ 639 static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi) 640 { 641 register struct index_array *ap; 642 register int i; 643 register int newsize = arsize(arp,maxi+1); 644 if (maxi >= ARRAY_MAX) 645 errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0)); 646 i = (newsize-1)*sizeof(union Value*)+newsize; 647 ap = new_of(struct index_array,i); 648 memset((void*)ap,0,sizeof(*ap)+i); 649 ap->maxi = newsize; 650 ap->cur = maxi; 651 ap->bits = (unsigned char*)&ap->val[newsize]; 652 memset(ap->bits, 0, newsize); 653 if(arp) 654 { 655 ap->header = arp->header; 656 ap->header.hdr.dsize = sizeof(*ap) + i; 657 for(i=0;i < arp->maxi;i++) 658 ap->val[i].cp = arp->val[i].cp; 659 memcpy(ap->bits, arp->bits, arp->maxi); 660 array_setptr(np,arp,ap); 661 free((void*)arp); 662 } 663 else 664 { 665 Namval_t *mp=0; 666 ap->header.hdr.dsize = sizeof(*ap) + i; 667 i = 0; 668 ap->header.fun = 0; 669 if(nv_isnull(np) && nv_isattr(np,NV_NOFREE)) 670 { 671 i = ARRAY_TREE; 672 nv_offattr(np,NV_NOFREE); 673 } 674 if(np->nvalue.cp==Empty) 675 np->nvalue.cp=0; 676 if(nv_hasdisc(np,&array_disc) || nv_isvtree(np)) 677 { 678 ap->header.table = dtopen(&_Nvdisc,Dtoset); 679 mp = nv_search("0", ap->header.table,NV_ADD); 680 if(mp && nv_isnull(mp)) 681 { 682 Namfun_t *fp; 683 ap->val[0].np = mp; 684 array_setbit(ap->bits,0,ARRAY_CHILD); 685 for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next); 686 if(fp && fp->disc && fp->disc->readf) 687 (*fp->disc->readf)(mp,(Sfio_t*)0,0,fp); 688 i++; 689 } 690 } 691 else if((ap->val[0].cp=np->nvalue.cp)) 692 i++; 693 else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np)) 694 { 695 Sfdouble_t d= nv_getnum(np); 696 i++; 697 } 698 ap->header.nelem = i; 699 ap->header.hdr.disc = &array_disc; 700 nv_disc(np,(Namfun_t*)ap, NV_FIRST); 701 nv_onattr(np,NV_ARRAY); 702 if(mp) 703 { 704 array_copytree(np,mp); 705 ap->header.hdr.nofree &= ~1; 706 } 707 } 708 for(;i < newsize;i++) 709 ap->val[i].cp = 0; 710 return(ap); 711 } 712 713 int nv_atypeindex(Namval_t *np, const char *tname) 714 { 715 Namval_t *tp; 716 int offset = staktell(); 717 int n = strlen(tname)-1; 718 sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0); 719 tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME); 720 stakseek(offset); 721 if(tp) 722 { 723 struct index_array *ap = (struct index_array*)nv_arrayptr(np); 724 if(!nv_hasdisc(tp,&ENUM_disc)) 725 errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname); 726 if(!ap) 727 ap = array_grow(np,ap,1); 728 ap->xp = calloc(NV_MINSZ,1); 729 np = nv_namptr(ap->xp,0); 730 np->nvname = tp->nvname; 731 nv_onattr(np,NV_MINIMAL); 732 nv_clone(tp,np,NV_NOFREE); 733 nv_offattr(np,NV_RDONLY); 734 return(1); 735 } 736 errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname); 737 return(0); 738 } 739 740 Namarr_t *nv_arrayptr(register Namval_t *np) 741 { 742 if(nv_isattr(np,NV_ARRAY)) 743 return((Namarr_t*)nv_hasdisc(np, &array_disc)); 744 return(0); 745 } 746 747 /* 748 * Verify that argument is an indexed array and convert to associative, 749 * freeing relevant storage 750 */ 751 static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 752 { 753 register Namarr_t *ap; 754 char numbuff[NUMSIZE+1]; 755 unsigned dot, digit, n; 756 union Value *up; 757 struct index_array *save_ap; 758 register char *string_index=&numbuff[NUMSIZE]; 759 numbuff[NUMSIZE]='\0'; 760 761 if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap)) 762 return(NIL(Namarr_t*)); 763 764 nv_stack(np,&ap->hdr); 765 save_ap = (struct index_array*)nv_stack(np,0); 766 ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)); 767 ap->nelem = 0; 768 ap->fun = fun; 769 nv_onattr(np,NV_ARRAY); 770 771 for(dot = 0; dot < (unsigned)save_ap->maxi; dot++) 772 { 773 if(save_ap->val[dot].cp) 774 { 775 if ((digit = dot)== 0) 776 *--string_index = '0'; 777 else while( n = digit ) 778 { 779 digit /= 10; 780 *--string_index = '0' + (n-10*digit); 781 } 782 nv_putsub(np, string_index, ARRAY_ADD); 783 up = (union Value*)((*ap->fun)(np,NIL(char*),0)); 784 up->cp = save_ap->val[dot].cp; 785 save_ap->val[dot].cp = 0; 786 } 787 string_index = &numbuff[NUMSIZE]; 788 } 789 free((void*)save_ap); 790 return(ap); 791 } 792 793 /* 794 * set the associative array processing method for node <np> to <fun> 795 * The array pointer is returned if sucessful. 796 */ 797 Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 798 { 799 register Namarr_t *ap; 800 char *value=0; 801 Namfun_t *fp; 802 int nelem = 0; 803 if(fun && (ap = nv_arrayptr(np))) 804 { 805 /* 806 * if it's already an indexed array, convert to 807 * associative structure 808 */ 809 if(!is_associative(ap)) 810 ap = nv_changearray(np, fun); 811 return(ap); 812 } 813 if(nv_isnull(np) && nv_isattr(np,NV_NOFREE)) 814 { 815 nelem = ARRAY_TREE; 816 nv_offattr(np,NV_NOFREE); 817 } 818 if(!(fp=nv_isvtree(np))) 819 value = nv_getval(np); 820 if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)))) 821 { 822 /* check for preexisting initialization and save */ 823 ap->nelem = nelem; 824 ap->fun = fun; 825 nv_onattr(np,NV_ARRAY); 826 if(fp || value) 827 { 828 nv_putsub(np, "0", ARRAY_ADD); 829 if(value) 830 nv_putval(np, value, 0); 831 else 832 { 833 Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT)); 834 array_copytree(np,mp); 835 } 836 } 837 return(ap); 838 } 839 return(NIL(Namarr_t*)); 840 } 841 842 /* 843 * move parent subscript into child 844 */ 845 Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c) 846 { 847 Namfun_t *fp; 848 register Namarr_t *ap = nv_arrayptr(np); 849 union Value *up; 850 Namval_t *tp; 851 if(!nq) 852 return(ap?array_find(np,ap, ARRAY_LOOKUP):0); 853 if(!ap) 854 { 855 nv_putsub(np, NIL(char*), ARRAY_FILL); 856 ap = nv_arrayptr(np); 857 } 858 if(!(up = array_getup(np,ap,0))) 859 return((Namval_t*)0); 860 np->nvalue.cp = up->cp; 861 if((tp=nv_type(np)) || c) 862 { 863 ap->nelem |= ARRAY_NOCLONE; 864 nq->nvenv = (char*)np; 865 if(c=='t') 866 nv_clone(tp,nq, 0); 867 else 868 nv_clone(np, nq, NV_NODISC); 869 nv_offattr(nq,NV_ARRAY); 870 ap->nelem &= ~ARRAY_NOCLONE; 871 } 872 nq->nvenv = (char*)np; 873 if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP))) 874 free((void*)fp); 875 if(!ap->fun) 876 { 877 struct index_array *aq = (struct index_array*)ap; 878 array_setbit(aq->bits,aq->cur,ARRAY_CHILD); 879 up->np = nq; 880 } 881 if(c=='.') 882 nv_setvtree(nq); 883 return(nq); 884 } 885 886 /* 887 * This routine sets subscript of <np> to the next element, if any. 888 * The return value is zero, if there are no more elements 889 * Otherwise, 1 is returned. 890 */ 891 int nv_nextsub(Namval_t *np) 892 { 893 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 894 register unsigned dot; 895 struct index_array *aq=0, *ar=0; 896 if(!ap || !(ap->header.nelem&ARRAY_SCAN)) 897 return(0); 898 if(is_associative(ap)) 899 { 900 Namval_t *nq; 901 if(nq=(*ap->header.fun)(np,NIL(char*),NV_ANEXT)) 902 { 903 if(nv_isattr(nq,NV_CHILD)) 904 nv_putsub(nq->nvalue.np,NIL(char*),ARRAY_UNDEF); 905 return(1); 906 } 907 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 908 return(0); 909 } 910 if(!(ap->header.nelem&ARRAY_NOSCOPE)) 911 ar = (struct index_array*)ap->header.scope; 912 for(dot=ap->cur+1; dot < (unsigned)ap->maxi; dot++) 913 { 914 aq = ap; 915 if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE)) 916 { 917 if(!(aq=ar) || dot>=(unsigned)aq->maxi) 918 continue; 919 } 920 if(aq->val[dot].cp) 921 { 922 ap->cur = dot; 923 if(array_isbit(aq->bits, dot,ARRAY_CHILD)) 924 { 925 Namval_t *mp = aq->val[dot].np; 926 if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize) 927 continue; 928 if(nv_isarray(mp)) 929 nv_putsub(mp,NIL(char*),ARRAY_UNDEF); 930 } 931 return(1); 932 } 933 } 934 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 935 ap->cur = 0; 936 return(0); 937 } 938 939 /* 940 * Set an array subscript for node <np> given the subscript <sp> 941 * An array is created if necessary. 942 * <mode> can be a number, plus or more of symbolic constants 943 * ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD 944 * The node pointer is returned which can be NULL if <np> is 945 * not already array and the ARRAY_ADD bit of <mode> is not set. 946 * ARRAY_FILL sets the specified subscript to the empty string when 947 * ARRAY_ADD is specified and there is no value or sets all 948 * the elements up to the number specified if ARRAY_ADD is not specified 949 */ 950 Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode) 951 { 952 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 953 register int size = (mode&ARRAY_MASK); 954 if(!ap || !ap->header.fun) 955 { 956 if(sp) 957 { 958 if(ap && ap->xp && !strmatch(sp,"+([0-9])")) 959 { 960 Namval_t *mp = nv_namptr(ap->xp,0); 961 nv_putval(mp, sp,0); 962 size = nv_getnum(mp); 963 } 964 else 965 size = (int)sh_arith((char*)sp); 966 } 967 if(size <0 && ap) 968 size += array_maxindex(np); 969 if(size >= ARRAY_MAX || (size < 0)) 970 { 971 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 972 return(NIL(Namval_t*)); 973 } 974 if(!ap || size>=ap->maxi) 975 { 976 if(size==0 && !(mode&ARRAY_FILL)) 977 return(NIL(Namval_t*)); 978 if(sh.subshell) 979 np = sh_assignok(np,1); 980 ap = array_grow(np, ap,size); 981 } 982 ap->header.nelem &= ~ARRAY_UNDEF; 983 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE)); 984 #if 0 985 if(array_isbit(ap->bits,oldsize,ARRAY_CHILD)) 986 mp = ap->val[oldsize].np; 987 if(size != oldsize && mp->nvalue.cp) 988 { 989 Namfun_t *nfp; 990 for(nfp=np->nvfun; nfp; nfp=nfp->next) 991 { 992 if(nfp->disc && nfp->disc->readf) 993 { 994 (*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp); 995 break; 996 } 997 } 998 } 999 #endif 1000 ap->cur = size; 1001 if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np))) 1002 np = 0; 1003 if(mode&(ARRAY_FILL|ARRAY_ADD)) 1004 { 1005 if(!(mode&ARRAY_ADD)) 1006 { 1007 int n; 1008 for(n=0; n <= size; n++) 1009 { 1010 if(!ap->val[n].cp) 1011 { 1012 ap->val[n].cp = Empty; 1013 if(!array_covered(np,ap)) 1014 ap->header.nelem++; 1015 } 1016 } 1017 if(n=ap->maxi-ap->maxi) 1018 memset(&ap->val[size],0,n*sizeof(union Value)); 1019 } 1020 else if(!ap->val[size].cp) 1021 { 1022 if(sh.subshell) 1023 np = sh_assignok(np,1); 1024 ap->val[size].cp = Empty; 1025 if(!array_covered(np,ap)) 1026 ap->header.nelem++; 1027 } 1028 } 1029 else if(!(mode&ARRAY_SCAN)) 1030 { 1031 ap->header.nelem &= ~ARRAY_SCAN; 1032 if(array_isbit(ap->bits,size,ARRAY_CHILD)) 1033 nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF); 1034 if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp) 1035 np = 0; 1036 } 1037 return((Namval_t*)np); 1038 } 1039 ap->header.nelem &= ~ARRAY_UNDEF; 1040 if(!(mode&ARRAY_FILL)) 1041 ap->header.nelem &= ~ARRAY_SCAN; 1042 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE)); 1043 if(sp) 1044 { 1045 if(mode&ARRAY_SETSUB) 1046 { 1047 (*ap->header.fun)(np, sp, NV_ASETSUB); 1048 return(np); 1049 } 1050 (*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0); 1051 if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT)) 1052 np = 0; 1053 } 1054 else if(mode&ARRAY_SCAN) 1055 (*ap->header.fun)(np,(char*)np,0); 1056 else if(mode&ARRAY_UNDEF) 1057 (*ap->header.fun)(np, "",0); 1058 if((mode&ARRAY_SCAN) && !nv_nextsub(np)) 1059 np = 0; 1060 return(np); 1061 } 1062 1063 /* 1064 * process an array subscript for node <np> given the subscript <cp> 1065 * returns pointer to character after the subscript 1066 */ 1067 char *nv_endsubscript(Namval_t *np, register char *cp, int mode) 1068 { 1069 register int count=1, quoted=0, c; 1070 register char *sp = cp+1; 1071 /* first find matching ']' */ 1072 while(count>0 && (c= *++cp)) 1073 { 1074 if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@')) 1075 { 1076 quoted=1; 1077 cp++; 1078 } 1079 else if(c=='[') 1080 count++; 1081 else if(c==']') 1082 count--; 1083 } 1084 *cp = 0; 1085 if(quoted) 1086 { 1087 /* strip escape characters */ 1088 count = staktell(); 1089 stakwrite(sp,1+cp-sp); 1090 sh_trim(sp=stakptr(count)); 1091 } 1092 if(mode && np) 1093 { 1094 Namarr_t *ap = nv_arrayptr(np); 1095 int scan = 0; 1096 if(ap) 1097 scan = ap->nelem&ARRAY_SCAN; 1098 if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+')) 1099 mode |= NV_ADD; 1100 nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL)); 1101 if(scan) 1102 ap->nelem |= scan; 1103 } 1104 if(quoted) 1105 stakseek(count); 1106 *cp++ = c; 1107 return(cp); 1108 } 1109 1110 1111 Namval_t *nv_opensub(Namval_t* np) 1112 { 1113 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1114 if(ap) 1115 { 1116 if(is_associative(ap)) 1117 return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT))); 1118 else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD)) 1119 return(ap->val[ap->cur].np); 1120 } 1121 return(NIL(Namval_t*)); 1122 } 1123 1124 char *nv_getsub(Namval_t* np) 1125 { 1126 static char numbuff[NUMSIZE]; 1127 register struct index_array *ap; 1128 register unsigned dot, n; 1129 register char *cp = &numbuff[NUMSIZE]; 1130 if(!np || !(ap = (struct index_array*)nv_arrayptr(np))) 1131 return(NIL(char*)); 1132 if(is_associative(ap)) 1133 return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME))); 1134 if(ap->xp) 1135 { 1136 np = nv_namptr(ap->xp,0); 1137 np->nvalue.s = ap->cur; 1138 return(nv_getval(np)); 1139 } 1140 if((dot = ap->cur)==0) 1141 *--cp = '0'; 1142 else while(n=dot) 1143 { 1144 dot /= 10; 1145 *--cp = '0' + (n-10*dot); 1146 } 1147 return(cp); 1148 } 1149 1150 /* 1151 * If <np> is an indexed array node, the current subscript index 1152 * returned, otherwise returns -1 1153 */ 1154 int nv_aindex(register Namval_t* np) 1155 { 1156 Namarr_t *ap = nv_arrayptr(np); 1157 if(!ap) 1158 return(0); 1159 else if(is_associative(ap)) 1160 return(-1); 1161 return(((struct index_array*)(ap))->cur&ARRAY_MASK); 1162 } 1163 1164 int nv_arraynsub(register Namarr_t* ap) 1165 { 1166 return(array_elem(ap)); 1167 } 1168 1169 int nv_aimax(register Namval_t* np) 1170 { 1171 struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1172 int sub = -1; 1173 if(!ap || is_associative(&ap->header)) 1174 return(-1); 1175 sub = ap->maxi; 1176 while(--sub>0 && ap->val[sub].cp==0); 1177 return(sub); 1178 } 1179 1180 /* 1181 * This is the default implementation for associative arrays 1182 */ 1183 void *nv_associative(register Namval_t *np,const char *sp,int mode) 1184 { 1185 register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np); 1186 register int type; 1187 switch(mode) 1188 { 1189 case NV_AINIT: 1190 if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array))) 1191 { 1192 ap->header.table = dtopen(&_Nvdisc,Dtoset); 1193 ap->cur = 0; 1194 ap->pos = 0; 1195 ap->header.hdr.disc = &array_disc; 1196 nv_disc(np,(Namfun_t*)ap, NV_FIRST); 1197 ap->header.hdr.dsize = sizeof(struct assoc_array); 1198 ap->header.hdr.nofree &= ~1; 1199 } 1200 return((void*)ap); 1201 case NV_ADELETE: 1202 if(ap->cur) 1203 { 1204 if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0)) 1205 ap->header.nelem--; 1206 _nv_unset(ap->cur,NV_RDONLY); 1207 nv_delete(ap->cur,ap->header.table,0); 1208 ap->cur = 0; 1209 } 1210 return((void*)ap); 1211 case NV_AFREE: 1212 ap->pos = 0; 1213 if(ap->header.scope) 1214 { 1215 ap->header.table = dtview(ap->header.table,(Dt_t*)0); 1216 dtclose(ap->header.scope); 1217 ap->header.scope = 0; 1218 } 1219 else 1220 dtclose(ap->header.table); 1221 return((void*)ap); 1222 case NV_ANEXT: 1223 if(!ap->pos) 1224 { 1225 if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table)) 1226 { 1227 ap->header.scope = dtvnext(ap->header.table); 1228 ap->header.table->view = 0; 1229 } 1230 if(!(ap->pos=ap->cur)) 1231 ap->pos = (Namval_t*)dtfirst(ap->header.table); 1232 } 1233 else 1234 ap->pos = ap->nextpos; 1235 for(;ap->cur=ap->pos; ap->pos=ap->nextpos) 1236 { 1237 ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos); 1238 if(ap->cur->nvalue.cp) 1239 { 1240 if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD)) 1241 continue; 1242 return((void*)ap); 1243 } 1244 } 1245 if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table)) 1246 { 1247 ap->header.table->view = (Dt_t*)ap->header.scope; 1248 ap->header.scope = ap->header.table; 1249 } 1250 return(NIL(void*)); 1251 case NV_ASETSUB: 1252 ap->cur = (Namval_t*)sp; 1253 return((void*)ap->cur); 1254 case NV_ACURRENT: 1255 if(ap->cur) 1256 ap->cur->nvenv = (char*)np; 1257 return((void*)ap->cur); 1258 case NV_ANAME: 1259 if(ap->cur) 1260 { 1261 Shell_t *shp = sh_getinterp(); 1262 if(!shp->instance && nv_isnull(ap->cur)) 1263 return(NIL(void*)); 1264 return((void*)ap->cur->nvname); 1265 } 1266 return(NIL(void*)); 1267 default: 1268 if(sp) 1269 { 1270 Namval_t *mp=0; 1271 ap->cur = 0; 1272 if(sp==(char*)np) 1273 return(0); 1274 type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL)); 1275 if(mode) 1276 mode = NV_ADD|HASH_NOSCOPE; 1277 else if(ap->header.nelem&ARRAY_NOSCOPE) 1278 mode = HASH_NOSCOPE; 1279 if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD)) 1280 errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript"); 1281 if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp)) 1282 ap->cur = mp; 1283 if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD)) 1284 { 1285 nv_onattr(mp,type); 1286 mp->nvenv = (char*)np; 1287 if((mode&NV_ADD) && nv_type(np)) 1288 nv_arraychild(np,mp,0); 1289 if(sh.subshell) 1290 np = sh_assignok(np,1); 1291 if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0)) 1292 ap->header.nelem++; 1293 if(nv_isnull(mp)) 1294 { 1295 if(ap->header.nelem&ARRAY_TREE) 1296 nv_setvtree(mp); 1297 mp->nvalue.cp = Empty; 1298 } 1299 } 1300 else if(ap->header.nelem&ARRAY_SCAN) 1301 { 1302 Namval_t fake; 1303 fake.nvname = (char*)sp; 1304 ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake); 1305 ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp); 1306 } 1307 else if(!mp && *sp && mode==0) 1308 mp = nv_search(sp,ap->header.table,NV_ADD); 1309 np = mp; 1310 if(ap->pos && ap->pos==np) 1311 ap->header.nelem |= ARRAY_SCAN; 1312 else if(!(ap->header.nelem&ARRAY_SCAN)) 1313 ap->pos = 0; 1314 ap->cur = np; 1315 } 1316 if(ap->cur) 1317 return((void*)(&ap->cur->nvalue)); 1318 else 1319 return((void*)(&ap->cur)); 1320 } 1321 } 1322 1323 /* 1324 * Assign values to an array 1325 */ 1326 void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[]) 1327 { 1328 int arg0=0; 1329 struct index_array *ap=0,*aq; 1330 if(nv_isarray(np)) 1331 { 1332 ap = (struct index_array*)nv_arrayptr(np); 1333 if(ap && is_associative(ap)) 1334 errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np)); 1335 } 1336 if(append) 1337 { 1338 if(ap) 1339 { 1340 if(!(aq = (struct index_array*)ap->header.scope)) 1341 aq = ap; 1342 arg0 = ap->maxi; 1343 while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0); 1344 arg0++; 1345 } 1346 else if(!nv_isnull(np)) 1347 arg0=1; 1348 } 1349 while(--argc >= 0) 1350 { 1351 nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD); 1352 nv_putval(np,argv[argc],0); 1353 } 1354 } 1355 1356