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 * David Korn 23 * AT&T Labs 24 * 25 */ 26 27#include "defs.h" 28 29static const char sh_opttype[] = 30"[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-07-01 $\n]" 31USAGE_LICENSE 32"[+NAME?\f?\f - set the type of variables to \b\f?\f\b]" 33"[+DESCRIPTION?\b\f?\f\b sets the type on each of the variables specified " 34 "by \aname\a to \b\f?\f\b. If \b=\b\avalue\a is specified, " 35 "the variable \aname\a is set to \avalue\a before the variable " 36 "is converted to \b\f?\f\b.]" 37"[+?If no \aname\as are specified then the names and values of all " 38 "variables of this type are written to standard output.]" 39"[+?\b\f?\f\b is built-in to the shell as a declaration command so that " 40 "field splitting and pathname expansion are not performed on " 41 "the arguments. Tilde expansion occurs on \avalue\a.]" 42"[r?Enables readonly. Once enabled, the value cannot be changed or unset.]" 43"[a]:?[type?Indexed array. Each \aname\a will converted to an index " 44 "array of type \b\f?\f\b. If a variable already exists, the current " 45 "value will become index \b0\b. If \b[\b\atype\a\b]]\b is " 46 "specified, each subscript is interpreted as a value of enumeration " 47 "type \atype\a.]" 48"[A?Associative array. Each \aname\a will converted to an associate " 49 "array of type \b\f?\f\b. If a variable already exists, the current " 50 "value will become subscript \b0\b.]" 51"[h]:[string?Used within a type definition to provide a help string " 52 "for variable \aname\a. Otherwise, it is ignored.]" 53"[S?Used with a type definition to indicate that the variable is shared by " 54 "each instance of the type. When used inside a function defined " 55 "with the \bfunction\b reserved word, the specified variables " 56 "will have function static scope. Otherwise, the variable is " 57 "unset prior to processing the assignment list.]" 58"[+DETAILS]\ftypes\f" 59"\n" 60"\n[name[=value]...]\n" 61"\n" 62"[+EXIT STATUS?]{" 63 "[+0?Successful completion.]" 64 "[+>0?An error occurred.]" 65"}" 66 67"[+SEE ALSO?\fother\f \breadonly\b(1), \btypeset\b(1)]" 68; 69 70typedef struct Namtype Namtype_t; 71typedef struct Namchld 72{ 73 Namfun_t fun; 74 Namtype_t *ptype; 75 Namtype_t *ttype; 76} Namchld_t; 77 78struct Namtype 79{ 80 Namfun_t fun; 81 Shell_t *sh; 82 Namval_t *np; 83 Namval_t *parent; 84 Namval_t *bp; 85 Namval_t *cp; 86 char *nodes; 87 char *data; 88 Namchld_t childfun; 89 int numnodes; 90 char **names; 91 size_t dsize; 92 short strsize; 93 unsigned short ndisc; 94 unsigned short current; 95 unsigned short nref; 96}; 97 98#if 0 99struct type 100{ 101 Namtype_t hdr; 102 unsigned short ndisc; 103 unsigned short current; 104 unsigned short nref; 105}; 106#endif 107 108typedef struct 109{ 110 char _cSfdouble_t; 111 Sfdouble_t _dSfdouble_t; 112 char _cdouble; 113 double _ddouble; 114 char _cfloat; 115 float _dfloat; 116 char _cSflong_t; 117 Sflong_t _dSflong_t; 118 char _clong; 119 long _dlong; 120 char _cshort; 121 short _dshort; 122 char _cpointer; 123 char *_dpointer; 124} _Align_; 125 126#define alignof(t) ((char*)&((_Align_*)0)->_d##t-(char*)&((_Align_*)0)->_c##t) 127 128static void put_type(Namval_t*, const char*, int, Namfun_t*); 129static Namval_t* create_type(Namval_t*, const char*, int, Namfun_t*); 130static Namfun_t* clone_type(Namval_t*, Namval_t*, int, Namfun_t*); 131static Namval_t* next_type(Namval_t*, Dt_t*, Namfun_t*); 132 133static const Namdisc_t type_disc = 134{ 135 sizeof(Namtype_t), 136 put_type, 137 0, 138 0, 139 0, 140 create_type, 141 clone_type, 142 0, 143 next_type, 144 0, 145#if 0 146 read_type 147#endif 148}; 149 150static size_t datasize(Namval_t *np, size_t *offset) 151{ 152 size_t s=0, a=0; 153 Namarr_t *ap; 154 if(nv_isattr(np,NV_INTEGER)) 155 { 156 if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) 157 { 158 if(nv_isattr(np, NV_LONG)) 159 { 160 a = alignof(Sfdouble_t); 161 s = sizeof(Sfdouble_t); 162 } 163 else if(nv_isattr(np, NV_SHORT)) 164 { 165 a = alignof(float); 166 s = sizeof(float); 167 } 168 else 169 { 170 a = alignof(double); 171 s = sizeof(double); 172 } 173 } 174 else 175 { 176 if(nv_isattr(np, NV_LONG)) 177 { 178 a = alignof(Sflong_t); 179 s = sizeof(Sflong_t); 180 } 181 else if(nv_isattr(np, NV_SHORT)) 182 { 183 a = alignof(short); 184 s = sizeof(short); 185 } 186 else 187 { 188 a = alignof(long); 189 s = sizeof(long); 190 } 191 } 192 } 193 else if(nv_isattr(np, NV_BINARY) || nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL)) 194 s = nv_size(np); 195 else 196 { 197 a = alignof(pointer); 198 s = nv_size(np); 199 } 200 if(a>1 && offset) 201 *offset = a*((*offset +a-1)/a); 202 if(nv_isarray(np) && (ap = nv_arrayptr(np))) 203 s *= array_elem(ap); 204 return(s); 205} 206 207static char *name_chtype(Namval_t *np, Namfun_t *fp) 208{ 209 Namchld_t *pp = (Namchld_t*)fp; 210 char *cp, *sub; 211 Namval_t *tp = sh.last_table; 212 Namval_t *nq = pp->ptype->np; 213 Namarr_t *ap; 214 if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED)) 215 sh.last_table = 0; 216 cp = nv_name(nq); 217 if((ap = nv_arrayptr(nq)) && !(ap->nelem&ARRAY_UNDEF) && (sub= nv_getsub(nq))) 218 sfprintf(sh.strbuf,"%s[%s].%s",cp,sub,np->nvname); 219 else 220 sfprintf(sh.strbuf,"%s.%s",cp,np->nvname); 221 sh.last_table = tp; 222 return(sfstruse(sh.strbuf)); 223} 224 225static void put_chtype(Namval_t* np, const char* val, int flag, Namfun_t* fp) 226{ 227 if(!val && nv_isattr(np,NV_REF)) 228 return; 229 nv_putv(np,val,flag,fp); 230 if(!val) 231 { 232 Namchld_t *pp = (Namchld_t*)fp; 233 size_t dsize=0,offset = (char*)np-(char*)pp->ptype; 234 Namval_t *mp = (Namval_t*)((char*)pp->ttype+offset); 235 dsize = datasize(mp,&dsize); 236 if(mp->nvalue.cp >= pp->ttype->data && mp->nvalue.cp < (char*)pp+pp->ttype->fun.dsize) 237 { 238 np->nvalue.cp = pp->ptype->data + (mp->nvalue.cp-pp->ptype->data); 239 memcpy((char*)np->nvalue.cp,mp->nvalue.cp,dsize); 240 } 241 else if(!nv_isarray(mp) && mp->nvalue.cp) 242 { 243 np->nvalue.cp = mp->nvalue.cp; 244 nv_onattr(np,NV_NOFREE); 245 } 246 np->nvsize = mp->nvsize; 247 np->nvflag = mp->nvflag&~NV_RDONLY; 248 } 249} 250 251static Namfun_t *clone_chtype(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 252{ 253 if(flags&NV_NODISC) 254 return(0); 255 return(nv_clone_disc(fp,flags)); 256} 257 258static const Namdisc_t chtype_disc = 259{ 260 sizeof(Namchld_t), 261 put_chtype, 262 0, 263 0, 264 0, 265 0, 266 clone_chtype, 267 name_chtype 268}; 269 270static Namval_t *findref(void *nodes, int n) 271{ 272 Namval_t *tp,*np = nv_namptr(nodes,n); 273 char *name = np->nvname; 274 int i=n, len= strrchr(name,'.')-name; 275 Namtype_t *pp; 276 while(--i>0) 277 { 278 np = nv_namptr(nodes,i); 279 if(np->nvname[len]==0) 280 { 281 tp = nv_type(np); 282 pp = (Namtype_t*)nv_hasdisc(tp,&type_disc); 283 return(nv_namptr(pp->nodes,n-i-1)); 284 } 285 } 286 return(0); 287} 288 289static int fixnode(Namtype_t *dp, Namtype_t *pp, int i, struct Namref *nrp,int flag) 290{ 291 Namval_t *nq = nv_namptr(dp->nodes,i); 292 Namfun_t *fp; 293 if(fp=nv_hasdisc(nq,&chtype_disc)) 294 nv_disc(nq, fp, NV_POP); 295 if(nv_isattr(nq,NV_REF)) 296 { 297 nq->nvalue.nrp = nrp++; 298 nv_setsize(nq,0); 299 if(strchr(nq->nvname,'.')) 300 nq->nvalue.nrp->np = findref(dp->nodes,i); 301 else 302 nq->nvalue.nrp->np = nv_namptr(pp->childfun.ttype->nodes,i); 303 nq->nvalue.nrp->root = sh.last_root; 304 nq->nvalue.nrp->table = pp->np; 305 nq ->nvflag = NV_REF|NV_NOFREE|NV_MINIMAL; 306 return(1); 307 } 308 if(nq->nvalue.cp || nq->nvfun) 309 { 310 const char *data = nq->nvalue.cp; 311 if(nq->nvfun) 312 { 313 Namval_t *np = nv_namptr(pp->nodes,i); 314 if(nv_isarray(nq)) 315 nq->nvalue.cp = 0; 316 nq->nvfun = 0; 317 if(nv_isarray(nq) && nv_type(np)) 318 clone_all_disc(np,nq,flag&~NV_TYPE); 319 else 320 clone_all_disc(np,nq,flag); 321 if(fp) 322 nv_disc(np, fp, NV_LAST); 323 } 324#if 0 325 if(nq->nvalue.cp >= pp->data && nq->nvalue.cp < (char*)pp +pp->fun.dsize) 326 nq->nvalue.cp = dp->data + (nq->nvalue.cp-pp->data); 327#else 328 if(data >= pp->data && data < (char*)pp +pp->fun.dsize) 329 nq->nvalue.cp = dp->data + (data-pp->data); 330#endif 331 else if(!nq->nvfun && pp->childfun.ttype!=pp->childfun.ptype) 332 { 333 Namval_t *nr = nv_namptr( pp->childfun.ttype->nodes,i); 334 if(nr->nvalue.cp!=nq->nvalue.cp) 335 { 336 if(i=nv_size(nq)) 337 { 338 const char *cp = nq->nvalue.cp; 339 nq->nvalue.cp = (char*)malloc(i); 340 memcpy((char*)nq->nvalue.cp,cp,i); 341 } 342 else 343 nq->nvalue.cp = strdup(nq->nvalue.cp); 344 nv_offattr(nq,NV_NOFREE); 345 } 346 } 347 348 } 349 if(fp) 350 nv_disc(nq, &dp->childfun.fun, NV_LAST); 351 return(0); 352} 353 354static Namfun_t *clone_type(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 355{ 356 Namtype_t *dp, *pp=(Namtype_t*)fp; 357 register int i; 358 register Namval_t *nq, *nr; 359 size_t size = fp->dsize; 360 int save, offset=staktell(); 361 char *cp; 362 Dt_t *root = sh.last_root; 363 Namval_t *last_table = sh.last_table; 364 struct Namref *nrp = 0; 365 Namarr_t *ap; 366 if(flags&NV_MOVE) 367 { 368 pp->np = mp; 369 pp->childfun.ptype = pp; 370 return(fp); 371 } 372 if(flags&NV_TYPE) 373 return(nv_clone_disc(fp,flags)); 374 if(size==0 && (!fp->disc || (size=fp->disc->dsize)==0)) 375 size = sizeof(Namfun_t); 376 dp = (Namtype_t*)malloc(size+pp->nref*sizeof(struct Namref)); 377 if(pp->nref) 378 { 379 nrp = (struct Namref*)((char*)dp + size); 380 memset((void*)nrp,0,pp->nref*sizeof(struct Namref)); 381 } 382 memcpy((void*)dp,(void*)pp,size); 383#if 0 384 dp->parent = nv_lastdict(); 385#else 386 dp->parent = mp; 387#endif 388 dp->fun.nofree = (flags&NV_RDONLY?1:0); 389 dp->np = mp; 390 dp->childfun.ptype = dp; 391#if 0 392 dp->childfun.ttype = (Namtype_t*)nv_hasdisc(dp->fun.type,&type_disc); 393#endif 394 dp->nodes = (char*)(dp+1); 395 dp->data = (char*)dp + (pp->data - (char*)pp); 396 for(i=dp->numnodes; --i >= 0; ) 397 { 398 nq = nv_namptr(dp->nodes,i); 399 if(fixnode(dp,pp,i,nrp,NV_TYPE)) 400 { 401 nrp++; 402 nq = nq->nvalue.nrp->np; 403 } 404 if(nq->nvalue.cp || !nv_isvtree(nq) || nv_isattr(nq,NV_RDONLY)) 405 { 406 /* see if default value has been overwritten */ 407 if(!mp->nvname) 408 continue; 409 sh.last_table = last_table; 410 if(pp->strsize<0) 411 cp = nv_name(np); 412 else 413 cp = nv_name(mp); 414 stakputs(cp); 415 stakputc('.'); 416 stakputs(nq->nvname); 417 stakputc(0); 418 root = nv_dict(mp); 419 save = fp->nofree; 420 fp->nofree = 1; 421 nr = nv_create(stakptr(offset),root,NV_VARNAME|NV_NOADD,fp); 422 fp->nofree = save; 423 stakseek(offset); 424 if(nr) 425 { 426 if(nv_isattr(nq,NV_RDONLY) && (nq->nvalue.cp || nv_isattr(nq,NV_INTEGER))) 427 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nq->nvname); 428 if(nv_isref(nq)) 429 nq = nv_refnode(nq); 430 if((size = datasize(nr,(size_t*)0)) && size==datasize(nq,(size_t*)0)) 431 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,size); 432 else if(ap=nv_arrayptr(nr)) 433 { 434 nv_putsub(nr,NIL(char*),ARRAY_SCAN|ARRAY_NOSCOPE); 435 do 436 { 437 if(array_assoc(ap)) 438 cp = (char*)((*ap->fun)(nr,NIL(char*),NV_ANAME)); 439 else 440 cp = nv_getsub(nr); 441 nv_putsub(nq,cp,ARRAY_ADD|ARRAY_NOSCOPE); 442 if(array_assoc(ap)) 443 { 444 Namval_t *mp = (Namval_t*)((*ap->fun)(nr,NIL(char*),NV_ACURRENT)); 445 Namval_t *mq = (Namval_t*)((*ap->fun)(nq,NIL(char*),NV_ACURRENT)); 446 nv_clone(mp,mq,NV_MOVE); 447 ap->nelem--; 448 nv_delete(mp,ap->table,0); 449 } 450 else 451 { 452 cp = nv_getval(nr); 453 nv_putval(nq,cp,0); 454 } 455 } 456 while(nv_nextsub(nr)); 457 } 458 else 459 nv_putval(nq,nv_getval(nr),NV_RDONLY); 460#if SHOPT_TYPEDEF 461 if(sh.mktype) 462 nv_addnode(nr,1); 463#endif /* SHOPT_TYPEDEF */ 464 if(pp->strsize<0) 465 continue; 466 _nv_unset(nr,0); 467 if(!nv_isattr(nr,NV_MINIMAL)) 468 nv_delete(nr,sh.last_root,0); 469 } 470 else if(nv_isattr(nq,NV_RDONLY) && !nq->nvalue.cp && !nv_isattr(nq,NV_INTEGER)) 471 errormsg(SH_DICT,ERROR_exit(1),e_required,nq->nvname,nv_name(mp)); 472 } 473 } 474 if(nv_isattr(mp,NV_BINARY)) 475 mp->nvalue.cp = dp->data; 476 if(pp->strsize<0) 477 dp->strsize = -pp->strsize; 478 return(&dp->fun); 479} 480 481 482/* 483 * return Namval_t* corresponding to child <name> in <np> 484 */ 485static Namval_t *create_type(Namval_t *np,const char *name,int flag,Namfun_t *fp) 486{ 487 Namtype_t *dp = (Namtype_t*)fp; 488 register const char *cp=name; 489 register int i=0,n; 490 Namval_t *nq=0; 491 if(!name) 492 return(dp->parent); 493 while((n=*cp++) && n != '=' && n != '+' && n!='['); 494 n = (cp-1) -name; 495 if(dp->numnodes && dp->strsize<0) 496 { 497 char *base = (char*)np-sizeof(Dtlink_t); 498 int m=strlen(np->nvname); 499 while((nq=nv_namptr(base,++i)) && memcmp(nq->nvname,np->nvname,m)==0) 500 { 501 if(nq->nvname[m]=='.' && memcmp(name,&nq->nvname[m+1],n)==0 && nq->nvname[m+n+1]==0) 502 goto found; 503 } 504 nq = 0; 505 } 506 else for(i=0; i < dp->numnodes; i++) 507 { 508 nq = nv_namptr(dp->nodes,i); 509 if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0) 510 { 511 while(nv_isref(nq)) 512 nq = nq->nvalue.nrp->np; 513 goto found; 514 } 515 } 516 nq = 0; 517found: 518 if(nq) 519 { 520 fp->last = (char*)&name[n]; 521 sh.last_table = dp->parent; 522 } 523 else 524 { 525 if(name[n]!='=') for(i=0; i < dp->ndisc; i++) 526 { 527 if((memcmp(name,dp->names[i],n)==0) && dp->names[i][n]==0) 528 return(nq); 529 } 530 errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np)); 531 } 532 return(nq); 533} 534 535static void put_type(Namval_t* np, const char* val, int flag, Namfun_t* fp) 536{ 537 Namval_t *nq; 538 if(val && (nq=nv_open(val,sh.var_tree,NV_VARNAME|NV_ARRAY|NV_NOADD|NV_NOFAIL))) 539 { 540 Namfun_t *pp; 541 if((pp=nv_hasdisc(nq,fp->disc)) && pp->type==fp->type) 542 543 { 544 _nv_unset(np, flag); 545 nv_clone(nq,np,0); 546 return; 547 } 548 } 549 nv_putv(np,val,flag,fp); 550 if(!val) 551 { 552 Namtype_t *dp = (Namtype_t*)fp; 553 Namval_t *nq; 554 Namarr_t *ap; 555 int i; 556 if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0) 557 return; 558 for(i=0; i < dp->numnodes; i++) 559 { 560 nq = nv_namptr(dp->nodes,i); 561 if(ap=nv_arrayptr(nq)) 562 ap->nelem |= ARRAY_UNDEF; 563 if(!nv_hasdisc(nq,&type_disc)) 564 _nv_unset(nq,flag|NV_TYPE|nv_isattr(nq,NV_RDONLY)); 565 } 566 nv_disc(np,fp,NV_POP); 567 if(!(fp->nofree&1)) 568 free((void*)fp); 569 } 570} 571 572static Namval_t *next_type(register Namval_t* np, Dt_t *root,Namfun_t *fp) 573{ 574 Namtype_t *dp = (Namtype_t*)fp; 575 if(!root) 576 { 577 Namarr_t *ap = nv_arrayptr(np); 578 if(ap && (ap->nelem&ARRAY_UNDEF)) 579 nv_putsub(np,(char*)0,ARRAY_SCAN); 580 dp->current = 0; 581 } 582 else if(++dp->current>=dp->numnodes) 583 return(0); 584 return(nv_namptr(dp->nodes,dp->current)); 585} 586 587static Namfun_t *clone_inttype(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 588{ 589 Namfun_t *pp= (Namfun_t*)malloc(fp->dsize); 590 memcpy((void*)pp, (void*)fp, fp->dsize); 591 fp->nofree &= ~1; 592 if(nv_isattr(mp,NV_NOFREE) && mp->nvalue.cp) 593 memcpy((void*)mp->nvalue.cp,np->nvalue.cp, fp->dsize-sizeof(*fp)); 594 else 595 mp->nvalue.cp = (char*)(fp+1); 596 if(!nv_isattr(mp,NV_MINIMAL)) 597 mp->nvenv = 0; 598 nv_offattr(mp,NV_RDONLY); 599 return(pp); 600} 601 602static int typeinfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp) 603{ 604 char *cp,**help,buffer[256]; 605 Namtype_t *dp; 606 Namval_t *np,*nq,*tp; 607 int n, i, offset=staktell(); 608 Sfio_t *sp; 609 610 np = *(Namval_t**)(fp+1); 611 stakputs(NV_CLASS); 612 stakputc('.'); 613 stakputs(np->nvname); 614 stakputc(0); 615 np = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME); 616 stakseek(offset); 617 if(!np) 618 { 619 sfprintf(sfstderr,"%s: no such variable\n",np->nvname); 620 return(-1); 621 } 622 if(!(dp=(Namtype_t*)nv_hasdisc(np,&type_disc))) 623 { 624 Namfun_t *fp; 625 for(fp=np->nvfun;fp;fp=fp->next) 626 { 627 if(fp->disc && fp->disc->clonef==clone_inttype) 628 break; 629 } 630 if(!fp) 631 { 632 sfprintf(sfstderr,"%s: not a type\n",np->nvname); 633 return(-1); 634 } 635 if(strcmp(str,"other")==0) 636 return(0); 637 tp = fp->type; 638 nv_offattr(np,NV_RDONLY); 639 fp->type = 0; 640 if(np->nvenv) 641 sfprintf(out,"[+?\b%s\b is a %s.]\n", tp->nvname, np->nvenv); 642 cp = (char*)out->_next; 643 sfprintf(out,"[+?\b%s\b is a %n ", tp->nvname, &i); 644 nv_attribute(np,out,(char*)0, 1); 645 if(cp[i+1]=='i') 646 cp[i-1]='n'; 647 fp->type = tp; 648 nv_onattr(np,NV_RDONLY); 649 sfprintf(out," with default value \b%s\b.]",nv_getval(np)); 650 return(0); 651 } 652 if(strcmp(str,"other")==0) 653 { 654 Nambfun_t *bp; 655 if(bp=(Nambfun_t*)nv_hasdisc(np,nv_discfun(NV_DCADD))) 656 { 657 for(i=0; i < bp->num; i++) 658 { 659 if(nv_isattr(bp->bltins[i],NV_OPTGET)) 660 sfprintf(out,"\b%s.%s\b(3), ",np->nvname,bp->bnames[i]); 661 } 662 } 663 return(0); 664 } 665 help = &dp->names[dp->ndisc]; 666 sp = sfnew((Sfio_t*)0,buffer,sizeof(buffer),-1,SF_STRING|SF_WRITE); 667 sfprintf(out,"[+?\b%s\b defines the following fields:]{\n",np->nvname); 668 for(i=0; i < dp->numnodes; i++) 669 { 670 nq = nv_namptr(dp->nodes,i); 671 if(tp=nv_type(nq)) 672 { 673 Namfun_t *pp = nv_hasdisc(nq,&type_disc); 674 sfprintf(out,"\t[+%s?%s.\n",nq->nvname,tp->nvname); 675 n = strlen(nq->nvname); 676 while((cp=nv_namptr(dp->nodes,i+1)->nvname) && memcmp(cp,nq->nvname,n)==0 && cp[n]=='.') 677 i++; 678 } 679 else 680 { 681 sfseek(sp,(Sfoff_t)0, SEEK_SET); 682 nv_attribute(nq,sp,(char*)0,1); 683 cp = 0; 684 if(!nv_isattr(nq,NV_REF)) 685 cp = sh_fmtq(nv_getval(nq)); 686 sfputc(sp,0); 687 for(n=strlen(buffer); n>0 && buffer[n-1]==' '; n--); 688 buffer[n] = 0; 689 if(cp) 690 sfprintf(out,"\t[+%s?%s, default value is %s.\n",nq->nvname,*buffer?buffer:"string",cp); 691 else 692 sfprintf(out,"\t[+%s?%s.\n",nq->nvname,*buffer?buffer:"string"); 693 } 694 if(help[i]) 695 sfprintf(out," %s.",help[i]); 696 sfputc(out,']'); 697 } 698 sfprintf(out,"}\n"); 699 if(dp->ndisc>0) 700 { 701 stakseek(offset); 702 stakputs(NV_CLASS); 703 stakputc('.'); 704 stakputs(np->nvname); 705 stakputc('.'); 706 n = staktell(); 707 sfprintf(out,"[+?\b%s\b defines the following discipline functions:]{\n",np->nvname); 708 for(i=0; i < dp->ndisc; i++) 709 { 710 stakputs(dp->names[i]); 711 stakputc(0); 712 cp = 0; 713 if((nq = nv_search(stakptr(offset),sh.fun_tree,0)) && nq->nvalue.cp) 714 cp = nq->nvalue.rp->help; 715 sfprintf(out,"\t[+%s?%s]\n",dp->names[i],cp?cp:Empty); 716 if(cp) 717 sfputc(out,'.'); 718 stakseek(n); 719 } 720 sfprintf(out,"}\n"); 721 } 722 stakseek(offset); 723 sfclose(sp); 724 return(0); 725} 726 727static int std_disc(Namval_t *mp, Namtype_t *pp) 728{ 729 register const char *sp, *cp = strrchr(mp->nvname,'.'); 730 register const char **argv; 731 register int i; 732 Namval_t *np=0,*nq; 733 if(cp) 734 cp++; 735 else 736 cp = mp->nvname; 737 if(strcmp(cp,"create")==0) 738 { 739 if(pp) 740 pp->cp = mp; 741 return(0); 742 } 743 for(argv=nv_discnames; sp=*argv; argv++) 744 { 745 if(strcmp(cp,sp)==0) 746 { 747 if(!pp) 748 return(1); 749 goto found; 750 } 751 } 752 return(0); 753found: 754 if(memcmp(sp=mp->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0) 755 sp += sizeof(NV_CLASS); 756 sp += strlen(pp->fun.type->nvname)+1; 757 if(sp == cp) 758 np = pp->fun.type; 759 else for(i=1; i < pp->numnodes; i++) 760 { 761 nq = nv_namptr(pp->nodes,i); 762 if(memcmp(nq->nvname, sp, cp-sp-1)==0) 763 { 764 np = nq; 765 break; 766 } 767 } 768 if(np) 769 { 770 nv_onattr(mp,NV_NOFREE); 771 if(!nv_setdisc(np,cp, mp, (Namfun_t*)np)) 772 sfprintf(sfstderr," nvsetdisc failed name=%s sp=%s cp=%s\n",np->nvname,sp,cp); 773 } 774 else 775 sfprintf(sfstderr,"can't set discipline %s cp=%s \n",sp,cp); 776 return(1); 777} 778 779 780void nv_addtype(Namval_t *np, const char *optstr, Optdisc_t *op, size_t optsz) 781{ 782 Namdecl_t *cp = newof((Namdecl_t*)0,Namdecl_t,1,optsz); 783 Optdisc_t *dp = (Optdisc_t*)(cp+1); 784 Shell_t *shp = sh_getinterp(); 785 Namval_t *mp,*bp; 786 char *name; 787 if(optstr) 788 cp->optstring = optstr; 789 else 790 cp->optstring = sh_opttype; 791 memcpy((void*)dp,(void*)op, optsz); 792 cp->optinfof = (void*)dp; 793 cp->tp = np; 794 mp = nv_search("typeset",shp->bltin_tree,0); 795 if(name=strrchr(np->nvname,'.')) 796 name++; 797 else 798 name = np->nvname; 799 if((bp=nv_search(name,shp->fun_tree,NV_NOSCOPE)) && !bp->nvalue.ip) 800 nv_delete(bp,shp->fun_tree,0); 801 bp = sh_addbuiltin(name, mp->nvalue.bfp, (void*)cp); 802 nv_onattr(bp,nv_isattr(mp,NV_PUBLIC)); 803 nv_onattr(np, NV_RDONLY); 804} 805 806void nv_newtype(Namval_t *mp) 807{ 808 struct { 809 Optdisc_t opt; 810 Namval_t *np; 811 } optdisc; 812 memset(&optdisc,0,sizeof(optdisc)); 813 optdisc.opt.infof = typeinfo; 814 optdisc.np = mp; 815 nv_addtype(mp,sh_opttype, &optdisc.opt, sizeof(optdisc)); 816} 817 818/* 819 * This function creates a type out of the <numnodes> nodes in the 820 * array <nodes>. The first node is the name for the type 821 */ 822Namval_t *nv_mktype(Namval_t **nodes, int numnodes) 823{ 824 Namval_t *mp=nodes[0], *bp=0, *np, *nq, **mnodes=nodes; 825 int i,j,k,m,n,nd=0,nref=0,iref=0,inherit=0; 826 int size=sizeof(NV_DATA), dsize=0, nnodes; 827 size_t offset=0; 828 char *name=0, *cp, *sp, **help; 829 Namtype_t *pp,*qp=0,*dp,*tp; 830 Dt_t *root = nv_dict(mp); 831 struct Namref *nrp = 0; 832 Namfun_t *fp; 833 m = strlen(mp->nvname)+1; 834 for(nnodes=1,i=1; i <numnodes; i++) 835 { 836 np=nodes[i]; 837 if(is_afunction(np)) 838 { 839 if(!std_disc(np, (Namtype_t*)0)) 840 { 841 size += strlen(np->nvname+m)+1; 842 if(memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0) 843 size -= sizeof(NV_CLASS); 844 nd++; 845 } 846 continue; 847 } 848 if(nv_isattr(np,NV_REF)) 849 iref++; 850 if(np->nvenv) 851 size += strlen((char*)np->nvenv)+1; 852 if(strcmp(&np->nvname[m],NV_DATA)==0 && !nv_type(np)) 853 continue; 854 if(qp) 855 { /* delete duplicates */ 856 for(j=0; j < qp->numnodes;j++) 857 { 858 nq = nv_namptr(qp->nodes,j); 859 if(strcmp(nq->nvname,&np->nvname[m])==0) 860 break; 861 } 862 if(j < qp->numnodes) 863 continue; 864 } 865 nnodes++; 866 if(name && memcmp(&name[m],&np->nvname[m],n)==0 && np->nvname[m+n]=='.') 867 offset -= sizeof(char*); 868 dsize = datasize(np,&offset); 869 if(!nv_isarray(np) && (dp=(Namtype_t*)nv_hasdisc(np, &type_disc))) 870 { 871 nnodes += dp->numnodes; 872 if((n=dp->strsize)<0) 873 n = -n; 874 iref = nref += dp->nref; 875 if(np->nvname[m]=='_' && np->nvname[m+1]==0 && (bp=nv_type(np))) 876 { 877 qp = dp; 878 nd = dp->ndisc; 879 nnodes = dp->numnodes; 880 offset = 0; 881 dsize = nv_size(np); 882 size += n; 883 } 884 else 885 size += n + dp->numnodes*(strlen(&np->nvname[m])+1); 886 n = strlen(np->nvname); 887 while((i+1) < numnodes && (cp=nodes[i+1]->nvname) && memcmp(cp,np->nvname,n)==0 && cp[n]=='.') 888 i++; 889 } 890 else if(nv_isattr(np,NV_REF)) 891 nref++; 892 offset += (dsize?dsize:4); 893 size += (n=strlen(name=np->nvname)-m+1); 894 } 895 offset = roundof(offset,sizeof(char*)); 896 nv_setsize(mp,offset); 897 if(nd) 898 nd++; 899 k = roundof(sizeof(Namtype_t),sizeof(Sfdouble_t)) - sizeof(Namtype_t); 900 pp = newof(NiL, Namtype_t, 1, nnodes*NV_MINSZ + offset + size + (nnodes+nd)*sizeof(char*) + iref*sizeof(struct Namref)+k); 901 pp->fun.dsize = sizeof(Namtype_t)+nnodes*NV_MINSZ +offset+k; 902 pp->fun.type = mp; 903 pp->parent = nv_lastdict(); 904 pp->np = mp; 905 pp->bp = bp; 906 pp->childfun.fun.disc = &chtype_disc; 907 pp->childfun.fun.nofree = 1; 908 pp->childfun.ttype = pp; 909 pp->childfun.ptype = pp; 910 pp->fun.disc = &type_disc; 911 pp->nodes = (char*)(pp+1); 912 pp->numnodes = nnodes; 913 pp->data = pp->nodes + nnodes*NV_MINSZ +k; 914 pp->dsize = offset; 915 nrp = (struct Namref*)(pp->data+offset); 916 pp->names = (char**)(nrp+iref); 917 help = &pp->names[nd]; 918 pp->strsize = size; 919 cp = (char*)&pp->names[nd+nnodes]; 920 if(qp) 921 mnodes = newof(NiL, Namval_t*, nd+1, 0); 922 nd = 0; 923 nq = nv_namptr(pp->nodes,0); 924 nq->nvname = cp; 925 nv_onattr(nq,NV_MINIMAL); 926 cp = strcopy(cp,NV_DATA); 927 *cp++ = 0; 928 for(name=0, offset=0, k=i=1; i < numnodes; i++) 929 { 930 np=nodes[i]; 931 if(is_afunction(np)) 932 { 933 sp = np->nvname+m; 934 if(memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0) 935 sp += sizeof(NV_CLASS); 936 if(!std_disc(np, pp)) 937 { 938 /* see if discipline already defined */ 939 for(j=0; j< nd; j++) 940 { 941 if(strcmp(sp,pp->names[j])==0) 942 { 943 mnodes[j] = nodes[i]; 944 break; 945 } 946 } 947 if(j>=nd) 948 { 949 pp->names[nd] = cp; 950 mnodes[nd++] = nodes[i]; 951 cp = strcopy(cp,sp); 952 *cp++ = 0; 953 } 954 nv_onattr(mnodes[j],NV_NOFREE); 955 } 956 continue; 957 } 958 if(inherit) 959 { 960 for(j=0; j < k ; j++) 961 { 962 nq = nv_namptr(pp->nodes,j); 963 if(strcmp(nq->nvname,&np->nvname[m])==0) 964 break; 965 } 966 if(j < k) 967 { 968 sp = nv_getval(np); 969 if(nv_isvtree(np)) 970 sfprintf(sfstderr,"initialization not implemented\n"); 971 else if(sp) 972 nv_putval(nq,sp,0); 973 goto skip; 974 } 975 } 976 if(strcmp(&np->nvname[m],NV_DATA)==0 && !nv_type(np)) 977 { 978 char *val=nv_getval(np); 979 nq = nv_namptr(pp->nodes,0); 980 nq->nvfun = 0; 981 nv_putval(nq,(val?val:0),nv_isattr(np,~(NV_IMPORT|NV_EXPORT|NV_ARRAY))); 982 nq->nvflag = np->nvflag|NV_NOFREE|NV_MINIMAL; 983 goto skip; 984 } 985 if(qp) 986 { 987 Nambfun_t *bp; 988 dp = (Namtype_t*)nv_hasdisc(nv_type(np), &type_disc); 989 memcpy(pp->nodes,dp->nodes,dp->numnodes*NV_MINSZ); 990 offset = nv_size(np); 991 memcpy(pp->data,dp->data,offset); 992 for(k=0;k < dp->numnodes; k++) 993 { 994 Namval_t *nr = nv_namptr(qp->nodes,k); 995 nq = nv_namptr(pp->nodes,k); 996 if(fixnode(pp,dp,k,nrp,0)) 997 { 998 nrp++; 999 nq = nq->nvalue.nrp->np; 1000 } 1001 if(!nv_isattr(nr,NV_REF) && !nv_hasdisc(nr,&type_disc)) 1002 { 1003 if(nr->nvsize) 1004 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,size=datasize(nr,(size_t*)0)); 1005 else 1006 { 1007 nq->nvalue.cp = nr->nvalue.cp; 1008 nv_onattr(nq,NV_NOFREE); 1009 } 1010 } 1011 } 1012 if(bp=(Nambfun_t*)nv_hasdisc(np,nv_discfun(NV_DCADD))) 1013 { 1014 for(j=0; j < bp->num; j++) 1015 { 1016 pp->names[nd++] = (char*)bp->bnames[j]; 1017 mnodes[j] = bp->bltins[j]; 1018 } 1019 } 1020 qp = 0; 1021 inherit=1; 1022 goto skip; 1023 } 1024 nq = nv_namptr(pp->nodes,k); 1025 if(np->nvenv) 1026 { 1027 /* need to save the string pointer */ 1028 nv_offattr(np,NV_EXPORT); 1029 help[k] = cp; 1030 cp = strcopy(cp,np->nvenv); 1031 j = *help[k]; 1032 if(islower(j)) 1033 *help[k] = toupper(j); 1034 *cp++ = 0; 1035 np->nvenv = 0; 1036 } 1037 nq->nvname = cp; 1038 if(name && memcmp(name,&np->nvname[m],n)==0 && np->nvname[m+n]=='.') 1039 offset -= sizeof(char*); 1040 dsize = datasize(np,&offset); 1041 cp = strcopy(name=cp, &np->nvname[m]); 1042 n = cp-name; 1043 *cp++ = 0; 1044 nq->nvsize = np->nvsize; 1045 nq->nvflag = (np->nvflag&~(NV_IMPORT|NV_EXPORT))|NV_NOFREE|NV_MINIMAL; 1046 if(dp = (Namtype_t*)nv_hasdisc(np, &type_disc)) 1047 { 1048 int r,kfirst=k; 1049 char *cname = &np->nvname[m]; 1050 /* 1051 * If field is a type, mark the type by setting 1052 * strsize<0. This changes create_type() 1053 */ 1054 clone_all_disc(np,nq,NV_RDONLY); 1055 if(nv_isarray(np)) 1056 { 1057 nv_disc(nq, &pp->childfun.fun, NV_LAST); 1058 k++; 1059 goto skip; 1060 } 1061 if(fp=nv_hasdisc(nq,&chtype_disc)) 1062 nv_disc(nq, &pp->childfun.fun, NV_LAST); 1063 if(tp = (Namtype_t*)nv_hasdisc(nq, &type_disc)) 1064 tp->strsize = -tp->strsize; 1065else sfprintf(sfstderr,"tp==NULL\n"); 1066 for(r=0; r < dp->numnodes; r++) 1067 { 1068 Namval_t *nr = nv_namptr(dp->nodes,r); 1069 nq = nv_namptr(pp->nodes,++k); 1070 nq->nvname = cp; 1071 dsize = datasize(nr,&offset); 1072 nq->nvflag = nr->nvflag; 1073 if(nr->nvalue.cp) 1074 { 1075 Namchld_t *xp = (Namchld_t*)nv_hasdisc(nr,&chtype_disc); 1076 if(xp && nr->nvalue.cp >= xp->ptype->data && nr->nvalue.cp < xp->ptype->data+xp->ptype->fun.dsize) 1077 { 1078 nq->nvalue.cp = pp->data+offset; 1079 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,dsize); 1080 nv_onattr(nq,NV_NOFREE); 1081 } 1082 else 1083 nq->nvalue.cp = strdup(nr->nvalue.cp); 1084 nv_disc(nq, &pp->childfun.fun, NV_LAST); 1085 } 1086 nq->nvsize = nr->nvsize; 1087 offset += dsize; 1088 if(*cname!='_' || cname[1]) 1089 { 1090 cp = strcopy(cp,cname); 1091 *cp++ = '.'; 1092 } 1093 cp = strcopy(cp,nr->nvname); 1094 *cp++ = 0; 1095 } 1096 while((i+1) < numnodes && (cname=&nodes[i+1]->nvname[m]) && memcmp(cname,&np->nvname[m],n)==0 && cname[n]=='.') 1097 { 1098 int j=kfirst; 1099 nv_unset(np); 1100 nv_delete(np,root,0); 1101 np = nodes[++i]; 1102 while(j < k) 1103 { 1104 nq = nv_namptr(pp->nodes,++j); 1105 if(strcmp(nq->nvname,cname)==0) 1106 { 1107 sfprintf(sfstderr,"%s found at k=%d\n",nq->nvname,k); 1108 if(nq->nvalue.cp>=pp->data && nq->nvalue.cp< (char*)pp->names) 1109 memcpy((char*)nq->nvalue.cp,np->nvalue.cp,datasize(np,0)); 1110 break; 1111 } 1112 } 1113 } 1114 } 1115 else 1116 { 1117 j = nv_isattr(np,NV_NOFREE); 1118 nq->nvfun = np->nvfun; 1119 np->nvfun = 0; 1120 if(nv_isarray(nq) && !nq->nvfun) 1121 { 1122 nv_putsub(nq, (char*)0, ARRAY_FILL); 1123 if(nv_isattr(nq,NV_INTEGER)) 1124 nv_putval(nq, "0",0); 1125 else 1126 ((Namarr_t*)nq->nvfun)->nelem--; 1127 } 1128 nv_disc(nq, &pp->childfun.fun, NV_LAST); 1129 if(nq->nvfun) 1130 { 1131 for(fp=nq->nvfun; fp; fp = fp->next) 1132 fp->nofree |= 1; 1133 } 1134 nq->nvalue.cp = np->nvalue.cp; 1135 if(dsize) 1136 { 1137 nq->nvalue.cp = pp->data+offset; 1138 sp = (char*)np->nvalue.cp; 1139 if(nv_isattr(np,NV_INT16P) ==NV_INT16) 1140 { 1141 sp= (char*)&np->nvalue; 1142 nv_onattr(nq,NV_INT16P); 1143 j = 1; 1144 } 1145 if(sp) 1146 memcpy((char*)nq->nvalue.cp,sp,dsize); 1147 else if(nv_isattr(np,NV_LJUST|NV_RJUST)) 1148 memset((char*)nq->nvalue.cp,' ',dsize); 1149 if(!j) 1150 free((void*)np->nvalue.cp); 1151 } 1152 if(!nq->nvalue.cp && nq->nvfun== &pp->childfun.fun) 1153 nq->nvalue.cp = Empty; 1154 np->nvalue.cp = 0; 1155#if 0 1156 offset += dsize; 1157#else 1158 offset += (dsize?dsize:4); 1159#endif 1160 } 1161 k++; 1162 skip: 1163 if(!nv_isnull(np)) 1164 _nv_unset(np,0); 1165 nv_delete(np,root,0); 1166 } 1167 pp->ndisc = nd; 1168 pp->nref = nref; 1169 if(k>1) 1170 { 1171 nv_setsize(mp,offset); 1172 mp->nvalue.cp = pp->data; 1173 nv_onattr(mp,NV_NOFREE|NV_BINARY|NV_RAW); 1174 } 1175 else if(!mp->nvalue.cp) 1176 mp->nvalue.cp = Empty; 1177 nv_disc(mp, &pp->fun, NV_LAST); 1178 if(nd>0) 1179 { 1180 pp->names[nd] = 0; 1181 nv_adddisc(mp, (const char**)pp->names, mnodes); 1182 } 1183 if(mnodes!=nodes) 1184 free((void*)mnodes); 1185 nv_newtype(mp); 1186 return(mp); 1187} 1188 1189Namval_t *nv_mkinttype(char *name, size_t size, int sign, const char *help, Namdisc_t *ep) 1190{ 1191 Namval_t *mp; 1192 Namfun_t *fp; 1193 Namdisc_t *dp; 1194 int offset=staktell(); 1195 stakputs(NV_CLASS); 1196 stakputc('.'); 1197 stakputs(name); 1198 stakputc(0); 1199 mp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME); 1200 stakseek(offset); 1201 offset = size + sizeof(Namdisc_t); 1202 fp = newof(NiL, Namfun_t, 1, offset); 1203 fp->type = mp; 1204 fp->nofree |= 1; 1205 fp->dsize = sizeof(Namfun_t)+size; 1206 dp = (Namdisc_t*)(fp+1); 1207 if(ep) 1208 *dp = *ep; 1209 dp->clonef = clone_inttype; 1210 fp->disc = dp; 1211 mp->nvalue.cp = (char*)(fp+1) + sizeof(Namdisc_t); 1212 nv_setsize(mp,10); 1213 mp->nvenv = (char*)help; 1214 nv_onattr(mp,NV_NOFREE|NV_RDONLY|NV_INTEGER|NV_EXPORT); 1215 if(size==16) 1216 nv_onattr(mp,NV_INT16P); 1217 else if(size==64) 1218 nv_onattr(mp,NV_INT64); 1219 if(!sign) 1220 nv_onattr(mp,NV_UNSIGN); 1221 nv_disc(mp, fp, NV_LAST); 1222 nv_newtype(mp); 1223 return(mp); 1224} 1225 1226void nv_typename(Namval_t *tp, Sfio_t *out) 1227{ 1228 char *v,*cp; 1229 Namtype_t *dp; 1230 cp = nv_name(tp); 1231 if(v=strrchr(cp,'.')) 1232 cp = v+1; 1233 if((dp = (Namtype_t*)nv_hasdisc(tp,&type_disc)) && dp->bp) 1234 { 1235 nv_typename(dp->bp,out); 1236 sfprintf(out,"%s.%s",sfstruse(out),cp); 1237 } 1238 else 1239 sfputr(out,cp,-1); 1240} 1241 1242Namval_t *nv_type(Namval_t *np) 1243{ 1244 Namfun_t *fp; 1245 if(nv_isattr(np,NV_BLTIN|BLT_DCL)==(NV_BLTIN|BLT_DCL)) 1246 { 1247 Namdecl_t *ntp = (Namdecl_t*)nv_context(np); 1248 return(ntp?ntp->tp:0); 1249 } 1250 for(fp=np->nvfun; fp; fp=fp->next) 1251 { 1252 if(fp->type) 1253 return(fp->type); 1254 if(fp->disc && fp->disc->typef && (np= (*fp->disc->typef)(np,fp))) 1255 return(np); 1256 } 1257 return(0); 1258} 1259 1260/* 1261 * call any and all create functions 1262 */ 1263static void type_init(Namval_t *np) 1264{ 1265 int i; 1266 Namtype_t *dp, *pp=(Namtype_t*)nv_hasdisc(np,&type_disc); 1267 Namval_t *nq; 1268 if(!pp) 1269 return; 1270 for(i=0; i < pp->numnodes; i++) 1271 { 1272 nq = nv_namptr(pp->nodes,i); 1273 if((dp=(Namtype_t*)nv_hasdisc(nq,&type_disc)) && dp->cp) 1274 sh_fun(dp->cp,nq, (char**)0); 1275 } 1276 if(pp->cp) 1277 sh_fun(pp->cp, np, (char**)0); 1278} 1279 1280/* 1281 * This function turns variable <np> to the type <tp> 1282 */ 1283int nv_settype(Namval_t* np, Namval_t *tp, int flags) 1284{ 1285 int isnull = nv_isnull(np); 1286 int rdonly = nv_isattr(np,NV_RDONLY); 1287 char *val=0; 1288 Namarr_t *ap=0; 1289 int nelem=0; 1290#if SHOPT_TYPEDEF 1291 Namval_t *tq; 1292 if(nv_type(np)==tp) 1293 return(0); 1294 if(nv_isarray(np) && (tq=nv_type(np))) 1295 { 1296 if(tp==tq) 1297 return(0); 1298 errormsg(SH_DICT,ERROR_exit(1),e_redef,nv_name(np)); 1299 } 1300 if((ap=nv_arrayptr(np)) && ap->nelem>0) 1301 { 1302 nv_putsub(np,NIL(char*),ARRAY_SCAN); 1303 ap->hdr.type = tp; 1304 do 1305 { 1306 nv_arraysettype(np, tp, nv_getsub(np),flags); 1307 } 1308 while(nv_nextsub(np)); 1309 } 1310 else if(ap || nv_isarray(np)) 1311 { 1312 flags &= ~NV_APPEND; 1313 if(!ap) 1314 { 1315 nv_putsub(np,"0",ARRAY_FILL); 1316 ap = nv_arrayptr(np); 1317 nelem = 1; 1318 1319 } 1320 } 1321 else 1322#endif /*SHOPT_TYPEDEF */ 1323 { 1324 if(isnull) 1325 flags &= ~NV_APPEND; 1326 else if(!nv_isvtree(np)) 1327 { 1328 val = strdup(nv_getval(np)); 1329 if(!(flags&NV_APPEND)) 1330 _nv_unset(np, NV_RDONLY); 1331 } 1332 if(!nv_clone(tp,np,flags|NV_NOFREE)) 1333 return(0); 1334 } 1335 if(ap) 1336 { 1337 int nofree; 1338 nv_disc(np,&ap->hdr,NV_POP); 1339 np->nvalue.up = 0; 1340 nv_clone(tp,np,flags|NV_NOFREE); 1341 if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE)) 1342 free((void*)np->nvalue.cp); 1343 np->nvalue.up = 0; 1344 nofree = ap->hdr.nofree; 1345 ap->hdr.nofree = 0; 1346 ap->hdr.type = tp; 1347 nv_disc(np, &ap->hdr, NV_FIRST); 1348 ap->hdr.nofree = nofree; 1349 nv_onattr(np,NV_ARRAY); 1350 if(nelem) 1351 { 1352 ap->nelem++; 1353 nv_putsub(np,"0",0); 1354 _nv_unset(np,NV_RDONLY); 1355 ap->nelem--; 1356 } 1357 } 1358 type_init(np); 1359 if(!rdonly) 1360 nv_offattr(np,NV_RDONLY); 1361 if(val) 1362 { 1363 nv_putval(np,val,NV_RDONLY); 1364 free((void*)val); 1365 } 1366 return(0); 1367} 1368 1369#define S(x) #x 1370#define FIELD(x,y) { S(y##x), S(x##_t), offsetof(struct stat,st_##y##x) } 1371typedef struct _field_ 1372{ 1373 char *name; 1374 char *type; 1375 int offset; 1376} Fields_t; 1377 1378Fields_t foo[]= 1379{ 1380 FIELD(dev,), 1381 FIELD(ino,), 1382 FIELD(nlink,), 1383 FIELD(mode,), 1384 FIELD(uid,), 1385 FIELD(gid,), 1386 FIELD(size,), 1387 FIELD(time,a), 1388 FIELD(time,m), 1389 FIELD(time,c), 1390#if 0 1391 FIELD(blksize,), 1392 FIELD(blocks,), 1393#endif 1394 0 1395}; 1396 1397 1398Namval_t *nv_mkstruct(const char *name, int rsize, Fields_t *fields) 1399{ 1400 Namval_t *mp, *nq, *nr, *tp; 1401 Fields_t *fp; 1402 Namtype_t *dp, *pp; 1403 char *cp, *sp; 1404 int nnodes=0, offset=staktell(), n, r, i, j; 1405 size_t m, size=0; 1406 stakputs(NV_CLASS); 1407 stakputc('.'); 1408 r = staktell(); 1409 stakputs(name); 1410 stakputc(0); 1411 mp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME); 1412 stakseek(r); 1413 1414 for(fp=fields; fp->name; fp++) 1415 { 1416 m = strlen(fp->name)+1; 1417 size += m; 1418 nnodes++; 1419 if(memcmp(fp->type,"typeset",7)) 1420 { 1421 stakputs(fp->type); 1422 stakputc(0); 1423 tp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME|NV_NOADD|NV_NOFAIL); 1424 stakseek(r); 1425 if(!tp) 1426 errormsg(SH_DICT,ERROR_exit(1),e_unknowntype,strlen(fp->type),fp->type); 1427 if(dp = (Namtype_t*)nv_hasdisc(tp,&type_disc)) 1428 { 1429 nnodes += dp->numnodes; 1430 if((i=dp->strsize) < 0) 1431 i = -i; 1432 size += i + dp->numnodes*m; 1433 } 1434 } 1435 } 1436 pp = newof(NiL,Namtype_t, 1, nnodes*NV_MINSZ + rsize + size); 1437 pp->fun.dsize = sizeof(Namtype_t)+nnodes*NV_MINSZ +rsize; 1438 pp->fun.type = mp; 1439 pp->np = mp; 1440 pp->childfun.fun.disc = &chtype_disc; 1441 pp->childfun.fun.nofree = 1; 1442 pp->childfun.ttype = pp; 1443 pp->childfun.ptype = pp; 1444 pp->fun.disc = &type_disc; 1445 pp->nodes = (char*)(pp+1); 1446 pp->numnodes = nnodes; 1447 pp->strsize = size; 1448 pp->data = pp->nodes + nnodes*NV_MINSZ; 1449 cp = pp->data + rsize; 1450 for(i=0,fp=fields; fp->name; fp++) 1451 { 1452 nq = nv_namptr(pp->nodes,i++); 1453 nq->nvname = cp; 1454 nq->nvalue.cp = pp->data + fp->offset; 1455 nv_onattr(nq,NV_MINIMAL|NV_NOFREE); 1456 m = strlen(fp->name)+1; 1457 memcpy(cp, fp->name, m); 1458 cp += m; 1459 if(memcmp(fp->type,"typeset",7)) 1460 { 1461 stakputs(fp->type); 1462 stakputc(0); 1463 tp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME); 1464 stakseek(r); 1465 clone_all_disc(tp,nq,NV_RDONLY); 1466 nq->nvflag = tp->nvflag|NV_MINIMAL|NV_NOFREE; 1467 nq->nvsize = tp->nvsize; 1468 if(dp = (Namtype_t*)nv_hasdisc(nq,&type_disc)) 1469 dp->strsize = -dp->strsize; 1470 if(dp = (Namtype_t*)nv_hasdisc(tp,&type_disc)) 1471 { 1472 if(nv_hasdisc(nq,&chtype_disc)) 1473 nv_disc(nq, &pp->childfun.fun, NV_LAST); 1474 sp = (char*)nq->nvalue.cp; 1475 memcpy(sp, dp->data, nv_size(tp)); 1476 for(j=0; j < dp->numnodes; j++) 1477 { 1478 nr = nv_namptr(dp->nodes,j); 1479 nq = nv_namptr(pp->nodes,i++); 1480 nq->nvname = cp; 1481 memcpy(cp,fp->name,m); 1482 cp[m-1] = '.'; 1483 cp += m; 1484 n = strlen(nr->nvname)+1; 1485 memcpy(cp,nr->nvname,n); 1486 cp += n; 1487 if(nr->nvalue.cp>=dp->data && nr->nvalue.cp < (char*)pp + pp->fun.dsize) 1488 { 1489 nq->nvalue.cp = sp + (nr->nvalue.cp-dp->data); 1490 } 1491 nq->nvflag = nr->nvflag; 1492 nq->nvsize = nr->nvsize; 1493 } 1494 } 1495 } 1496 else if(strmatch(fp->type+7,"*-*i*")==0) 1497 { 1498 nv_onattr(nq,NV_NOFREE|NV_RDONLY|NV_INTEGER); 1499 if(strmatch(fp->type+7,"*-*s*")==0) 1500 nv_onattr(nq,NV_INT16P); 1501 else if(strmatch(fp->type+7,"*-*l*")==0) 1502 nv_onattr(nq,NV_INT64); 1503 if(strmatch(fp->type+7,"*-*u*")==0) 1504 nv_onattr(nq,NV_UNSIGN); 1505 } 1506 1507 } 1508 stakseek(offset); 1509 nv_onattr(mp,NV_RDONLY|NV_NOFREE|NV_BINARY); 1510 nv_setsize(mp,rsize); 1511 nv_disc(mp, &pp->fun, NV_LAST); 1512 mp->nvalue.cp = pp->data; 1513 nv_newtype(mp); 1514 return(mp); 1515} 1516 1517static void put_stat(Namval_t* np, const char* val, int flag, Namfun_t* nfp) 1518{ 1519 if(val) 1520 { 1521 if(stat(val,(struct stat*)np->nvalue.cp)<0) 1522 sfprintf(sfstderr,"stat of %s failed\n",val); 1523 return; 1524 } 1525 nv_putv(np,val,flag,nfp); 1526 nv_disc(np,nfp,NV_POP); 1527 if(!(nfp->nofree&1)) 1528 free((void*)nfp); 1529} 1530 1531static const Namdisc_t stat_disc = 1532{ 1533 0, 1534 put_stat 1535}; 1536 1537 1538void nv_mkstat(void) 1539{ 1540 Namval_t *tp; 1541 Namfun_t *fp; 1542 tp = nv_mkstruct("stat_t", sizeof(struct stat), foo); 1543 nv_offattr(tp,NV_RDONLY); 1544 nv_setvtree(tp); 1545 fp = newof(NiL,Namfun_t,1,0); 1546 fp->type = tp; 1547 fp->disc = &stat_disc; 1548 nv_disc(tp,fp,NV_FIRST); 1549 nv_putval(tp,"/dev/null",0); 1550 nv_onattr(tp,NV_RDONLY); 1551} 1552