1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1982-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...]
1N/A *
1N/A * David Korn
1N/A * AT&T Labs
1N/A *
1N/A */
1N/A
1N/A#include <ast.h>
1N/A#include <error.h>
1N/A#include "defs.h"
1N/A#include "variables.h"
1N/A#include "lexstates.h"
1N/A#include "io.h"
1N/A#include "name.h"
1N/A#include "builtins.h"
1N/A#include "history.h"
1N/A#include "terminal.h"
1N/A#include "edit.h"
1N/A
1N/A#define R_FLAG 1 /* raw mode */
1N/A#define S_FLAG 2 /* save in history file */
1N/A#define A_FLAG 4 /* read into array */
1N/A#define N_FLAG 8 /* fixed size read at most */
1N/A#define NN_FLAG 0x10 /* fixed size read exact */
1N/A#define V_FLAG 0x20 /* use default value */
1N/A#define C_FLAG 0x40 /* read into compound variable */
1N/A#define D_FLAG 8 /* must be number of bits for all flags */
1N/A
1N/Astruct read_save
1N/A{
1N/A char **argv;
1N/A char *prompt;
1N/A short fd;
1N/A short plen;
1N/A int flags;
1N/A long timeout;
1N/A};
1N/A
1N/Aint b_read(int argc,char *argv[], void *extra)
1N/A{
1N/A Sfdouble_t sec;
1N/A register char *name;
1N/A register int r, flags=0, fd=0;
1N/A register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1N/A long timeout = 1000*shp->st.tmout;
1N/A int save_prompt, fixargs=((Shbltin_t*)extra)->invariant;
1N/A struct read_save *rp;
1N/A static char default_prompt[3] = {ESC,ESC};
1N/A rp = (struct read_save*)(((Shbltin_t*)extra)->data);
1N/A if(argc==0)
1N/A {
1N/A if(rp)
1N/A free((void*)rp);
1N/A return(0);
1N/A }
1N/A if(rp)
1N/A {
1N/A flags = rp->flags;
1N/A timeout = rp->timeout;
1N/A fd = rp->fd;
1N/A argv = rp->argv;
1N/A name = rp->prompt;
1N/A r = rp->plen;
1N/A goto bypass;
1N/A }
1N/A while((r = optget(argv,sh_optread))) switch(r)
1N/A {
1N/A case 'A':
1N/A flags |= A_FLAG;
1N/A break;
1N/A case 'C':
1N/A flags |= C_FLAG;
1N/A break;
1N/A case 't':
1N/A sec = sh_strnum(opt_info.arg, (char**)0,1);
1N/A timeout = sec ? 1000*sec : 1;
1N/A break;
1N/A case 'd':
1N/A if(opt_info.arg && *opt_info.arg!='\n')
1N/A {
1N/A char *cp = opt_info.arg;
1N/A flags &= ~((1<<D_FLAG)-1);
1N/A flags |= (mbchar(cp)<< D_FLAG);
1N/A }
1N/A break;
1N/A case 'p':
1N/A if((fd = shp->cpipe[0])<=0)
1N/A errormsg(SH_DICT,ERROR_exit(1),e_query);
1N/A break;
1N/A case 'n': case 'N':
1N/A flags &= ((1<<D_FLAG)-1);
1N/A flags |= (r=='n'?N_FLAG:NN_FLAG);
1N/A r = (int)opt_info.num;
1N/A if((unsigned)r > (1<<((8*sizeof(int))-D_FLAG))-1)
1N/A errormsg(SH_DICT,ERROR_exit(1),e_overlimit,opt_info.name);
1N/A flags |= (r<< D_FLAG);
1N/A break;
1N/A case 'r':
1N/A flags |= R_FLAG;
1N/A break;
1N/A case 's':
1N/A /* save in history file */
1N/A flags |= S_FLAG;
1N/A break;
1N/A case 'u':
1N/A fd = (int)opt_info.num;
1N/A if(sh_inuse(shp,fd))
1N/A fd = -1;
1N/A break;
1N/A case 'v':
1N/A flags |= V_FLAG;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT,2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argv += opt_info.index;
1N/A if(error_info.errors)
1N/A errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
1N/A if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK)))
1N/A r = sh_iocheckfd(shp,fd);
1N/A if(fd<0 || !(r&IOREAD))
1N/A errormsg(SH_DICT,ERROR_system(1),e_file+4);
1N/A /* look for prompt */
1N/A if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
1N/A r = strlen(name++);
1N/A else
1N/A r = 0;
1N/A if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0)))
1N/A {
1N/A ((Shbltin_t*)extra)->data = (void*)rp;
1N/A rp->fd = fd;
1N/A rp->flags = flags;
1N/A rp->timeout = timeout;
1N/A rp->argv = argv;
1N/A rp->prompt = name;
1N/A rp->plen = r;
1N/A }
1N/Abypass:
1N/A shp->prompt = default_prompt;
1N/A if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)))
1N/A {
1N/A memcpy(shp->prompt,name,r);
1N/A sfwrite(sfstderr,shp->prompt,r-1);
1N/A }
1N/A shp->timeout = 0;
1N/A save_prompt = shp->nextprompt;
1N/A shp->nextprompt = 0;
1N/A r=sh_readline(shp,argv,fd,flags,timeout);
1N/A shp->nextprompt = save_prompt;
1N/A if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd]))))
1N/A {
1N/A if(fd == shp->cpipe[0])
1N/A {
1N/A sh_pclose(shp->cpipe);
1N/A return(1);
1N/A }
1N/A }
1N/A sfclrerr(shp->sftable[fd]);
1N/A return(r);
1N/A}
1N/A
1N/A/*
1N/A * here for read timeout
1N/A */
1N/Astatic void timedout(void *handle)
1N/A{
1N/A sfclrlock((Sfio_t*)handle);
1N/A sh_exit(1);
1N/A}
1N/A
1N/A/*
1N/A * This is the code to read a line and to split it into tokens
1N/A * <names> is an array of variable names
1N/A * <fd> is the file descriptor
1N/A * <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
1N/A * <timeout> is number of milli-seconds until timeout
1N/A */
1N/A
1N/Aint sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout)
1N/A{
1N/A register ssize_t c;
1N/A register unsigned char *cp;
1N/A register Namval_t *np;
1N/A register char *name, *val;
1N/A register Sfio_t *iop;
1N/A Namfun_t *nfp;
1N/A char *ifs;
1N/A unsigned char *cpmax;
1N/A unsigned char *del;
1N/A char was_escape = 0;
1N/A char use_stak = 0;
1N/A volatile char was_write = 0;
1N/A volatile char was_share = 1;
1N/A int rel, wrd;
1N/A long array_index = 0;
1N/A void *timeslot=0;
1N/A int delim = '\n';
1N/A int jmpval=0;
1N/A ssize_t size = 0;
1N/A int binary;
1N/A int oflags=NV_NOASSIGN|NV_VARNAME;
1N/A struct checkpt buff;
1N/A if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd)))
1N/A return(1);
1N/A sh_stats(STAT_READS);
1N/A if(names && (name = *names))
1N/A {
1N/A Namval_t *mp;
1N/A if(val= strchr(name,'?'))
1N/A *val = 0;
1N/A if(flags&C_FLAG)
1N/A oflags |= NV_ARRAY;
1N/A np = nv_open(name,shp->var_tree,oflags);
1N/A if(np && nv_isarray(np) && (mp=nv_opensub(np)))
1N/A np = mp;
1N/A if((flags&V_FLAG) && shp->gd->ed_context)
1N/A ((struct edit*)shp->gd->ed_context)->e_default = np;
1N/A if(flags&A_FLAG)
1N/A {
1N/A flags &= ~A_FLAG;
1N/A array_index = 1;
1N/A nv_unset(np);
1N/A nv_putsub(np,NIL(char*),0L);
1N/A }
1N/A else if(flags&C_FLAG)
1N/A {
1N/A char *sp = np->nvenv;
1N/A delim = -1;
1N/A nv_unset(np);
1N/A if(!nv_isattr(np,NV_MINIMAL))
1N/A np->nvenv = sp;
1N/A nv_setvtree(np);
1N/A }
1N/A else
1N/A name = *++names;
1N/A if(val)
1N/A *val = '?';
1N/A }
1N/A else
1N/A {
1N/A name = 0;
1N/A if(dtvnext(shp->var_tree) || shp->namespace)
1N/A np = nv_open(nv_name(REPLYNOD),shp->var_tree,0);
1N/A else
1N/A np = REPLYNOD;
1N/A }
1N/A if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */
1N/A {
1N/A if(flags&(N_FLAG|NN_FLAG))
1N/A size = ((unsigned)flags)>>D_FLAG;
1N/A else
1N/A delim = ((unsigned)flags)>>D_FLAG;
1N/A if(shp->fdstatus[fd]&IOTTY)
1N/A tty_raw(fd,1);
1N/A }
1N/A binary = nv_isattr(np,NV_BINARY);
1N/A if(!binary && !(flags&(N_FLAG|NN_FLAG)))
1N/A {
1N/A Namval_t *mp;
1N/A /* set up state table based on IFS */
1N/A ifs = nv_getval(mp=sh_scoped(shp,IFSNOD));
1N/A if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC)
1N/A shp->ifstable['\\'] = 0;
1N/A else if(!(flags&R_FLAG) && shp->ifstable['\\']==0)
1N/A shp->ifstable['\\'] = S_ESC;
1N/A if(delim>0)
1N/A shp->ifstable[delim] = S_NL;
1N/A if(delim!='\n')
1N/A {
1N/A shp->ifstable['\n'] = 0;
1N/A nv_putval(mp, ifs, NV_RDONLY);
1N/A }
1N/A shp->ifstable[0] = S_EOF;
1N/A }
1N/A sfclrerr(iop);
1N/A for(nfp=np->nvfun; nfp; nfp = nfp->next)
1N/A {
1N/A if(nfp->disc && nfp->disc->readf)
1N/A {
1N/A if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0)
1N/A return(c);
1N/A }
1N/A }
1N/A if(binary && !(flags&(N_FLAG|NN_FLAG)))
1N/A {
1N/A flags |= NN_FLAG;
1N/A size = nv_size(np);
1N/A }
1N/A was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0;
1N/A if(fd==0)
1N/A was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0;
1N/A if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
1N/A {
1N/A sh_pushcontext(shp,&buff,1);
1N/A jmpval = sigsetjmp(buff.buff,0);
1N/A if(jmpval)
1N/A goto done;
1N/A if(timeout)
1N/A timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop);
1N/A }
1N/A if(flags&(N_FLAG|NN_FLAG))
1N/A {
1N/A char buf[256],*var=buf,*cur,*end,*up,*v;
1N/A /* reserved buffer */
1N/A if((c=size)>=sizeof(buf))
1N/A {
1N/A if(!(var = (char*)malloc(c+1)))
1N/A sh_exit(1);
1N/A end = var + c;
1N/A }
1N/A else
1N/A end = var + sizeof(buf) - 1;
1N/A up = cur = var;
1N/A if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0)
1N/A was_share = 1;
1N/A if(size==0)
1N/A {
1N/A cp = sfreserve(iop,0,0);
1N/A c = 0;
1N/A }
1N/A else
1N/A {
1N/A ssize_t m;
1N/A int f;
1N/A for (;;)
1N/A {
1N/A c = size;
1N/A cp = sfreserve(iop,c,SF_LOCKR);
1N/A f = 1;
1N/A if(cp)
1N/A m = sfvalue(iop);
1N/A else if(flags&NN_FLAG)
1N/A {
1N/A c = size;
1N/A m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0;
1N/A f = 0;
1N/A }
1N/A else
1N/A {
1N/A c = sfvalue(iop);
1N/A m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0;
1N/A }
1N/A if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m)))
1N/A {
1N/A *v++ = 0;
1N/A m = v-(char*)cp;
1N/A }
1N/A if((c=m)>size)
1N/A c = size;
1N/A if(c>0)
1N/A {
1N/A if(c > (end-cur))
1N/A {
1N/A ssize_t cx = cur - var, ux = up - var;
1N/A m = (end - var) + (c - (end - cur));
1N/A if (var == buf)
1N/A {
1N/A v = (char*)malloc(m+1);
1N/A var = memcpy(v, var, cur - var);
1N/A }
1N/A else
1N/A var = newof(var, char, m, 1);
1N/A end = var + m;
1N/A cur = var + cx;
1N/A up = var + ux;
1N/A }
1N/A memcpy((void*)cur,cp,c);
1N/A if(f)
1N/A sfread(iop,cp,c);
1N/A cur += c;
1N/A#if SHOPT_MULTIBYTE
1N/A if(!binary && mbwide())
1N/A {
1N/A int x;
1N/A int z;
1N/A
1N/A mbinit();
1N/A *cur = 0;
1N/A x = z = 0;
1N/A while (up < cur && (z = mbsize(up)) > 0)
1N/A {
1N/A up += z;
1N/A x++;
1N/A }
1N/A if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c))
1N/A continue;
1N/A }
1N/A#endif
1N/A }
1N/A#if SHOPT_MULTIBYTE
1N/A if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size))
1N/A cur = var;
1N/A#endif
1N/A *cur = 0;
1N/A if(c>=size || (flags&N_FLAG) || m==0)
1N/A {
1N/A if(m)
1N/A sfclrerr(iop);
1N/A break;
1N/A }
1N/A size -= c;
1N/A }
1N/A }
1N/A if(timeslot)
1N/A timerdel(timeslot);
1N/A if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size))
1N/A {
1N/A if((c==size) && np->nvalue.cp && !nv_isarray(np))
1N/A memcpy((char*)np->nvalue.cp,var,c);
1N/A else
1N/A {
1N/A Namval_t *mp;
1N/A if(var==buf)
1N/A var = memdup(var,c+1);
1N/A nv_putval(np,var,NV_RAW);
1N/A nv_setsize(np,c);
1N/A if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv))
1N/A nv_setsize(mp,c);
1N/A }
1N/A }
1N/A else
1N/A {
1N/A nv_putval(np,var,0);
1N/A if(var!=buf)
1N/A free((void*)var);
1N/A }
1N/A goto done;
1N/A }
1N/A else if(cp = (unsigned char*)sfgetr(iop,delim,0))
1N/A c = sfvalue(iop);
1N/A else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
1N/A c = sfvalue(iop)+1;
1N/A if(timeslot)
1N/A timerdel(timeslot);
1N/A if((flags&S_FLAG) && !shp->gd->hist_ptr)
1N/A {
1N/A sh_histinit((void*)shp);
1N/A if(!shp->gd->hist_ptr)
1N/A flags &= ~S_FLAG;
1N/A }
1N/A if(cp)
1N/A {
1N/A cpmax = cp + c;
1N/A#if SHOPT_CRNL
1N/A if(delim=='\n' && c>=2 && cpmax[-2]=='\r')
1N/A cpmax--;
1N/A#endif /* SHOPT_CRNL */
1N/A if(*(cpmax-1) != delim)
1N/A *(cpmax-1) = delim;
1N/A if(flags&S_FLAG)
1N/A sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c);
1N/A c = shp->ifstable[*cp++];
1N/A#if !SHOPT_MULTIBYTE
1N/A if(!name && (flags&R_FLAG)) /* special case single argument */
1N/A {
1N/A /* skip over leading blanks */
1N/A while(c==S_SPACE)
1N/A c = shp->ifstable[*cp++];
1N/A /* strip trailing delimiters */
1N/A if(cpmax[-1] == '\n')
1N/A cpmax--;
1N/A if(cpmax>cp)
1N/A {
1N/A while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
1N/A cpmax[1] = 0;
1N/A }
1N/A else
1N/A *cpmax =0;
1N/A if(nv_isattr(np, NV_RDONLY))
1N/A {
1N/A errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
1N/A jmpval = 1;
1N/A }
1N/A else
1N/A nv_putval(np,(char*)cp-1,0);
1N/A goto done;
1N/A }
1N/A#endif /* !SHOPT_MULTIBYTE */
1N/A }
1N/A else
1N/A c = S_NL;
1N/A shp->nextprompt = 2;
1N/A rel= staktell();
1N/A /* val==0 at the start of a field */
1N/A val = 0;
1N/A del = 0;
1N/A while(1)
1N/A {
1N/A switch(c)
1N/A {
1N/A#if SHOPT_MULTIBYTE
1N/A case S_MBYTE:
1N/A if(val==0)
1N/A val = (char*)(cp-1);
1N/A if(sh_strchr(ifs,(char*)cp-1)>=0)
1N/A {
1N/A c = mbsize((char*)cp-1);
1N/A if(name)
1N/A cp[-1] = 0;
1N/A if(c>1)
1N/A cp += (c-1);
1N/A c = S_DELIM;
1N/A }
1N/A else
1N/A c = 0;
1N/A continue;
1N/A#endif /*SHOPT_MULTIBYTE */
1N/A case S_ESC:
1N/A /* process escape character */
1N/A if((c = shp->ifstable[*cp++]) == S_NL)
1N/A was_escape = 1;
1N/A else
1N/A c = 0;
1N/A if(val)
1N/A {
1N/A stakputs(val);
1N/A use_stak = 1;
1N/A was_escape = 1;
1N/A *val = 0;
1N/A }
1N/A continue;
1N/A
1N/A case S_EOF:
1N/A /* check for end of buffer */
1N/A if(val && *val)
1N/A {
1N/A stakputs(val);
1N/A use_stak = 1;
1N/A }
1N/A val = 0;
1N/A if(cp>=cpmax)
1N/A {
1N/A c = S_NL;
1N/A break;
1N/A }
1N/A /* eliminate null bytes */
1N/A c = shp->ifstable[*cp++];
1N/A if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
1N/A c = 0;
1N/A continue;
1N/A case S_NL:
1N/A if(was_escape)
1N/A {
1N/A was_escape = 0;
1N/A if(cp = (unsigned char*)sfgetr(iop,delim,0))
1N/A c = sfvalue(iop);
1N/A else if(cp=(unsigned char*)sfgetr(iop,delim,-1))
1N/A c = sfvalue(iop)+1;
1N/A if(cp)
1N/A {
1N/A if(flags&S_FLAG)
1N/A sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c);
1N/A cpmax = cp + c;
1N/A c = shp->ifstable[*cp++];
1N/A val=0;
1N/A if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
1N/A c = 0;
1N/A continue;
1N/A }
1N/A }
1N/A c = S_NL;
1N/A break;
1N/A
1N/A case S_SPACE:
1N/A /* skip over blanks */
1N/A while((c=shp->ifstable[*cp++])==S_SPACE);
1N/A if(!val)
1N/A continue;
1N/A#if SHOPT_MULTIBYTE
1N/A if(c==S_MBYTE)
1N/A {
1N/A if(sh_strchr(ifs,(char*)cp-1)>=0)
1N/A {
1N/A if((c = mbsize((char*)cp-1))>1)
1N/A cp += (c-1);
1N/A c = S_DELIM;
1N/A }
1N/A else
1N/A c = 0;
1N/A }
1N/A#endif /* SHOPT_MULTIBYTE */
1N/A if(c!=S_DELIM)
1N/A break;
1N/A /* FALL THRU */
1N/A
1N/A case S_DELIM:
1N/A if(!del)
1N/A del = cp - 1;
1N/A if(name)
1N/A {
1N/A /* skip over trailing blanks */
1N/A while((c=shp->ifstable[*cp++])==S_SPACE);
1N/A break;
1N/A }
1N/A /* FALL THRU */
1N/A
1N/A case 0:
1N/A if(val==0 || was_escape)
1N/A {
1N/A val = (char*)(cp-1);
1N/A was_escape = 0;
1N/A }
1N/A /* skip over word characters */
1N/A wrd = -1;
1N/A while(1)
1N/A {
1N/A while((c=shp->ifstable[*cp++])==0)
1N/A if(!wrd)
1N/A wrd = 1;
1N/A if(!del&&c==S_DELIM)
1N/A del = cp - 1;
1N/A if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
1N/A break;
1N/A if(wrd<0)
1N/A wrd = 0;
1N/A }
1N/A if(wrd>0)
1N/A del = (unsigned char*)"";
1N/A if(c!=S_MBYTE)
1N/A cp[-1] = 0;
1N/A continue;
1N/A }
1N/A /* assign value and advance to next variable */
1N/A if(!val)
1N/A val = "";
1N/A if(use_stak)
1N/A {
1N/A stakputs(val);
1N/A stakputc(0);
1N/A val = stakptr(rel);
1N/A }
1N/A if(!name && *val)
1N/A {
1N/A /* strip off trailing space delimiters */
1N/A register unsigned char *vp = (unsigned char*)val + strlen(val);
1N/A while(shp->ifstable[*--vp]==S_SPACE);
1N/A if(vp==del)
1N/A {
1N/A if(vp==(unsigned char*)val)
1N/A vp--;
1N/A else
1N/A while(shp->ifstable[*--vp]==S_SPACE);
1N/A }
1N/A vp[1] = 0;
1N/A }
1N/A if(nv_isattr(np, NV_RDONLY))
1N/A {
1N/A errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
1N/A jmpval = 1;
1N/A }
1N/A else
1N/A nv_putval(np,val,0);
1N/A val = 0;
1N/A del = 0;
1N/A if(use_stak)
1N/A {
1N/A stakseek(rel);
1N/A use_stak = 0;
1N/A }
1N/A if(array_index)
1N/A {
1N/A nv_putsub(np, NIL(char*), array_index++);
1N/A if(c!=S_NL)
1N/A continue;
1N/A name = *++names;
1N/A }
1N/A while(1)
1N/A {
1N/A if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT))
1N/A {
1N/A nv_onattr(np,NV_EXPORT);
1N/A sh_envput(shp->env,np);
1N/A }
1N/A if(name)
1N/A {
1N/A nv_close(np);
1N/A np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
1N/A name = *++names;
1N/A }
1N/A else
1N/A np = 0;
1N/A if(c!=S_NL)
1N/A break;
1N/A if(!np)
1N/A goto done;
1N/A if(nv_isattr(np, NV_RDONLY))
1N/A {
1N/A errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
1N/A jmpval = 1;
1N/A }
1N/A else
1N/A nv_putval(np, "", 0);
1N/A }
1N/A }
1N/Adone:
1N/A if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
1N/A sh_popcontext(shp,&buff);
1N/A if(was_write)
1N/A sfset(iop,SF_WRITE,1);
1N/A if(!was_share)
1N/A sfset(iop,SF_SHARE,0);
1N/A nv_close(np);
1N/A if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY))
1N/A tty_cooked(fd);
1N/A if(flags&S_FLAG)
1N/A hist_flush(shp->gd->hist_ptr);
1N/A if(jmpval > 1)
1N/A siglongjmp(*shp->jmplist,jmpval);
1N/A return(jmpval);
1N/A}
1N/A