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 51 struct 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 62 int 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 } 167 bypass: 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 */ 190 static 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 204 int 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 /* FALLTHROUGH */ 595 case S_EOF: 596 /* check for end of buffer */ 597 if(val && *val) 598 { 599 stakputs(val); 600 use_stak = 1; 601 } 602 val = 0; 603 if(cp>=cpmax) 604 { 605 c = S_NL; 606 break; 607 } 608 /* eliminate null bytes */ 609 c = shp->ifstable[*cp++]; 610 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) 611 c = 0; 612 continue; 613 case S_NL: 614 if(was_escape) 615 { 616 was_escape = 0; 617 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 618 c = sfvalue(iop); 619 else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) 620 c = sfvalue(iop)+1; 621 if(cp) 622 { 623 if(flags&S_FLAG) 624 sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c); 625 cpmax = cp + c; 626 c = shp->ifstable[*cp++]; 627 val=0; 628 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) 629 c = 0; 630 continue; 631 } 632 } 633 c = S_NL; 634 break; 635 636 case S_SPACE: 637 /* skip over blanks */ 638 while((c=shp->ifstable[*cp++])==S_SPACE); 639 if(!val) 640 continue; 641 #if SHOPT_MULTIBYTE 642 if(c==S_MBYTE) 643 { 644 if(sh_strchr(ifs,(char*)cp-1)>=0) 645 { 646 if((c = mbsize((char*)cp-1))>1) 647 cp += (c-1); 648 c = S_DELIM; 649 } 650 else 651 c = 0; 652 } 653 #endif /* SHOPT_MULTIBYTE */ 654 if(c!=S_DELIM) 655 break; 656 /* FALL THRU */ 657 658 case S_DELIM: 659 if(!del) 660 del = cp - 1; 661 if(name) 662 { 663 /* skip over trailing blanks */ 664 while((c=shp->ifstable[*cp++])==S_SPACE); 665 break; 666 } 667 /* FALL THRU */ 668 669 case 0: 670 if(val==0 || was_escape) 671 { 672 val = (char*)(cp-1); 673 was_escape = 0; 674 } 675 /* skip over word characters */ 676 wrd = -1; 677 while(1) 678 { 679 while((c=shp->ifstable[*cp++])==0) 680 if(!wrd) 681 wrd = 1; 682 if(inquote) 683 { 684 if(c==S_QUOTE) 685 { 686 if(shp->ifstable[*cp]==S_QUOTE) 687 { 688 if(val) 689 { 690 stakwrite(val,cp-(unsigned char*)val); 691 use_stak = 1; 692 } 693 val = (char*)++cp; 694 } 695 else 696 break; 697 } 698 if(c && c!=S_EOF) 699 { 700 if(c==S_NL) 701 { 702 if(val) 703 { 704 stakwrite(val,cp-(unsigned char*)val); 705 use_stak=1; 706 } 707 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 708 c = sfvalue(iop); 709 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 710 c = sfvalue(iop)+1; 711 val = (char*)cp; 712 } 713 continue; 714 } 715 } 716 if(!del&&c==S_DELIM) 717 del = cp - 1; 718 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) 719 break; 720 if(wrd<0) 721 wrd = 0; 722 } 723 if(wrd>0) 724 del = (unsigned char*)""; 725 if(c!=S_MBYTE) 726 cp[-1] = 0; 727 continue; 728 } 729 /* assign value and advance to next variable */ 730 if(!val) 731 val = ""; 732 if(use_stak) 733 { 734 stakputs(val); 735 stakputc(0); 736 val = stakptr(rel); 737 } 738 if(!name && *val) 739 { 740 /* strip off trailing space delimiters */ 741 register unsigned char *vp = (unsigned char*)val + strlen(val); 742 while(shp->ifstable[*--vp]==S_SPACE); 743 if(vp==del) 744 { 745 if(vp==(unsigned char*)val) 746 vp--; 747 else 748 while(shp->ifstable[*--vp]==S_SPACE); 749 } 750 vp[1] = 0; 751 } 752 if(nv_isattr(np, NV_RDONLY)) 753 { 754 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 755 jmpval = 1; 756 } 757 else 758 nv_putval(np,val,0); 759 val = 0; 760 del = 0; 761 if(use_stak) 762 { 763 stakseek(rel); 764 use_stak = 0; 765 } 766 if(array_index) 767 { 768 nv_putsub(np, NIL(char*), array_index++); 769 if(c!=S_NL) 770 continue; 771 name = *++names; 772 } 773 while(1) 774 { 775 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 776 { 777 nv_onattr(np,NV_EXPORT); 778 sh_envput(shp->env,np); 779 } 780 if(name) 781 { 782 nv_close(np); 783 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 784 name = *++names; 785 } 786 else 787 np = 0; 788 if(c!=S_NL) 789 break; 790 if(!np) 791 goto done; 792 if(nv_isattr(np, NV_RDONLY)) 793 { 794 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 795 jmpval = 1; 796 } 797 else 798 nv_putval(np, "", 0); 799 } 800 } 801 done: 802 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 803 sh_popcontext(shp,&buff); 804 if(was_write) 805 sfset(iop,SF_WRITE,1); 806 if(!was_share) 807 sfset(iop,SF_SHARE,0); 808 nv_close(np); 809 if((shp->fdstatus[fd]&IOTTY) && !keytrap) 810 tty_cooked(fd); 811 if(flags&S_FLAG) 812 hist_flush(shp->gd->hist_ptr); 813 if(jmpval > 1) 814 siglongjmp(*shp->jmplist,jmpval); 815 return(jmpval); 816 } 817 818