1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2011 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 * 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 45struct 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 65static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); 66static void print_attribute(Namval_t*,void*); 67static void print_all(Sfio_t*, Dt_t*, struct tdata*); 68static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*); 69static int b_unall(int, char**, Dt_t*, Shell_t*); 70static int b_common(char**, int, Dt_t*, struct tdata*); 71static void pushname(Namval_t*,void*); 72static void(*nullscan)(Namval_t*,void*); 73 74static 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[],void *extra){} 86#endif 87int b_readonly(int argc,char *argv[],void *extra) 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 = ((Shbltin_t*)extra)->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(b_common(argv,flag,tdata.sh->var_tree, &tdata)); 133} 134 135 136int b_alias(int argc,register char *argv[],void *extra) 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 = ((Shbltin_t*)extra)->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(b_common(argv,flag,troot,&tdata)); 201} 202 203 204#if 0 205 /* for the dictionary generator */ 206 int b_local(int argc,char *argv[],void *extra){} 207#endif 208int b_typeset(int argc,register char *argv[],void *extra) 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*)((Shbltin_t*)extra)->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 = ((Shbltin_t*)extra)->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 case 'F': 255 case 'X': 256 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 257 tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10); 258 isfloat = 1; 259 if(n=='E') 260 { 261 flag &= ~NV_HEXFLOAT; 262 flag |= NV_EXPNOTE; 263 } 264 else if(n=='X') 265 { 266 flag &= ~NV_EXPNOTE; 267 flag |= NV_HEXFLOAT; 268 } 269 break; 270 case 'b': 271 flag |= NV_BINARY; 272 break; 273 case 'm': 274 flag |= NV_MOVE; 275 break; 276 case 'n': 277 flag &= ~NV_VARNAME; 278 flag |= (NV_REF|NV_IDENT); 279 break; 280 case 'H': 281 flag |= NV_HOST; 282 break; 283 case 'T': 284 flag |= NV_TYPE; 285 tdata.prefix = opt_info.arg; 286 break; 287 case 'L': case 'Z': case 'R': 288 if(tdata.argnum==0) 289 tdata.argnum = (int)opt_info.num; 290 if(tdata.argnum < 0) 291 errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); 292 if(n=='Z') 293 flag |= NV_ZFILL; 294 else 295 { 296 flag &= ~(NV_LJUST|NV_RJUST); 297 flag |= (n=='L'?NV_LJUST:NV_RJUST); 298 } 299 break; 300 case 'M': 301 if((tdata.wctname = opt_info.arg) && !nv_mapchar((Namval_t*)0,tdata.wctname)) 302 errormsg(SH_DICT, ERROR_exit(1),e_unknownmap, tdata.wctname); 303 if(tdata.wctname && strcmp(tdata.wctname,e_tolower)==0) 304 flag |= NV_UTOL; 305 else 306 flag |= NV_LTOU; 307 if(!tdata.wctname) 308 flag |= NV_UTOL; 309 break; 310 case 'f': 311 flag &= ~(NV_VARNAME|NV_ASSIGN); 312 troot = tdata.sh->fun_tree; 313 break; 314 case 'i': 315 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 316 tdata.argnum = 10; 317 flag |= NV_INTEGER; 318 break; 319 case 'l': 320 tdata.wctname = e_tolower; 321 flag |= NV_UTOL; 322 break; 323 case 'p': 324 tdata.prefix = argv[0]; 325 tdata.pflag = 1; 326 flag &= ~NV_ASSIGN; 327 break; 328 case 'r': 329 flag |= NV_RDONLY; 330 break; 331#ifdef SHOPT_TYPEDEF 332 case 'S': 333 sflag=1; 334 break; 335 case 'h': 336 tdata.help = opt_info.arg; 337 break; 338#endif /*SHOPT_TYPEDEF*/ 339 case 's': 340 shortint=1; 341 break; 342 case 't': 343 flag |= NV_TAGGED; 344 break; 345 case 'u': 346 tdata.wctname = e_toupper; 347 flag |= NV_LTOU; 348 break; 349 case 'x': 350 flag &= ~NV_VARNAME; 351 flag |= (NV_EXPORT|NV_IDENT); 352 break; 353 case ':': 354 errormsg(SH_DICT,2, "%s", opt_info.arg); 355 break; 356 case '?': 357 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 358 opt_info.disc = 0; 359 return(2); 360 } 361 } 362endargs: 363 argv += opt_info.index; 364 opt_info.disc = 0; 365 /* handle argument of + and - specially */ 366 if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-')) 367 tdata.aflag = *argv[0]; 368 else 369 argv--; 370 if((flag&NV_ZFILL) && !(flag&NV_LJUST)) 371 flag |= NV_RJUST; 372 if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) 373 error_info.errors++; 374 if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) 375 error_info.errors++; 376 if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN))) 377 error_info.errors++; 378 if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN))) 379 error_info.errors++; 380 if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU)))) 381 error_info.errors++; 382 if(sflag && troot==tdata.sh->fun_tree) 383 { 384 /* static function */ 385 sflag = 0; 386 flag |= NV_STATICF; 387 } 388 if(error_info.errors) 389 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 390 if(isfloat) 391 flag |= NV_DOUBLE; 392 if(shortint) 393 { 394 flag &= ~NV_LONG; 395 flag |= NV_SHORT|NV_INTEGER; 396 } 397 if(sflag) 398 { 399 if(tdata.sh->mktype) 400 flag |= NV_REF|NV_TAGGED; 401 else if(!tdata.sh->typeinit) 402 flag |= NV_STATIC|NV_IDENT; 403 } 404 if(tdata.sh->fn_depth && !tdata.pflag) 405 flag |= NV_NOSCOPE; 406 if(tdata.help) 407 tdata.help = strdup(tdata.help); 408 if(flag&NV_TYPE) 409 { 410 Stk_t *stkp = tdata.sh->stk; 411 int offset = stktell(stkp); 412 if(!tdata.prefix) 413 return(sh_outtype(tdata.sh,sfstdout)); 414 sfputr(stkp,NV_CLASS,-1); 415 if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') 416 sfputc(stkp,'.'); 417 sfputr(stkp,tdata.prefix,0); 418 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); 419 stkseek(stkp,offset); 420 if(!tdata.tp) 421 errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); 422 else if(nv_isnull(tdata.tp)) 423 nv_newtype(tdata.tp); 424 tdata.tp->nvenv = tdata.help; 425 flag &= ~NV_TYPE; 426 } 427 else if(tdata.aflag==0 && ntp && ntp->tp) 428 tdata.aflag = '-'; 429 if(!tdata.sh->mktype) 430 tdata.help = 0; 431 if(tdata.aflag=='+' && (flag&(NV_ARRAY|NV_IARRAY|NV_COMVAR))) 432 errormsg(SH_DICT,ERROR_exit(1),e_nounattr); 433 return(b_common(argv,flag,troot,&tdata)); 434} 435 436static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) 437{ 438 char *name; 439 int aflag=tp->aflag; 440 if(nv_isnull(np)) 441 { 442 if(!np->nvflag) 443 return; 444 aflag = '+'; 445 } 446 else if(nv_istable(np)) 447 { 448 Dt_t *root = nv_dict(np); 449 name = nv_name(np); 450 if(*name=='.') 451 name++; 452 if(tp->indent) 453 sfnputc(iop,'\t',tp->indent); 454 sfprintf(iop,"namespace %s\n", name); 455 if(tp->indent) 456 sfnputc(iop,'\t',tp->indent); 457 sfprintf(iop,"{\n", name); 458 tp->indent++; 459 print_scan(iop,NV_NOSCOPE,root,aflag=='+',tp); 460 tp->indent--; 461 if(tp->indent) 462 sfnputc(iop,'\t',tp->indent); 463 sfwrite(iop,"}\n",2); 464 return; 465 } 466 sfputr(iop,nv_name(np),aflag=='+'?'\n':'='); 467 if(aflag=='+') 468 return; 469 if(nv_isarray(np) && nv_arrayptr(np)) 470 { 471 nv_outnode(np,iop,-1,0); 472 sfwrite(iop,")\n",2); 473 } 474 else 475 { 476 if(nv_isvtree(np)) 477 nv_onattr(np,NV_EXPORT); 478 if(!(name = nv_getval(np))) 479 name = Empty; 480 if(!nv_isvtree(np)) 481 name = sh_fmtq(name); 482 sfputr(iop,name,'\n'); 483 } 484} 485 486static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata *tp) 487{ 488 register char *name; 489 char *last = 0; 490 int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); 491 int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); 492 Shell_t *shp =tp->sh; 493 if(!shp->prefix) 494 { 495 if(!tp->pflag) 496 nvflags |= NV_NOSCOPE; 497 } 498 else if(*shp->prefix==0) 499 shp->prefix = 0; 500 flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); 501 if(argv[1]) 502 { 503 if(flag&NV_REF) 504 { 505 flag &= ~NV_REF; 506 ref=1; 507 if(tp->aflag!='-') 508 nvflags |= NV_NOREF; 509 } 510 if(tp->pflag) 511 nvflags |= NV_NOREF; 512 while(name = *++argv) 513 { 514 register unsigned newflag; 515 register Namval_t *np; 516 unsigned curflag; 517 if(troot == shp->fun_tree) 518 { 519 /* 520 *functions can be exported or 521 * traced but not set 522 */ 523 flag &= ~NV_ASSIGN; 524 if(flag&NV_LTOU) 525 { 526 /* Function names cannot be special builtin */ 527 if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) 528 errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); 529#if SHOPT_NAMESPACE 530 if(shp->namespace) 531 np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE); 532 else 533#endif /* SHOPT_NAMESPACE */ 534 np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); 535 } 536 else 537 { 538 if(shp->prefix) 539 { 540 sfprintf(shp->strbuf,"%s.%s%c",shp->prefix,name,0); 541 name = sfstruse(shp->strbuf); 542 } 543#if SHOPT_NAMESPACE 544 np = 0; 545 if(shp->namespace) 546 np = sh_fsearch(shp,name,HASH_NOSCOPE); 547 if(!np) 548#endif /* SHOPT_NAMESPACE */ 549 if((np=nv_search(name,troot,0)) && !is_afunction(np)) 550 np = 0; 551 } 552 if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) 553 { 554 if(flag==0 && !tp->help) 555 { 556 print_namval(sfstdout,np,tp->aflag=='+',tp); 557 continue; 558 } 559 if(shp->subshell && !shp->subshare) 560 sh_subfork(); 561 if(tp->aflag=='-') 562 nv_onattr(np,flag|NV_FUNCTION); 563 else if(tp->aflag=='+') 564 nv_offattr(np,flag); 565 } 566 else 567 r++; 568 if(tp->help) 569 { 570 int offset = stktell(shp->stk); 571 if(!np) 572 { 573 sfputr(shp->stk,shp->prefix,'.'); 574 sfputr(shp->stk,name,0); 575 np = nv_search(stkptr(shp->stk,offset),troot,0); 576 stkseek(shp->stk,offset); 577 } 578 if(np && np->nvalue.cp) 579 np->nvalue.rp->help = tp->help; 580 } 581 continue; 582 } 583 /* tracked alias */ 584 if(troot==shp->track_tree && tp->aflag=='-') 585 { 586 np = nv_search(name,troot,NV_ADD); 587 path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*))); 588 continue; 589 } 590 np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|NV_FARRAY); 591 if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE)) 592 nv_offattr(np,NV_NOFREE); 593 if(tp->pflag) 594 { 595 nv_attribute(np,sfstdout,tp->prefix,1); 596 print_value(sfstdout,np,tp); 597 continue; 598 } 599 if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) 600 { 601 if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) 602 { 603 sfprintf(sfstderr,sh_translate(e_noalias),name); 604 r++; 605 } 606 if(!comvar && !iarray) 607 continue; 608 } 609 if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name))) 610 { 611 if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&NV_EXPORT) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT))))) 612{ 613 _nv_unset(np,0); 614} 615 } 616 if(troot==shp->var_tree) 617 { 618 if(iarray) 619 { 620 if(tp->tname) 621 nv_atypeindex(np,tp->tname+1); 622 else if(nv_isnull(np)) 623 nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0)); 624 else 625 { 626 Namarr_t *ap=nv_arrayptr(np); 627 if(ap && comvar) 628 ap->nelem |= ARRAY_TREE; 629 nv_putsub(np, (char*)0, 0); 630 } 631 } 632 else if(nvflags&NV_ARRAY) 633 { 634 if(comvar) 635 { 636 Namarr_t *ap=nv_arrayptr(np); 637 if(ap) 638 ap->nelem |= ARRAY_TREE; 639 else 640 { 641 _nv_unset(np,NV_RDONLY); 642 nv_onattr(np,NV_NOFREE); 643 } 644 } 645 nv_setarray(np,nv_associative); 646 } 647 else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR)) 648 nv_setvtree(np); 649 } 650 if(flag&NV_MOVE) 651 { 652 nv_rename(np, flag); 653 nv_close(np); 654 continue; 655 } 656 if(tp->tp && nv_type(np)!=tp->tp) 657 { 658 nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); 659 flag = (np->nvflag&NV_NOCHANGE); 660 } 661 flag &= ~NV_ASSIGN; 662 if(last=strchr(name,'=')) 663 *last = 0; 664 if (shp->typeinit) 665 continue; 666 curflag = np->nvflag; 667 if(!(flag&NV_INTEGER) && (flag&(NV_LTOU|NV_UTOL))) 668 { 669 Namfun_t *fp; 670 char *cp; 671 if(!tp->wctname) 672 errormsg(SH_DICT,ERROR_exit(1),e_mapchararg,nv_name(np)); 673 cp = (char*)nv_mapchar(np,0); 674 if(fp=nv_mapchar(np,tp->wctname)) 675 { 676 if(tp->aflag=='+') 677 { 678 if(cp && strcmp(cp,tp->wctname)==0) 679 { 680 nv_disc(np,fp,NV_POP); 681 if(!(fp->nofree&1)) 682 free((void*)fp); 683 nv_offattr(np,flag&(NV_LTOU|NV_UTOL)); 684 } 685 } 686 else if(!cp || strcmp(cp,tp->wctname)) 687 { 688 nv_disc(np,fp,NV_LAST); 689 nv_onattr(np,flag&(NV_LTOU|NV_UTOL)); 690 } 691 } 692 } 693 if (tp->aflag == '-') 694 { 695 if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np))) 696 errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); 697#if SHOPT_BSH 698 if(flag&NV_EXPORT) 699 nv_offattr(np,NV_IMPORT); 700#endif /* SHOPT_BSH */ 701 newflag = curflag; 702 if(flag&~NV_NOCHANGE) 703 newflag &= NV_NOCHANGE; 704 newflag |= flag; 705 if (flag & (NV_LJUST|NV_RJUST)) 706 { 707 if(!(flag&NV_RJUST)) 708 newflag &= ~NV_RJUST; 709 710 else if(!(flag&NV_LJUST)) 711 newflag &= ~NV_LJUST; 712 } 713 } 714 else 715 { 716 if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) 717 errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); 718 newflag = curflag & ~flag; 719 } 720 if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) 721 { 722 if(shp->subshell) 723 sh_assignok(np,1); 724 if(troot!=shp->var_tree) 725 nv_setattr(np,newflag&~NV_ASSIGN); 726 else 727 { 728 char *oldname=0; 729 int len=strlen(name); 730 if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 731 tp->argnum = 10; 732 /* use reference name for export */ 733 if((newflag^curflag)&NV_EXPORT) 734 { 735 oldname = np->nvname; 736 np->nvname = name; 737 } 738 if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') 739 newflag |= NV_NODISC; 740 nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); 741 if(oldname) 742 np->nvname = oldname; 743 } 744 } 745 if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) 746 { 747 np->nvenv = tp->help; 748 nv_onattr(np,NV_EXPORT); 749 } 750 if(last) 751 *last = '='; 752 /* set or unset references */ 753 if(ref) 754 { 755 if(tp->aflag=='-') 756 { 757 Dt_t *hp=0; 758 if(nv_isattr(np,NV_PARAM) && shp->st.prevst) 759 { 760 if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) 761 hp = dtvnext(shp->var_tree); 762 } 763 if(tp->sh->mktype) 764 nv_onattr(np,NV_REF|NV_FUNCT); 765 else 766 nv_setref(np,hp,NV_VARNAME); 767 } 768 else 769 nv_unref(np); 770 } 771 nv_close(np); 772 } 773 } 774 else 775 { 776 if(shp->prefix) 777 errormsg(SH_DICT,2, e_subcomvar,shp->prefix); 778 if(tp->aflag) 779 { 780 if(troot==shp->fun_tree) 781 { 782 flag |= NV_FUNCTION; 783 tp->prefix = 0; 784 } 785 else if(troot==shp->var_tree) 786 { 787 flag |= (nvflags&NV_ARRAY); 788 if(flag&NV_IARRAY) 789 flag |= NV_ARRAY; 790 if(!(flag&~NV_ASSIGN)) 791 tp->noref = 1; 792 } 793 if((flag&(NV_UTOL|NV_LTOU)) ==(NV_UTOL|NV_LTOU)) 794 { 795 print_scan(sfstdout,flag&~NV_UTOL,troot,tp->aflag=='+',tp); 796 flag &= ~NV_LTOU; 797 } 798 print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); 799 if(tp->noref) 800 { 801 tp->noref = 0; 802 print_scan(sfstdout,flag|NV_REF,troot,tp->aflag=='+',tp); 803 } 804 } 805 else if(troot==shp->alias_tree) 806 print_scan(sfstdout,0,troot,0,tp); 807 else 808 print_all(sfstdout,troot,tp); 809 sfsync(sfstdout); 810 } 811 return(r); 812} 813 814typedef void (*Iptr_t)(int,void*); 815typedef int (*Fptr_t)(int, char*[], void*); 816 817#define GROWLIB 4 818 819static void **liblist; 820static unsigned short *libattr; 821static int nlib; 822static int maxlib; 823 824/* 825 * This allows external routines to load from the same library */ 826void **sh_getliblist(void) 827{ 828 return(liblist); 829} 830 831/* 832 * add library to loaded list 833 * call (*lib_init)() on first load if defined 834 * always move to head of search list 835 * return: 0: already loaded 1: first load 836 */ 837#if SHOPT_DYNAMIC 838int sh_addlib(Shell_t *shp,void* library) 839{ 840 register int n; 841 register int r; 842 Iptr_t initfn; 843 Shbltin_t *sp = &shp->bltindata; 844 845 sp->nosfio = 0; 846 for (n = r = 0; n < nlib; n++) 847 { 848 if (r) 849 { 850 liblist[n-1] = liblist[n]; 851 libattr[n-1] = libattr[n]; 852 } 853 else if (liblist[n] == library) 854 r++; 855 } 856 if (r) 857 nlib--; 858 else if ((initfn = (Iptr_t)dlllook(library, "lib_init"))) 859 (*initfn)(0,sp); 860 if (nlib >= maxlib) 861 { 862 maxlib += GROWLIB; 863 if (liblist) 864 { 865 liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**)); 866 libattr = (unsigned short*)realloc((void*)liblist, (maxlib+1)*sizeof(unsigned short*)); 867 } 868 else 869 { 870 liblist = (void**)malloc((maxlib+1)*sizeof(void**)); 871 libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short*)); 872 } 873 } 874 libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0); 875 liblist[nlib++] = library; 876 liblist[nlib] = 0; 877 return !r; 878} 879#else 880int sh_addlib(Shell_t *shp,void* library) 881{ 882 return 0; 883} 884#endif /* SHOPT_DYNAMIC */ 885 886/* 887 * add change or list built-ins 888 * adding builtins requires dlopen() interface 889 */ 890int b_builtin(int argc,char *argv[],void *extra) 891{ 892 register char *arg=0, *name; 893 register int n, r=0, flag=0; 894 register Namval_t *np; 895 long dlete=0; 896 struct tdata tdata; 897 Fptr_t addr; 898 Stk_t *stkp; 899 void *library=0; 900 char *errmsg; 901#ifdef SH_PLUGIN_VERSION 902 unsigned long ver; 903 int list = 0; 904 char path[1024]; 905#endif 906 NOT_USED(argc); 907 memset(&tdata,0,sizeof(tdata)); 908 tdata.sh = ((Shbltin_t*)extra)->shp; 909 stkp = tdata.sh->stk; 910 if(!tdata.sh->pathlist) 911 path_absolute(tdata.sh,argv[0],NIL(Pathcomp_t*)); 912 while (n = optget(argv,sh_optbuiltin)) switch (n) 913 { 914 case 's': 915 flag = BLT_SPC; 916 break; 917 case 'd': 918 dlete=1; 919 break; 920 case 'f': 921#if SHOPT_DYNAMIC 922 arg = opt_info.arg; 923#else 924 errormsg(SH_DICT,2, "adding built-ins not supported"); 925 error_info.errors++; 926#endif /* SHOPT_DYNAMIC */ 927 break; 928 case 'l': 929#ifdef SH_PLUGIN_VERSION 930 list = 1; 931#endif 932 break; 933 case ':': 934 errormsg(SH_DICT,2, "%s", opt_info.arg); 935 break; 936 case '?': 937 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 938 break; 939 } 940 argv += opt_info.index; 941 if(error_info.errors) 942 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 943 if(arg || *argv) 944 { 945 if(sh_isoption(SH_RESTRICTED)) 946 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); 947 if(sh_isoption(SH_PFSH)) 948 errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); 949 if(tdata.sh->subshell && !tdata.sh->subshare) 950 sh_subfork(); 951 } 952#if SHOPT_DYNAMIC 953 if(arg) 954 { 955#ifdef SH_PLUGIN_VERSION 956 if(!(library = dllplugin(SH_ID, arg, NiL, SH_PLUGIN_VERSION, &ver, RTLD_LAZY, path, sizeof(path)))) 957 { 958 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dllerror(0)); 959 return(1); 960 } 961 if(list) 962 sfprintf(sfstdout, "%s %08lu %s\n", arg, ver, path); 963#else 964#if (_AST_VERSION>=20040404) 965 if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 966#else 967 if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 968#endif 969 { 970 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); 971 return(1); 972 } 973#endif 974 sh_addlib(tdata.sh,library); 975 } 976 else 977#endif /* SHOPT_DYNAMIC */ 978 if(*argv==0 && !dlete) 979 { 980 print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); 981 return(0); 982 } 983 r = 0; 984 flag = stktell(stkp); 985 while(arg = *argv) 986 { 987 name = path_basename(arg); 988 sfwrite(stkp,"b_",2); 989 sfputr(stkp,name,0); 990 errmsg = 0; 991 addr = 0; 992 for(n=(nlib?nlib:dlete); --n>=0;) 993 { 994 /* (char*) added for some sgi-mips compilers */ 995#if SHOPT_DYNAMIC 996 if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stkptr(stkp,flag)))) 997#else 998 if(dlete) 999#endif /* SHOPT_DYNAMIC */ 1000 { 1001 if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) 1002 { 1003 if(dlete || nv_isattr(np,BLT_SPC)) 1004 errmsg = "restricted name"; 1005 else 1006 nv_onattr(np,libattr[n]); 1007 } 1008 break; 1009 } 1010 } 1011 if(!dlete && !addr) 1012 { 1013 np = sh_addbuiltin(arg, 0 ,0); 1014 if(np && nv_isattr(np,BLT_SPC)) 1015 errmsg = "restricted name"; 1016 else if(!np) 1017 errmsg = "not found"; 1018 } 1019 if(errmsg) 1020 { 1021 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); 1022 r = 1; 1023 } 1024 stkseek(stkp,flag); 1025 argv++; 1026 } 1027 return(r); 1028} 1029 1030int b_set(int argc,register char *argv[],void *extra) 1031{ 1032 struct tdata tdata; 1033 memset(&tdata,0,sizeof(tdata)); 1034 tdata.sh = ((Shbltin_t*)extra)->shp; 1035 tdata.prefix=0; 1036 if(argv[1]) 1037 { 1038 if(sh_argopts(argc,argv,tdata.sh) < 0) 1039 return(2); 1040 if(sh_isoption(SH_VERBOSE)) 1041 sh_onstate(SH_VERBOSE); 1042 else 1043 sh_offstate(SH_VERBOSE); 1044 if(sh_isoption(SH_MONITOR)) 1045 sh_onstate(SH_MONITOR); 1046 else 1047 sh_offstate(SH_MONITOR); 1048 } 1049 else 1050 /*scan name chain and print*/ 1051 print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); 1052 return(0); 1053} 1054 1055/* 1056 * The removing of Shell variable names, aliases, and functions 1057 * is performed here. 1058 * Unset functions with unset -f 1059 * Non-existent items being deleted give non-zero exit status 1060 */ 1061 1062int b_unalias(int argc,register char *argv[],void *extra) 1063{ 1064 Shell_t *shp = ((Shbltin_t*)extra)->shp; 1065 return(b_unall(argc,argv,shp->alias_tree,shp)); 1066} 1067 1068int b_unset(int argc,register char *argv[],void *extra) 1069{ 1070 Shell_t *shp = ((Shbltin_t*)extra)->shp; 1071 return(b_unall(argc,argv,shp->var_tree,shp)); 1072} 1073 1074static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) 1075{ 1076 register Namval_t *np; 1077 register const char *name; 1078 register int r; 1079 Dt_t *dp; 1080 int nflag=0,all=0,isfun,jmpval; 1081 struct checkpt buff; 1082 NOT_USED(argc); 1083 if(troot==shp->alias_tree) 1084 { 1085 name = sh_optunalias; 1086 if(shp->subshell) 1087 troot = sh_subaliastree(0); 1088 } 1089 else 1090 name = sh_optunset; 1091 while(r = optget(argv,name)) switch(r) 1092 { 1093 case 'f': 1094 troot = sh_subfuntree(1); 1095 break; 1096 case 'a': 1097 all=1; 1098 break; 1099 case 'n': 1100 nflag = NV_NOREF; 1101 case 'v': 1102 troot = shp->var_tree; 1103 break; 1104 case ':': 1105 errormsg(SH_DICT,2, "%s", opt_info.arg); 1106 break; 1107 case '?': 1108 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 1109 return(2); 1110 } 1111 argv += opt_info.index; 1112 if(error_info.errors || (*argv==0 &&!all)) 1113 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 1114 if(!troot) 1115 return(1); 1116 r = 0; 1117 if(troot==shp->var_tree) 1118 nflag |= NV_VARNAME; 1119 else 1120 nflag = NV_NOSCOPE; 1121 if(all) 1122 { 1123 dtclear(troot); 1124 return(r); 1125 } 1126 sh_pushcontext(shp,&buff,1); 1127 while(name = *argv++) 1128 { 1129 jmpval = sigsetjmp(buff.buff,0); 1130 np = 0; 1131 if(jmpval==0) 1132 { 1133#if SHOPT_NAMESPACE 1134 if(shp->namespace && troot!=shp->var_tree) 1135 np = sh_fsearch(shp,name,nflag?HASH_NOSCOPE:0); 1136 if(!np) 1137#endif /* SHOPT_NAMESPACE */ 1138 np=nv_open(name,troot,NV_NOADD|nflag); 1139 } 1140 else 1141 { 1142 r = 1; 1143 continue; 1144 } 1145 if(np) 1146 { 1147 if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY)) 1148 { 1149 if(nv_isattr(np,NV_RDONLY)) 1150 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 1151 r = 1; 1152 continue; 1153 } 1154 isfun = is_afunction(np); 1155 if(troot==shp->var_tree) 1156 { 1157 Namarr_t *ap; 1158#if SHOPT_FIXEDARRAY 1159 if((ap=nv_arrayptr(np)) && !ap->fixed && name[strlen(name)-1]==']' && !nv_getsub(np)) 1160#else 1161 if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) 1162#endif /* SHOPT_FIXEDARRAY */ 1163 { 1164 r=1; 1165 continue; 1166 } 1167 1168 if(shp->subshell) 1169 np=sh_assignok(np,0); 1170 } 1171 if(!nv_isnull(np)) 1172 _nv_unset(np,0); 1173 if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) 1174 nv_delete(np,dp,NV_NOFREE); 1175 else if(isfun) 1176 nv_delete(np,troot,NV_NOFREE); 1177#if 0 1178 /* causes unsetting local variable to expose global */ 1179 else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE)) 1180 nv_delete(np,shp->var_tree,0); 1181#endif 1182 else 1183 nv_close(np); 1184 1185 } 1186 else if(troot==shp->alias_tree) 1187 r = 1; 1188 } 1189 sh_popcontext(shp,&buff); 1190 return(r); 1191} 1192 1193/* 1194 * print out the name and value of a name-value pair <np> 1195 */ 1196 1197static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) 1198{ 1199 register char *cp; 1200 int indent=tp->indent, outname=0; 1201 sh_sigcheck(tp->sh); 1202 if(flag) 1203 flag = '\n'; 1204 if(tp->noref && nv_isref(np)) 1205 return(0); 1206 if(nv_istable(np)) 1207 { 1208 print_value(file,np,tp); 1209 return(0); 1210 } 1211 if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) 1212 { 1213 if(is_abuiltin(np)) 1214 sfputr(file,nv_name(np),'\n'); 1215 return(0); 1216 } 1217 if(tp->prefix) 1218 { 1219 outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT))); 1220 if(indent && (outname || *tp->prefix!='t')) 1221 { 1222 sfnputc(file,'\t',indent); 1223 indent = 0; 1224 } 1225 if(*tp->prefix=='t') 1226 nv_attribute(np,tp->outfile,tp->prefix,tp->aflag); 1227 else 1228 sfputr(file,tp->prefix,' '); 1229 } 1230 if(is_afunction(np)) 1231 { 1232 Sfio_t *iop=0; 1233 char *fname=0; 1234 if(nv_isattr(np,NV_NOFREE)) 1235 return(0); 1236 if(!flag && !np->nvalue.ip) 1237 sfputr(file,"typeset -fu",' '); 1238 else if(!flag && !nv_isattr(np,NV_FPOSIX)) 1239 sfputr(file,"function",' '); 1240 sfputr(file,nv_name(np),-1); 1241 if(nv_isattr(np,NV_FPOSIX)) 1242 sfwrite(file,"()",2); 1243 if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1244 fname = np->nvalue.rp->fname; 1245 else 1246 flag = '\n'; 1247 if(flag) 1248 { 1249 if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1250 sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); 1251 else 1252 sfputc(file, '\n'); 1253 } 1254 else 1255 { 1256 if(nv_isattr(np,NV_FTMP)) 1257 { 1258 fname = 0; 1259 iop = tp->sh->heredocs; 1260 } 1261 else if(fname) 1262 iop = sfopen(iop,fname,"r"); 1263 else if(tp->sh->gd->hist_ptr) 1264 iop = (tp->sh->gd->hist_ptr)->histfp; 1265 if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) 1266 sfmove(iop,file, nv_size(np), -1); 1267 else 1268 flag = '\n'; 1269 if(fname) 1270 sfclose(iop); 1271 } 1272 return(nv_size(np)+1); 1273 } 1274 if(nv_arrayptr(np)) 1275 { 1276 if(indent) 1277 sfnputc(file,'\t',indent); 1278 print_value(file,np,tp); 1279 return(0); 1280 } 1281 if(nv_isvtree(np)) 1282 nv_onattr(np,NV_EXPORT); 1283 if(cp=nv_getval(np)) 1284 { 1285 if(indent) 1286 sfnputc(file,'\t',indent); 1287 sfputr(file,nv_name(np),-1); 1288 if(!flag) 1289 flag = '='; 1290 sfputc(file,flag); 1291 if(flag != '\n') 1292 { 1293 if(nv_isref(np) && nv_refsub(np)) 1294 { 1295 sfputr(file,sh_fmtq(cp),-1); 1296 sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); 1297 } 1298 else 1299#if SHOPT_TYPEDEF 1300 sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); 1301#else 1302 sfputr(file,sh_fmtq(cp),'\n'); 1303#endif /* SHOPT_TYPEDEF */ 1304 } 1305 return(1); 1306 } 1307 else if(outname || (tp->scanmask && tp->scanroot==tp->sh->var_tree)) 1308 sfputr(file,nv_name(np),'\n'); 1309 return(0); 1310} 1311 1312/* 1313 * print attributes at all nodes 1314 */ 1315static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) 1316{ 1317 tp->outfile = file; 1318 nv_scan(root, print_attribute, (void*)tp, 0, 0); 1319} 1320 1321/* 1322 * print the attributes of name value pair give by <np> 1323 */ 1324static void print_attribute(register Namval_t *np,void *data) 1325{ 1326 register struct tdata *dp = (struct tdata*)data; 1327 nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); 1328} 1329 1330/* 1331 * print the nodes in tree <root> which have attributes <flag> set 1332 * of <option> is non-zero, no subscript or value is printed. 1333 */ 1334 1335static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp) 1336{ 1337 register char **argv; 1338 register Namval_t *np; 1339 register int namec; 1340 Namval_t *onp = 0; 1341 tp->sh->last_table=0; 1342 flag &= ~NV_ASSIGN; 1343 tp->scanmask = flag&~NV_NOSCOPE; 1344 tp->scanroot = root; 1345 tp->outfile = file; 1346#if SHOPT_TYPEDEF 1347 if(!tp->prefix && tp->tp) 1348 tp->prefix = nv_name(tp->tp); 1349#endif /* SHOPT_TYPEDEF */ 1350 if(flag&NV_INTEGER) 1351 tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE); 1352 if(flag==NV_LTOU || flag==NV_UTOL) 1353 tp->scanmask |= NV_UTOL|NV_LTOU; 1354 namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag); 1355 argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*)); 1356 namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY); 1357 if(mbcoll()) 1358 strsort(argv,namec,strcoll); 1359 while(namec--) 1360 { 1361 if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))) 1362 { 1363 onp = np; 1364 if(flag&NV_ARRAY) 1365 { 1366 if(nv_aindex(np)>=0) 1367 { 1368 if(!(flag&NV_IARRAY)) 1369 continue; 1370 } 1371 else if((flag&NV_IARRAY)) 1372 continue; 1373 1374 } 1375 tp->scanmask = flag&~NV_NOSCOPE; 1376 tp->scanroot = root; 1377 print_namval(file,np,option,tp); 1378 } 1379 } 1380} 1381 1382/* 1383 * add the name of the node to the argument list argnam 1384 */ 1385 1386static void pushname(Namval_t *np,void *data) 1387{ 1388 struct tdata *tp = (struct tdata*)data; 1389 *tp->argnam++ = nv_name(np); 1390} 1391 1392