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
b_read(int argc,char * argv[],Shbltin_t * context)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 */
timedout(void * handle)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
sh_readline(register Shell_t * shp,char ** names,volatile int fd,int flags,ssize_t size,long timeout)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