1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 11 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 #if SHOPT_FIXEDARRAY 62 struct fixed_array 63 { 64 unsigned char ndim; 65 unsigned char dim; 66 unsigned char level; 67 unsigned char ptr; 68 short size; 69 int nelem; 70 int curi; 71 int *max; 72 int *incr; 73 int *cur; 74 char *data; 75 }; 76 # define array_fixed_data(ap) ((ap)?((struct fixed_array*)((ap)->fixed))->data:0) 77 static void array_fixed_setdata(Namval_t*,Namarr_t*,struct fixed_array*); 78 #endif /* SHOPT_FIXEDARRAY */ 79 80 static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags) 81 { 82 Namarr_t *aq; 83 #if SHOPT_FIXEDARRAY 84 struct fixed_array *fp; 85 #endif /* SHOPT_FIXEDARRAY */ 86 struct index_array *ar; 87 size_t size = ap->hdr.dsize; 88 if(size==0) 89 size = ap->hdr.disc->dsize; 90 if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t)))) 91 return(0); 92 memcpy(aq,ap,size); 93 aq->hdr.nofree &= ~1; 94 aq->hdr.nofree |= (flags&NV_RDONLY)?1:0; 95 if(is_associative(aq)) 96 { 97 aq->scope = (void*)dtopen(&_Nvdisc,Dtoset); 98 dtview((Dt_t*)aq->scope,aq->table); 99 aq->table = (Dt_t*)aq->scope; 100 return(aq); 101 } 102 #if SHOPT_FIXEDARRAY 103 else if(fp = (struct fixed_array*)ap->fixed) 104 { 105 aq->scope = (void*)ap; 106 fp = (struct fixed_array*)(aq+1); 107 aq->fixed = (void*)fp; 108 fp->max = (int*)(fp+1); 109 fp->incr = fp->max+fp->ndim; 110 fp->cur = fp->incr+fp->ndim; 111 return(aq); 112 } 113 #endif /* SHOPT_FIXEDARRAY */ 114 aq->scope = (void*)ap; 115 ar = (struct index_array*)aq; 116 memset(ar->val, 0, ar->maxi*sizeof(char*)); 117 ar->bits = (unsigned char*)&ar->val[ar->maxi]; 118 return(aq); 119 } 120 121 static int array_unscope(Namval_t *np,Namarr_t *ap) 122 { 123 Namfun_t *fp; 124 if(!ap->scope) 125 return(0); 126 if(is_associative(ap)) 127 (*ap->fun)(np, NIL(char*), NV_AFREE); 128 if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1)) 129 free((void*)fp); 130 nv_delete(np,(Dt_t*)0,0); 131 return(1); 132 } 133 134 static void array_syncsub(Namarr_t *ap, Namarr_t *aq) 135 { 136 ((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur; 137 } 138 139 static int array_covered(Namval_t *np, struct index_array *ap) 140 { 141 struct index_array *aq = (struct index_array*)ap->header.scope; 142 if(!ap->header.fun && aq) 143 #if SHOPT_FIXEDARRAY 144 return (ap->header.fixed || ((ap->cur<aq->maxi) && aq->val[ap->cur].cp)); 145 #else 146 return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp); 147 #endif /* SHOPT_FIXEDARRAY */ 148 return(0); 149 } 150 151 /* 152 * replace discipline with new one 153 */ 154 static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new) 155 { 156 register Namfun_t **fp = &np->nvfun; 157 while(*fp && *fp!= &old->header.hdr) 158 fp = &((*fp)->next); 159 if(*fp) 160 { 161 new->header.hdr.next = (*fp)->next; 162 *fp = &new->header.hdr; 163 } 164 else sfprintf(sfstderr,"discipline not replaced\n"); 165 } 166 167 /* 168 * Calculate the amount of space to be allocated to hold an 169 * indexed array into which <maxi> is a legal index. The number of 170 * elements that will actually fit into the array (> <maxi> 171 * but <= ARRAY_MAX) is returned. 172 * 173 */ 174 static int arsize(struct index_array *ap, register int maxi) 175 { 176 if(ap && maxi < 2*ap->maxi) 177 maxi = 2*ap->maxi; 178 maxi = roundof(maxi,ARRAY_INCR); 179 return (maxi>ARRAY_MAX?ARRAY_MAX:maxi); 180 } 181 182 static struct index_array *array_grow(Namval_t*, struct index_array*,int); 183 184 /* return index of highest element of an array */ 185 int array_maxindex(Namval_t *np) 186 { 187 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 188 register int i = ap->maxi; 189 if(is_associative(ap)) 190 return(-1); 191 while(i>0 && ap->val[--i].cp==0); 192 return(i+1); 193 } 194 195 static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update) 196 { 197 register struct index_array *ap = (struct index_array*)arp; 198 register union Value *up; 199 #if SHOPT_FIXEDARRAY 200 struct fixed_array *fp; 201 #endif /* SHOPT_FIXEDARRAY */ 202 int nofree=0; 203 if(!arp) 204 return(&np->nvalue); 205 if(is_associative(ap)) 206 { 207 Namval_t *mp; 208 mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT)); 209 if(mp) 210 { 211 nofree = nv_isattr(mp,NV_NOFREE); 212 up = &mp->nvalue; 213 } 214 else 215 return((union Value*)((*arp->fun)(np,NIL(char*),0))); 216 } 217 #if SHOPT_FIXEDARRAY 218 else if(fp = (struct fixed_array*)arp->fixed) 219 { 220 if(!fp->data) 221 array_fixed_setdata(np,arp,fp); 222 up = &np->nvalue; 223 if(fp->ptr) 224 up->cp = *(((char**)fp->data)+fp->curi); 225 else 226 up->cp = fp->data+fp->size*fp->curi; 227 } 228 #endif /* SHOPT_FIXEDARRAY */ 229 else 230 { 231 if(ap->cur >= ap->maxi) 232 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 233 up = &(ap->val[ap->cur]); 234 nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE); 235 } 236 if(update) 237 { 238 if(nofree) 239 nv_onattr(np,NV_NOFREE); 240 else 241 nv_offattr(np,NV_NOFREE); 242 } 243 return(up); 244 } 245 246 int nv_arrayisset(Namval_t *np, Namarr_t *arp) 247 { 248 register struct index_array *ap = (struct index_array*)arp; 249 union Value *up; 250 if(is_associative(ap)) 251 return((np = nv_opensub(np)) && !nv_isnull(np)); 252 if(ap->cur >= ap->maxi) 253 return(0); 254 up = &(ap->val[ap->cur]); 255 if(up->cp==Empty) 256 { 257 Namfun_t *fp = &arp->hdr; 258 for(fp=fp->next; fp; fp = fp->next) 259 { 260 if(fp->disc && (fp->disc->getnum || fp->disc->getval)) 261 return(1); 262 } 263 } 264 return(up->cp && up->cp!=Empty); 265 } 266 267 /* 268 * Get the Value pointer for an array. 269 * Delete space as necessary if flag is ARRAY_DELETE 270 * After the lookup is done the last @ or * subscript is incremented 271 */ 272 static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag) 273 { 274 register struct index_array *ap = (struct index_array*)arp; 275 register union Value *up; 276 Namval_t *mp; 277 int wasundef; 278 #if SHOPT_FIXEDARRAY 279 struct fixed_array *fp=(struct fixed_array*)(arp->fixed); 280 #endif /* SHOPT_FIXEDARRAY */ 281 if(flag&ARRAY_LOOKUP) 282 ap->header.nelem &= ~ARRAY_NOSCOPE; 283 else 284 ap->header.nelem |= ARRAY_NOSCOPE; 285 if(wasundef = ap->header.nelem&ARRAY_UNDEF) 286 { 287 ap->header.nelem &= ~ARRAY_UNDEF; 288 /* delete array is the same as delete array[@] */ 289 if(flag&ARRAY_DELETE) 290 { 291 #if SHOPT_FIXEDARRAY 292 nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE|(ap->header.fixed?(ARRAY_UNDEF|ARRAY_FIXED):0)); 293 #else 294 nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE); 295 #endif /* SHOPT_FIXEDARRAY */ 296 ap->header.nelem |= ARRAY_SCAN; 297 } 298 else /* same as array[0] */ 299 { 300 if(is_associative(ap)) 301 (*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0); 302 #if SHOPT_FIXEDARRAY 303 else if(fp) 304 { 305 int n=fp->ndim; 306 fp->curi = 0; 307 while(--n>=0) 308 fp->cur[n] = 0; 309 } 310 #endif /* SHOPT_FIXEDARRAY */ 311 else 312 ap->cur = 0; 313 } 314 } 315 if(is_associative(ap)) 316 { 317 mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT)); 318 if(!mp) 319 up = (union Value*)∓ 320 else if(nv_isarray(mp)) 321 { 322 if(wasundef) 323 nv_putsub(mp,NIL(char*),ARRAY_UNDEF); 324 return(mp); 325 } 326 else 327 { 328 up = &mp->nvalue; 329 if(nv_isvtree(mp)) 330 { 331 if(!up->cp && flag==ARRAY_ASSIGN) 332 { 333 nv_arraychild(np,mp,0); 334 ap->header.nelem++; 335 } 336 return(mp); 337 } 338 } 339 } 340 #if SHOPT_FIXEDARRAY 341 else if(fp) 342 { 343 char *data = array_fixed_data((Namarr_t*)ap->header.scope); 344 if(flag==ARRAY_ASSIGN && data==fp->data) 345 { 346 if(data) 347 { 348 fp->data = (char*)malloc(fp->nelem*fp->size); 349 memcpy(fp->data,data,fp->nelem*fp->size); 350 } 351 else 352 array_fixed_setdata(np,&ap->header,fp); 353 } 354 if(fp->ptr) 355 { 356 if(!fp->data) 357 array_fixed_setdata(np,&ap->header,fp); 358 np->nvalue.cp = *(((char**)fp->data)+fp->curi); 359 } 360 else 361 np->nvalue.cp = fp->data+fp->size*fp->curi; 362 return(np); 363 } 364 #endif /* SHOPT_FIXEDARRAY */ 365 else 366 { 367 if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi) 368 ap = array_grow(np, ap, (int)ap->cur); 369 if(ap->cur>=ap->maxi) 370 errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np)); 371 up = &(ap->val[ap->cur]); 372 if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np)) 373 { 374 char *cp; 375 if(!ap->header.table) 376 ap->header.table = dtopen(&_Nvdisc,Dtoset); 377 sfprintf(sh.strbuf,"%d",ap->cur); 378 cp = sfstruse(sh.strbuf); 379 mp = nv_search(cp, ap->header.table, NV_ADD); 380 mp->nvenv = (char*)np; 381 nv_arraychild(np,mp,0); 382 } 383 if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD)) 384 { 385 if(wasundef && nv_isarray(up->np)) 386 nv_putsub(up->np,NIL(char*),ARRAY_UNDEF); 387 return(up->np); 388 } 389 } 390 np->nvalue.cp = up->cp; 391 if(!up->cp) 392 { 393 char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np); 394 if(flag!=ARRAY_ASSIGN) 395 return(xp && xp!=(char*)np?np:0); 396 if(!array_covered(np,ap)) 397 ap->header.nelem++; 398 } 399 return(np); 400 } 401 402 #if SHOPT_TYPEDEF 403 int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags) 404 { 405 Namval_t *nq; 406 char *av[2]; 407 int rdonly = nv_isattr(np,NV_RDONLY); 408 int xtrace = sh_isoption(SH_XTRACE); 409 Namarr_t *ap = nv_arrayptr(np); 410 av[1] = 0; 411 sh.last_table = 0; 412 if(!ap->table) 413 ap->table = dtopen(&_Nvdisc,Dtoset); 414 if(nq = nv_search(sub, ap->table, NV_ADD)) 415 { 416 if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0) 417 _nv_unset(nq,NV_RDONLY); 418 nv_arraychild(np,nq,0); 419 if(!nv_isattr(tp,NV_BINARY)) 420 { 421 sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np)); 422 av[0] = strdup(sfstruse(sh.strbuf)); 423 } 424 if(!nv_clone(tp,nq,flags|NV_NOFREE)) 425 return(0); 426 ap->nelem |= ARRAY_SCAN; 427 if(!rdonly) 428 nv_offattr(nq,NV_RDONLY); 429 if(!nv_isattr(tp,NV_BINARY)) 430 { 431 if(xtrace) 432 sh_offoption(SH_XTRACE); 433 ap->nelem &= ~ARRAY_SCAN; 434 sh_eval(sh_sfeval(av),0); 435 ap->nelem |= ARRAY_SCAN; 436 free((void*)av[0]); 437 if(xtrace) 438 sh_onoption(SH_XTRACE); 439 } 440 return(1); 441 } 442 return(0); 443 } 444 #endif /* SHOPT_TYPEDEF */ 445 446 447 static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp) 448 { 449 Namarr_t *ap = (Namarr_t*)fp; 450 Namval_t *nq, *mq; 451 char *name, *sub=0; 452 int nelem, skipped=0; 453 Dt_t *otable=ap->table; 454 struct index_array *aq = (struct index_array*)ap, *ar; 455 Shell_t *shp = sh_getinterp(); 456 if(flags&NV_MOVE) 457 { 458 if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN)) 459 { 460 do 461 { 462 if(nq=nv_opensub(np)) 463 nq->nvenv = (void*)mp; 464 } 465 while(nv_nextsub(np)); 466 } 467 return(fp); 468 } 469 nelem = ap->nelem; 470 if(nelem&ARRAY_NOCLONE) 471 return(0); 472 if((flags&NV_TYPE) && !ap->scope) 473 { 474 ap = array_scope(np,ap,flags); 475 return(&ap->hdr); 476 } 477 ap = (Namarr_t*)nv_clone_disc(fp,0); 478 if(flags&NV_COMVAR) 479 { 480 ap->scope = 0; 481 ap->nelem = 0; 482 sh.prev_table = sh.last_table; 483 sh.prev_root = sh.last_root; 484 } 485 if(ap->table) 486 { 487 ap->table = dtopen(&_Nvdisc,Dtoset); 488 if(ap->scope && !(flags&NV_COMVAR)) 489 { 490 ap->scope = ap->table; 491 dtview(ap->table, otable->view); 492 } 493 } 494 mp->nvfun = (Namfun_t*)ap; 495 mp->nvflag &= NV_MINIMAL; 496 mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE)); 497 if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np))) 498 sub = strdup(sub); 499 ar = (struct index_array*)ap; 500 if(!is_associative(ap)) 501 ar->bits = (unsigned char*)&ar->val[ar->maxi]; 502 if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE))) 503 { 504 if(ap->fun) 505 (*ap->fun)(np,(char*)np,0); 506 skipped=1; 507 goto skip; 508 } 509 do 510 { 511 name = nv_getsub(np); 512 nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE); 513 mq = 0; 514 if(nq=nv_opensub(np)) 515 mq = nv_search(name,ap->table,NV_ADD); 516 if(nq && (((flags&NV_COMVAR) && nv_isvtree(nq)) || nv_isarray(nq))) 517 { 518 mq->nvalue.cp = 0; 519 if(!is_associative(ap)) 520 ar->val[ar->cur].np = mq; 521 nv_clone(nq,mq,flags); 522 } 523 else if(flags&NV_ARRAY) 524 { 525 if((flags&NV_NOFREE) && !is_associative(ap)) 526 array_setbit(aq->bits,aq->cur,ARRAY_NOFREE); 527 else if(nq && (flags&NV_NOFREE)) 528 { 529 mq->nvalue = nq->nvalue; 530 nv_onattr(nq,NV_NOFREE); 531 } 532 } 533 else if(nv_isattr(np,NV_INTEGER)) 534 { 535 Sfdouble_t d= nv_getnum(np); 536 if(!is_associative(ap)) 537 ar->val[ar->cur].cp = 0; 538 nv_putval(mp,(char*)&d,NV_LDOUBLE); 539 } 540 else 541 { 542 if(!is_associative(ap)) 543 ar->val[ar->cur].cp = 0; 544 nv_putval(mp,nv_getval(np),NV_RDONLY); 545 } 546 aq->header.nelem |= ARRAY_NOSCOPE; 547 } 548 while(nv_nextsub(np)); 549 skip: 550 if(sub) 551 { 552 if(!skipped) 553 nv_putsub(np,sub,0L); 554 free((void*)sub); 555 } 556 aq->header.nelem = ap->nelem = nelem; 557 return(&ap->hdr); 558 } 559 560 static char *array_getval(Namval_t *np, Namfun_t *disc) 561 { 562 register Namarr_t *aq,*ap = (Namarr_t*)disc; 563 register Namval_t *mp; 564 register char *cp=0; 565 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 566 { 567 if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope)) 568 { 569 array_syncsub(aq,ap); 570 if((mp=array_find(np,aq,ARRAY_LOOKUP))==np) 571 return(nv_getv(np,&aq->hdr)); 572 } 573 if(mp) 574 { 575 cp = nv_getval(mp); 576 nv_offattr(mp,NV_EXPORT); 577 } 578 return(cp); 579 } 580 #if SHOPT_FIXEDARRAY 581 if(ap->fixed && nv_isattr(np,NV_INT16P) == NV_INT16) 582 np->nvalue.s = *np->nvalue.sp; 583 #endif /* SHOPT_FIXEDARRAY */ 584 return(nv_getv(np,&ap->hdr)); 585 } 586 587 static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc) 588 { 589 register Namarr_t *aq,*ap = (Namarr_t*)disc; 590 register Namval_t *mp; 591 if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np) 592 { 593 if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope)) 594 { 595 array_syncsub(aq,ap); 596 if((mp=array_find(np,aq,ARRAY_LOOKUP))==np) 597 return(nv_getn(np,&aq->hdr)); 598 } 599 return(mp?nv_getnum(mp):0); 600 } 601 return(nv_getn(np,&ap->hdr)); 602 } 603 604 static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp) 605 { 606 register Namarr_t *ap = (Namarr_t*)dp; 607 register union Value *up; 608 register Namval_t *mp; 609 register struct index_array *aq = (struct index_array*)ap; 610 int scan,nofree = nv_isattr(np,NV_NOFREE); 611 #if SHOPT_FIXEDARRAY 612 struct fixed_array *fp; 613 #endif /* SHOPT_FIXEDARRAY */ 614 do 615 { 616 int xfree = (ap->fixed||is_associative(ap))?0:array_isbit(aq->bits,aq->cur,ARRAY_NOFREE); 617 mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE); 618 scan = ap->nelem&ARRAY_SCAN; 619 if(mp && mp!=np) 620 { 621 if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp) && !(ap->nelem&ARRAY_TREE)) 622 623 { 624 if(!nv_isattr(np,NV_NOFREE)) 625 _nv_unset(mp,flags&NV_RDONLY); 626 array_clrbit(aq->bits,aq->cur,ARRAY_CHILD); 627 aq->val[aq->cur].cp = 0; 628 if(!nv_isattr(mp,NV_NOFREE)) 629 nv_delete(mp,ap->table,0); 630 goto skip; 631 } 632 if(!xfree) 633 nv_putval(mp, string, flags); 634 if(string) 635 { 636 #if SHOPT_TYPEDEF 637 if(ap->hdr.type && ap->hdr.type!=nv_type(mp)) 638 nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0); 639 #endif /* SHOPT_TYPEDEF */ 640 continue; 641 } 642 ap->nelem |= scan; 643 } 644 if(!string) 645 { 646 if(mp) 647 { 648 if(is_associative(ap)) 649 { 650 (*ap->fun)(np,NIL(char*),NV_ADELETE); 651 np->nvalue.cp = 0; 652 } 653 else 654 { 655 if(mp!=np) 656 { 657 array_clrbit(aq->bits,aq->cur,ARRAY_CHILD); 658 aq->val[aq->cur].cp = 0; 659 if(!xfree) 660 nv_delete(mp,ap->table,0); 661 } 662 if(!array_covered(np,(struct index_array*)ap)) 663 { 664 if(array_elem(ap)) 665 ap->nelem--; 666 } 667 #if SHOPT_FIXEDARRAY 668 else if(fp=(struct fixed_array*)ap->fixed) 669 { 670 char *data = array_fixed_data((Namarr_t*)ap->scope); 671 int n = fp->size*fp->curi; 672 if(data) 673 { 674 memcpy(fp->data+n,data+n,fp->size); 675 continue; 676 } 677 } 678 #endif /* SHOPT_FIXEDARRAY */ 679 } 680 } 681 if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN)) 682 { 683 if(is_associative(ap)) 684 (*ap->fun)(np, NIL(char*), NV_AFREE); 685 else if(ap->table) 686 dtclose(ap->table); 687 nv_offattr(np,NV_ARRAY); 688 } 689 if(!mp || mp!=np || is_associative(ap)) 690 continue; 691 } 692 skip: 693 /* prevent empty string from being deleted */ 694 up = array_getup(np,ap,!nofree); 695 if(up->cp == Empty) 696 up->cp = 0; 697 #if SHOPT_FIXEDARRAY 698 if(nv_isarray(np) && !ap->fixed) 699 #else 700 if(nv_isarray(np)) 701 #endif /* SHOPT_FIXEDARRAY */ 702 np->nvalue.up = up; 703 nv_putv(np,string,flags,&ap->hdr); 704 #if SHOPT_FIXEDARRAY 705 if(fp = (struct fixed_array*)ap->fixed) 706 { 707 if(fp->ptr) 708 { 709 char **cp = (char**)fp->data; 710 cp[fp->curi] = (char*)(np->nvalue.cp?np->nvalue.cp:Empty); 711 } 712 } 713 else 714 #endif /* SHOPT_FIXEDARRAY */ 715 if(!is_associative(ap)) 716 { 717 if(string) 718 array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE); 719 else if(mp==np) 720 aq->val[aq->cur].cp = 0; 721 } 722 #if SHOPT_TYPEDEF 723 if(string && ap->hdr.type && nv_isvtree(np)) 724 nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0); 725 #endif /* SHOPT_TYPEDEF */ 726 } 727 while(!string && nv_nextsub(np)); 728 if(ap) 729 ap->nelem &= ~ARRAY_NOSCOPE; 730 if(nofree) 731 nv_onattr(np,NV_NOFREE); 732 else 733 nv_offattr(np,NV_NOFREE); 734 if(!string && !nv_isattr(np,NV_ARRAY)) 735 { 736 Namfun_t *nfp; 737 #if SHOPT_FIXEDARRAY 738 char *data = array_fixed_data((Namarr_t*)ap->scope); 739 fp = (struct fixed_array*)ap->fixed; 740 if(fp && (!ap->scope || data!=fp->data)) 741 { 742 if(fp->ptr) 743 { 744 int n = fp->nelem; 745 char **cp = (char**)fp->data; 746 while(n-->0) 747 { 748 if(cp && *cp!=Empty) 749 free(*cp); 750 cp++; 751 } 752 } 753 free((void*)fp->data); 754 if(data) 755 fp->data = data; 756 } 757 else 758 #endif /* SHOPT_FIXEDARRAY */ 759 if(!is_associative(ap) && aq->xp) 760 { 761 _nv_unset(nv_namptr(aq->xp,0),NV_RDONLY); 762 free((void*)aq->xp); 763 } 764 if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1)) 765 free((void*)nfp); 766 if(!nv_isnull(np)) 767 { 768 if(!np->nvfun) 769 nv_onattr(np,NV_NOFREE); 770 _nv_unset(np,flags); 771 } 772 else 773 nv_offattr(np,NV_NOFREE); 774 if(np->nvalue.cp==Empty) 775 np->nvalue.cp = 0; 776 } 777 if(!string && (flags&NV_TYPE)) 778 array_unscope(np,ap); 779 } 780 781 static const Namdisc_t array_disc = 782 { 783 sizeof(Namarr_t), 784 array_putval, 785 array_getval, 786 array_getnum, 787 0, 788 0, 789 array_clone 790 }; 791 792 static void array_copytree(Namval_t *np, Namval_t *mp) 793 { 794 Namfun_t *fp = nv_disc(np,NULL,NV_POP); 795 nv_offattr(np,NV_ARRAY); 796 nv_clone(np,mp,0); 797 if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE)) 798 free((void*)np->nvalue.cp); 799 np->nvalue.cp = 0; 800 np->nvalue.up = &mp->nvalue; 801 fp->nofree &= ~1; 802 nv_disc(np,(Namfun_t*)fp, NV_FIRST); 803 fp->nofree |= 1; 804 nv_onattr(np,NV_ARRAY); 805 mp->nvenv = (char*)np; 806 } 807 808 /* 809 * Increase the size of the indexed array of elements in <arp> 810 * so that <maxi> is a legal index. If <arp> is 0, an array 811 * of the required size is allocated. A pointer to the 812 * allocated Namarr_t structure is returned. 813 * <maxi> becomes the current index of the array. 814 */ 815 static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi) 816 { 817 register struct index_array *ap; 818 register int i; 819 register int newsize = arsize(arp,maxi+1); 820 if (maxi >= ARRAY_MAX) 821 errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0)); 822 i = (newsize-1)*sizeof(union Value*)+newsize; 823 ap = new_of(struct index_array,i); 824 memset((void*)ap,0,sizeof(*ap)+i); 825 ap->maxi = newsize; 826 ap->cur = maxi; 827 ap->bits = (unsigned char*)&ap->val[newsize]; 828 memset(ap->bits, 0, newsize); 829 if(arp) 830 { 831 ap->header = arp->header; 832 ap->header.hdr.dsize = sizeof(*ap) + i; 833 for(i=0;i < arp->maxi;i++) 834 { 835 ap->bits[i] = arp->bits[i]; 836 ap->val[i].cp = arp->val[i].cp; 837 } 838 memcpy(ap->bits, arp->bits, arp->maxi); 839 array_setptr(np,arp,ap); 840 free((void*)arp); 841 } 842 else 843 { 844 Namval_t *mp=0; 845 ap->header.hdr.dsize = sizeof(*ap) + i; 846 i = 0; 847 ap->header.fun = 0; 848 if((nv_isnull(np)||np->nvalue.cp==Empty) && nv_isattr(np,NV_NOFREE)) 849 { 850 i = ARRAY_TREE; 851 nv_offattr(np,NV_NOFREE); 852 } 853 if(np->nvalue.cp==Empty) 854 np->nvalue.cp=0; 855 if(nv_hasdisc(np,&array_disc) || (nv_type(np) && nv_isvtree(np))) 856 { 857 ap->header.table = dtopen(&_Nvdisc,Dtoset); 858 mp = nv_search("0", ap->header.table,NV_ADD); 859 if(mp && nv_isnull(mp)) 860 { 861 Namfun_t *fp; 862 ap->val[0].np = mp; 863 array_setbit(ap->bits,0,ARRAY_CHILD); 864 for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next); 865 if(fp && fp->disc && fp->disc->readf) 866 (*fp->disc->readf)(mp,(Sfio_t*)0,0,fp); 867 i++; 868 } 869 } 870 else 871 if((ap->val[0].cp=np->nvalue.cp)) 872 i++; 873 else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np)) 874 { 875 Sfdouble_t d= nv_getnum(np); 876 i++; 877 } 878 ap->header.nelem = i; 879 ap->header.hdr.disc = &array_disc; 880 nv_disc(np,(Namfun_t*)ap, NV_FIRST); 881 nv_onattr(np,NV_ARRAY); 882 if(mp) 883 { 884 array_copytree(np,mp); 885 ap->header.hdr.nofree &= ~1; 886 } 887 } 888 for(;i < newsize;i++) 889 ap->val[i].cp = 0; 890 return(ap); 891 } 892 893 int nv_atypeindex(Namval_t *np, const char *tname) 894 { 895 Namval_t *tp; 896 int offset = staktell(); 897 size_t n = strlen(tname)-1; 898 sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0); 899 tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME); 900 stakseek(offset); 901 if(tp) 902 { 903 struct index_array *ap = (struct index_array*)nv_arrayptr(np); 904 if(!nv_hasdisc(tp,&ENUM_disc)) 905 errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname); 906 if(!ap) 907 ap = array_grow(np,ap,1); 908 ap->xp = calloc(NV_MINSZ,1); 909 np = nv_namptr(ap->xp,0); 910 np->nvname = tp->nvname; 911 nv_onattr(np,NV_MINIMAL); 912 nv_clone(tp,np,NV_NOFREE); 913 nv_offattr(np,NV_RDONLY); 914 return(1); 915 } 916 errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname); 917 return(0); 918 } 919 920 Namarr_t *nv_arrayptr(register Namval_t *np) 921 { 922 if(nv_isattr(np,NV_ARRAY)) 923 return((Namarr_t*)nv_hasdisc(np, &array_disc)); 924 return(0); 925 } 926 927 /* 928 * Verify that argument is an indexed array and convert to associative, 929 * freeing relevant storage 930 */ 931 static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 932 { 933 register Namarr_t *ap; 934 char numbuff[NUMSIZE+1]; 935 unsigned dot, digit, n; 936 union Value *up; 937 struct index_array *save_ap; 938 register char *string_index=&numbuff[NUMSIZE]; 939 numbuff[NUMSIZE]='\0'; 940 941 if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap)) 942 return(NIL(Namarr_t*)); 943 944 nv_stack(np,&ap->hdr); 945 save_ap = (struct index_array*)nv_stack(np,0); 946 ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)); 947 ap->nelem = 0; 948 ap->fun = fun; 949 nv_onattr(np,NV_ARRAY); 950 951 for(dot = 0; dot < (unsigned)save_ap->maxi; dot++) 952 { 953 if(save_ap->val[dot].cp) 954 { 955 if ((digit = dot)== 0) 956 *--string_index = '0'; 957 else while( n = digit ) 958 { 959 digit /= 10; 960 *--string_index = '0' + (n-10*digit); 961 } 962 nv_putsub(np, string_index, ARRAY_ADD); 963 up = (union Value*)((*ap->fun)(np,NIL(char*),0)); 964 up->cp = save_ap->val[dot].cp; 965 save_ap->val[dot].cp = 0; 966 } 967 string_index = &numbuff[NUMSIZE]; 968 } 969 free((void*)save_ap); 970 return(ap); 971 } 972 973 /* 974 * set the associative array processing method for node <np> to <fun> 975 * The array pointer is returned if sucessful. 976 */ 977 Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int)) 978 { 979 register Namarr_t *ap; 980 char *value=0; 981 Namfun_t *fp; 982 int nelem = 0; 983 if(fun && (ap = nv_arrayptr(np))) 984 { 985 /* 986 * if it's already an indexed array, convert to 987 * associative structure 988 */ 989 if(!is_associative(ap)) 990 ap = nv_changearray(np, fun); 991 return(ap); 992 } 993 if(nv_isnull(np) && nv_isattr(np,NV_NOFREE)) 994 { 995 nelem = ARRAY_TREE; 996 nv_offattr(np,NV_NOFREE); 997 } 998 if(!(fp=nv_isvtree(np))) 999 value = nv_getval(np); 1000 if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT)))) 1001 { 1002 /* check for preexisting initialization and save */ 1003 ap->nelem = nelem; 1004 ap->fun = fun; 1005 nv_onattr(np,NV_ARRAY); 1006 if(fp || (value && value!=Empty)) 1007 { 1008 nv_putsub(np, "0", ARRAY_ADD); 1009 if(value) 1010 nv_putval(np, value, 0); 1011 else 1012 { 1013 Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT)); 1014 array_copytree(np,mp); 1015 } 1016 } 1017 return(ap); 1018 } 1019 return(NIL(Namarr_t*)); 1020 } 1021 1022 /* 1023 * move parent subscript into child 1024 */ 1025 Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c) 1026 { 1027 Namfun_t *fp; 1028 register Namarr_t *ap = nv_arrayptr(np); 1029 union Value *up; 1030 Namval_t *tp; 1031 if(!nq) 1032 return(ap?array_find(np,ap, ARRAY_LOOKUP):0); 1033 if(!ap) 1034 { 1035 nv_putsub(np, NIL(char*), ARRAY_FILL); 1036 ap = nv_arrayptr(np); 1037 } 1038 if(!(up = array_getup(np,ap,0))) 1039 return((Namval_t*)0); 1040 np->nvalue.cp = up->cp; 1041 if((tp=nv_type(np)) || c) 1042 { 1043 ap->nelem |= ARRAY_NOCLONE; 1044 nq->nvenv = (char*)np; 1045 if(c=='t') 1046 nv_clone(tp,nq, 0); 1047 else 1048 nv_clone(np, nq, NV_NODISC); 1049 nv_offattr(nq,NV_ARRAY); 1050 ap->nelem &= ~ARRAY_NOCLONE; 1051 } 1052 nq->nvenv = (char*)np; 1053 if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP))) 1054 free((void*)fp); 1055 if(!ap->fun) 1056 { 1057 struct index_array *aq = (struct index_array*)ap; 1058 array_setbit(aq->bits,aq->cur,ARRAY_CHILD); 1059 if(c=='.' && !nq->nvalue.cp) 1060 ap->nelem++; 1061 up->np = nq; 1062 } 1063 if(c=='.') 1064 nv_setvtree(nq); 1065 return(nq); 1066 } 1067 1068 /* 1069 * This routine sets subscript of <np> to the next element, if any. 1070 * The return value is zero, if there are no more elements 1071 * Otherwise, 1 is returned. 1072 */ 1073 int nv_nextsub(Namval_t *np) 1074 { 1075 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1076 register unsigned dot; 1077 struct index_array *aq=0, *ar=0; 1078 #if SHOPT_FIXEDARRAY 1079 struct fixed_array *fp; 1080 #endif /* SHOPT_FIXEDARRAY */ 1081 if(!ap || !(ap->header.nelem&ARRAY_SCAN)) 1082 return(0); 1083 if(is_associative(ap)) 1084 { 1085 if((*ap->header.fun)(np,NIL(char*),NV_ANEXT)) 1086 return(1); 1087 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 1088 return(0); 1089 } 1090 #if SHOPT_FIXEDARRAY 1091 else if(fp = (struct fixed_array*)ap->header.fixed) 1092 { 1093 if(ap->header.nelem&ARRAY_FIXED) 1094 { 1095 while(++fp->curi < fp->nelem) 1096 { 1097 nv_putsub(np,0,fp->curi|ARRAY_FIXED|ARRAY_SCAN); 1098 if(fp->ptr && *(((char**)fp->data)+fp->curi)) 1099 return(1); 1100 } 1101 ap->header.nelem &= ~ARRAY_FIXED; 1102 return(0); 1103 } 1104 dot = fp->dim; 1105 if((fp->cur[dot]+1) < fp->max[dot]) 1106 { 1107 fp->cur[dot]++; 1108 for(fp->curi=0,dot=0; dot < fp->ndim; dot++) 1109 fp->curi += fp->incr[dot]*fp->cur[dot]; 1110 return(1); 1111 } 1112 if(fp->level) 1113 { 1114 dot= --fp->dim; 1115 while((dot+1) < fp->ndim) 1116 fp->cur[++dot] = 0; 1117 fp->level--; 1118 fp->curi = 0; 1119 } 1120 else 1121 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 1122 return(0); 1123 } 1124 #endif /* SHOPT_FIXEDARRAY */ 1125 if(!(ap->header.nelem&ARRAY_NOSCOPE)) 1126 ar = (struct index_array*)ap->header.scope; 1127 for(dot=ap->cur+1; dot < (unsigned)ap->maxi; dot++) 1128 { 1129 aq = ap; 1130 if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE)) 1131 { 1132 if(!(aq=ar) || dot>=(unsigned)aq->maxi) 1133 continue; 1134 } 1135 if(aq->val[dot].cp==Empty && array_elem(&aq->header) < nv_aimax(np)+1) { 1136 ap->cur = dot; 1137 if(nv_getval(np)==Empty) 1138 continue; 1139 } 1140 if(aq->val[dot].cp) 1141 { 1142 ap->cur = dot; 1143 if(array_isbit(aq->bits, dot,ARRAY_CHILD)) 1144 { 1145 Namval_t *mp = aq->val[dot].np; 1146 if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize) 1147 continue; 1148 if(nv_isarray(mp)) 1149 nv_putsub(mp,NIL(char*),ARRAY_SCAN); 1150 } 1151 return(1); 1152 } 1153 } 1154 ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD); 1155 ap->cur = 0; 1156 return(0); 1157 } 1158 1159 /* 1160 * Set an array subscript for node <np> given the subscript <sp> 1161 * An array is created if necessary. 1162 * <mode> can be a number, plus or more of symbolic constants 1163 * ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD 1164 * The node pointer is returned which can be NULL if <np> is 1165 * not already array and the ARRAY_ADD bit of <mode> is not set. 1166 * ARRAY_FILL sets the specified subscript to the empty string when 1167 * ARRAY_ADD is specified and there is no value or sets all 1168 * the elements up to the number specified if ARRAY_ADD is not specified 1169 */ 1170 Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode) 1171 { 1172 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1173 register int size = (mode&ARRAY_MASK); 1174 #if SHOPT_FIXEDARRAY 1175 struct fixed_array *fp; 1176 if(!ap || (!ap->header.fixed && !ap->header.fun)) 1177 #else 1178 if(!ap || !ap->header.fun) 1179 #endif /* SHOPT_FIXEDARRAY */ 1180 { 1181 if(sp) 1182 { 1183 Shell_t *shp = sh_getinterp(); 1184 if(ap && ap->xp && !strmatch(sp,"+([0-9])")) 1185 { 1186 Namval_t *mp = nv_namptr(ap->xp,0); 1187 nv_putval(mp, sp,0); 1188 size = nv_getnum(mp); 1189 } 1190 else 1191 size = (int)sh_arith(shp,(char*)sp); 1192 } 1193 if(size <0 && ap) 1194 size += array_maxindex(np); 1195 if(size >= ARRAY_MAX || (size < 0)) 1196 { 1197 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 1198 return(NIL(Namval_t*)); 1199 } 1200 if(!ap || size>=ap->maxi) 1201 { 1202 if(size==0 && !(mode&ARRAY_FILL)) 1203 return(NIL(Namval_t*)); 1204 if(sh.subshell) 1205 np = sh_assignok(np,1); 1206 ap = array_grow(np, ap,size); 1207 } 1208 ap->header.nelem &= ~ARRAY_UNDEF; 1209 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE)); 1210 #if 0 1211 if(array_isbit(ap->bits,oldsize,ARRAY_CHILD)) 1212 mp = ap->val[oldsize].np; 1213 if(size != oldsize && mp->nvalue.cp) 1214 { 1215 Namfun_t *nfp; 1216 for(nfp=np->nvfun; nfp; nfp=nfp->next) 1217 { 1218 if(nfp->disc && nfp->disc->readf) 1219 { 1220 (*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp); 1221 break; 1222 } 1223 } 1224 } 1225 #endif 1226 ap->cur = size; 1227 if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np))) 1228 np = 0; 1229 if(mode&(ARRAY_FILL|ARRAY_ADD)) 1230 { 1231 if(!(mode&ARRAY_ADD)) 1232 { 1233 int n; 1234 if(mode&ARRAY_SETSUB) 1235 { 1236 for(n=0; n <= ap->maxi; n++) 1237 ap->val[n].cp = 0; 1238 ap->header.nelem = 0; 1239 } 1240 for(n=0; n <= size; n++) 1241 { 1242 if(!ap->val[n].cp) 1243 { 1244 ap->val[n].cp = Empty; 1245 if(!array_covered(np,ap)) 1246 ap->header.nelem++; 1247 } 1248 } 1249 if(n=ap->maxi-ap->maxi) 1250 memset(&ap->val[size],0,n*sizeof(union Value)); 1251 } 1252 else if(!(sp=(char*)ap->val[size].cp) || sp==Empty) 1253 { 1254 if(sh.subshell) 1255 np = sh_assignok(np,1); 1256 if(ap->header.nelem&ARRAY_TREE) 1257 { 1258 char *cp; 1259 Namval_t *mp; 1260 if(!ap->header.table) 1261 ap->header.table = dtopen(&_Nvdisc,Dtoset); 1262 sfprintf(sh.strbuf,"%d",ap->cur); 1263 cp = sfstruse(sh.strbuf); 1264 mp = nv_search(cp, ap->header.table, NV_ADD); 1265 mp->nvenv = (char*)np; 1266 nv_arraychild(np,mp,0); 1267 nv_setvtree(mp); 1268 } 1269 else 1270 ap->val[size].cp = Empty; 1271 if(!sp && !array_covered(np,ap)) 1272 ap->header.nelem++; 1273 } 1274 } 1275 else if(!(mode&ARRAY_SCAN)) 1276 { 1277 ap->header.nelem &= ~ARRAY_SCAN; 1278 if(array_isbit(ap->bits,size,ARRAY_CHILD)) 1279 nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF); 1280 if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp) 1281 np = 0; 1282 } 1283 return((Namval_t*)np); 1284 } 1285 #if SHOPT_FIXEDARRAY 1286 if(fp=(struct fixed_array*)ap->header.fixed) 1287 { 1288 if(!fp->data) 1289 return(np); 1290 if(mode&ARRAY_UNDEF) 1291 { 1292 fp->dim = 0; 1293 fp->curi = 0; 1294 for(size=fp->ndim;--size>=0;) 1295 fp->cur[size] = 0; 1296 ap->header.nelem &= ~ARRAY_MASK; 1297 if(mode&ARRAY_FIXED) 1298 { 1299 mode &= ~ARRAY_UNDEF; 1300 ap->header.nelem |= (ARRAY_FIXED|fp->nelem); 1301 } 1302 else 1303 ap->header.nelem |= fp->max[0]; 1304 } 1305 else if(mode&ARRAY_FIXED) 1306 { 1307 size = (mode&ARRAY_MASK)&~(ARRAY_FIXED); 1308 fp->curi = size; 1309 for(fp->dim=0;size>0 && fp->dim<fp->ndim; fp->dim++) 1310 { 1311 fp->cur[fp->dim] = size/fp->incr[fp->dim]; 1312 size -= fp->incr[fp->dim]*fp->cur[fp->dim]; 1313 } 1314 while(fp->dim < fp->ndim) 1315 fp->cur[fp->dim++] = 0; 1316 fp->dim = ap->header.nelem; 1317 ap->header.nelem |= ARRAY_FIXED; 1318 } 1319 else if(fp->dim< fp->ndim) 1320 { 1321 fp->curi += (size-fp->cur[fp->dim])*fp->incr[fp->dim]; 1322 fp->cur[fp->dim] = size; 1323 } 1324 } 1325 #endif /* SHOPT_FIXEDARRAY */ 1326 ap->header.nelem &= ~ARRAY_UNDEF; 1327 if(!(mode&ARRAY_FILL)) 1328 ap->header.nelem &= ~ARRAY_SCAN; 1329 ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE)); 1330 #if SHOPT_FIXEDARRAY 1331 if(fp) 1332 return(np); 1333 else 1334 #endif /* SHOPT_FIXEDARRAY */ 1335 if(sp) 1336 { 1337 if(mode&ARRAY_SETSUB) 1338 { 1339 (*ap->header.fun)(np, sp, NV_ASETSUB); 1340 return(np); 1341 } 1342 (*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0); 1343 if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT)) 1344 np = 0; 1345 } 1346 else if(mode&ARRAY_SCAN) 1347 (*ap->header.fun)(np,(char*)np,0); 1348 else if(mode&ARRAY_UNDEF) 1349 (*ap->header.fun)(np, "",0); 1350 if((mode&ARRAY_SCAN) && !nv_nextsub(np)) 1351 np = 0; 1352 return(np); 1353 } 1354 1355 #if SHOPT_FIXEDARRAY 1356 int nv_arrfixed(Namval_t *np, Sfio_t *out, int flag, char *dim) 1357 { 1358 Namarr_t *ap = nv_arrayptr(np); 1359 struct fixed_array *fp = (struct fixed_array*)ap->fixed; 1360 int n; 1361 if(flag) 1362 { 1363 if(out) 1364 { 1365 for(n=0; n < fp->dim; n++) 1366 sfprintf(out,"[%d]",fp->cur[n]); 1367 } 1368 if(dim) 1369 *dim = fp->dim; 1370 return(fp->curi); 1371 } 1372 if(out) 1373 { 1374 for(n=0; n < fp->ndim; n++) 1375 sfprintf(out,"[%d]",fp->max[n]); 1376 } 1377 fp->dim = 0; 1378 return(fp->curi); 1379 } 1380 1381 static void array_fixed_setdata(Namval_t *np,Namarr_t* ap,struct fixed_array* fp) 1382 { 1383 int n = ap->nelem; 1384 ap->nelem = 1; 1385 fp->size = fp->ptr?sizeof(void*):nv_datasize(np,0); 1386 ap->nelem = n; 1387 fp->data = (char*)calloc(fp->nelem,fp->size); 1388 if(fp->ptr) 1389 { 1390 char **cp = (char**)fp->data; 1391 for(n=fp->nelem; n-->0;) 1392 *cp++ = Empty; 1393 } 1394 } 1395 1396 static int array_fixed_init(Namval_t *np, char *sub, char *cp) 1397 { 1398 Shell_t *shp=sh_getinterp(); 1399 Namarr_t *ap; 1400 struct fixed_array *fp; 1401 int n=1,sz; 1402 char *ep=cp; 1403 while(*ep=='[') 1404 { 1405 ep = nv_endsubscript(np,ep,0); 1406 n++; 1407 } 1408 if(*ep) 1409 return(0); 1410 sz = sizeof(struct fixed_array)+ 3*n*sizeof(int); 1411 if(!(ap=newof(NIL(Namarr_t*),Namarr_t,1,sz))) 1412 return(0); 1413 ap->hdr.disc = &array_disc; 1414 ap->hdr.dsize = sizeof(Namarr_t)+sz; 1415 ap->hdr.nofree &= ~1; 1416 fp = (struct fixed_array*)(ap+1); 1417 ap->fixed = (void*)fp; 1418 fp->ndim = n; 1419 fp->max = (int*)(fp+1); 1420 fp->incr = fp->max+n; 1421 fp->cur = fp->incr+n; 1422 fp->max[0] = (int)sh_arith(shp,(char*)sub); 1423 for(n=1,ep=cp;*ep=='['; ep=cp) 1424 { 1425 cp = nv_endsubscript(np,ep,0); 1426 cp[-1]=0; 1427 fp->max[n++] = sz = (int)sh_arith(shp,(char*)ep+1); 1428 if(sz<0) 1429 { 1430 free((void*)ap); 1431 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 1432 } 1433 cp[-1] = ']'; 1434 } 1435 nv_disc(np,(Namfun_t*)ap, NV_FIRST); 1436 fp->ptr = !np->nvsize; 1437 nv_onattr(np,NV_ARRAY|(fp->ptr?0:NV_NOFREE)); 1438 fp->incr[n=fp->ndim-1] = 1; 1439 for(sz=1; --n>=0;) 1440 sz = fp->incr[n] = sz*fp->max[n+1]; 1441 fp->nelem = sz*fp->max[0]; 1442 ap->nelem = fp->max[0]; 1443 return(1); 1444 } 1445 1446 static char *array_fixed(Namval_t *np, char *sub, char *cp,int mode) 1447 { 1448 Shell_t *shp=sh_getinterp(); 1449 Namarr_t *ap = nv_arrayptr(np); 1450 struct fixed_array *fp = (struct fixed_array*)ap->fixed; 1451 char *ep; 1452 int size,n=0,sz; 1453 if(!fp->data) 1454 array_fixed_setdata(np,ap,fp); 1455 ap->nelem &= ~ARRAY_UNDEF; 1456 if(ap->nelem&ARRAY_FIXED) 1457 { 1458 ap->nelem &= ~ARRAY_FIXED; 1459 n = fp->dim; 1460 sz = fp->curi; 1461 if(*sub==0) 1462 goto skip; 1463 } 1464 else 1465 fp->curi = 0; 1466 size = (int)sh_arith(shp,(char*)sub); 1467 fp->cur[n] = size; 1468 if(size >= fp->max[n] || (size < 0)) 1469 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 1470 *cp++ = ']'; 1471 sz = fp->curi + fp->cur[n]*fp->incr[n]; 1472 for(n++,ep=cp;*ep=='['; ep=cp,n++) 1473 { 1474 if(n >= fp->ndim) 1475 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 1476 cp = nv_endsubscript(np,ep,0); 1477 cp[-1]=0; 1478 size = (int)sh_arith(shp,(char*)ep+1); 1479 if(size >= fp->max[n] || (size < 0)) 1480 errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np)); 1481 fp->cur[n] = size; 1482 cp[-1] = ']'; 1483 sz += fp->cur[n]*fp->incr[n]; 1484 } 1485 skip: 1486 fp->dim = n; 1487 ap->nelem &= ~ARRAY_MASK; 1488 ap->nelem |= fp->max[n]; 1489 while(n < fp->ndim) 1490 fp->cur[n++] = 0; 1491 fp->curi = sz; 1492 return(cp-1); 1493 } 1494 #endif /* SHOPT_FIXEDARRAY */ 1495 1496 /* 1497 * process an array subscript for node <np> given the subscript <cp> 1498 * returns pointer to character after the subscript 1499 */ 1500 char *nv_endsubscript(Namval_t *np, register char *cp, int mode) 1501 { 1502 register int count=1, quoted=0, c; 1503 register char *sp = cp+1; 1504 /* first find matching ']' */ 1505 while(count>0 && (c= *++cp)) 1506 { 1507 if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@')) 1508 { 1509 quoted=1; 1510 cp++; 1511 } 1512 else if(c=='[') 1513 count++; 1514 else if(c==']') 1515 count--; 1516 } 1517 *cp = 0; 1518 if(quoted) 1519 { 1520 /* strip escape characters */ 1521 count = staktell(); 1522 stakwrite(sp,1+cp-sp); 1523 sh_trim(sp=stakptr(count)); 1524 } 1525 if(mode && np) 1526 { 1527 Namarr_t *ap = nv_arrayptr(np); 1528 int scan = 0; 1529 #if SHOPT_FIXEDARRAY 1530 if((mode&NV_FARRAY) && !nv_isarray(np)) 1531 { 1532 if(array_fixed_init(np,sp,cp+1)) 1533 { 1534 *cp++ = c; 1535 return(strchr(cp,0)); 1536 } 1537 } 1538 #endif /* SHOPT_FIXEDARRAY */ 1539 if(ap) 1540 scan = ap->nelem&ARRAY_SCAN; 1541 if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+')) 1542 mode |= NV_ADD; 1543 else if(ap && cp[1]=='.' && (mode&NV_FARRAY)) 1544 mode |= NV_ADD; 1545 #if SHOPT_FIXEDARRAY 1546 if(ap && ap->fixed) 1547 cp = array_fixed(np,sp,cp,mode); 1548 else 1549 #endif /* SHOPT_FIXEDARRAY */ 1550 nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL)); 1551 if(scan) 1552 ap->nelem |= scan; 1553 } 1554 if(quoted) 1555 stakseek(count); 1556 *cp++ = c; 1557 return(cp); 1558 } 1559 1560 1561 Namval_t *nv_opensub(Namval_t* np) 1562 { 1563 register struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1564 #if SHOPT_FIXEDARRAY 1565 struct fixed_array *fp; 1566 #endif /* SHOPT_FIXEDARRAY */ 1567 if(ap) 1568 { 1569 if(is_associative(ap)) 1570 return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT))); 1571 #if SHOPT_FIXEDARRAY 1572 else if(!(fp=(struct fixed_array*)ap->header.fixed) && array_isbit(ap->bits,ap->cur,ARRAY_CHILD)) 1573 #else 1574 else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD)) 1575 #endif /* SHOPT_FIXEDARRAY */ 1576 { 1577 return(ap->val[ap->cur].np); 1578 } 1579 #if SHOPT_FIXEDARRAY 1580 else if(fp) 1581 { 1582 int n = fp->dim; 1583 if((fp->dim+1) < fp->ndim) 1584 { 1585 fp->dim++; 1586 if(ap->header.nelem&ARRAY_SCAN) 1587 { 1588 while(++n < fp->ndim) 1589 fp->cur[n] = 0; 1590 fp->level++; 1591 } 1592 return(np); 1593 } 1594 } 1595 #endif /* SHOPT_FIXEDARRAY */ 1596 } 1597 return(NIL(Namval_t*)); 1598 } 1599 1600 char *nv_getsub(Namval_t* np) 1601 { 1602 static char numbuff[NUMSIZE+1]; 1603 register struct index_array *ap; 1604 register unsigned dot, n; 1605 register char *cp = &numbuff[NUMSIZE]; 1606 if(!np || !(ap = (struct index_array*)nv_arrayptr(np))) 1607 return(NIL(char*)); 1608 if(is_associative(ap)) 1609 return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME))); 1610 if(ap->xp) 1611 { 1612 np = nv_namptr(ap->xp,0); 1613 np->nvalue.s = ap->cur; 1614 return(nv_getval(np)); 1615 } 1616 if((dot = ap->cur)==0) 1617 *--cp = '0'; 1618 else while(n=dot) 1619 { 1620 dot /= 10; 1621 *--cp = '0' + (n-10*dot); 1622 } 1623 return(cp); 1624 } 1625 1626 /* 1627 * If <np> is an indexed array node, the current subscript index 1628 * returned, otherwise returns -1 1629 */ 1630 int nv_aindex(register Namval_t* np) 1631 { 1632 Namarr_t *ap = nv_arrayptr(np); 1633 if(!ap) 1634 return(0); 1635 else if(is_associative(ap)) 1636 return(-1); 1637 #if SHOPT_FIXEDARRAY 1638 else if(ap->fixed) 1639 return(-1); 1640 #endif /* SHOPT_FIXEDARRAY */ 1641 return(((struct index_array*)(ap))->cur&ARRAY_MASK); 1642 } 1643 1644 int nv_arraynsub(register Namarr_t* ap) 1645 { 1646 return(array_elem(ap)); 1647 } 1648 1649 int nv_aimax(register Namval_t* np) 1650 { 1651 struct index_array *ap = (struct index_array*)nv_arrayptr(np); 1652 int sub = -1; 1653 #if SHOPT_FIXEDARRAY 1654 if(!ap || is_associative(&ap->header) || ap->header.fixed) 1655 #else 1656 if(!ap || is_associative(&ap->header)) 1657 #endif /* SHOPT_FIXEDARRAY */ 1658 return(-1); 1659 sub = ap->maxi; 1660 while(--sub>0 && ap->val[sub].cp==0); 1661 return(sub); 1662 } 1663 1664 /* 1665 * This is the default implementation for associative arrays 1666 */ 1667 void *nv_associative(register Namval_t *np,const char *sp,int mode) 1668 { 1669 register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np); 1670 register int type; 1671 switch(mode) 1672 { 1673 case NV_AINIT: 1674 if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array))) 1675 { 1676 ap->header.table = dtopen(&_Nvdisc,Dtoset); 1677 ap->cur = 0; 1678 ap->pos = 0; 1679 ap->header.hdr.disc = &array_disc; 1680 nv_disc(np,(Namfun_t*)ap, NV_FIRST); 1681 ap->header.hdr.dsize = sizeof(struct assoc_array); 1682 ap->header.hdr.nofree &= ~1; 1683 } 1684 return((void*)ap); 1685 case NV_ADELETE: 1686 if(ap->cur) 1687 { 1688 if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0)) 1689 ap->header.nelem--; 1690 _nv_unset(ap->cur,NV_RDONLY); 1691 nv_delete(ap->cur,ap->header.table,0); 1692 ap->cur = 0; 1693 } 1694 return((void*)ap); 1695 case NV_AFREE: 1696 ap->pos = 0; 1697 if(ap->header.scope) 1698 { 1699 ap->header.table = dtview(ap->header.table,(Dt_t*)0); 1700 dtclose(ap->header.scope); 1701 ap->header.scope = 0; 1702 } 1703 else 1704 dtclose(ap->header.table); 1705 return((void*)ap); 1706 case NV_ANEXT: 1707 if(!ap->pos) 1708 { 1709 if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table)) 1710 { 1711 ap->header.scope = dtvnext(ap->header.table); 1712 ap->header.table->view = 0; 1713 } 1714 if(!(ap->pos=ap->cur)) 1715 ap->pos = (Namval_t*)dtfirst(ap->header.table); 1716 } 1717 else 1718 ap->pos = ap->nextpos; 1719 for(;ap->cur=ap->pos; ap->pos=ap->nextpos) 1720 { 1721 ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos); 1722 if(!nv_isnull(ap->cur)) 1723 { 1724 if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD)) 1725 continue; 1726 return((void*)ap); 1727 } 1728 } 1729 if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table)) 1730 { 1731 ap->header.table->view = (Dt_t*)ap->header.scope; 1732 ap->header.scope = ap->header.table; 1733 } 1734 return(NIL(void*)); 1735 case NV_ASETSUB: 1736 ap->cur = (Namval_t*)sp; 1737 return((void*)ap->cur); 1738 case NV_ACURRENT: 1739 if(ap->cur) 1740 ap->cur->nvenv = (char*)np; 1741 return((void*)ap->cur); 1742 case NV_ANAME: 1743 if(ap->cur) 1744 { 1745 Shell_t *shp = sh_getinterp(); 1746 if(!shp->instance && nv_isnull(ap->cur)) 1747 return(NIL(void*)); 1748 return((void*)ap->cur->nvname); 1749 } 1750 return(NIL(void*)); 1751 default: 1752 if(sp) 1753 { 1754 Namval_t *mp=0; 1755 ap->cur = 0; 1756 if(sp==(char*)np) 1757 return(0); 1758 type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL)); 1759 if(mode) 1760 mode = NV_ADD|HASH_NOSCOPE; 1761 else if(ap->header.nelem&ARRAY_NOSCOPE) 1762 mode = HASH_NOSCOPE; 1763 if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD)) 1764 errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript"); 1765 if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp)) 1766 ap->cur = mp; 1767 if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD)) 1768 { 1769 nv_onattr(mp,type); 1770 mp->nvenv = (char*)np; 1771 if((mode&NV_ADD) && nv_type(np)) 1772 nv_arraychild(np,mp,0); 1773 if(sh.subshell) 1774 np = sh_assignok(np,1); 1775 if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0)) 1776 ap->header.nelem++; 1777 if(nv_isnull(mp)) 1778 { 1779 if(ap->header.nelem&ARRAY_TREE) 1780 nv_setvtree(mp); 1781 mp->nvalue.cp = Empty; 1782 } 1783 } 1784 else if(ap->header.nelem&ARRAY_SCAN) 1785 { 1786 Namval_t fake; 1787 fake.nvname = (char*)sp; 1788 ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake); 1789 ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp); 1790 } 1791 else if(!mp && *sp && mode==0) 1792 mp = nv_search(sp,ap->header.table,NV_ADD|HASH_NOSCOPE); 1793 np = mp; 1794 if(ap->pos && ap->pos==np) 1795 ap->header.nelem |= ARRAY_SCAN; 1796 else if(!(ap->header.nelem&ARRAY_SCAN)) 1797 ap->pos = 0; 1798 ap->cur = np; 1799 } 1800 if(ap->cur) 1801 return((void*)(&ap->cur->nvalue)); 1802 else 1803 return((void*)(&ap->cur)); 1804 } 1805 } 1806 1807 /* 1808 * Assign values to an array 1809 */ 1810 void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[]) 1811 { 1812 int arg0=0; 1813 struct index_array *ap=0,*aq; 1814 if(nv_isarray(np)) 1815 { 1816 ap = (struct index_array*)nv_arrayptr(np); 1817 if(ap && is_associative(ap)) 1818 errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np)); 1819 } 1820 if(append) 1821 { 1822 if(ap) 1823 { 1824 if(!(aq = (struct index_array*)ap->header.scope)) 1825 aq = ap; 1826 arg0 = ap->maxi; 1827 while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0); 1828 arg0++; 1829 } 1830 else 1831 { 1832 nv_offattr(np,NV_ARRAY); 1833 if(!nv_isnull(np) && np->nvalue.cp!=Empty) 1834 arg0=1; 1835 } 1836 } 1837 while(--argc >= 0) 1838 { 1839 nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD); 1840 nv_putval(np,argv[argc],0); 1841 } 1842 } 1843 1844