1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2009 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 (at) 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 = (n=='X'?2*sizeof(Sfdouble_t):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 else if(nv_isnull(tdata.tp)) 393 nv_newtype(tdata.tp); 394 tdata.tp->nvenv = tdata.help; 395 flag &= ~NV_TYPE; 396 } 397 else if(tdata.aflag==0 && ntp && ntp->tp) 398 tdata.aflag = '-'; 399 if(!tdata.sh->mktype) 400 tdata.help = 0; 401 return(b_common(argv,flag,troot,&tdata)); 402 } 403 404 static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) 405 { 406 char *name; 407 int aflag=tp->aflag; 408 if(nv_isnull(np)) 409 { 410 if(!np->nvflag) 411 return; 412 aflag = '+'; 413 } 414 sfputr(iop,nv_name(np),aflag=='+'?'\n':'='); 415 if(aflag=='+') 416 return; 417 if(nv_isarray(np) && nv_arrayptr(np)) 418 { 419 nv_outnode(np,iop,-1,0); 420 sfwrite(iop,")\n",2); 421 } 422 else 423 { 424 if(nv_isvtree(np)) 425 nv_onattr(np,NV_EXPORT); 426 if(!(name = nv_getval(np))) 427 name = Empty; 428 if(!nv_isvtree(np)) 429 name = sh_fmtq(name); 430 sfputr(iop,name,'\n'); 431 } 432 } 433 434 static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata *tp) 435 { 436 register char *name; 437 char *last = 0; 438 int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); 439 int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); 440 Shell_t *shp =tp->sh; 441 if(!shp->prefix) 442 { 443 if(!tp->pflag) 444 nvflags |= NV_NOSCOPE; 445 } 446 else if(*shp->prefix==0) 447 shp->prefix = 0; 448 flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); 449 if(argv[1]) 450 { 451 if(flag&NV_REF) 452 { 453 flag &= ~NV_REF; 454 ref=1; 455 if(tp->aflag!='-') 456 nvflags |= NV_NOREF; 457 } 458 if(tp->pflag) 459 nvflags |= NV_NOREF; 460 while(name = *++argv) 461 { 462 register unsigned newflag; 463 register Namval_t *np; 464 unsigned curflag; 465 if(troot == shp->fun_tree) 466 { 467 /* 468 *functions can be exported or 469 * traced but not set 470 */ 471 flag &= ~NV_ASSIGN; 472 if(flag&NV_LTOU) 473 { 474 /* Function names cannot be special builtin */ 475 if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) 476 errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); 477 np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); 478 } 479 else if((np=nv_search(name,troot,0)) && !is_afunction(np)) 480 np = 0; 481 if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) 482 { 483 if(flag==0) 484 { 485 print_namval(sfstdout,np,tp->aflag=='+',tp); 486 continue; 487 } 488 if(shp->subshell && !shp->subshare) 489 sh_subfork(); 490 if(tp->aflag=='-') 491 nv_onattr(np,flag|NV_FUNCTION); 492 else if(tp->aflag=='+') 493 nv_offattr(np,flag); 494 } 495 else 496 r++; 497 if(tp->help) 498 { 499 int offset = stktell(shp->stk); 500 sfputr(shp->stk,shp->prefix,'.'); 501 sfputr(shp->stk,name,0); 502 if((np=nv_search(stkptr(shp->stk,offset),troot,0)) && np->nvalue.cp) 503 np->nvalue.rp->help = tp->help; 504 stkseek(shp->stk,offset); 505 } 506 continue; 507 } 508 /* tracked alias */ 509 if(troot==shp->track_tree && tp->aflag=='-') 510 { 511 np = nv_search(name,troot,NV_ADD); 512 path_alias(np,path_absolute(nv_name(np),NIL(Pathcomp_t*))); 513 continue; 514 } 515 np = nv_open(name,troot,nvflags|NV_ARRAY); 516 if(tp->pflag) 517 { 518 nv_attribute(np,sfstdout,tp->prefix,1); 519 print_value(sfstdout,np,tp); 520 continue; 521 } 522 if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) 523 { 524 if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) 525 { 526 sfprintf(sfstderr,sh_translate(e_noalias),name); 527 r++; 528 } 529 if(!comvar && !iarray) 530 continue; 531 } 532 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))) 533 _nv_unset(np,0); 534 if(troot==shp->var_tree) 535 { 536 if(iarray) 537 { 538 if(tp->tname) 539 nv_atypeindex(np,tp->tname+1); 540 else if(nv_isnull(np)) 541 nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0)); 542 else 543 nv_putsub(np, (char*)0, 0); 544 } 545 else if(nvflags&NV_ARRAY) 546 { 547 if(comvar) 548 { 549 Namarr_t *ap=nv_arrayptr(np); 550 if(ap) 551 ap->nelem |= ARRAY_TREE; 552 else 553 { 554 _nv_unset(np,NV_RDONLY); 555 nv_onattr(np,NV_NOFREE); 556 } 557 } 558 nv_setarray(np,nv_associative); 559 } 560 else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR)) 561 nv_setvtree(np); 562 } 563 if(flag&NV_MOVE) 564 { 565 nv_rename(np, flag); 566 nv_close(np); 567 continue; 568 } 569 if(tp->tp && nv_type(np)!=tp->tp) 570 { 571 nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); 572 flag = (np->nvflag&NV_NOCHANGE); 573 } 574 curflag = np->nvflag; 575 flag &= ~NV_ASSIGN; 576 if(last=strchr(name,'=')) 577 *last = 0; 578 if (shp->typeinit) 579 continue; 580 if (tp->aflag == '-') 581 { 582 if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np))) 583 errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); 584 #if SHOPT_BSH 585 if(flag&NV_EXPORT) 586 nv_offattr(np,NV_IMPORT); 587 #endif /* SHOPT_BSH */ 588 newflag = curflag; 589 if(flag&~NV_NOCHANGE) 590 newflag &= NV_NOCHANGE; 591 newflag |= flag; 592 if (flag & (NV_LJUST|NV_RJUST)) 593 { 594 if(!(flag&NV_RJUST)) 595 newflag &= ~NV_RJUST; 596 597 else if(!(flag&NV_LJUST)) 598 newflag &= ~NV_LJUST; 599 } 600 if(!(flag&NV_INTEGER)) 601 { 602 if (flag & NV_UTOL) 603 newflag &= ~NV_LTOU; 604 else if (flag & NV_LTOU) 605 newflag &= ~NV_UTOL; 606 } 607 } 608 else 609 { 610 if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) 611 errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); 612 newflag = curflag & ~flag; 613 } 614 if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) 615 { 616 if(shp->subshell) 617 sh_assignok(np,1); 618 if(troot!=shp->var_tree) 619 nv_setattr(np,newflag&~NV_ASSIGN); 620 else 621 { 622 char *oldname=0; 623 int len=strlen(name); 624 if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 625 tp->argnum = 10; 626 /* use reference name for export */ 627 if((newflag^curflag)&NV_EXPORT) 628 { 629 oldname = np->nvname; 630 np->nvname = name; 631 } 632 if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') 633 newflag |= NV_NODISC; 634 nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); 635 if(oldname) 636 np->nvname = oldname; 637 } 638 } 639 if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) 640 { 641 np->nvenv = tp->help; 642 nv_onattr(np,NV_EXPORT); 643 } 644 if(last) 645 *last = '='; 646 /* set or unset references */ 647 if(ref) 648 { 649 if(tp->aflag=='-') 650 { 651 Dt_t *hp=0; 652 if(nv_isattr(np,NV_PARAM) && shp->st.prevst) 653 { 654 if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) 655 hp = dtvnext(shp->var_tree); 656 } 657 if(tp->sh->mktype) 658 nv_onattr(np,NV_REF|NV_FUNCT); 659 else 660 nv_setref(np,hp,NV_VARNAME); 661 } 662 else 663 nv_unref(np); 664 } 665 nv_close(np); 666 } 667 } 668 else if(!tp->sh->envlist) 669 { 670 if(shp->prefix) 671 errormsg(SH_DICT,2, "%s: compound assignment requires sub-variable name",shp->prefix); 672 if(tp->aflag) 673 { 674 if(troot==shp->fun_tree) 675 { 676 flag |= NV_FUNCTION; 677 tp->prefix = 0; 678 } 679 else if(troot==shp->var_tree) 680 { 681 flag |= (nvflags&NV_ARRAY); 682 if(flag&NV_IARRAY) 683 flag |= NV_ARRAY; 684 } 685 print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); 686 } 687 else if(troot==shp->alias_tree) 688 print_scan(sfstdout,0,troot,0,tp); 689 else 690 print_all(sfstdout,troot,tp); 691 sfsync(sfstdout); 692 } 693 return(r); 694 } 695 696 typedef void (*Iptr_t)(int,void*); 697 typedef int (*Fptr_t)(int, char*[], void*); 698 699 #define GROWLIB 4 700 701 static void **liblist; 702 static unsigned short *libattr; 703 static int nlib; 704 static int maxlib; 705 706 /* 707 * This allows external routines to load from the same library */ 708 void **sh_getliblist(void) 709 { 710 return(liblist); 711 } 712 713 /* 714 * add library to loaded list 715 * call (*lib_init)() on first load if defined 716 * always move to head of search list 717 * return: 0: already loaded 1: first load 718 */ 719 #if SHOPT_DYNAMIC 720 int sh_addlib(void* library) 721 { 722 register int n; 723 register int r; 724 Iptr_t initfn; 725 Shbltin_t *sp = &sh.bltindata; 726 727 sp->nosfio = 0; 728 for (n = r = 0; n < nlib; n++) 729 { 730 if (r) 731 { 732 liblist[n-1] = liblist[n]; 733 libattr[n-1] = libattr[n]; 734 } 735 else if (liblist[n] == library) 736 r++; 737 } 738 if (r) 739 nlib--; 740 else if ((initfn = (Iptr_t)dlllook(library, "lib_init"))) 741 (*initfn)(0,sp); 742 if (nlib >= maxlib) 743 { 744 maxlib += GROWLIB; 745 if (liblist) 746 { 747 liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**)); 748 libattr = (unsigned short*)realloc((void*)liblist, (maxlib+1)*sizeof(unsigned short*)); 749 } 750 else 751 { 752 liblist = (void**)malloc((maxlib+1)*sizeof(void**)); 753 libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short*)); 754 } 755 } 756 libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0); 757 liblist[nlib++] = library; 758 liblist[nlib] = 0; 759 return !r; 760 } 761 #else 762 int sh_addlib(void* library) 763 { 764 return 0; 765 } 766 #endif /* SHOPT_DYNAMIC */ 767 768 /* 769 * add change or list built-ins 770 * adding builtins requires dlopen() interface 771 */ 772 int b_builtin(int argc,char *argv[],void *extra) 773 { 774 register char *arg=0, *name; 775 register int n, r=0, flag=0; 776 register Namval_t *np; 777 long dlete=0; 778 struct tdata tdata; 779 Fptr_t addr; 780 Stk_t *stkp; 781 void *library=0; 782 char *errmsg; 783 NOT_USED(argc); 784 memset(&tdata,0,sizeof(tdata)); 785 tdata.sh = ((Shbltin_t*)extra)->shp; 786 stkp = tdata.sh->stk; 787 if(!tdata.sh->pathlist) 788 path_absolute(argv[0],NIL(Pathcomp_t*)); 789 while (n = optget(argv,sh_optbuiltin)) switch (n) 790 { 791 case 's': 792 flag = BLT_SPC; 793 break; 794 case 'd': 795 dlete=1; 796 break; 797 case 'f': 798 #if SHOPT_DYNAMIC 799 arg = opt_info.arg; 800 #else 801 errormsg(SH_DICT,2, "adding built-ins not supported"); 802 error_info.errors++; 803 #endif /* SHOPT_DYNAMIC */ 804 break; 805 case ':': 806 errormsg(SH_DICT,2, "%s", opt_info.arg); 807 break; 808 case '?': 809 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 810 break; 811 } 812 argv += opt_info.index; 813 if(error_info.errors) 814 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); 815 if(arg || *argv) 816 { 817 if(sh_isoption(SH_RESTRICTED)) 818 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); 819 if(sh_isoption(SH_PFSH)) 820 errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); 821 if(tdata.sh->subshell && !tdata.sh->subshare) 822 sh_subfork(); 823 } 824 #if SHOPT_DYNAMIC 825 if(arg) 826 { 827 #if (_AST_VERSION>=20040404) 828 if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 829 #else 830 if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) 831 #endif 832 { 833 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); 834 return(1); 835 } 836 sh_addlib(library); 837 } 838 else 839 #endif /* SHOPT_DYNAMIC */ 840 if(*argv==0 && !dlete) 841 { 842 print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); 843 return(0); 844 } 845 r = 0; 846 flag = stktell(stkp); 847 while(arg = *argv) 848 { 849 name = path_basename(arg); 850 sfwrite(stkp,"b_",2); 851 sfputr(stkp,name,0); 852 errmsg = 0; 853 addr = 0; 854 for(n=(nlib?nlib:dlete); --n>=0;) 855 { 856 /* (char*) added for some sgi-mips compilers */ 857 #if SHOPT_DYNAMIC 858 if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stkptr(stkp,flag)))) 859 #else 860 if(dlete) 861 #endif /* SHOPT_DYNAMIC */ 862 { 863 if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) 864 { 865 if(dlete || nv_isattr(np,BLT_SPC)) 866 errmsg = "restricted name"; 867 else 868 nv_onattr(np,libattr[n]); 869 } 870 break; 871 } 872 } 873 if(!dlete && !addr) 874 { 875 np = sh_addbuiltin(arg, 0 ,0); 876 if(np && nv_isattr(np,BLT_SPC)) 877 errmsg = "restricted name"; 878 else if(!np) 879 errmsg = "not found"; 880 } 881 if(errmsg) 882 { 883 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); 884 r = 1; 885 } 886 stkseek(stkp,flag); 887 argv++; 888 } 889 return(r); 890 } 891 892 int b_set(int argc,register char *argv[],void *extra) 893 { 894 struct tdata tdata; 895 memset(&tdata,0,sizeof(tdata)); 896 tdata.sh = ((Shbltin_t*)extra)->shp; 897 tdata.prefix=0; 898 if(argv[1]) 899 { 900 if(sh_argopts(argc,argv,tdata.sh) < 0) 901 return(2); 902 if(sh_isoption(SH_VERBOSE)) 903 sh_onstate(SH_VERBOSE); 904 else 905 sh_offstate(SH_VERBOSE); 906 if(sh_isoption(SH_MONITOR)) 907 sh_onstate(SH_MONITOR); 908 else 909 sh_offstate(SH_MONITOR); 910 } 911 else 912 /*scan name chain and print*/ 913 print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); 914 return(0); 915 } 916 917 /* 918 * The removing of Shell variable names, aliases, and functions 919 * is performed here. 920 * Unset functions with unset -f 921 * Non-existent items being deleted give non-zero exit status 922 */ 923 924 int b_unalias(int argc,register char *argv[],void *extra) 925 { 926 Shell_t *shp = ((Shbltin_t*)extra)->shp; 927 return(b_unall(argc,argv,shp->alias_tree,shp)); 928 } 929 930 int b_unset(int argc,register char *argv[],void *extra) 931 { 932 Shell_t *shp = ((Shbltin_t*)extra)->shp; 933 return(b_unall(argc,argv,shp->var_tree,shp)); 934 } 935 936 static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) 937 { 938 register Namval_t *np; 939 register const char *name; 940 register int r; 941 Dt_t *dp; 942 int nflag=0,all=0,isfun,jmpval; 943 struct checkpt buff; 944 NOT_USED(argc); 945 if(troot==shp->alias_tree) 946 { 947 name = sh_optunalias; 948 if(shp->subshell) 949 troot = sh_subaliastree(0); 950 } 951 else 952 name = sh_optunset; 953 while(r = optget(argv,name)) switch(r) 954 { 955 case 'f': 956 troot = sh_subfuntree(1); 957 break; 958 case 'a': 959 all=1; 960 break; 961 case 'n': 962 nflag = NV_NOREF; 963 case 'v': 964 troot = shp->var_tree; 965 break; 966 case ':': 967 errormsg(SH_DICT,2, "%s", opt_info.arg); 968 break; 969 case '?': 970 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 971 return(2); 972 } 973 argv += opt_info.index; 974 if(error_info.errors || (*argv==0 &&!all)) 975 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 976 if(!troot) 977 return(1); 978 r = 0; 979 if(troot==shp->var_tree) 980 nflag |= NV_VARNAME; 981 else 982 nflag = NV_NOSCOPE; 983 if(all) 984 { 985 dtclear(troot); 986 return(r); 987 } 988 sh_pushcontext(&buff,1); 989 while(name = *argv++) 990 { 991 jmpval = sigsetjmp(buff.buff,0); 992 np = 0; 993 if(jmpval==0) 994 np=nv_open(name,troot,NV_NOADD|nflag); 995 else 996 { 997 r = 1; 998 continue; 999 } 1000 if(np) 1001 { 1002 if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY)) 1003 { 1004 if(nv_isattr(np,NV_RDONLY)) 1005 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 1006 r = 1; 1007 continue; 1008 } 1009 isfun = is_afunction(np); 1010 if(troot==shp->var_tree) 1011 { 1012 if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) 1013 { 1014 r=1; 1015 continue; 1016 } 1017 1018 if(shp->subshell) 1019 np=sh_assignok(np,0); 1020 } 1021 if(!nv_isnull(np)) 1022 nv_unset(np); 1023 nv_close(np); 1024 if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) 1025 nv_delete(np,dp,NV_NOFREE); 1026 else if(isfun) 1027 nv_delete(np,troot,NV_NOFREE); 1028 } 1029 } 1030 sh_popcontext(&buff); 1031 return(r); 1032 } 1033 1034 /* 1035 * print out the name and value of a name-value pair <np> 1036 */ 1037 1038 static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) 1039 { 1040 register char *cp; 1041 sh_sigcheck(); 1042 if(flag) 1043 flag = '\n'; 1044 if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) 1045 { 1046 if(is_abuiltin(np)) 1047 sfputr(file,nv_name(np),'\n'); 1048 return(0); 1049 } 1050 if(tp->prefix) 1051 { 1052 if(*tp->prefix=='t') 1053 nv_attribute(np,tp->outfile,tp->prefix,tp->aflag); 1054 else 1055 sfputr(file,tp->prefix,' '); 1056 } 1057 if(is_afunction(np)) 1058 { 1059 Sfio_t *iop=0; 1060 char *fname=0; 1061 if(!flag && !np->nvalue.ip) 1062 sfputr(file,"typeset -fu",' '); 1063 else if(!flag && !nv_isattr(np,NV_FPOSIX)) 1064 sfputr(file,"function",' '); 1065 sfputr(file,nv_name(np),-1); 1066 if(nv_isattr(np,NV_FPOSIX)) 1067 sfwrite(file,"()",2); 1068 if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1069 fname = np->nvalue.rp->fname; 1070 else 1071 flag = '\n'; 1072 if(flag) 1073 { 1074 if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0) 1075 sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); 1076 else 1077 sfputc(file, '\n'); 1078 } 1079 else 1080 { 1081 if(nv_isattr(np,NV_FTMP)) 1082 { 1083 fname = 0; 1084 iop = tp->sh->heredocs; 1085 } 1086 else if(fname) 1087 iop = sfopen(iop,fname,"r"); 1088 else if(tp->sh->hist_ptr) 1089 iop = (tp->sh->hist_ptr)->histfp; 1090 if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) 1091 sfmove(iop,file, nv_size(np), -1); 1092 else 1093 flag = '\n'; 1094 if(fname) 1095 sfclose(iop); 1096 } 1097 return(nv_size(np)+1); 1098 } 1099 if(nv_arrayptr(np)) 1100 { 1101 print_value(file,np,tp); 1102 return(0); 1103 } 1104 if(nv_isvtree(np)) 1105 nv_onattr(np,NV_EXPORT); 1106 if(cp=nv_getval(np)) 1107 { 1108 sfputr(file,nv_name(np),-1); 1109 if(!flag) 1110 flag = '='; 1111 sfputc(file,flag); 1112 if(flag != '\n') 1113 { 1114 if(nv_isref(np) && nv_refsub(np)) 1115 { 1116 sfputr(file,sh_fmtq(cp),-1); 1117 sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); 1118 } 1119 else 1120 #if SHOPT_TYPEDEF 1121 sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); 1122 #else 1123 sfputr(file,sh_fmtq(cp),'\n'); 1124 #endif /* SHOPT_TYPEDEF */ 1125 } 1126 return(1); 1127 } 1128 else if(tp->scanmask && tp->scanroot==tp->sh->var_tree) 1129 sfputr(file,nv_name(np),'\n'); 1130 return(0); 1131 } 1132 1133 /* 1134 * print attributes at all nodes 1135 */ 1136 static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) 1137 { 1138 tp->outfile = file; 1139 nv_scan(root, print_attribute, (void*)tp, 0, 0); 1140 } 1141 1142 /* 1143 * print the attributes of name value pair give by <np> 1144 */ 1145 static void print_attribute(register Namval_t *np,void *data) 1146 { 1147 register struct tdata *dp = (struct tdata*)data; 1148 nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); 1149 } 1150 1151 /* 1152 * print the nodes in tree <root> which have attributes <flag> set 1153 * of <option> is non-zero, no subscript or value is printed. 1154 */ 1155 1156 static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp) 1157 { 1158 register char **argv; 1159 register Namval_t *np; 1160 register int namec; 1161 Namval_t *onp = 0; 1162 tp->sh->last_table=0; 1163 flag &= ~NV_ASSIGN; 1164 tp->scanmask = flag&~NV_NOSCOPE; 1165 tp->scanroot = root; 1166 tp->outfile = file; 1167 #if SHOPT_TYPEDEF 1168 if(!tp->prefix && tp->tp) 1169 tp->prefix = nv_name(tp->tp); 1170 #endif /* SHOPT_TYPEDEF */ 1171 if(flag&NV_INTEGER) 1172 tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE); 1173 namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag); 1174 argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*)); 1175 namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY); 1176 if(mbcoll()) 1177 strsort(argv,namec,strcoll); 1178 while(namec--) 1179 { 1180 if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))) 1181 { 1182 onp = np; 1183 if(flag&NV_ARRAY) 1184 { 1185 if(nv_aindex(np)>=0) 1186 { 1187 if(!(flag&NV_IARRAY)) 1188 continue; 1189 } 1190 else if((flag&NV_IARRAY)) 1191 continue; 1192 1193 } 1194 print_namval(file,np,option,tp); 1195 } 1196 } 1197 } 1198 1199 /* 1200 * add the name of the node to the argument list argnam 1201 */ 1202 1203 static void pushname(Namval_t *np,void *data) 1204 { 1205 struct tdata *tp = (struct tdata*)data; 1206 *tp->argnam++ = nv_name(np); 1207 } 1208 1209