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