1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2012 AT&T Intellectual Property * 5* and is licensed under the * 6* Eclipse Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.eclipse.org/org/documents/epl-v10.html * 11* (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12* * 13* Information and Software Systems Research * 14* AT&T Research * 15* Florham Park NJ * 16* * 17* David Korn <dgk@research.att.com> * 18* * 19***********************************************************************/ 20#pragma prototyped 21/* 22 * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...] 23 * 24 * David Korn 25 * AT&T Labs 26 * 27 */ 28 29#include <ast.h> 30#include <error.h> 31#include "defs.h" 32#include "variables.h" 33#include "lexstates.h" 34#include "io.h" 35#include "name.h" 36#include "builtins.h" 37#include "history.h" 38#include "terminal.h" 39#include "edit.h" 40 41#define R_FLAG 1 /* raw mode */ 42#define S_FLAG 2 /* save in history file */ 43#define A_FLAG 4 /* read into array */ 44#define N_FLAG 8 /* fixed size read at most */ 45#define NN_FLAG 0x10 /* fixed size read exact */ 46#define V_FLAG 0x20 /* use default value */ 47#define C_FLAG 0x40 /* read into compound variable */ 48#define D_FLAG 8 /* must be number of bits for all flags */ 49#define SS_FLAG 0x80 /* read .csv format file */ 50 51struct read_save 52{ 53 char **argv; 54 char *prompt; 55 short fd; 56 short plen; 57 int flags; 58 ssize_t len; 59 long timeout; 60}; 61 62int b_read(int argc,char *argv[], Shbltin_t *context) 63{ 64 Sfdouble_t sec; 65 register char *name; 66 register int r, flags=0, fd=0; 67 register Shell_t *shp = context->shp; 68 ssize_t len=0; 69 long timeout = 1000*shp->st.tmout; 70 int save_prompt, fixargs=context->invariant; 71 struct read_save *rp; 72 static char default_prompt[3] = {ESC,ESC}; 73 rp = (struct read_save*)(context->data); 74 if(argc==0) 75 { 76 if(rp) 77 free((void*)rp); 78 return(0); 79 } 80 if(rp) 81 { 82 flags = rp->flags; 83 timeout = rp->timeout; 84 fd = rp->fd; 85 argv = rp->argv; 86 name = rp->prompt; 87 r = rp->plen; 88 goto bypass; 89 } 90 while((r = optget(argv,sh_optread))) switch(r) 91 { 92 case 'A': 93 flags |= A_FLAG; 94 break; 95 case 'C': 96 flags |= C_FLAG; 97 break; 98 case 't': 99 sec = sh_strnum(opt_info.arg, (char**)0,1); 100 timeout = sec ? 1000*sec : 1; 101 break; 102 case 'd': 103 if(opt_info.arg && *opt_info.arg!='\n') 104 { 105 char *cp = opt_info.arg; 106 flags &= ~((1<<D_FLAG)-1); 107 flags |= (mbchar(cp)<< D_FLAG); 108 } 109 break; 110 case 'p': 111 if((fd = shp->cpipe[0])<=0) 112 errormsg(SH_DICT,ERROR_exit(1),e_query); 113 break; 114 case 'n': case 'N': 115 flags &= ((1<<D_FLAG)-1); 116 flags |= (r=='n'?N_FLAG:NN_FLAG); 117 len = opt_info.num; 118 break; 119 case 'r': 120 flags |= R_FLAG; 121 break; 122 case 's': 123 /* save in history file */ 124 flags |= S_FLAG; 125 break; 126 case 'S': 127 flags |= SS_FLAG; 128 break; 129 case 'u': 130 fd = (int)opt_info.num; 131 if(sh_inuse(shp,fd)) 132 fd = -1; 133 break; 134 case 'v': 135 flags |= V_FLAG; 136 break; 137 case ':': 138 errormsg(SH_DICT,2, "%s", opt_info.arg); 139 break; 140 case '?': 141 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 142 break; 143 } 144 argv += opt_info.index; 145 if(error_info.errors) 146 errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); 147 if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK))) 148 r = sh_iocheckfd(shp,fd); 149 if(fd<0 || !(r&IOREAD)) 150 errormsg(SH_DICT,ERROR_system(1),e_file+4); 151 /* look for prompt */ 152 if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY)) 153 r = strlen(name++); 154 else 155 r = 0; 156 if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0))) 157 { 158 context->data = (void*)rp; 159 rp->fd = fd; 160 rp->flags = flags; 161 rp->timeout = timeout; 162 rp->argv = argv; 163 rp->prompt = name; 164 rp->plen = r; 165 rp->len = len; 166 } 167bypass: 168 shp->prompt = default_prompt; 169 if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR))) 170 { 171 memcpy(shp->prompt,name,r); 172 sfwrite(sfstderr,shp->prompt,r-1); 173 } 174 shp->timeout = 0; 175 save_prompt = shp->nextprompt; 176 shp->nextprompt = 0; 177 r=sh_readline(shp,argv,fd,flags,len,timeout); 178 shp->nextprompt = save_prompt; 179 if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd])))) 180 { 181 if(fd == shp->cpipe[0] && errno!=EINTR) 182 sh_pclose(shp->cpipe); 183 } 184 return(r); 185} 186 187/* 188 * here for read timeout 189 */ 190static void timedout(void *handle) 191{ 192 sfclrlock((Sfio_t*)handle); 193 sh_exit(1); 194} 195 196/* 197 * This is the code to read a line and to split it into tokens 198 * <names> is an array of variable names 199 * <fd> is the file descriptor 200 * <flags> is union of -A, -r, -s, and contains delimiter if not '\n' 201 * <timeout> is number of milli-seconds until timeout 202 */ 203 204int sh_readline(register Shell_t *shp,char **names, volatile int fd, int flags,ssize_t size,long timeout) 205{ 206 register ssize_t c; 207 register unsigned char *cp; 208 register Namval_t *np; 209 register char *name, *val; 210 register Sfio_t *iop; 211 Namfun_t *nfp; 212 char *ifs; 213 unsigned char *cpmax; 214 unsigned char *del; 215 char was_escape = 0; 216 char use_stak = 0; 217 volatile char was_write = 0; 218 volatile char was_share = 1; 219 volatile int keytrap; 220 int rel, wrd; 221 long array_index = 0; 222 void *timeslot=0; 223 int delim = '\n'; 224 int jmpval=0; 225 int binary; 226 int oflags=NV_ASSIGN|NV_VARNAME; 227 char inquote = 0; 228 struct checkpt buff; 229 Edit_t *ep = (struct edit*)shp->gd->ed_context; 230 if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd))) 231 return(1); 232 sh_stats(STAT_READS); 233 if(names && (name = *names)) 234 { 235 Namval_t *mp; 236 if(val= strchr(name,'?')) 237 *val = 0; 238 if(flags&C_FLAG) 239 oflags |= NV_ARRAY; 240 np = nv_open(name,shp->var_tree,oflags); 241 if(np && nv_isarray(np) && (mp=nv_opensub(np))) 242 np = mp; 243 if((flags&V_FLAG) && shp->gd->ed_context) 244 ((struct edit*)shp->gd->ed_context)->e_default = np; 245 if(flags&A_FLAG) 246 { 247 Namarr_t *ap; 248 flags &= ~A_FLAG; 249 array_index = 1; 250 if((ap=nv_arrayptr(np)) && !ap->fun) 251 ap->nelem++; 252 nv_unset(np); 253 if((ap=nv_arrayptr(np)) && !ap->fun) 254 ap->nelem--; 255 nv_putsub(np,NIL(char*),0L); 256 } 257 else if(flags&C_FLAG) 258 { 259 char *sp = np->nvenv; 260 delim = -1; 261 nv_unset(np); 262 if(!nv_isattr(np,NV_MINIMAL)) 263 np->nvenv = sp; 264 nv_setvtree(np); 265 } 266 else 267 name = *++names; 268 if(val) 269 *val = '?'; 270 } 271 else 272 { 273 name = 0; 274 if(dtvnext(shp->var_tree) || shp->namespace) 275 np = nv_open(nv_name(REPLYNOD),shp->var_tree,0); 276 else 277 np = REPLYNOD; 278 } 279 keytrap = ep?ep->e_keytrap:0; 280 if(size || (flags>>D_FLAG)) /* delimiter not new-line or fixed size read */ 281 { 282 if((shp->fdstatus[fd]&IOTTY) && !keytrap) 283 tty_raw(fd,1); 284 if(!(flags&(N_FLAG|NN_FLAG))) 285 { 286 delim = ((unsigned)flags)>>D_FLAG; 287 ep->e_nttyparm.c_cc[VEOL] = delim; 288 ep->e_nttyparm.c_lflag |= ISIG; 289 tty_set(fd,TCSADRAIN,&ep->e_nttyparm); 290 } 291 } 292 binary = nv_isattr(np,NV_BINARY); 293 if(!binary && !(flags&(N_FLAG|NN_FLAG))) 294 { 295 Namval_t *mp; 296 /* set up state table based on IFS */ 297 ifs = nv_getval(mp=sh_scoped(shp,IFSNOD)); 298 if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC) 299 shp->ifstable['\\'] = 0; 300 else if(!(flags&R_FLAG) && shp->ifstable['\\']==0) 301 shp->ifstable['\\'] = S_ESC; 302 if(delim>0) 303 shp->ifstable[delim] = S_NL; 304 if(delim!='\n') 305 { 306 shp->ifstable['\n'] = 0; 307 nv_putval(mp, ifs, NV_RDONLY); 308 } 309 shp->ifstable[0] = S_EOF; 310 if((flags&SS_FLAG)) 311 { 312 shp->ifstable['"'] = S_QUOTE; 313 shp->ifstable['\r'] = S_ERR; 314 } 315 } 316 sfclrerr(iop); 317 for(nfp=np->nvfun; nfp; nfp = nfp->next) 318 { 319 if(nfp->disc && nfp->disc->readf) 320 { 321 Namval_t *mp = nv_open(name,shp->var_tree,oflags|NV_NOREF); 322 if((c=(*nfp->disc->readf)(mp,iop,delim,nfp))>=0) 323 return(c); 324 } 325 } 326 if(binary && !(flags&(N_FLAG|NN_FLAG))) 327 { 328 flags |= NN_FLAG; 329 size = nv_size(np); 330 } 331 was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; 332 if(fd==0) 333 was_share = (sfset(iop,SF_SHARE,shp->redir0!=2)&SF_SHARE)!=0; 334 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 335 { 336 sh_pushcontext(shp,&buff,1); 337 jmpval = sigsetjmp(buff.buff,0); 338 if(jmpval) 339 goto done; 340 if(timeout) 341 timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop); 342 } 343 if(flags&(N_FLAG|NN_FLAG)) 344 { 345 char buf[256],*var=buf,*cur,*end,*up,*v; 346 /* reserved buffer */ 347 if((c=size)>=sizeof(buf)) 348 { 349 if(!(var = (char*)malloc(c+1))) 350 sh_exit(1); 351 end = var + c; 352 } 353 else 354 end = var + sizeof(buf) - 1; 355 up = cur = var; 356 if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0) 357 was_share = 1; 358 if(size==0) 359 { 360 cp = sfreserve(iop,0,0); 361 c = 0; 362 } 363 else 364 { 365 ssize_t m; 366 int f; 367 for (;;) 368 { 369 c = size; 370 if(keytrap) 371 { 372 cp = 0; 373 f = 0; 374 m = 0; 375 while(c-->0 && (buf[m]=ed_getchar(ep,0))) 376 m++; 377 if(m>0) 378 cp = (unsigned char*)buf; 379 } 380 else 381 { 382 f = 1; 383 if(cp = sfreserve(iop,c,SF_LOCKR)) 384 m = sfvalue(iop); 385 else if(flags&NN_FLAG) 386 { 387 c = size; 388 m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0; 389 f = 0; 390 } 391 else 392 { 393 c = sfvalue(iop); 394 m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0; 395 } 396 } 397 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) 398 { 399 *v++ = 0; 400 m = v-(char*)cp; 401 } 402 if((c=m)>size) 403 c = size; 404 if(c>0) 405 { 406 if(c > (end-cur)) 407 { 408 ssize_t cx = cur - var, ux = up - var; 409 m = (end - var) + (c - (end - cur)); 410 if (var == buf) 411 { 412 v = (char*)malloc(m+1); 413 var = memcpy(v, var, cur - var); 414 } 415 else 416 var = newof(var, char, m, 1); 417 end = var + m; 418 cur = var + cx; 419 up = var + ux; 420 } 421 if(cur!=(char*)cp) 422 memcpy((void*)cur,cp,c); 423 if(f) 424 sfread(iop,cp,c); 425 cur += c; 426#if SHOPT_MULTIBYTE 427 if(!binary && mbwide()) 428 { 429 int x; 430 int z; 431 432 mbinit(); 433 *cur = 0; 434 x = z = 0; 435 while (up < cur && (z = mbsize(up)) > 0) 436 { 437 up += z; 438 x++; 439 } 440 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c)) 441 continue; 442 } 443#endif 444 } 445#if SHOPT_MULTIBYTE 446 if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size)) 447 cur = var; 448#endif 449 *cur = 0; 450 if(c>=size || (flags&N_FLAG) || m==0) 451 { 452 if(m) 453 sfclrerr(iop); 454 break; 455 } 456 size -= c; 457 } 458 } 459 if(timeslot) 460 timerdel(timeslot); 461 if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) 462 { 463 if((c==size) && np->nvalue.cp && !nv_isarray(np)) 464 memcpy((char*)np->nvalue.cp,var,c); 465 else 466 { 467 Namval_t *mp; 468 if(var==buf) 469 var = memdup(var,c+1); 470 nv_putval(np,var,NV_RAW); 471 nv_setsize(np,c); 472 if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv)) 473 nv_setsize(mp,c); 474 } 475 } 476 else 477 { 478 nv_putval(np,var,0); 479 if(var!=buf) 480 free((void*)var); 481 } 482 goto done; 483 } 484 else if(cp = (unsigned char*)sfgetr(iop,delim,0)) 485 c = sfvalue(iop); 486 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 487 { 488 c = sfvalue(iop)+1; 489 if(!sferror(iop) && sfgetc(iop) >=0) 490 errormsg(SH_DICT,ERROR_exit(1),e_overlimit,"line length"); 491 } 492 if(timeslot) 493 timerdel(timeslot); 494 if((flags&S_FLAG) && !shp->gd->hist_ptr) 495 { 496 sh_histinit((void*)shp); 497 if(!shp->gd->hist_ptr) 498 flags &= ~S_FLAG; 499 } 500 if(cp) 501 { 502 cpmax = cp + c; 503#if SHOPT_CRNL 504 if(delim=='\n' && c>=2 && cpmax[-2]=='\r') 505 cpmax--; 506#endif /* SHOPT_CRNL */ 507 if(*(cpmax-1) != delim) 508 *(cpmax-1) = delim; 509 if(flags&S_FLAG) 510 sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c); 511 c = shp->ifstable[*cp++]; 512#if !SHOPT_MULTIBYTE 513 if(!name && (flags&R_FLAG)) /* special case single argument */ 514 { 515 /* skip over leading blanks */ 516 while(c==S_SPACE) 517 c = shp->ifstable[*cp++]; 518 /* strip trailing delimiters */ 519 if(cpmax[-1] == '\n') 520 cpmax--; 521 if(cpmax>cp) 522 { 523 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); 524 cpmax[1] = 0; 525 } 526 else 527 *cpmax =0; 528 if(nv_isattr(np, NV_RDONLY)) 529 { 530 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 531 jmpval = 1; 532 } 533 else 534 nv_putval(np,(char*)cp-1,0); 535 goto done; 536 } 537#endif /* !SHOPT_MULTIBYTE */ 538 } 539 else 540 c = S_NL; 541 shp->nextprompt = 2; 542 rel= staktell(); 543 /* val==0 at the start of a field */ 544 val = 0; 545 del = 0; 546 while(1) 547 { 548 switch(c) 549 { 550#if SHOPT_MULTIBYTE 551 case S_MBYTE: 552 if(val==0) 553 val = (char*)(cp-1); 554 if(sh_strchr(ifs,(char*)cp-1)>=0) 555 { 556 c = mbsize((char*)cp-1); 557 if(name) 558 cp[-1] = 0; 559 if(c>1) 560 cp += (c-1); 561 c = S_DELIM; 562 } 563 else 564 c = 0; 565 continue; 566#endif /*SHOPT_MULTIBYTE */ 567 case S_QUOTE: 568 c = shp->ifstable[*cp++]; 569 inquote = !inquote; 570 if(val) 571 { 572 stakputs(val); 573 use_stak = 1; 574 *val = 0; 575 } 576 continue; 577 case S_ESC: 578 /* process escape character */ 579 if((c = shp->ifstable[*cp++]) == S_NL) 580 was_escape = 1; 581 else 582 c = 0; 583 if(val) 584 { 585 stakputs(val); 586 use_stak = 1; 587 was_escape = 1; 588 *val = 0; 589 } 590 continue; 591 592 case S_ERR: 593 cp++; 594 case S_EOF: 595 /* check for end of buffer */ 596 if(val && *val) 597 { 598 stakputs(val); 599 use_stak = 1; 600 } 601 val = 0; 602 if(cp>=cpmax) 603 { 604 c = S_NL; 605 break; 606 } 607 /* eliminate null bytes */ 608 c = shp->ifstable[*cp++]; 609 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) 610 c = 0; 611 continue; 612 case S_NL: 613 if(was_escape) 614 { 615 was_escape = 0; 616 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 617 c = sfvalue(iop); 618 else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) 619 c = sfvalue(iop)+1; 620 if(cp) 621 { 622 if(flags&S_FLAG) 623 sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c); 624 cpmax = cp + c; 625 c = shp->ifstable[*cp++]; 626 val=0; 627 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) 628 c = 0; 629 continue; 630 } 631 } 632 c = S_NL; 633 break; 634 635 case S_SPACE: 636 /* skip over blanks */ 637 while((c=shp->ifstable[*cp++])==S_SPACE); 638 if(!val) 639 continue; 640#if SHOPT_MULTIBYTE 641 if(c==S_MBYTE) 642 { 643 if(sh_strchr(ifs,(char*)cp-1)>=0) 644 { 645 if((c = mbsize((char*)cp-1))>1) 646 cp += (c-1); 647 c = S_DELIM; 648 } 649 else 650 c = 0; 651 } 652#endif /* SHOPT_MULTIBYTE */ 653 if(c!=S_DELIM) 654 break; 655 /* FALL THRU */ 656 657 case S_DELIM: 658 if(!del) 659 del = cp - 1; 660 if(name) 661 { 662 /* skip over trailing blanks */ 663 while((c=shp->ifstable[*cp++])==S_SPACE); 664 break; 665 } 666 /* FALL THRU */ 667 668 case 0: 669 if(val==0 || was_escape) 670 { 671 val = (char*)(cp-1); 672 was_escape = 0; 673 } 674 /* skip over word characters */ 675 wrd = -1; 676 while(1) 677 { 678 while((c=shp->ifstable[*cp++])==0) 679 if(!wrd) 680 wrd = 1; 681 if(inquote) 682 { 683 if(c==S_QUOTE) 684 { 685 if(shp->ifstable[*cp]==S_QUOTE) 686 { 687 if(val) 688 { 689 stakwrite(val,cp-(unsigned char*)val); 690 use_stak = 1; 691 } 692 val = (char*)++cp; 693 } 694 else 695 break; 696 } 697 if(c && c!=S_EOF) 698 { 699 if(c==S_NL) 700 { 701 if(val) 702 { 703 stakwrite(val,cp-(unsigned char*)val); 704 use_stak=1; 705 } 706 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 707 c = sfvalue(iop); 708 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 709 c = sfvalue(iop)+1; 710 val = (char*)cp; 711 } 712 continue; 713 } 714 } 715 if(!del&&c==S_DELIM) 716 del = cp - 1; 717 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) 718 break; 719 if(wrd<0) 720 wrd = 0; 721 } 722 if(wrd>0) 723 del = (unsigned char*)""; 724 if(c!=S_MBYTE) 725 cp[-1] = 0; 726 continue; 727 } 728 /* assign value and advance to next variable */ 729 if(!val) 730 val = ""; 731 if(use_stak) 732 { 733 stakputs(val); 734 stakputc(0); 735 val = stakptr(rel); 736 } 737 if(!name && *val) 738 { 739 /* strip off trailing space delimiters */ 740 register unsigned char *vp = (unsigned char*)val + strlen(val); 741 while(shp->ifstable[*--vp]==S_SPACE); 742 if(vp==del) 743 { 744 if(vp==(unsigned char*)val) 745 vp--; 746 else 747 while(shp->ifstable[*--vp]==S_SPACE); 748 } 749 vp[1] = 0; 750 } 751 if(nv_isattr(np, NV_RDONLY)) 752 { 753 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 754 jmpval = 1; 755 } 756 else 757 nv_putval(np,val,0); 758 val = 0; 759 del = 0; 760 if(use_stak) 761 { 762 stakseek(rel); 763 use_stak = 0; 764 } 765 if(array_index) 766 { 767 nv_putsub(np, NIL(char*), array_index++); 768 if(c!=S_NL) 769 continue; 770 name = *++names; 771 } 772 while(1) 773 { 774 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 775 { 776 nv_onattr(np,NV_EXPORT); 777 sh_envput(shp->env,np); 778 } 779 if(name) 780 { 781 nv_close(np); 782 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 783 name = *++names; 784 } 785 else 786 np = 0; 787 if(c!=S_NL) 788 break; 789 if(!np) 790 goto done; 791 if(nv_isattr(np, NV_RDONLY)) 792 { 793 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 794 jmpval = 1; 795 } 796 else 797 nv_putval(np, "", 0); 798 } 799 } 800done: 801 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 802 sh_popcontext(shp,&buff); 803 if(was_write) 804 sfset(iop,SF_WRITE,1); 805 if(!was_share) 806 sfset(iop,SF_SHARE,0); 807 nv_close(np); 808 if((shp->fdstatus[fd]&IOTTY) && !keytrap) 809 tty_cooked(fd); 810 if(flags&S_FLAG) 811 hist_flush(shp->gd->hist_ptr); 812 if(jmpval > 1) 813 siglongjmp(*shp->jmplist,jmpval); 814 return(jmpval); 815} 816 817