1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2008 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 45 struct tdata 46 { 47 Shell_t *sh; 48 Namval_t *tp; 49 Sfio_t *outfile; 50 char *prefix; 51 char *tname; 52 char *help; 53 short aflag; 54 short pflag; 55 int argnum; 56 int scanmask; 57 Dt_t *scanroot; 58 char **argnam; 59 }; 60 61 62 static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); 63 static void print_attribute(Namval_t*,void*); 64 static void print_all(Sfio_t*, Dt_t*, struct tdata*); 65 static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*); 66 static int b_unall(int, char**, Dt_t*, Shell_t*); 67 static int b_common(char**, int, Dt_t*, struct tdata*); 68 static void pushname(Namval_t*,void*); 69 static void(*nullscan)(Namval_t*,void*); 70 71 static Namval_t *load_class(const char *name) 72 { 73 errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name); 74 return(0); 75 } 76 77 /* 78 * Note export and readonly are the same 79 */ 80 #if 0 81 /* for the dictionary generator */ 82 int b_export(int argc,char *argv[],void *extra){} 83 #endif 84 int b_readonly(int argc,char *argv[],void *extra) 85 { 86 register int flag; 87 char *command = argv[0]; 88 struct tdata tdata; 89 NOT_USED(argc); 90 memset((void*)&tdata,0,sizeof(tdata)); 91 tdata.sh = ((Shbltin_t*)extra)->shp; 92 tdata.aflag = '-'; 93 while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag) 94 { 95 case 'p': 96 tdata.prefix = command; 97 break; 98 case ':': 99 errormsg(SH_DICT,2, "%s", opt_info.arg); 100 break; 101 case '?': 102 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 103 return(2); 104 } 105 if(error_info.errors) 106 errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); 107 argv += (opt_info.index-1); 108 if(*command=='r') 109 flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME); 110 #ifdef _ENV_H 111 else if(!argv[1]) 112 { 113 char *cp,**env=env_get(tdata.sh->env); 114 while(cp = *env++) 115 { 116 if(tdata.prefix) 117 sfputr(sfstdout,tdata.prefix,' '); 118 sfprintf(sfstdout,"%s\n",sh_fmtq(cp)); 119 } 120 return(0); 121 } 122 #endif 123 else 124 { 125 flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT); 126 if(!tdata.sh->prefix) 127 tdata.sh->prefix = ""; 128 } 129 return(b_common(argv,flag,tdata.sh->var_tree, &tdata)); 130 } 131 132 133 int b_alias(int argc,register char *argv[],void *extra) 134 { 135 register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN; 136 register Dt_t *troot; 137 register int n; 138 struct tdata tdata; 139 NOT_USED(argc); 140 memset((void*)&tdata,0,sizeof(tdata)); 141 tdata.sh = ((Shbltin_t*)extra)->shp; 142 troot = tdata.sh->alias_tree; 143 if(*argv[0]=='h') 144 flag = NV_TAGGED; 145 if(argv[1]) 146 { 147 opt_info.offset = 0; 148 opt_info.index = 1; 149 *opt_info.option = 0; 150 tdata.argnum = 0; 151 tdata.aflag = *argv[1]; 152 while((n = optget(argv,sh_optalias))) switch(n) 153 { 154 case 'p': 155 tdata.prefix = argv[0]; 156 break; 157 case 't': 158 flag |= NV_TAGGED; 159 break; 160 case 'x': 161 flag |= NV_EXPORT; 162 break; 163 case ':': 164 errormsg(SH_DICT,2, "%s", opt_info.arg); 165 break; 166 case '?': 167 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 168 return(2); 169 } 170 if(error_info.errors) 171 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 172 argv += (opt_info.index-1); 173 if(flag&NV_TAGGED) 174 { 175 /* hacks to handle hash -r | -- */ 176 if(argv[1] && argv[1][0]=='-') 177 { 178 if(argv[1][1]=='r' && argv[1][2]==0) 179 { 180 nv_putval(PATHNOD,nv_getval(PATHNOD),NV_RDONLY); 181 argv++; 182 if(!argv[1]) 183 return(0); 184 } 185 if(argv[1][0]=='-') 186 { 187 if(argv[1][1]=='-' && argv[1][2]==0) 188 argv++; 189 else 190 errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]); 191 } 192 } 193 troot = tdata.sh->track_tree; 194 } 195 } 196 return(b_common(argv,flag,troot,&tdata)); 197 } 198 199 200 #if 0 201 /* for the dictionary generator */ 202 int b_local(int argc,char *argv[],void *extra){} 203 #endif 204 int b_typeset(int argc,register char *argv[],void *extra) 205 { 206 register int n, flag = NV_VARNAME|NV_ASSIGN; 207 struct tdata tdata; 208 const char *optstring = sh_opttypeset; 209 Namdecl_t *ntp = (Namdecl_t*)((Shbltin_t*)extra)->ptr; 210 Dt_t *troot; 211 int isfloat=0, shortint=0, sflag=0; 212 NOT_USED(argc); 213 memset((void*)&tdata,0,sizeof(tdata)); 214 tdata.sh = ((Shbltin_t*)extra)->shp; 215 if(ntp) 216 { 217 tdata.tp = ntp->tp; 218 opt_info.disc = (Optdisc_t*)ntp->optinfof; 219 optstring = ntp->optstring; 220 } 221 troot = tdata.sh->var_tree; 222 while((n = optget(argv,optstring))) 223 { 224 switch(n) 225 { 226 case 'a': 227 flag |= NV_IARRAY; 228 if(opt_info.arg && *opt_info.arg!='[') 229 { 230 opt_info.index--; 231 goto endargs; 232 } 233 tdata.tname = opt_info.arg; 234 break; 235 case 'A': 236 flag |= NV_ARRAY; 237 break; 238 case 'C': 239 flag |= NV_COMVAR; 240 break; 241 case 'E': 242 /* The following is for ksh88 compatibility */ 243 if(opt_info.offset && !strchr(argv[opt_info.index],'E')) 244 { 245 tdata.argnum = (int)opt_info.num; 246 break; 247 } 248 case 'F': 249 case 'X': 250 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 251 tdata.argnum = 10; 252 isfloat = 1; 253 if(n=='E') 254 { 255 flag &= ~NV_HEXFLOAT; 256 flag |= NV_EXPNOTE; 257 } 258 else if(n=='X') 259 { 260 flag &= ~NV_EXPNOTE; 261 flag |= NV_HEXFLOAT; 262 } 263 break; 264 case 'b': 265 flag |= NV_BINARY; 266 break; 267 case 'm': 268 flag |= NV_MOVE; 269 break; 270 case 'n': 271 flag &= ~NV_VARNAME; 272 flag |= (NV_REF|NV_IDENT); 273 break; 274 case 'H': 275 flag |= NV_HOST; 276 break; 277 case 'T': 278 flag |= NV_TYPE; 279 tdata.prefix = opt_info.arg; 280 break; 281 case 'L': case 'Z': case 'R': 282 if(tdata.argnum==0) 283 tdata.argnum = (int)opt_info.num; 284 if(tdata.argnum < 0) 285 errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); 286 if(n=='Z') 287 flag |= NV_ZFILL; 288 else 289 { 290 flag &= ~(NV_LJUST|NV_RJUST); 291 flag |= (n=='L'?NV_LJUST:NV_RJUST); 292 } 293 break; 294 case 'f': 295 flag &= ~(NV_VARNAME|NV_ASSIGN); 296 troot = tdata.sh->fun_tree; 297 break; 298 case 'i': 299 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) 300 tdata.argnum = 10; 301 flag |= NV_INTEGER; 302 break; 303 case 'l': 304 flag |= NV_UTOL; 305 break; 306 case 'p': 307 tdata.prefix = argv[0]; 308 tdata.pflag = 1; 309 break; 310 case 'r': 311 flag |= NV_RDONLY; 312 break; 313 #ifdef SHOPT_TYPEDEF 314 case 'S': 315 sflag=1; 316 break; 317 case 'h': 318 tdata.help = opt_info.arg; 319 break; 320 #endif /*SHOPT_TYPEDEF*/ 321 case 's': 322 shortint=1; 323 break; 324 case 't': 325 flag |= NV_TAGGED; 326 break; 327 case 'u': 328 flag |= NV_LTOU; 329 break; 330 case 'x': 331 flag &= ~NV_VARNAME; 332 flag |= (NV_EXPORT|NV_IDENT); 333 break; 334 case ':': 335 errormsg(SH_DICT,2, "%s", opt_info.arg); 336 break; 337 case '?': 338 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 339 opt_info.disc = 0; 340 return(2); 341 } 342 if(tdata.aflag==0) 343 tdata.aflag = *opt_info.option; 344 } 345 endargs: 346 argv += opt_info.index; 347 opt_info.disc = 0; 348 /* handle argument of + and - specially */ 349 if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-')) 350 tdata.aflag = *argv[0]; 351 else 352 argv--; 353 if((flag&NV_ZFILL) && !(flag&NV_LJUST)) 354 flag |= NV_RJUST; 355 if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) 356 error_info.errors++; 357 if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) 358 error_info.errors++; 359 if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN))) 360 error_info.errors++; 361 if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN))) 362 error_info.errors++; 363 if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU)))) 364 error_info.errors++; 365 if(error_info.errors) 366 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 367 if(isfloat) 368 flag |= NV_DOUBLE; 369 if(shortint) 370 flag |= NV_SHORT|NV_INTEGER; 371 if(sflag) 372 { 373 if(tdata.sh->mktype) 374 flag |= NV_REF|NV_TAGGED; 375 else if(!tdata.sh->typeinit) 376 flag |= NV_STATIC|NV_IDENT; 377 } 378 if(tdata.sh->fn_depth && !tdata.pflag) 379 flag |= NV_NOSCOPE; 380 if(flag&NV_TYPE) 381 { 382 Stk_t *stkp = tdata.sh->stk; 383 int offset = stktell(stkp); 384 sfputr(stkp,NV_CLASS,-1); 385 if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') 386 sfputc(stkp,'.'); 387 sfputr(stkp,tdata.prefix,0); 388 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); 389 stkseek(stkp,offset); 390 if(!tdata.tp) 391 errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); 392 tdata.tp->nvenv = tdata.help; 393 flag &= ~NV_TYPE; 394 } 395 else if(tdata.aflag==0 && ntp && ntp->tp) 396 tdata.aflag = '-'; 397 if(!tdata.sh->mktype) 398 tdata.help = 0; 399 return(b_common(argv,flag,troot,&tdata)); 400 } 401 402 static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) 403 { 404 char *name; 405 if(nv_isnull(np)) 406 return; 407 sfputr(iop,nv_name(np),tp->aflag=='+'?'\n':'='); 408 if(tp->aflag=='+') 409 return; 410 if(nv_isarray(np) && nv_arrayptr(np)) 411 { 412 nv_outnode(np,iop,-1,0); 413 sfwrite(iop,")\n",2); 414 } 415 else 416 { 417 if(nv_isvtree(np)) 418 nv_onattr(np,NV_EXPORT); 419 if(!(name = nv_getval(np))) 420 name = Empty; 421 if(!nv_isvtree(np)) 422 name = sh_fmtq(name); 423 sfputr(iop,name,'\n'); 424 } 425 } 426 427 static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata *tp) 428 { 429 register char *name; 430 char *last = 0; 431 int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); 432 int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); 433 Shell_t *shp =tp->sh; 434 if(!shp->prefix) 435 { 436 if(!tp->pflag) 437 nvflags |= NV_NOSCOPE; 438 } 439 else if(*shp->prefix==0) 440 shp->prefix = 0; 441 flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); 442 if(argv[1]) 443 { 444 if(flag&NV_REF) 445 { 446 flag &= ~NV_REF; 447 ref=1; 448 if(tp->aflag!='-') 449 nvflags |= NV_NOREF; 450 } 451 if(tp->pflag) 452 nvflags |= NV_NOREF; 453 while(name = *++argv) 454 { 455 register unsigned newflag; 456 register Namval_t *np; 457 unsigned curflag; 458 if(troot == shp->fun_tree) 459 { 460 /* 461 *functions can be exported or 462 * traced but not set 463 */ 464 flag &= ~NV_ASSIGN; 465 if(flag&NV_LTOU) 466 { 467 /* Function names cannot be special builtin */ 468 if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) 469 errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); 470 np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); 471 } 472 else if((np=nv_search(name,troot,0)) && !is_afunction(np)) 473 np = 0; 474 if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) 475 { 476 if(flag==0) 477 { 478 print_namval(sfstdout,np,tp->aflag=='+',tp); 479 continue; 480 } 481 if(shp->subshell) 482 sh_subfork(); 483 if(tp->aflag=='-') 484 nv_onattr(np,flag|NV_FUNCTION); 485 else if(tp->aflag=='+') 486 nv_offattr(np,flag); 487 } 488 else 489 r++; 490 if(tp->help) 491 { 492 int offset = stktell(shp->stk); 493 sfputr(shp->stk,shp->prefix,'.'); 494 sfputr(shp->stk,name,0); 495 if((np=nv_search(stkptr(shp->stk,offset),troot,0)) && np->nvalue.cp) 496 np->nvalue.rp->help = tp->help; 497 stkseek(shp->stk,offset); 498 } 499 continue; 500 } 501 /* tracked alias */ 502 if(troot==shp->track_tree && tp->aflag=='-') 503 { 504 np = nv_search(name,troot,NV_ADD); 505 path_alias(np,path_absolute(nv_name(np),NIL(Pathcomp_t*))); 506 continue; 507 } 508 np = nv_open(name,troot,nvflags|NV_ARRAY); 509 if(tp->pflag) 510 { 511 nv_attribute(np,sfstdout,tp->prefix,1); 512 print_value(sfstdout,np,tp); 513 continue; 514 } 515 if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) 516 { 517 if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) 518 { 519 sfprintf(sfstderr,sh_translate(e_noalias),name); 520 r++; 521 } 522 if(!comvar && !iarray) 523 continue; 524 } 525 if(troot==shp->var_tree && ((tp->tp && !nv_isarray(np)) || !shp->st.real_fun && (nvflags&NV_STATIC)) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name))) 526 _nv_unset(np,0); 527 if(troot==shp->var_tree) 528 { 529 if(iarray) 530 { 531 if(tp->tname) 532 nv_atypeindex(np,tp->tname+1); 533 else if(nv_isnull(np)) 534 nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0)); 535 else 536 nv_putsub(np, (char*)0, 0); 537 } 538 else if(nvflags&NV_ARRAY) 539 { 540 if(comvar) 541 { 542 _nv_unset(np,NV_RDONLY); 543 nv_onattr(np,NV_NOFREE); 544 } 545 nv_setarray(np,nv_associative); 546 } 547 else if(comvar && !nv_rename(np,flag|NV_COMVAR)) 548 nv_setvtree(np); 549 } 550 if(flag&NV_MOVE) 551 { 552 nv_rename(np, flag); 553 nv_close(np); 554 continue; 555 } 556 if(tp->tp) 557 { 558 nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); 559 flag = (np->nvflag&NV_NOCHANGE); 560 } 561 curflag = np->nvflag; 562 flag &= ~NV_ASSIGN; 563 if(last=strchr(name,'=')) 564 *last = 0; 565 if (tp->aflag == '-') 566 { 567 if((flag&NV_EXPORT) && strchr(name,'.')) 568 errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); 569 #if SHOPT_BSH 570 if(flag&NV_EXPORT) 571 nv_offattr(np,NV_IMPORT); 572 #endif /* SHOPT_BSH */ 573 newflag = curflag; 574 if(flag&~NV_NOCHANGE) 575 newflag &= NV_NOCHANGE; 576 newflag |= flag; 577 if (flag & (NV_LJUST|NV_RJUST)) 578 { 579 if(!(flag&NV_RJUST)) 580 newflag &= ~NV_RJUST; 581 582 else if(!(flag&NV_LJUST)) 583 newflag &= ~NV_LJUST; 584 } 585 if(!(flag&NV_INTEGER)) 586 { 587 if (flag & NV_UTOL) 588 newflag &= ~NV_LTOU; 589 else if (flag & NV_LTOU) 590 newflag &= ~NV_UTOL; 591 } 592 } 593 else 594 { 595 if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) 596 errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); 597 newflag = curflag & ~flag; 598 } 599 if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) 600 { 601 if(shp->subshell) 602 sh_assignok(np,1); 603 if(troot!=shp->var_tree) 604 nv_setattr(np,newflag&~NV_ASSIGN); 605 else 606 { 607 char *oldname=0; 608 int len=strlen(name); 609 if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 610 tp->argnum = 10; 611 /* use reference name for export */ 612 if((newflag^curflag)&NV_EXPORT) 613 { 614 oldname = np->nvname; 615 np->nvname = name; 616 } 617 if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') 618 newflag |= NV_NODISC; 619 nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); 620 if(oldname) 621 np->nvname = oldname; 622 } 623 } 624 if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) 625 { 626 np->nvenv = tp->help; 627 nv_onattr(np,NV_EXPORT); 628 } 629 if(last) 630 *last = '='; 631 /* set or unset references */ 632 if(ref) 633 { 634 if(tp->aflag=='-') 635 { 636 Dt_t *hp=0; 637 if(nv_isattr(np,NV_PARAM) && shp->st.prevst) 638 { 639 if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) 640 hp = dtvnext(shp->var_tree); 641 } 642 if(tp->sh->mktype) 643 nv_onattr(np,NV_REF|NV_FUNCT); 644 else 645 nv_setref(np,hp,NV_VARNAME); 646 } 647 else 648 nv_unref(np); 649 } 650 nv_close(np); 651 } 652 } 653 else if(!tp->sh->envlist) 654 { 655 if(shp->prefix) 656 errormsg(SH_DICT,2, "%s: compound assignment requires sub-variable name",shp->prefix); 657 if(tp->aflag) 658 { 659 if(troot==shp->fun_tree) 660 { 661 flag |= NV_FUNCTION; 662 tp->prefix = 0; 663 } 664 else if(troot==shp->var_tree) 665 { 666 flag |= (nvflags&NV_ARRAY); 667 if(flag&NV_IARRAY) 668 flag |= NV_ARRAY; 669 } 670 print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); 671 } 672 else if(troot==shp->alias_tree) 673 print_scan(sfstdout,0,troot,0,tp); 674 else 675 print_all(sfstdout,troot,tp); 676 sfsync(sfstdout); 677 } 678 return(r); 679 } 680 681 typedef void (*Iptr_t)(int,void*); 682 typedef int (*Fptr_t)(int, char*[], void*); 683 684 #define GROWLIB 4 685 686 static void **liblist; 687 static unsigned short *libattr; 688 static int nlib; 689 static int maxlib; 690 691 /* 692 * This allows external routines to load from the same library */ 693 void **sh_getliblist(void) 694 { 695 return(liblist); 696 } 697 698 /* 699 * add library to loaded list 700 * call (*lib_init)() on first load if defined 701 * always move to head of search list 702 * return: 0: already loaded 1: first load 703 */ 704 #if SHOPT_DYNAMIC 705 int sh_addlib(void* library) 706 { 707 register int n; 708 register int r; 709 Iptr_t initfn; 710 Shbltin_t *sp = &sh.bltindata; 711 712 sp->nosfio = 0; 713 for (n = r = 0; n < nlib; n++) 714 { 715 if (r) 716 { 717 liblist[n-1] = liblist[n]; 718 libattr[n-1] = libattr[n]; 719 } 720 else if (liblist[n] == library) 721 r++; 722 } 723 if (r) 724 nlib--; 725 else if ((initfn = (Iptr_t)dlllook(library, "lib_init"))) 726 (*initfn)(0,sp); 727 if (nlib >= maxlib) 728 { 729 maxlib += GROWLIB; 730 if (liblist) 731 { 732 liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**)); 733 libattr = (unsigned short*)realloc((void*)liblist, (maxlib+1)*sizeof(unsigned short*)); 734 } 735 else 736 { 737 liblist = (void**)malloc((maxlib+1)*sizeof(void**)); 738 libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short*)); 739 } 740 } 741 libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0); 742 liblist[nlib++] = library; 743 liblist[nlib] = 0; 744 return !r; 745 } 746 #else 747 int sh_addlib(void* library) 748 { 749 return 0; 750 } 751 #endif /* SHOPT_DYNAMIC */ 752 753 /* 754 * add change or list built-ins 755 * adding builtins requires dlopen() interface 756 */ 757 int b_builtin(int argc,char *argv[],void *extra) 758 { 759 register char *arg=0, *name; 760 register int n, r=0, flag=0; 761 register Namval_t *np; 762 long dlete=0; 763 struct tdata tdata; 764 Fptr_t addr; 765 Stk_t *stkp; 766 void *library=0; 767 char *errmsg; 768 NOT_USED(argc); 769 memset(&tdata,0,sizeof(tdata)); 770 tdata.sh = ((Shbltin_t*)extra)->shp; 771 stkp = tdata.sh->stk; 772 while (n = optget(argv,sh_optbuiltin)) switch (n) 773 { 774 case 's': 775 flag = BLT_SPC; 776 break; 777 case 'd': 778 dlete=1; 779 break; 780 case 'f': 781 #if SHOPT_DYNAMIC 782 arg = opt_info.arg; 783 #else 784 errormsg(SH_DICT,2, "adding built-ins not supported"); 785 error_info.errors++; 786 #endif /* SHOPT_DYNAMIC */ 787 break; 788 case ':': 789 errormsg(SH_DICT,2, "%s", opt_info.arg); 790 break; 791 case '?': 792 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 793 break; 794 } 795 argv += opt_info.index; 796 if(error_info.errors) 797 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 798 if(arg || *argv) 799 { 800 if(sh_isoption(SH_RESTRICTED)) 801 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); 802 if(sh_isoption(SH_PFSH)) 803 errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); 804 if(tdata.sh->subshell) 805 sh_subfork(); 806 } 807 #if SHOPT_DYNAMIC 808 if(arg) 809 { 810 #if (_AST_VERSION>=20040404) 811 if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 812 #else 813 if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 814 #endif 815 { 816 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); 817 return(1); 818 } 819 sh_addlib(library); 820 } 821 else 822 #endif /* SHOPT_DYNAMIC */ 823 if(*argv==0 && !dlete) 824 { 825 print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); 826 return(0); 827 } 828 r = 0; 829 flag = stktell(stkp); 830 while(arg = *argv) 831 { 832 name = path_basename(arg); 833 sfwrite(stkp,"b_",2); 834 sfputr(stkp,name,0); 835 errmsg = 0; 836 addr = 0; 837 for(n=(nlib?nlib:dlete); --n>=0;) 838 { 839 /* (char*) added for some sgi-mips compilers */ 840 #if SHOPT_DYNAMIC 841 if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stkptr(stkp,flag)))) 842 #else 843 if(dlete) 844 #endif /* SHOPT_DYNAMIC */ 845 { 846 if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) 847 { 848 if(dlete || nv_isattr(np,BLT_SPC)) 849 errmsg = "restricted name"; 850 else 851 nv_onattr(np,libattr[n]); 852 } 853 break; 854 } 855 } 856 if(!dlete && !addr) 857 { 858 np = sh_addbuiltin(arg, 0 ,0); 859 if(np && nv_isattr(np,BLT_SPC)) 860 errmsg = "restricted name"; 861 else if(!np) 862 errmsg = "not found"; 863 } 864 if(errmsg) 865 { 866 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); 867 r = 1; 868 } 869 stkseek(stkp,flag); 870 argv++; 871 } 872 return(r); 873 } 874 875 int b_set(int argc,register char *argv[],void *extra) 876 { 877 struct tdata tdata; 878 memset(&tdata,0,sizeof(tdata)); 879 tdata.sh = ((Shbltin_t*)extra)->shp; 880 tdata.prefix=0; 881 if(argv[1]) 882 { 883 if(sh_argopts(argc,argv,tdata.sh) < 0) 884 return(2); 885 if(sh_isoption(SH_VERBOSE)) 886 sh_onstate(SH_VERBOSE); 887 else 888 sh_offstate(SH_VERBOSE); 889 if(sh_isoption(SH_MONITOR)) 890 sh_onstate(SH_MONITOR); 891 else 892 sh_offstate(SH_MONITOR); 893 } 894 else 895 /*scan name chain and print*/ 896 print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); 897 return(0); 898 } 899 900 /* 901 * The removing of Shell variable names, aliases, and functions 902 * is performed here. 903 * Unset functions with unset -f 904 * Non-existent items being deleted give non-zero exit status 905 */ 906 907 int b_unalias(int argc,register char *argv[],void *extra) 908 { 909 Shell_t *shp = ((Shbltin_t*)extra)->shp; 910 return(b_unall(argc,argv,shp->alias_tree,shp)); 911 } 912 913 int b_unset(int argc,register char *argv[],void *extra) 914 { 915 Shell_t *shp = ((Shbltin_t*)extra)->shp; 916 return(b_unall(argc,argv,shp->var_tree,shp)); 917 } 918 919 static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) 920 { 921 register Namval_t *np; 922 register const char *name; 923 register int r; 924 Dt_t *dp; 925 int nflag=0,all=0,isfun; 926 NOT_USED(argc); 927 if(troot==shp->alias_tree) 928 { 929 name = sh_optunalias; 930 if(shp->subshell) 931 troot = sh_subaliastree(0); 932 } 933 else 934 name = sh_optunset; 935 while(r = optget(argv,name)) switch(r) 936 { 937 case 'f': 938 troot = sh_subfuntree(1); 939 break; 940 case 'a': 941 all=1; 942 break; 943 case 'n': 944 nflag = NV_NOREF; 945 case 'v': 946 troot = shp->var_tree; 947 break; 948 case ':': 949 errormsg(SH_DICT,2, "%s", opt_info.arg); 950 break; 951 case '?': 952 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 953 return(2); 954 } 955 argv += opt_info.index; 956 if(error_info.errors || (*argv==0 &&!all)) 957 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 958 if(!troot) 959 return(1); 960 r = 0; 961 if(troot==shp->var_tree) 962 nflag |= NV_VARNAME; 963 else 964 nflag = NV_NOSCOPE; 965 if(all) 966 dtclear(troot); 967 else while(name = *argv++) 968 { 969 if(np=nv_open(name,troot,NV_NOADD|NV_NOFAIL|nflag)) 970 { 971 if(is_abuiltin(np)) 972 { 973 r = 1; 974 continue; 975 } 976 isfun = is_afunction(np); 977 if(troot==shp->var_tree) 978 { 979 if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) 980 { 981 r=1; 982 continue; 983 } 984 985 if(shp->subshell) 986 np=sh_assignok(np,0); 987 } 988 nv_unset(np); 989 nv_close(np); 990 if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) 991 nv_delete(np,dp,NV_NOFREE); 992 else if(isfun) 993 nv_delete(np,troot,NV_NOFREE); 994 } 995 else 996 r = 1; 997 } 998 return(r); 999 } 1000 1001 /* 1002 * print out the name and value of a name-value pair <np> 1003 */ 1004 1005 static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) 1006 { 1007 register char *cp; 1008 sh_sigcheck(); 1009 if(flag) 1010 flag = '\n'; 1011 if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) 1012 { 1013 if(is_abuiltin(np)) 1014 sfputr(file,nv_name(np),'\n'); 1015 return(0); 1016 } 1017 if(tp->prefix) 1018 { 1019 if(*tp->prefix=='t') 1020 nv_attribute(np,tp->outfile,tp->prefix,tp->aflag); 1021 else 1022 sfputr(file,tp->prefix,' '); 1023 } 1024 if(is_afunction(np)) 1025 { 1026 Sfio_t *iop=0; 1027 char *fname=0; 1028 if(!flag && !np->nvalue.ip) 1029 sfputr(file,"typeset -fu",' '); 1030 else if(!flag && !nv_isattr(np,NV_FPOSIX)) 1031 sfputr(file,"function",' '); 1032 sfputr(file,nv_name(np),-1); 1033 if(nv_isattr(np,NV_FPOSIX)) 1034 sfwrite(file,"()",2); 1035 if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1036 fname = np->nvalue.rp->fname; 1037 else 1038 flag = '\n'; 1039 if(flag) 1040 { 1041 if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1042 sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); 1043 else 1044 sfputc(file, '\n'); 1045 } 1046 else 1047 { 1048 if(nv_isattr(np,NV_FTMP)) 1049 { 1050 fname = 0; 1051 iop = tp->sh->heredocs; 1052 } 1053 else if(fname) 1054 iop = sfopen(iop,fname,"r"); 1055 else if(tp->sh->hist_ptr) 1056 iop = (tp->sh->hist_ptr)->histfp; 1057 if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) 1058 sfmove(iop,file, nv_size(np), -1); 1059 else 1060 flag = '\n'; 1061 if(fname) 1062 sfclose(iop); 1063 } 1064 return(nv_size(np)+1); 1065 } 1066 if(nv_arrayptr(np)) 1067 { 1068 print_value(file,np,tp); 1069 return(0); 1070 } 1071 if(nv_isvtree(np)) 1072 nv_onattr(np,NV_EXPORT); 1073 if(cp=nv_getval(np)) 1074 { 1075 sfputr(file,nv_name(np),-1); 1076 if(!flag) 1077 flag = '='; 1078 sfputc(file,flag); 1079 if(flag != '\n') 1080 { 1081 if(nv_isref(np) && nv_refsub(np)) 1082 { 1083 sfputr(file,sh_fmtq(cp),-1); 1084 sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); 1085 } 1086 else 1087 #if SHOPT_TYPEDEF 1088 sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); 1089 #else 1090 sfputr(file,sh_fmtq(cp),'\n'); 1091 #endif /* SHOPT_TYPEDEF */ 1092 } 1093 return(1); 1094 } 1095 else if(tp->scanmask && tp->scanroot==tp->sh->var_tree) 1096 sfputr(file,nv_name(np),'\n'); 1097 return(0); 1098 } 1099 1100 /* 1101 * print attributes at all nodes 1102 */ 1103 static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) 1104 { 1105 tp->outfile = file; 1106 nv_scan(root, print_attribute, (void*)tp, 0, 0); 1107 } 1108 1109 /* 1110 * print the attributes of name value pair give by <np> 1111 */ 1112 static void print_attribute(register Namval_t *np,void *data) 1113 { 1114 register struct tdata *dp = (struct tdata*)data; 1115 nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); 1116 } 1117 1118 /* 1119 * print the nodes in tree <root> which have attributes <flag> set 1120 * of <option> is non-zero, no subscript or value is printed. 1121 */ 1122 1123 static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp) 1124 { 1125 register char **argv; 1126 register Namval_t *np; 1127 register int namec; 1128 Namval_t *onp = 0; 1129 tp->sh->last_table=0; 1130 flag &= ~NV_ASSIGN; 1131 tp->scanmask = flag&~NV_NOSCOPE; 1132 tp->scanroot = root; 1133 tp->outfile = file; 1134 #if SHOPT_TYPEDEF 1135 if(!tp->prefix && tp->tp) 1136 tp->prefix = nv_name(tp->tp); 1137 #endif /* SHOPT_TYPEDEF */ 1138 if(flag&NV_INTEGER) 1139 tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE); 1140 namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag); 1141 argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*)); 1142 namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY); 1143 if(mbcoll()) 1144 strsort(argv,namec,strcoll); 1145 while(namec--) 1146 { 1147 if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))) 1148 { 1149 onp = np; 1150 if(flag&NV_ARRAY) 1151 { 1152 if(nv_aindex(np)>=0) 1153 { 1154 if(!(flag&NV_IARRAY)) 1155 continue; 1156 } 1157 else if((flag&NV_IARRAY)) 1158 continue; 1159 1160 } 1161 print_namval(file,np,option,tp); 1162 } 1163 } 1164 } 1165 1166 /* 1167 * add the name of the node to the argument list argnam 1168 */ 1169 1170 static void pushname(Namval_t *np,void *data) 1171 { 1172 struct tdata *tp = (struct tdata*)data; 1173 *tp->argnam++ = nv_name(np); 1174 } 1175 1176