Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/bltins/read.c
1810 views
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 <[email protected]> *
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
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
}
800
done:
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
818