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