mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-24 23:14:14 +00:00
File descriptors that are too far out of range will cause the read builtin to crash. The following example will generate two crashes: $ ksh -c 'read -u 2000000' || ksh -c 'read -u-2000000' The fix is to error out when the given file descriptor is out of range. This bugfix is from Tomas Klacko, although it was modified to use 'sh_iovalidfd' and reject numbers greater than 'INT_MAX': https://www.mail-archive.com/ast-developers@lists.research.att.com/msg01912.html The question about 'shp->fdstatus[-1]' only applies to ksh93v- (ksh93u+ doesn't have any references to 'shp->fdstatus[-1]'). src/cmd/ksh93/bltins/read.c: - File descriptors that are out of range should be rejected with an error message (like invalid file descriptors that are in range). The seemingly redundant check for negative numbers is there because out of range negative numbers also cause memory faults despite the later 'fd<0' check. src/cmd/ksh93/tests/io.sh: - Add three tests for attempting 'read -u' on various invalid file descriptor numbers.
826 lines
18 KiB
C
826 lines
18 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1982-2012 AT&T Intellectual Property *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* David Korn <dgk@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
/*
|
|
* read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...]
|
|
*
|
|
* David Korn
|
|
* AT&T Labs
|
|
*
|
|
*/
|
|
|
|
#include <ast.h>
|
|
#include <error.h>
|
|
#include "defs.h"
|
|
#include "variables.h"
|
|
#include "lexstates.h"
|
|
#include "io.h"
|
|
#include "name.h"
|
|
#include "builtins.h"
|
|
#include "history.h"
|
|
#include "terminal.h"
|
|
#include "edit.h"
|
|
|
|
#define R_FLAG 1 /* raw mode */
|
|
#define S_FLAG 2 /* save in history file */
|
|
#define A_FLAG 4 /* read into array */
|
|
#define N_FLAG 8 /* fixed size read at most */
|
|
#define NN_FLAG 0x10 /* fixed size read exact */
|
|
#define V_FLAG 0x20 /* use default value */
|
|
#define C_FLAG 0x40 /* read into compound variable */
|
|
#define D_FLAG 8 /* must be number of bits for all flags */
|
|
#define SS_FLAG 0x80 /* read .csv format file */
|
|
|
|
struct read_save
|
|
{
|
|
char **argv;
|
|
char *prompt;
|
|
short fd;
|
|
short plen;
|
|
int flags;
|
|
ssize_t len;
|
|
long timeout;
|
|
};
|
|
|
|
int b_read(int argc,char *argv[], Shbltin_t *context)
|
|
{
|
|
Sfdouble_t sec;
|
|
register char *name;
|
|
register int r, flags=0, fd=0;
|
|
register Shell_t *shp = context->shp;
|
|
ssize_t len=0;
|
|
long timeout = 1000*shp->st.tmout;
|
|
int save_prompt, fixargs=context->invariant;
|
|
struct read_save *rp;
|
|
static char default_prompt[3] = {ESC,ESC};
|
|
rp = (struct read_save*)(context->data);
|
|
if(argc==0)
|
|
{
|
|
if(rp)
|
|
free((void*)rp);
|
|
return(0);
|
|
}
|
|
if(rp)
|
|
{
|
|
flags = rp->flags;
|
|
timeout = rp->timeout;
|
|
fd = rp->fd;
|
|
argv = rp->argv;
|
|
name = rp->prompt;
|
|
r = rp->plen;
|
|
goto bypass;
|
|
}
|
|
while((r = optget(argv,sh_optread))) switch(r)
|
|
{
|
|
case 'A':
|
|
flags |= A_FLAG;
|
|
break;
|
|
case 'C':
|
|
flags |= C_FLAG;
|
|
break;
|
|
case 't':
|
|
sec = sh_strnum(opt_info.arg, (char**)0,1);
|
|
timeout = sec ? 1000*sec : 1;
|
|
break;
|
|
case 'd':
|
|
if(opt_info.arg && *opt_info.arg!='\n')
|
|
{
|
|
char *cp = opt_info.arg;
|
|
flags &= ((1<<D_FLAG+1)-1);
|
|
flags |= (mbchar(cp)<<D_FLAG+1) | (1<<D_FLAG);
|
|
}
|
|
break;
|
|
case 'p':
|
|
if((fd = shp->cpipe[0])<=0)
|
|
errormsg(SH_DICT,ERROR_exit(1),e_query);
|
|
break;
|
|
case 'n': case 'N':
|
|
flags &= ((1<<D_FLAG)-1);
|
|
flags |= (r=='n'?N_FLAG:NN_FLAG);
|
|
len = opt_info.num;
|
|
break;
|
|
case 'r':
|
|
flags |= R_FLAG;
|
|
break;
|
|
case 's':
|
|
/* save in history file */
|
|
flags |= S_FLAG;
|
|
break;
|
|
case 'S':
|
|
flags |= SS_FLAG;
|
|
break;
|
|
case 'u':
|
|
fd = (int)opt_info.num;
|
|
if(opt_info.num<0 || opt_info.num>INT_MAX || (fd>=shp->gd->lim.open_max && !sh_iovalidfd(shp,fd)))
|
|
errormsg(SH_DICT,ERROR_exit(1),e_file,opt_info.arg); /* reject invalid file descriptors */
|
|
if(sh_inuse(shp,fd))
|
|
fd = -1;
|
|
break;
|
|
case 'v':
|
|
flags |= V_FLAG;
|
|
break;
|
|
case ':':
|
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
|
break;
|
|
case '?':
|
|
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
|
|
break;
|
|
}
|
|
argv += opt_info.index;
|
|
if(error_info.errors)
|
|
errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
|
|
if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK)))
|
|
r = sh_iocheckfd(shp,fd);
|
|
if(fd<0 || !(r&IOREAD))
|
|
errormsg(SH_DICT,ERROR_system(1),e_file+4);
|
|
/* look for prompt */
|
|
if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
|
|
r = strlen(name++);
|
|
else
|
|
r = 0;
|
|
if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0)))
|
|
{
|
|
context->data = (void*)rp;
|
|
rp->fd = fd;
|
|
rp->flags = flags;
|
|
rp->timeout = timeout;
|
|
rp->argv = argv;
|
|
rp->prompt = name;
|
|
rp->plen = r;
|
|
rp->len = len;
|
|
}
|
|
bypass:
|
|
shp->prompt = default_prompt;
|
|
if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)))
|
|
{
|
|
memcpy(shp->prompt,name,r);
|
|
sfwrite(sfstderr,shp->prompt,r-1);
|
|
}
|
|
shp->timeout = 0;
|
|
save_prompt = shp->nextprompt;
|
|
shp->nextprompt = 0;
|
|
r=sh_readline(shp,argv,fd,flags,len,timeout);
|
|
shp->nextprompt = save_prompt;
|
|
if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd]))))
|
|
{
|
|
if(fd == shp->cpipe[0] && errno!=EINTR)
|
|
sh_pclose(shp->cpipe);
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
/*
|
|
* here for read timeout
|
|
*/
|
|
static void timedout(void *handle)
|
|
{
|
|
sfclrlock((Sfio_t*)handle);
|
|
sh_exit(1);
|
|
}
|
|
|
|
/*
|
|
* This is the code to read a line and to split it into tokens
|
|
* <names> is an array of variable names
|
|
* <fd> is the file descriptor
|
|
* <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
|
|
* <timeout> is number of milli-seconds until timeout
|
|
*/
|
|
|
|
int sh_readline(register Shell_t *shp,char **names, volatile int fd, int flags,ssize_t size,long timeout)
|
|
{
|
|
register ssize_t c;
|
|
register unsigned char *cp;
|
|
register Namval_t *np;
|
|
register char *name, *val;
|
|
register Sfio_t *iop;
|
|
Namfun_t *nfp;
|
|
char *ifs;
|
|
unsigned char *cpmax;
|
|
unsigned char *del;
|
|
char was_escape = 0;
|
|
char use_stak = 0;
|
|
volatile char was_write = 0;
|
|
volatile char was_share = 1;
|
|
volatile int keytrap;
|
|
int rel, wrd;
|
|
long array_index = 0;
|
|
void *timeslot=0;
|
|
int delim = '\n';
|
|
int jmpval=0;
|
|
int binary;
|
|
int oflags=NV_ASSIGN|NV_VARNAME;
|
|
char inquote = 0;
|
|
struct checkpt buff;
|
|
Edit_t *ep = (struct edit*)shp->gd->ed_context;
|
|
if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd)))
|
|
return(1);
|
|
sh_stats(STAT_READS);
|
|
if(names && (name = *names))
|
|
{
|
|
Namval_t *mp;
|
|
if(val= strchr(name,'?'))
|
|
*val = 0;
|
|
if(flags&C_FLAG)
|
|
oflags |= NV_ARRAY;
|
|
np = nv_open(name,shp->var_tree,oflags);
|
|
if(np && nv_isarray(np) && (mp=nv_opensub(np)))
|
|
np = mp;
|
|
if((flags&V_FLAG) && shp->gd->ed_context)
|
|
((struct edit*)shp->gd->ed_context)->e_default = np;
|
|
if(flags&A_FLAG)
|
|
{
|
|
Namarr_t *ap;
|
|
flags &= ~A_FLAG;
|
|
array_index = 1;
|
|
if((ap=nv_arrayptr(np)) && !ap->fun)
|
|
ap->nelem++;
|
|
nv_unset(np);
|
|
if((ap=nv_arrayptr(np)) && !ap->fun)
|
|
ap->nelem--;
|
|
nv_putsub(np,NIL(char*),0L);
|
|
}
|
|
else if(flags&C_FLAG)
|
|
{
|
|
char *sp = np->nvenv;
|
|
delim = -1;
|
|
nv_unset(np);
|
|
if(!nv_isattr(np,NV_MINIMAL))
|
|
np->nvenv = sp;
|
|
nv_setvtree(np);
|
|
}
|
|
else
|
|
name = *++names;
|
|
if(val)
|
|
*val = '?';
|
|
}
|
|
else
|
|
{
|
|
name = 0;
|
|
if(dtvnext(shp->var_tree) || shp->namespace)
|
|
np = nv_open(nv_name(REPLYNOD),shp->var_tree,0);
|
|
else
|
|
np = REPLYNOD;
|
|
}
|
|
keytrap = ep?ep->e_keytrap:0;
|
|
if(size || (flags>>D_FLAG)) /* delimiter not new-line or fixed size read */
|
|
{
|
|
if((shp->fdstatus[fd]&IOTTY) && !keytrap)
|
|
tty_raw(fd,1);
|
|
if(!(flags&(N_FLAG|NN_FLAG)))
|
|
{
|
|
delim = ((unsigned)flags)>>(D_FLAG+1);
|
|
ep->e_nttyparm.c_cc[VEOL] = delim;
|
|
ep->e_nttyparm.c_lflag |= ISIG;
|
|
tty_set(fd,TCSADRAIN,&ep->e_nttyparm);
|
|
}
|
|
}
|
|
binary = nv_isattr(np,NV_BINARY);
|
|
if(!binary && !(flags&(N_FLAG|NN_FLAG)))
|
|
{
|
|
Namval_t *mp;
|
|
/* set up state table based on IFS */
|
|
ifs = nv_getval(mp=sh_scoped(shp,IFSNOD));
|
|
if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC)
|
|
shp->ifstable['\\'] = 0;
|
|
else if(!(flags&R_FLAG) && shp->ifstable['\\']==0)
|
|
shp->ifstable['\\'] = S_ESC;
|
|
if(delim>0)
|
|
shp->ifstable[delim] = S_NL;
|
|
if(delim!='\n')
|
|
{
|
|
shp->ifstable['\n'] = 0;
|
|
nv_putval(mp, ifs, NV_RDONLY);
|
|
}
|
|
shp->ifstable[0] = S_EOF;
|
|
if((flags&SS_FLAG))
|
|
{
|
|
shp->ifstable['"'] = S_QUOTE;
|
|
shp->ifstable['\r'] = S_ERR;
|
|
}
|
|
}
|
|
sfclrerr(iop);
|
|
for(nfp=np->nvfun; nfp; nfp = nfp->next)
|
|
{
|
|
if(nfp->disc && nfp->disc->readf)
|
|
{
|
|
Namval_t *mp = nv_open(name,shp->var_tree,oflags|NV_NOREF);
|
|
if((c=(*nfp->disc->readf)(mp,iop,delim,nfp))>=0)
|
|
return(c);
|
|
}
|
|
}
|
|
if(binary && !(flags&(N_FLAG|NN_FLAG)))
|
|
{
|
|
flags |= NN_FLAG;
|
|
size = nv_size(np);
|
|
}
|
|
was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0;
|
|
if(fd==0)
|
|
was_share = (sfset(iop,SF_SHARE,shp->redir0!=2)&SF_SHARE)!=0;
|
|
if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
|
|
{
|
|
sh_pushcontext(shp,&buff,1);
|
|
jmpval = sigsetjmp(buff.buff,0);
|
|
if(jmpval)
|
|
goto done;
|
|
if(timeout)
|
|
timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop);
|
|
}
|
|
if(flags&(N_FLAG|NN_FLAG))
|
|
{
|
|
char buf[256],*var=buf,*cur,*end,*up,*v;
|
|
/* reserved buffer */
|
|
if((c=size)>=sizeof(buf))
|
|
{
|
|
if(!(var = (char*)malloc(c+1)))
|
|
sh_exit(1);
|
|
end = var + c;
|
|
}
|
|
else
|
|
end = var + sizeof(buf) - 1;
|
|
up = cur = var;
|
|
if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0)
|
|
was_share = 1;
|
|
if(size==0)
|
|
{
|
|
cp = sfreserve(iop,0,0);
|
|
c = 0;
|
|
}
|
|
else
|
|
{
|
|
ssize_t m;
|
|
int f;
|
|
for (;;)
|
|
{
|
|
c = size;
|
|
if(keytrap)
|
|
{
|
|
cp = 0;
|
|
f = 0;
|
|
m = 0;
|
|
while(c-->0 && (buf[m]=ed_getchar(ep,0)))
|
|
m++;
|
|
if(m>0)
|
|
cp = (unsigned char*)buf;
|
|
}
|
|
else
|
|
{
|
|
f = 1;
|
|
if(cp = sfreserve(iop,c,SF_LOCKR))
|
|
m = sfvalue(iop);
|
|
else if(flags&NN_FLAG)
|
|
{
|
|
c = size;
|
|
m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0;
|
|
f = 0;
|
|
}
|
|
else
|
|
{
|
|
c = sfvalue(iop);
|
|
m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0;
|
|
}
|
|
}
|
|
if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m)))
|
|
{
|
|
*v++ = 0;
|
|
m = v-(char*)cp;
|
|
}
|
|
if((c=m)>size)
|
|
c = size;
|
|
if(c>0)
|
|
{
|
|
if(c > (end-cur))
|
|
{
|
|
ssize_t cx = cur - var, ux = up - var;
|
|
m = (end - var) + (c - (end - cur));
|
|
if (var == buf)
|
|
{
|
|
v = (char*)malloc(m+1);
|
|
var = memcpy(v, var, cur - var);
|
|
}
|
|
else
|
|
var = newof(var, char, m, 1);
|
|
end = var + m;
|
|
cur = var + cx;
|
|
up = var + ux;
|
|
}
|
|
if(cur!=(char*)cp)
|
|
memcpy((void*)cur,cp,c);
|
|
if(f)
|
|
sfread(iop,cp,c);
|
|
cur += c;
|
|
#if SHOPT_MULTIBYTE
|
|
if(!binary && mbwide())
|
|
{
|
|
int x;
|
|
int z;
|
|
|
|
mbinit();
|
|
*cur = 0;
|
|
x = z = 0;
|
|
while (up < cur && (z = mbsize(up)) > 0)
|
|
{
|
|
up += z;
|
|
x++;
|
|
}
|
|
if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c))
|
|
continue;
|
|
}
|
|
#endif
|
|
}
|
|
#if SHOPT_MULTIBYTE
|
|
if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size))
|
|
cur = var;
|
|
#endif
|
|
*cur = 0;
|
|
if(c>=size || (flags&N_FLAG) || m==0)
|
|
{
|
|
if(m)
|
|
sfclrerr(iop);
|
|
break;
|
|
}
|
|
size -= c;
|
|
}
|
|
}
|
|
if(timeslot)
|
|
timerdel(timeslot);
|
|
if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size))
|
|
{
|
|
if((c==size) && np->nvalue.cp && !nv_isarray(np))
|
|
memcpy((char*)np->nvalue.cp,var,c);
|
|
else
|
|
{
|
|
Namval_t *mp;
|
|
if(var==buf)
|
|
var = memdup(var,c+1);
|
|
nv_putval(np,var,NV_RAW);
|
|
nv_setsize(np,c);
|
|
if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv))
|
|
nv_setsize(mp,c);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nv_putval(np,var,0);
|
|
if(var!=buf)
|
|
free((void*)var);
|
|
}
|
|
goto done;
|
|
}
|
|
else if(cp = (unsigned char*)sfgetr(iop,delim,0))
|
|
c = sfvalue(iop);
|
|
else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
|
|
{
|
|
c = sfvalue(iop)+1;
|
|
if(!sferror(iop) && sfgetc(iop) >=0)
|
|
errormsg(SH_DICT,ERROR_exit(1),e_overlimit,"line length");
|
|
}
|
|
if(timeslot)
|
|
timerdel(timeslot);
|
|
if((flags&S_FLAG) && !shp->gd->hist_ptr)
|
|
{
|
|
sh_histinit((void*)shp);
|
|
if(!shp->gd->hist_ptr)
|
|
flags &= ~S_FLAG;
|
|
}
|
|
if(cp)
|
|
{
|
|
cpmax = cp + c;
|
|
#if SHOPT_CRNL
|
|
if(delim=='\n' && c>=2 && cpmax[-2]=='\r')
|
|
cpmax--;
|
|
#endif /* SHOPT_CRNL */
|
|
if(*(cpmax-1) != delim)
|
|
*(cpmax-1) = delim;
|
|
if(flags&S_FLAG)
|
|
sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c);
|
|
c = shp->ifstable[*cp++];
|
|
#if !SHOPT_MULTIBYTE
|
|
if(!name && (flags&R_FLAG)) /* special case single argument */
|
|
{
|
|
/* skip over leading blanks */
|
|
while(c==S_SPACE)
|
|
c = shp->ifstable[*cp++];
|
|
/* strip trailing delimiters */
|
|
if(cpmax[-1] == '\n')
|
|
cpmax--;
|
|
if(cpmax>cp)
|
|
{
|
|
while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
|
|
cpmax[1] = 0;
|
|
}
|
|
else
|
|
*cpmax =0;
|
|
if(nv_isattr(np, NV_RDONLY))
|
|
{
|
|
errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
|
|
jmpval = 1;
|
|
}
|
|
else
|
|
nv_putval(np,(char*)cp-1,0);
|
|
goto done;
|
|
}
|
|
#endif /* !SHOPT_MULTIBYTE */
|
|
}
|
|
else
|
|
c = S_NL;
|
|
shp->nextprompt = 2;
|
|
rel= staktell();
|
|
/* val==0 at the start of a field */
|
|
val = 0;
|
|
del = 0;
|
|
while(1)
|
|
{
|
|
switch(c)
|
|
{
|
|
#if SHOPT_MULTIBYTE
|
|
case S_MBYTE:
|
|
if(val==0)
|
|
val = (char*)(cp-1);
|
|
if(sh_strchr(ifs,(char*)cp-1)>=0)
|
|
{
|
|
c = mbsize((char*)cp-1);
|
|
if(name)
|
|
cp[-1] = 0;
|
|
if(c>1)
|
|
cp += (c-1);
|
|
c = S_DELIM;
|
|
}
|
|
else
|
|
c = 0;
|
|
continue;
|
|
#endif /*SHOPT_MULTIBYTE */
|
|
case S_QUOTE:
|
|
c = shp->ifstable[*cp++];
|
|
if(inquote && c==S_QUOTE)
|
|
c = -1;
|
|
else
|
|
inquote = !inquote;
|
|
if(val)
|
|
{
|
|
stakputs(val);
|
|
use_stak = 1;
|
|
*val = 0;
|
|
}
|
|
if(c==-1)
|
|
{
|
|
stakputc('"');
|
|
c = shp->ifstable[*cp++];
|
|
}
|
|
continue;
|
|
case S_ESC:
|
|
/* process escape character */
|
|
if((c = shp->ifstable[*cp++]) == S_NL)
|
|
was_escape = 1;
|
|
else
|
|
c = 0;
|
|
if(val)
|
|
{
|
|
stakputs(val);
|
|
use_stak = 1;
|
|
was_escape = 1;
|
|
*val = 0;
|
|
}
|
|
continue;
|
|
|
|
case S_ERR:
|
|
cp++;
|
|
case S_EOF:
|
|
/* check for end of buffer */
|
|
if(val && *val)
|
|
{
|
|
stakputs(val);
|
|
use_stak = 1;
|
|
}
|
|
val = 0;
|
|
if(cp>=cpmax)
|
|
{
|
|
c = S_NL;
|
|
break;
|
|
}
|
|
/* eliminate null bytes */
|
|
c = shp->ifstable[*cp++];
|
|
if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
|
|
c = 0;
|
|
continue;
|
|
case S_NL:
|
|
if(was_escape)
|
|
{
|
|
was_escape = 0;
|
|
if(cp = (unsigned char*)sfgetr(iop,delim,0))
|
|
c = sfvalue(iop);
|
|
else if(cp=(unsigned char*)sfgetr(iop,delim,-1))
|
|
c = sfvalue(iop)+1;
|
|
if(cp)
|
|
{
|
|
if(flags&S_FLAG)
|
|
sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c);
|
|
cpmax = cp + c;
|
|
c = shp->ifstable[*cp++];
|
|
val=0;
|
|
if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
|
|
c = 0;
|
|
continue;
|
|
}
|
|
}
|
|
c = S_NL;
|
|
break;
|
|
|
|
case S_SPACE:
|
|
/* skip over blanks */
|
|
while((c=shp->ifstable[*cp++])==S_SPACE);
|
|
if(!val)
|
|
continue;
|
|
#if SHOPT_MULTIBYTE
|
|
if(c==S_MBYTE)
|
|
{
|
|
if(sh_strchr(ifs,(char*)cp-1)>=0)
|
|
{
|
|
if((c = mbsize((char*)cp-1))>1)
|
|
cp += (c-1);
|
|
c = S_DELIM;
|
|
}
|
|
else
|
|
c = 0;
|
|
}
|
|
#endif /* SHOPT_MULTIBYTE */
|
|
if(c!=S_DELIM)
|
|
break;
|
|
/* FALL THRU */
|
|
|
|
case S_DELIM:
|
|
if(!del)
|
|
del = cp - 1;
|
|
if(name)
|
|
{
|
|
/* skip over trailing blanks */
|
|
while((c=shp->ifstable[*cp++])==S_SPACE);
|
|
break;
|
|
}
|
|
/* FALL THRU */
|
|
|
|
case 0:
|
|
if(val==0 || was_escape)
|
|
{
|
|
val = (char*)(cp-1);
|
|
was_escape = 0;
|
|
}
|
|
/* skip over word characters */
|
|
wrd = -1;
|
|
while(1)
|
|
{
|
|
while((c=shp->ifstable[*cp++])==0)
|
|
if(!wrd)
|
|
wrd = 1;
|
|
if(inquote)
|
|
{
|
|
if(c==S_QUOTE)
|
|
{
|
|
if(shp->ifstable[*cp]==S_QUOTE)
|
|
{
|
|
if(val)
|
|
{
|
|
stakwrite(val,cp-(unsigned char*)val);
|
|
use_stak = 1;
|
|
}
|
|
val = (char*)++cp;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
if(c && c!=S_EOF)
|
|
{
|
|
if(c==S_NL)
|
|
{
|
|
if(val)
|
|
{
|
|
stakwrite(val,cp-(unsigned char*)val);
|
|
use_stak=1;
|
|
}
|
|
if(cp = (unsigned char*)sfgetr(iop,delim,0))
|
|
c = sfvalue(iop);
|
|
else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
|
|
c = sfvalue(iop)+1;
|
|
val = (char*)cp;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if(!del&&c==S_DELIM)
|
|
del = cp - 1;
|
|
if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
|
|
break;
|
|
if(wrd<0)
|
|
wrd = 0;
|
|
}
|
|
if(wrd>0)
|
|
del = (unsigned char*)"";
|
|
if(c!=S_MBYTE)
|
|
cp[-1] = 0;
|
|
continue;
|
|
}
|
|
/* assign value and advance to next variable */
|
|
if(!val)
|
|
val = "";
|
|
if(use_stak)
|
|
{
|
|
stakputs(val);
|
|
stakputc(0);
|
|
val = stakptr(rel);
|
|
}
|
|
if(!name && *val)
|
|
{
|
|
/* strip off trailing space delimiters */
|
|
register unsigned char *vp = (unsigned char*)val + strlen(val);
|
|
while(shp->ifstable[*--vp]==S_SPACE);
|
|
if(vp==del)
|
|
{
|
|
if(vp==(unsigned char*)val)
|
|
vp--;
|
|
else
|
|
while(shp->ifstable[*--vp]==S_SPACE);
|
|
}
|
|
vp[1] = 0;
|
|
}
|
|
if(nv_isattr(np, NV_RDONLY))
|
|
{
|
|
errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
|
|
jmpval = 1;
|
|
}
|
|
else
|
|
nv_putval(np,val,0);
|
|
val = 0;
|
|
del = 0;
|
|
if(use_stak)
|
|
{
|
|
stakseek(rel);
|
|
use_stak = 0;
|
|
}
|
|
if(array_index)
|
|
{
|
|
nv_putsub(np, NIL(char*), array_index++);
|
|
if(c!=S_NL)
|
|
continue;
|
|
name = *++names;
|
|
}
|
|
while(1)
|
|
{
|
|
if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT))
|
|
{
|
|
nv_onattr(np,NV_EXPORT);
|
|
sh_envput(shp->env,np);
|
|
}
|
|
if(name)
|
|
{
|
|
nv_close(np);
|
|
np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
|
|
name = *++names;
|
|
}
|
|
else
|
|
np = 0;
|
|
if(c!=S_NL)
|
|
break;
|
|
if(!np)
|
|
goto done;
|
|
if(nv_isattr(np, NV_RDONLY))
|
|
{
|
|
errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
|
|
jmpval = 1;
|
|
}
|
|
else
|
|
nv_putval(np, "", 0);
|
|
}
|
|
}
|
|
done:
|
|
if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
|
|
sh_popcontext(shp,&buff);
|
|
if(was_write)
|
|
sfset(iop,SF_WRITE,1);
|
|
if(!was_share)
|
|
sfset(iop,SF_SHARE,0);
|
|
nv_close(np);
|
|
if((shp->fdstatus[fd]&IOTTY) && !keytrap)
|
|
tty_cooked(fd);
|
|
if(flags&S_FLAG)
|
|
hist_flush(shp->gd->hist_ptr);
|
|
if(jmpval > 1)
|
|
siglongjmp(*shp->jmplist,jmpval);
|
|
return(jmpval);
|
|
}
|
|
|