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 * export [-p] [arg...] 23 * readonly [-p] [arg...] 24 * typeset [options] [arg...] 25 * alias [-ptx] [arg...] 26 * unalias [arg...] 27 * builtin [-sd] [-f file] [name...] 28 * set [options] [name...] 29 * unset [-fnv] [name...] 30 * 31 * David Korn 32 * AT&T Labs 33 * 34 */ 35 36 #include "defs.h" 37 #include <error.h> 38 #include "path.h" 39 #include "name.h" 40 #include "history.h" 41 #include "builtins.h" 42 #include "variables.h" 43 #include "FEATURE/dynamic" 44 45 struct tdata 46 { 47 Shell_t *sh; 48 Namval_t *tp; 49 const char *wctname; 50 Sfio_t *outfile; 51 char *prefix; 52 char *tname; 53 char *help; 54 short aflag; 55 short pflag; 56 int argnum; 57 int scanmask; 58 Dt_t *scanroot; 59 char **argnam; 60 int indent; 61 int noref; 62 }; 63 64 65 static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); 66 static void print_attribute(Namval_t*,void*); 67 static void print_all(Sfio_t*, Dt_t*, struct tdata*); 68 static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*); 69 static int unall(int, char**, Dt_t*, Shell_t*); 70 static int setall(char**, int, Dt_t*, struct tdata*); 71 static void pushname(Namval_t*,void*); 72 static void(*nullscan)(Namval_t*,void*); 73 74 static Namval_t *load_class(const char *name) 75 { 76 errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name); 77 return(0); 78 } 79 80 /* 81 * Note export and readonly are the same 82 */ 83 #if 0 84 /* for the dictionary generator */ 85 int b_export(int argc,char *argv[],Shbltin_t *context){} 86 #endif 87 int b_readonly(int argc,char *argv[],Shbltin_t *context) 88 { 89 register int flag; 90 char *command = argv[0]; 91 struct tdata tdata; 92 NOT_USED(argc); 93 memset((void*)&tdata,0,sizeof(tdata)); 94 tdata.sh = context->shp; 95 tdata.aflag = '-'; 96 while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag) 97 { 98 case 'p': 99 tdata.prefix = command; 100 break; 101 case ':': 102 errormsg(SH_DICT,2, "%s", opt_info.arg); 103 break; 104 case '?': 105 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 106 return(2); 107 } 108 if(error_info.errors) 109 errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); 110 argv += (opt_info.index-1); 111 if(*command=='r') 112 flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME); 113 #ifdef _ENV_H 114 else if(!argv[1]) 115 { 116 char *cp,**env=env_get(tdata.sh->env); 117 while(cp = *env++) 118 { 119 if(tdata.prefix) 120 sfputr(sfstdout,tdata.prefix,' '); 121 sfprintf(sfstdout,"%s\n",sh_fmtq(cp)); 122 } 123 return(0); 124 } 125 #endif 126 else 127 { 128 flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT); 129 if(!tdata.sh->prefix) 130 tdata.sh->prefix = ""; 131 } 132 return(setall(argv,flag,tdata.sh->var_tree, &tdata)); 133 } 134 135 136 int b_alias(int argc,register char *argv[],Shbltin_t *context) 137 { 138 register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN; 139 register Dt_t *troot; 140 register int n; 141 struct tdata tdata; 142 NOT_USED(argc); 143 memset((void*)&tdata,0,sizeof(tdata)); 144 tdata.sh = context->shp; 145 troot = tdata.sh->alias_tree; 146 if(*argv[0]=='h') 147 flag = NV_TAGGED; 148 if(argv[1]) 149 { 150 opt_info.offset = 0; 151 opt_info.index = 1; 152 *opt_info.option = 0; 153 tdata.argnum = 0; 154 tdata.aflag = *argv[1]; 155 while((n = optget(argv,sh_optalias))) switch(n) 156 { 157 case 'p': 158 tdata.prefix = argv[0]; 159 break; 160 case 't': 161 flag |= NV_TAGGED; 162 break; 163 case 'x': 164 flag |= NV_EXPORT; 165 break; 166 case ':': 167 errormsg(SH_DICT,2, "%s", opt_info.arg); 168 break; 169 case '?': 170 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 171 return(2); 172 } 173 if(error_info.errors) 174 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 175 argv += (opt_info.index-1); 176 if(flag&NV_TAGGED) 177 { 178 /* hacks to handle hash -r | -- */ 179 if(argv[1] && argv[1][0]=='-') 180 { 181 if(argv[1][1]=='r' && argv[1][2]==0) 182 { 183 Namval_t *np = nv_search((char*)PATHNOD,tdata.sh->var_tree,HASH_BUCKET); 184 nv_putval(np,nv_getval(np),NV_RDONLY); 185 argv++; 186 if(!argv[1]) 187 return(0); 188 } 189 if(argv[1][0]=='-') 190 { 191 if(argv[1][1]=='-' && argv[1][2]==0) 192 argv++; 193 else 194 errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]); 195 } 196 } 197 troot = tdata.sh->track_tree; 198 } 199 } 200 return(setall(argv,flag,troot,&tdata)); 201 } 202 203 204 #if 0 205 /* for the dictionary generator */ 206 int b_local(int argc,char *argv[],Shbltin_t *context){} 207 #endif 208 int b_typeset(int argc,register char *argv[],Shbltin_t *context) 209 { 210 register int n, flag = NV_VARNAME|NV_ASSIGN; 211 struct tdata tdata; 212 const char *optstring = sh_opttypeset; 213 Namdecl_t *ntp = (Namdecl_t*)context->ptr; 214 Dt_t *troot; 215 int isfloat=0, shortint=0, sflag=0; 216 NOT_USED(argc); 217 memset((void*)&tdata,0,sizeof(tdata)); 218 tdata.sh = context->shp; 219 if(ntp) 220 { 221 tdata.tp = ntp->tp; 222 opt_info.disc = (Optdisc_t*)ntp->optinfof; 223 optstring = ntp->optstring; 224 } 225 troot = tdata.sh->var_tree; 226 while((n = optget(argv,optstring))) 227 { 228 if(tdata.aflag==0) 229 tdata.aflag = *opt_info.option; 230 switch(n) 231 { 232 case 'a': 233 flag |= NV_IARRAY; 234 if(opt_info.arg && *opt_info.arg!='[') 235 { 236 opt_info.index--; 237 goto endargs; 238 } 239 tdata.tname = opt_info.arg; 240 break; 241 case 'A': 242 flag |= NV_ARRAY; 243 break; 244 case 'C': 245 flag |= NV_COMVAR; 246 break; 247 case 'E': 248 /* The following is for ksh88 compatibility */ 249 if(opt_info.offset && !strchr(argv[opt_info.index],'E')) 250 { 251 tdata.argnum = (int)opt_info.num; 252 break; 253 } 254 /* FALLTHROUGH */ 255 case 'F': 256 case 'X': 257 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 258 tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10); 259 isfloat = 1; 260 if(n=='E') 261 { 262 flag &= ~NV_HEXFLOAT; 263 flag |= NV_EXPNOTE; 264 } 265 else if(n=='X') 266 { 267 flag &= ~NV_EXPNOTE; 268 flag |= NV_HEXFLOAT; 269 } 270 break; 271 case 'b': 272 flag |= NV_BINARY; 273 break; 274 case 'm': 275 flag |= NV_MOVE; 276 break; 277 case 'n': 278 flag &= ~NV_VARNAME; 279 flag |= (NV_REF|NV_IDENT); 280 break; 281 case 'H': 282 flag |= NV_HOST; 283 break; 284 case 'T': 285 flag |= NV_TYPE; 286 tdata.prefix = opt_info.arg; 287 break; 288 case 'L': case 'Z': case 'R': 289 if(tdata.argnum==0) 290 tdata.argnum = (int)opt_info.num; 291 if(tdata.argnum < 0) 292 errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); 293 if(n=='Z') 294 flag |= NV_ZFILL; 295 else 296 { 297 flag &= ~(NV_LJUST|NV_RJUST); 298 flag |= (n=='L'?NV_LJUST:NV_RJUST); 299 } 300 break; 301 case 'M': 302 if((tdata.wctname = opt_info.arg) && !nv_mapchar((Namval_t*)0,tdata.wctname)) 303 errormsg(SH_DICT, ERROR_exit(1),e_unknownmap, tdata.wctname); 304 if(tdata.wctname && strcmp(tdata.wctname,e_tolower)==0) 305 flag |= NV_UTOL; 306 else 307 flag |= NV_LTOU; 308 if(!tdata.wctname) 309 flag |= NV_UTOL; 310 break; 311 case 'f': 312 flag &= ~(NV_VARNAME|NV_ASSIGN); 313 troot = tdata.sh->fun_tree; 314 break; 315 case 'i': 316 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 317 tdata.argnum = 10; 318 flag |= NV_INTEGER; 319 break; 320 case 'l': 321 tdata.wctname = e_tolower; 322 flag |= NV_UTOL; 323 break; 324 case 'p': 325 tdata.prefix = argv[0]; 326 tdata.pflag = 1; 327 flag &= ~NV_ASSIGN; 328 break; 329 case 'r': 330 flag |= NV_RDONLY; 331 break; 332 #ifdef SHOPT_TYPEDEF 333 case 'S': 334 sflag=1; 335 break; 336 case 'h': 337 tdata.help = opt_info.arg; 338 break; 339 #endif /*SHOPT_TYPEDEF*/ 340 case 's': 341 shortint=1; 342 break; 343 case 't': 344 flag |= NV_TAGGED; 345 break; 346 case 'u': 347 tdata.wctname = e_toupper; 348 flag |= NV_LTOU; 349 break; 350 case 'x': 351 flag &= ~NV_VARNAME; 352 flag |= (NV_EXPORT|NV_IDENT); 353 break; 354 case ':': 355 errormsg(SH_DICT,2, "%s", opt_info.arg); 356 break; 357 case '?': 358 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 359 opt_info.disc = 0; 360 return(2); 361 } 362 } 363 endargs: 364 argv += opt_info.index; 365 opt_info.disc = 0; 366 /* handle argument of + and - specially */ 367 if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-')) 368 tdata.aflag = *argv[0]; 369 else 370 argv--; 371 if((flag&NV_ZFILL) && !(flag&NV_LJUST)) 372 flag |= NV_RJUST; 373 if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) 374 error_info.errors++; 375 if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) 376 error_info.errors++; 377 if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN))) 378 error_info.errors++; 379 if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN))) 380 error_info.errors++; 381 if((flag&NV_TYPE) && (flag&~(NV_TYPE|NV_VARNAME|NV_ASSIGN))) 382 error_info.errors++; 383 if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU)))) 384 error_info.errors++; 385 if(sflag && troot==tdata.sh->fun_tree) 386 { 387 /* static function */ 388 sflag = 0; 389 flag |= NV_STATICF; 390 } 391 if(error_info.errors) 392 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 393 if(sizeof(char*)<8 && tdata.argnum > SHRT_MAX) 394 errormsg(SH_DICT,ERROR_exit(2),"option argument cannot be greater than %d",SHRT_MAX); 395 if(isfloat) 396 flag |= NV_DOUBLE; 397 if(shortint) 398 { 399 flag &= ~NV_LONG; 400 flag |= NV_SHORT|NV_INTEGER; 401 } 402 if(sflag) 403 { 404 if(tdata.sh->mktype) 405 flag |= NV_REF|NV_TAGGED; 406 else if(!tdata.sh->typeinit) 407 flag |= NV_STATIC|NV_IDENT; 408 } 409 if(tdata.sh->fn_depth && !tdata.pflag) 410 flag |= NV_NOSCOPE; 411 if(tdata.help) 412 tdata.help = strdup(tdata.help); 413 if(flag&NV_TYPE) 414 { 415 Stk_t *stkp = tdata.sh->stk; 416 int off=0,offset = stktell(stkp); 417 if(!tdata.prefix) 418 return(sh_outtype(tdata.sh,sfstdout)); 419 sfputr(stkp,NV_CLASS,-1); 420 #if SHOPT_NAMESPACE 421 if(tdata.sh->namespace) 422 { 423 off = stktell(stkp)+1; 424 sfputr(stkp,nv_name(tdata.sh->namespace),'.'); 425 } 426 else 427 #endif /* SHOPT_NAMESPACE */ 428 if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') 429 sfputc(stkp,'.'); 430 sfputr(stkp,tdata.prefix,0); 431 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); 432 #if SHOPT_NAMESPACE 433 if(!tdata.tp && off) 434 { 435 *stkptr(stkp,off)=0; 436 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); 437 } 438 #endif /* SHOPT_NAMESPACE */ 439 stkseek(stkp,offset); 440 if(!tdata.tp) 441 errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); 442 else if(nv_isnull(tdata.tp)) 443 nv_newtype(tdata.tp); 444 tdata.tp->nvenv = tdata.help; 445 flag &= ~NV_TYPE; 446 if(nv_isattr(tdata.tp,NV_TAGGED)) 447 { 448 nv_offattr(tdata.tp,NV_TAGGED); 449 return(0); 450 } 451 } 452 else if(tdata.aflag==0 && ntp && ntp->tp) 453 tdata.aflag = '-'; 454 if(!tdata.sh->mktype) 455 tdata.help = 0; 456 if(tdata.aflag=='+' && (flag&(NV_ARRAY|NV_IARRAY|NV_COMVAR)) && argv[1]) 457 errormsg(SH_DICT,ERROR_exit(1),e_nounattr); 458 return(setall(argv,flag,troot,&tdata)); 459 } 460 461 static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) 462 { 463 char *name; 464 int aflag=tp->aflag; 465 if(nv_isnull(np)) 466 { 467 if(!np->nvflag) 468 return; 469 aflag = '+'; 470 } 471 else if(nv_istable(np)) 472 { 473 Dt_t *root = tp->sh->last_root; 474 Namval_t *nsp = tp->sh->namespace; 475 char *cp; 476 if(!tp->pflag) 477 return; 478 cp = name = nv_name(np); 479 if(*name=='.') 480 name++; 481 if(tp->indent) 482 sfnputc(iop,'\t',tp->indent); 483 sfprintf(iop,"namespace %s\n", name); 484 if(tp->indent) 485 sfnputc(iop,'\t',tp->indent); 486 sfprintf(iop,"{\n", name); 487 tp->indent++; 488 /* output types from namespace */ 489 tp->sh->namespace = 0; 490 tp->sh->prefix = nv_name(np)+1; 491 sh_outtype(tp->sh,iop); 492 tp->sh->prefix = 0; 493 tp->sh->namespace = np; 494 tp->sh->last_root = root; 495 /* output variables from namespace */ 496 print_scan(iop,NV_NOSCOPE,nv_dict(np),aflag=='+',tp); 497 tp->wctname = cp; 498 tp->sh->namespace = 0; 499 /* output functions from namespace */ 500 print_scan(iop,NV_FUNCTION|NV_NOSCOPE,tp->sh->fun_tree,aflag=='+',tp); 501 tp->wctname = 0; 502 tp->sh->namespace = nsp; 503 if(--tp->indent) 504 sfnputc(iop,'\t',tp->indent); 505 sfwrite(iop,"}\n",2); 506 return; 507 } 508 sfputr(iop,nv_name(np),aflag=='+'?'\n':'='); 509 if(aflag=='+') 510 return; 511 if(nv_isarray(np) && nv_arrayptr(np)) 512 { 513 nv_outnode(np,iop,-1,0); 514 sfwrite(iop,")\n",2); 515 } 516 else 517 { 518 if(nv_isvtree(np)) 519 nv_onattr(np,NV_EXPORT); 520 if(!(name = nv_getval(np))) 521 name = Empty; 522 if(!nv_isvtree(np)) 523 name = sh_fmtq(name); 524 sfputr(iop,name,'\n'); 525 } 526 } 527 528 static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp) 529 { 530 register char *name; 531 char *last = 0; 532 int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); 533 int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); 534 Shell_t *shp =tp->sh; 535 if(!shp->prefix) 536 { 537 if(!tp->pflag) 538 nvflags |= NV_NOSCOPE; 539 } 540 else if(*shp->prefix==0) 541 shp->prefix = 0; 542 if(*argv[0]=='+') 543 nvflags |= NV_NOADD; 544 flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); 545 if(argv[1]) 546 { 547 if(flag&NV_REF) 548 { 549 flag &= ~NV_REF; 550 ref=1; 551 if(tp->aflag!='-') 552 nvflags |= NV_NOREF; 553 } 554 if(tp->pflag) 555 nvflags |= (NV_NOREF|NV_NOADD|NV_NOFAIL); 556 while(name = *++argv) 557 { 558 register unsigned newflag; 559 register Namval_t *np; 560 Namarr_t *ap; 561 Namval_t *mp; 562 unsigned curflag; 563 if(troot == shp->fun_tree) 564 { 565 /* 566 *functions can be exported or 567 * traced but not set 568 */ 569 flag &= ~NV_ASSIGN; 570 if(flag&NV_LTOU) 571 { 572 /* Function names cannot be special builtin */ 573 if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) 574 errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); 575 #if SHOPT_NAMESPACE 576 if(shp->namespace) 577 np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE); 578 else 579 #endif /* SHOPT_NAMESPACE */ 580 np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); 581 } 582 else 583 { 584 if(shp->prefix) 585 { 586 sfprintf(shp->strbuf,"%s.%s%c",shp->prefix,name,0); 587 name = sfstruse(shp->strbuf); 588 } 589 #if SHOPT_NAMESPACE 590 np = 0; 591 if(shp->namespace) 592 np = sh_fsearch(shp,name,HASH_NOSCOPE); 593 if(!np) 594 #endif /* SHOPT_NAMESPACE */ 595 if(np=nv_search(name,troot,0)) 596 { 597 if(!is_afunction(np)) 598 np = 0; 599 } 600 else if(memcmp(name,".sh.math.",9)==0 && sh_mathstd(name+9)) 601 continue; 602 } 603 if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) 604 { 605 if(flag==0 && !tp->help) 606 { 607 print_namval(sfstdout,np,tp->aflag=='+',tp); 608 continue; 609 } 610 if(shp->subshell && !shp->subshare) 611 sh_subfork(); 612 if(tp->aflag=='-') 613 nv_onattr(np,flag|NV_FUNCTION); 614 else if(tp->aflag=='+') 615 nv_offattr(np,flag); 616 } 617 else 618 r++; 619 if(tp->help) 620 { 621 int offset = stktell(shp->stk); 622 if(!np) 623 { 624 sfputr(shp->stk,shp->prefix,'.'); 625 sfputr(shp->stk,name,0); 626 np = nv_search(stkptr(shp->stk,offset),troot,0); 627 stkseek(shp->stk,offset); 628 } 629 if(np && np->nvalue.cp) 630 np->nvalue.rp->help = tp->help; 631 } 632 continue; 633 } 634 /* tracked alias */ 635 if(troot==shp->track_tree && tp->aflag=='-') 636 { 637 np = nv_search(name,troot,NV_ADD); 638 path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*))); 639 continue; 640 } 641 np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0)); 642 if(!np) 643 continue; 644 if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE)) 645 nv_offattr(np,NV_NOFREE); 646 else if(tp->tp && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp)) && (ap->nelem&ARRAY_TREE)) 647 errormsg(SH_DICT,ERROR_exit(1),e_typecompat,nv_name(np)); 648 else if((ap=nv_arrayptr(np)) && nv_aindex(np)>0 && ap->nelem==1 && nv_getval(np)==Empty) 649 { 650 ap->nelem++; 651 _nv_unset(np,0); 652 ap->nelem--; 653 } 654 else if(iarray && ap && ap->fun) 655 errormsg(SH_DICT,ERROR_exit(1),"cannot change associative array %s to index array",nv_name(np)); 656 else if( (iarray||(flag&NV_ARRAY)) && nv_isvtree(np) && !nv_type(np)) 657 _nv_unset(np,NV_EXPORT); 658 if(tp->pflag) 659 { 660 if(!nv_istable(np)) 661 nv_attribute(np,sfstdout,tp->prefix,1); 662 print_value(sfstdout,np,tp); 663 continue; 664 } 665 if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) 666 { 667 if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) 668 { 669 sfprintf(sfstderr,sh_translate(e_noalias),name); 670 r++; 671 } 672 if(!comvar && !iarray) 673 continue; 674 } 675 if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name))) 676 { 677 if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT))))) 678 { 679 _nv_unset(np,0); 680 } 681 } 682 if(troot==shp->var_tree) 683 { 684 if(iarray) 685 { 686 if(tp->tname) 687 nv_atypeindex(np,tp->tname+1); 688 else if(nv_isnull(np)) 689 nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0)); 690 else 691 { 692 if(ap && comvar) 693 ap->nelem |= ARRAY_TREE; 694 nv_putsub(np, (char*)0, 0); 695 } 696 } 697 else if(nvflags&NV_ARRAY) 698 { 699 if(comvar) 700 { 701 Namarr_t *ap=nv_arrayptr(np); 702 if(ap) 703 ap->nelem |= ARRAY_TREE; 704 else 705 { 706 _nv_unset(np,NV_RDONLY); 707 nv_onattr(np,NV_NOFREE); 708 } 709 } 710 nv_setarray(np,nv_associative); 711 } 712 else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR)) 713 nv_setvtree(np); 714 } 715 if(flag&NV_MOVE) 716 { 717 nv_rename(np, flag); 718 nv_close(np); 719 continue; 720 } 721 if(tp->tp && nv_type(np)!=tp->tp) 722 { 723 nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); 724 flag = (np->nvflag&NV_NOCHANGE); 725 } 726 flag &= ~NV_ASSIGN; 727 if(last=strchr(name,'=')) 728 *last = 0; 729 if (shp->typeinit) 730 continue; 731 curflag = np->nvflag; 732 if(!(flag&NV_INTEGER) && (flag&(NV_LTOU|NV_UTOL))) 733 { 734 Namfun_t *fp; 735 char *cp; 736 if(!tp->wctname) 737 errormsg(SH_DICT,ERROR_exit(1),e_mapchararg,nv_name(np)); 738 cp = (char*)nv_mapchar(np,0); 739 if(fp=nv_mapchar(np,tp->wctname)) 740 { 741 if(tp->aflag=='+') 742 { 743 if(cp && strcmp(cp,tp->wctname)==0) 744 { 745 nv_disc(np,fp,NV_POP); 746 if(!(fp->nofree&1)) 747 free((void*)fp); 748 nv_offattr(np,flag&(NV_LTOU|NV_UTOL)); 749 } 750 } 751 else if(!cp || strcmp(cp,tp->wctname)) 752 { 753 nv_disc(np,fp,NV_LAST); 754 nv_onattr(np,flag&(NV_LTOU|NV_UTOL)); 755 } 756 } 757 } 758 if (tp->aflag == '-') 759 { 760 if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np))) 761 errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); 762 #if SHOPT_BSH 763 if(flag&NV_EXPORT) 764 nv_offattr(np,NV_IMPORT); 765 #endif /* SHOPT_BSH */ 766 newflag = curflag; 767 if(flag&~NV_NOCHANGE) 768 newflag &= NV_NOCHANGE; 769 newflag |= flag; 770 if (flag & (NV_LJUST|NV_RJUST)) 771 { 772 if(!(flag&NV_RJUST)) 773 newflag &= ~NV_RJUST; 774 775 else if(!(flag&NV_LJUST)) 776 newflag &= ~NV_LJUST; 777 } 778 } 779 else 780 { 781 if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) 782 errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); 783 newflag = curflag & ~flag; 784 } 785 if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) 786 { 787 if(shp->subshell) 788 sh_assignok(np,1); 789 if(troot!=shp->var_tree) 790 nv_setattr(np,newflag&~NV_ASSIGN); 791 else 792 { 793 char *oldname=0; 794 int len=strlen(name); 795 if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 796 tp->argnum = 10; 797 if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') 798 newflag |= NV_NODISC; 799 nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); 800 if(oldname) 801 np->nvname = oldname; 802 } 803 } 804 if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) 805 { 806 np->nvenv = tp->help; 807 nv_onattr(np,NV_EXPORT); 808 } 809 if(last) 810 *last = '='; 811 /* set or unset references */ 812 if(ref) 813 { 814 if(tp->aflag=='-') 815 { 816 Dt_t *hp=0; 817 if(nv_isattr(np,NV_PARAM) && shp->st.prevst) 818 { 819 if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) 820 hp = dtvnext(shp->var_tree); 821 } 822 if(tp->sh->mktype) 823 nv_onattr(np,NV_REF|NV_FUNCT); 824 else 825 nv_setref(np,hp,NV_VARNAME); 826 } 827 else 828 nv_unref(np); 829 } 830 nv_close(np); 831 } 832 } 833 else 834 { 835 if(shp->prefix) 836 errormsg(SH_DICT,2, e_subcomvar,shp->prefix); 837 if(tp->aflag) 838 { 839 if(troot==shp->fun_tree) 840 { 841 flag |= NV_FUNCTION; 842 tp->prefix = 0; 843 } 844 else if(troot==shp->var_tree) 845 { 846 flag |= (nvflags&NV_ARRAY); 847 if(iarray) 848 flag |= NV_ARRAY|NV_IARRAY; 849 if(comvar) 850 flag |= NV_TABLE; 851 if(!(flag&~NV_ASSIGN)) 852 tp->noref = 1; 853 } 854 if((flag&(NV_UTOL|NV_LTOU)) ==(NV_UTOL|NV_LTOU)) 855 { 856 print_scan(sfstdout,flag&~NV_UTOL,troot,tp->aflag=='+',tp); 857 flag &= ~NV_LTOU; 858 } 859 print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); 860 if(tp->noref) 861 { 862 tp->noref = 0; 863 print_scan(sfstdout,flag|NV_REF,troot,tp->aflag=='+',tp); 864 } 865 } 866 else if(troot==shp->alias_tree) 867 print_scan(sfstdout,0,troot,0,tp); 868 else 869 print_all(sfstdout,troot,tp); 870 sfsync(sfstdout); 871 } 872 return(r); 873 } 874 875 #if SHOPT_DYNAMIC 876 877 typedef void (*Libinit_f)(int,void*); 878 879 typedef struct Libcomp_s 880 { 881 void* dll; 882 char* lib; 883 dev_t dev; 884 ino_t ino; 885 unsigned int attr; 886 } Libcomp_t; 887 888 #define GROWLIB 4 889 890 static Libcomp_t *liblist; 891 static int nlib; 892 static int maxlib; 893 894 /* 895 * add library to loaded list 896 * call (*lib_init)() on first load if defined 897 * always move to head of search list 898 * return: 0: already loaded 1: first load 899 */ 900 901 int sh_addlib(Shell_t* shp, void* dll, char* name, Pathcomp_t* pp) 902 { 903 register int n; 904 register int r; 905 Libinit_f initfn; 906 Shbltin_t *sp = &shp->bltindata; 907 908 sp->nosfio = 0; 909 for (n = r = 0; n < nlib; n++) 910 { 911 if (r) 912 liblist[n-1] = liblist[n]; 913 else if (liblist[n].dll == dll) 914 r++; 915 } 916 if (r) 917 nlib--; 918 else if ((initfn = (Libinit_f)dlllook(dll, "lib_init"))) 919 (*initfn)(0,sp); 920 if (nlib >= maxlib) 921 { 922 maxlib += GROWLIB; 923 liblist = newof(liblist, Libcomp_t, maxlib+1, 0); 924 } 925 liblist[nlib].dll = dll; 926 liblist[nlib].attr = (sp->nosfio?BLT_NOSFIO:0); 927 if (name) 928 liblist[nlib].lib = strdup(name); 929 if (pp) 930 { 931 liblist[nlib].dev = pp->dev; 932 liblist[nlib].ino = pp->ino; 933 } 934 nlib++; 935 return !r; 936 } 937 938 Shbltin_f sh_getlib(Shell_t* shp, char* sym, Pathcomp_t* pp) 939 { 940 register int n; 941 942 for (n = 0; n < nlib; n++) 943 if (liblist[n].ino == pp->ino && liblist[n].dev == pp->dev) 944 return (Shbltin_f)dlllook(liblist[n].dll, sym); 945 return 0; 946 } 947 948 #else 949 950 int sh_addlib(Shell_t* shp, void* library, char* name, Pathcomp_t* pp) 951 { 952 return 0; 953 } 954 955 Shbltin_f sh_getlib(Shell_t* shp, char* name, Pathcomp_t* pp) 956 { 957 return 0; 958 } 959 960 #endif /* SHOPT_DYNAMIC */ 961 962 /* 963 * add change or list built-ins 964 * adding builtins requires dlopen() interface 965 */ 966 int b_builtin(int argc,char *argv[],Shbltin_t *context) 967 { 968 register char *arg=0, *name; 969 register int n, r=0, flag=0; 970 register Namval_t *np; 971 long dlete=0; 972 struct tdata tdata; 973 Shbltin_f addr; 974 Stk_t *stkp; 975 void *library=0; 976 char *errmsg; 977 #ifdef SH_PLUGIN_VERSION 978 unsigned long ver; 979 int list = 0; 980 char path[1024]; 981 #endif 982 NOT_USED(argc); 983 memset(&tdata,0,sizeof(tdata)); 984 tdata.sh = context->shp; 985 stkp = tdata.sh->stk; 986 if(!tdata.sh->pathlist) 987 path_absolute(tdata.sh,argv[0],NIL(Pathcomp_t*)); 988 while (n = optget(argv,sh_optbuiltin)) switch (n) 989 { 990 case 's': 991 flag = BLT_SPC; 992 break; 993 case 'd': 994 dlete=1; 995 break; 996 case 'f': 997 #if SHOPT_DYNAMIC 998 arg = opt_info.arg; 999 #else 1000 errormsg(SH_DICT,2, "adding built-ins not supported"); 1001 error_info.errors++; 1002 #endif /* SHOPT_DYNAMIC */ 1003 break; 1004 case 'l': 1005 #ifdef SH_PLUGIN_VERSION 1006 list = 1; 1007 #endif 1008 break; 1009 case ':': 1010 errormsg(SH_DICT,2, "%s", opt_info.arg); 1011 break; 1012 case '?': 1013 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 1014 break; 1015 } 1016 argv += opt_info.index; 1017 if(error_info.errors) 1018 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 1019 if(arg || *argv) 1020 { 1021 if(sh_isoption(SH_RESTRICTED)) 1022 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); 1023 if(sh_isoption(SH_PFSH)) 1024 errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); 1025 if(tdata.sh->subshell && !tdata.sh->subshare) 1026 sh_subfork(); 1027 } 1028 #if SHOPT_DYNAMIC 1029 if(arg) 1030 { 1031 #ifdef SH_PLUGIN_VERSION 1032 if(!(library = dllplugin(SH_ID, arg, NiL, SH_PLUGIN_VERSION, &ver, RTLD_LAZY, path, sizeof(path)))) 1033 { 1034 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dllerror(0)); 1035 return(1); 1036 } 1037 if(list) 1038 sfprintf(sfstdout, "%s %08lu %s\n", arg, ver, path); 1039 #else 1040 #if (_AST_VERSION>=20040404) 1041 if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 1042 #else 1043 if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 1044 #endif 1045 { 1046 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); 1047 return(1); 1048 } 1049 #endif 1050 sh_addlib(tdata.sh,library,arg,NiL); 1051 } 1052 else 1053 #endif /* SHOPT_DYNAMIC */ 1054 if(*argv==0 && !dlete) 1055 { 1056 print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); 1057 return(0); 1058 } 1059 r = 0; 1060 flag = stktell(stkp); 1061 while(arg = *argv) 1062 { 1063 name = path_basename(arg); 1064 sfwrite(stkp,"b_",2); 1065 sfputr(stkp,name,0); 1066 errmsg = 0; 1067 addr = 0; 1068 if(dlete || liblist) 1069 for(n=(nlib?nlib:dlete); --n>=0;) 1070 { 1071 #if SHOPT_DYNAMIC 1072 if(!dlete && !liblist[n].dll) 1073 continue; 1074 if(dlete || (addr = (Shbltin_f)dlllook(liblist[n].dll,stkptr(stkp,flag)))) 1075 #else 1076 if(dlete) 1077 #endif /* SHOPT_DYNAMIC */ 1078 { 1079 if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) 1080 { 1081 if(dlete || nv_isattr(np,BLT_SPC)) 1082 errmsg = "restricted name"; 1083 #if SHOPT_DYNAMIC 1084 else 1085 nv_onattr(np,liblist[n].attr); 1086 #endif /* SHOPT_DYNAMIC */ 1087 } 1088 break; 1089 } 1090 } 1091 if(!addr && (np = nv_search(arg,context->shp->bltin_tree,0))) 1092 { 1093 if(nv_isattr(np,BLT_SPC)) 1094 errmsg = "restricted name"; 1095 addr = (Shbltin_f)np->nvalue.bfp; 1096 } 1097 if(!dlete && !addr && !(np=sh_addbuiltin(arg,(Shbltin_f)0 ,0))) 1098 errmsg = "not found"; 1099 if(errmsg) 1100 { 1101 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); 1102 r = 1; 1103 } 1104 stkseek(stkp,flag); 1105 argv++; 1106 } 1107 return(r); 1108 } 1109 1110 int b_set(int argc,register char *argv[],Shbltin_t *context) 1111 { 1112 struct tdata tdata; 1113 int was_monitor = sh_isoption(SH_MONITOR); 1114 memset(&tdata,0,sizeof(tdata)); 1115 tdata.sh = context->shp; 1116 tdata.prefix=0; 1117 if(argv[1]) 1118 { 1119 if(sh_argopts(argc,argv,tdata.sh) < 0) 1120 return(2); 1121 if(sh_isoption(SH_VERBOSE)) 1122 sh_onstate(SH_VERBOSE); 1123 else 1124 sh_offstate(SH_VERBOSE); 1125 if(sh_isoption(SH_MONITOR) && !was_monitor) 1126 sh_onstate(SH_MONITOR); 1127 else if(!sh_isoption(SH_MONITOR) && was_monitor) 1128 sh_offstate(SH_MONITOR); 1129 } 1130 else 1131 /*scan name chain and print*/ 1132 print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); 1133 return(0); 1134 } 1135 1136 /* 1137 * The removing of Shell variable names, aliases, and functions 1138 * is performed here. 1139 * Unset functions with unset -f 1140 * Non-existent items being deleted give non-zero exit status 1141 */ 1142 1143 int b_unalias(int argc,register char *argv[],Shbltin_t *context) 1144 { 1145 Shell_t *shp = context->shp; 1146 return(unall(argc,argv,shp->alias_tree,shp)); 1147 } 1148 1149 int b_unset(int argc,register char *argv[],Shbltin_t *context) 1150 { 1151 Shell_t *shp = context->shp; 1152 return(unall(argc,argv,shp->var_tree,shp)); 1153 } 1154 1155 static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) 1156 { 1157 register Namval_t *np; 1158 register const char *name; 1159 volatile int r; 1160 Dt_t *dp; 1161 int nflag=0,all=0,isfun,jmpval; 1162 struct checkpt buff; 1163 NOT_USED(argc); 1164 if(troot==shp->alias_tree) 1165 { 1166 name = sh_optunalias; 1167 if(shp->subshell) 1168 troot = sh_subaliastree(0); 1169 } 1170 else 1171 name = sh_optunset; 1172 while(r = optget(argv,name)) switch(r) 1173 { 1174 case 'f': 1175 troot = sh_subfuntree(1); 1176 break; 1177 case 'a': 1178 all=1; 1179 break; 1180 case 'n': 1181 nflag = NV_NOREF; 1182 /* FALLTHROUGH */ 1183 case 'v': 1184 troot = shp->var_tree; 1185 break; 1186 case ':': 1187 errormsg(SH_DICT,2, "%s", opt_info.arg); 1188 break; 1189 case '?': 1190 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 1191 return(2); 1192 } 1193 argv += opt_info.index; 1194 if(error_info.errors || (*argv==0 &&!all)) 1195 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 1196 if(!troot) 1197 return(1); 1198 r = 0; 1199 if(troot==shp->var_tree) 1200 nflag |= NV_VARNAME; 1201 else 1202 nflag = NV_NOSCOPE; 1203 if(all) 1204 { 1205 dtclear(troot); 1206 return(r); 1207 } 1208 sh_pushcontext(shp,&buff,1); 1209 while(name = *argv++) 1210 { 1211 jmpval = sigsetjmp(buff.buff,0); 1212 np = 0; 1213 if(jmpval==0) 1214 { 1215 #if SHOPT_NAMESPACE 1216 if(shp->namespace && troot!=shp->var_tree) 1217 np = sh_fsearch(shp,name,nflag?HASH_NOSCOPE:0); 1218 if(!np) 1219 #endif /* SHOPT_NAMESPACE */ 1220 np=nv_open(name,troot,NV_NOADD|nflag); 1221 } 1222 else 1223 { 1224 r = 1; 1225 continue; 1226 } 1227 if(np) 1228 { 1229 if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY)) 1230 { 1231 if(nv_isattr(np,NV_RDONLY)) 1232 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 1233 r = 1; 1234 continue; 1235 } 1236 isfun = is_afunction(np); 1237 if(troot==shp->var_tree) 1238 { 1239 Namarr_t *ap; 1240 #if SHOPT_FIXEDARRAY 1241 if((ap=nv_arrayptr(np)) && !ap->fixed && name[strlen(name)-1]==']' && !nv_getsub(np)) 1242 #else 1243 if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) 1244 #endif /* SHOPT_FIXEDARRAY */ 1245 { 1246 r=1; 1247 continue; 1248 } 1249 1250 if(shp->subshell) 1251 np=sh_assignok(np,0); 1252 } 1253 if(!nv_isnull(np) || nv_size(np) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE))) 1254 _nv_unset(np,0); 1255 if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) 1256 nv_delete(np,dp,NV_NOFREE); 1257 else if(isfun && !(np->nvalue.rp && np->nvalue.rp->running)) 1258 nv_delete(np,troot,0); 1259 #if 0 1260 /* causes unsetting local variable to expose global */ 1261 else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE)) 1262 nv_delete(np,shp->var_tree,0); 1263 #endif 1264 else 1265 nv_close(np); 1266 1267 } 1268 else if(troot==shp->alias_tree) 1269 r = 1; 1270 } 1271 sh_popcontext(shp,&buff); 1272 return(r); 1273 } 1274 1275 /* 1276 * print out the name and value of a name-value pair <np> 1277 */ 1278 1279 static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) 1280 { 1281 register char *cp; 1282 int indent=tp->indent, outname=0, isfun; 1283 sh_sigcheck(tp->sh); 1284 if(flag) 1285 flag = '\n'; 1286 if(tp->noref && nv_isref(np)) 1287 return(0); 1288 if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) 1289 { 1290 if(is_abuiltin(np) && strcmp(np->nvname,".sh.tilde")) 1291 sfputr(file,nv_name(np),'\n'); 1292 return(0); 1293 } 1294 if(nv_istable(np)) 1295 { 1296 print_value(file,np,tp); 1297 return(0); 1298 } 1299 isfun = is_afunction(np); 1300 if(tp->prefix) 1301 { 1302 outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT))); 1303 if(indent && (isfun || outname || *tp->prefix!='t')) 1304 { 1305 sfnputc(file,'\t',indent); 1306 indent = 0; 1307 } 1308 if(!isfun) 1309 { 1310 if(*tp->prefix=='t') 1311 nv_attribute(np,tp->outfile,tp->prefix,tp->aflag); 1312 else 1313 sfputr(file,tp->prefix,' '); 1314 } 1315 } 1316 if(isfun) 1317 { 1318 Sfio_t *iop=0; 1319 char *fname=0; 1320 if(nv_isattr(np,NV_NOFREE)) 1321 return(0); 1322 if(!flag && !np->nvalue.ip) 1323 sfputr(file,"typeset -fu",' '); 1324 else if(!flag && !nv_isattr(np,NV_FPOSIX)) 1325 sfputr(file,"function",' '); 1326 cp = nv_name(np); 1327 if(tp->wctname) 1328 cp += strlen(tp->wctname)+1; 1329 sfputr(file,cp,-1); 1330 if(nv_isattr(np,NV_FPOSIX)) 1331 sfwrite(file,"()",2); 1332 if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1333 fname = np->nvalue.rp->fname; 1334 else 1335 flag = '\n'; 1336 if(flag) 1337 { 1338 if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1339 sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); 1340 else 1341 sfputc(file, '\n'); 1342 } 1343 else 1344 { 1345 if(nv_isattr(np,NV_FTMP)) 1346 { 1347 fname = 0; 1348 iop = tp->sh->heredocs; 1349 } 1350 else if(fname) 1351 iop = sfopen(iop,fname,"r"); 1352 else if(tp->sh->gd->hist_ptr) 1353 iop = (tp->sh->gd->hist_ptr)->histfp; 1354 if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) 1355 sfmove(iop,file, nv_size(np), -1); 1356 else 1357 flag = '\n'; 1358 if(fname) 1359 sfclose(iop); 1360 } 1361 return(nv_size(np)+1); 1362 } 1363 if(nv_arrayptr(np)) 1364 { 1365 if(indent) 1366 sfnputc(file,'\t',indent); 1367 print_value(file,np,tp); 1368 return(0); 1369 } 1370 if(nv_isvtree(np)) 1371 nv_onattr(np,NV_EXPORT); 1372 if(cp=nv_getval(np)) 1373 { 1374 if(indent) 1375 sfnputc(file,'\t',indent); 1376 sfputr(file,nv_name(np),-1); 1377 if(!flag) 1378 flag = '='; 1379 sfputc(file,flag); 1380 if(flag != '\n') 1381 { 1382 if(nv_isref(np) && nv_refsub(np)) 1383 { 1384 sfputr(file,sh_fmtq(cp),-1); 1385 sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); 1386 } 1387 else 1388 #if SHOPT_TYPEDEF 1389 sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); 1390 #else 1391 sfputr(file,sh_fmtq(cp),'\n'); 1392 #endif /* SHOPT_TYPEDEF */ 1393 } 1394 return(1); 1395 } 1396 else if(outname || (tp->scanmask && tp->scanroot==tp->sh->var_tree)) 1397 sfputr(file,nv_name(np),'\n'); 1398 return(0); 1399 } 1400 1401 /* 1402 * print attributes at all nodes 1403 */ 1404 static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) 1405 { 1406 tp->outfile = file; 1407 nv_scan(root, print_attribute, (void*)tp, 0, 0); 1408 } 1409 1410 /* 1411 * print the attributes of name value pair give by <np> 1412 */ 1413 static void print_attribute(register Namval_t *np,void *data) 1414 { 1415 register struct tdata *dp = (struct tdata*)data; 1416 nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); 1417 } 1418 1419 /* 1420 * print the nodes in tree <root> which have attributes <flag> set 1421 * of <option> is non-zero, no subscript or value is printed. 1422 */ 1423 1424 static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp) 1425 { 1426 register char **argv; 1427 register Namval_t *np; 1428 register int namec; 1429 Namval_t *onp = 0; 1430 char *name=0; 1431 int len; 1432 tp->sh->last_table=0; 1433 flag &= ~NV_ASSIGN; 1434 tp->scanmask = flag&~NV_NOSCOPE; 1435 tp->scanroot = root; 1436 tp->outfile = file; 1437 #if SHOPT_TYPEDEF 1438 if(!tp->prefix && tp->tp) 1439 tp->prefix = nv_name(tp->tp); 1440 #endif /* SHOPT_TYPEDEF */ 1441 if(flag&NV_INTEGER) 1442 tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE); 1443 if(flag==NV_LTOU || flag==NV_UTOL) 1444 tp->scanmask |= NV_UTOL|NV_LTOU; 1445 namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag); 1446 argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*)); 1447 namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY); 1448 if(mbcoll()) 1449 strsort(argv,namec,strcoll); 1450 if(namec==0 && tp->sh->namespace && nv_dict(tp->sh->namespace)==root) 1451 { 1452 sfnputc(file,'\t',tp->indent); 1453 sfwrite(file,":\n",2); 1454 } 1455 else while(namec--) 1456 { 1457 if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))) 1458 { 1459 onp = np; 1460 if(name) 1461 { 1462 char *newname = nv_name(np); 1463 if(memcmp(name,newname,len)==0 && newname[len]== '.') 1464 continue; 1465 name = 0; 1466 } 1467 if(flag&NV_ARRAY) 1468 { 1469 if(nv_aindex(np)>=0) 1470 { 1471 if(!(flag&NV_IARRAY)) 1472 continue; 1473 } 1474 else if((flag&NV_IARRAY)) 1475 continue; 1476 1477 } 1478 tp->scanmask = flag&~NV_NOSCOPE; 1479 tp->scanroot = root; 1480 print_namval(file,np,option,tp); 1481 if(!is_abuiltin(np) && nv_isvtree(np)) 1482 { 1483 name = nv_name(np); 1484 len = strlen(name); 1485 } 1486 } 1487 } 1488 } 1489 1490 /* 1491 * add the name of the node to the argument list argnam 1492 */ 1493 1494 static void pushname(Namval_t *np,void *data) 1495 { 1496 struct tdata *tp = (struct tdata*)data; 1497 *tp->argnam++ = nv_name(np); 1498 } 1499 1500