xref: /titanic_41/usr/src/lib/libshell/common/bltins/read.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
227c2fbfb3SApril Chin  * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...]
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include	<ast.h>
30da2e3ebdSchin #include	<error.h>
31da2e3ebdSchin #include	"defs.h"
32da2e3ebdSchin #include	"variables.h"
33da2e3ebdSchin #include	"lexstates.h"
34da2e3ebdSchin #include	"io.h"
35da2e3ebdSchin #include	"name.h"
36da2e3ebdSchin #include	"builtins.h"
37da2e3ebdSchin #include	"history.h"
38da2e3ebdSchin #include	"terminal.h"
39da2e3ebdSchin #include	"edit.h"
40da2e3ebdSchin 
41da2e3ebdSchin #define	R_FLAG	1	/* raw mode */
42da2e3ebdSchin #define	S_FLAG	2	/* save in history file */
43da2e3ebdSchin #define	A_FLAG	4	/* read into array */
44da2e3ebdSchin #define N_FLAG	8	/* fixed size read at most */
45da2e3ebdSchin #define NN_FLAG	0x10	/* fixed size read exact */
46da2e3ebdSchin #define V_FLAG	0x20	/* use default value */
477c2fbfb3SApril Chin #define	C_FLAG	0x40	/* read into compound variable */
48da2e3ebdSchin #define D_FLAG	8	/* must be number of bits for all flags */
49da2e3ebdSchin 
507c2fbfb3SApril Chin struct read_save
517c2fbfb3SApril Chin {
527c2fbfb3SApril Chin         char	**argv;
537c2fbfb3SApril Chin 	char	*prompt;
547c2fbfb3SApril Chin         short	fd;
557c2fbfb3SApril Chin         short	plen;
567c2fbfb3SApril Chin 	int	flags;
577c2fbfb3SApril Chin         long	timeout;
587c2fbfb3SApril Chin };
597c2fbfb3SApril Chin 
b_read(int argc,char * argv[],void * extra)60da2e3ebdSchin int	b_read(int argc,char *argv[], void *extra)
61da2e3ebdSchin {
62da2e3ebdSchin 	Sfdouble_t sec;
63da2e3ebdSchin 	register char *name;
64da2e3ebdSchin 	register int r, flags=0, fd=0;
657c2fbfb3SApril Chin 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
66da2e3ebdSchin 	long timeout = 1000*shp->st.tmout;
677c2fbfb3SApril Chin 	int save_prompt, fixargs=((Shbltin_t*)extra)->invariant;
687c2fbfb3SApril Chin 	struct read_save *rp;
69da2e3ebdSchin 	static char default_prompt[3] = {ESC,ESC};
7034f9b3eeSRoland Mainz 	rp = (struct read_save*)(((Shbltin_t*)extra)->data);
717c2fbfb3SApril Chin 	if(argc==0)
7234f9b3eeSRoland Mainz 	{
7334f9b3eeSRoland Mainz 		if(rp)
7434f9b3eeSRoland Mainz 			free((void*)rp);
757c2fbfb3SApril Chin 		return(0);
7634f9b3eeSRoland Mainz 	}
7734f9b3eeSRoland Mainz 	if(rp)
787c2fbfb3SApril Chin 	{
797c2fbfb3SApril Chin 		flags = rp->flags;
807c2fbfb3SApril Chin 		timeout = rp->timeout;
817c2fbfb3SApril Chin 		fd = rp->fd;
827c2fbfb3SApril Chin 		argv = rp->argv;
837c2fbfb3SApril Chin 		name = rp->prompt;
847c2fbfb3SApril Chin 		r = rp->plen;
857c2fbfb3SApril Chin 		goto bypass;
867c2fbfb3SApril Chin 	}
87da2e3ebdSchin 	while((r = optget(argv,sh_optread))) switch(r)
88da2e3ebdSchin 	{
89da2e3ebdSchin 	    case 'A':
90da2e3ebdSchin 		flags |= A_FLAG;
91da2e3ebdSchin 		break;
927c2fbfb3SApril Chin 	    case 'C':
937c2fbfb3SApril Chin 		flags |= C_FLAG;
947c2fbfb3SApril Chin 		break;
95da2e3ebdSchin 	    case 't':
96da2e3ebdSchin 		sec = sh_strnum(opt_info.arg, (char**)0,1);
97da2e3ebdSchin 		timeout = sec ? 1000*sec : 1;
98da2e3ebdSchin 		break;
99da2e3ebdSchin 	    case 'd':
100da2e3ebdSchin 		if(opt_info.arg && *opt_info.arg!='\n')
101da2e3ebdSchin 		{
102da2e3ebdSchin 			char *cp = opt_info.arg;
103da2e3ebdSchin 			flags &= ~((1<<D_FLAG)-1);
104da2e3ebdSchin 			flags |= (mbchar(cp)<< D_FLAG);
105da2e3ebdSchin 		}
106da2e3ebdSchin 		break;
107da2e3ebdSchin 	    case 'p':
108da2e3ebdSchin 		if((fd = shp->cpipe[0])<=0)
109da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_query);
110da2e3ebdSchin 		break;
111da2e3ebdSchin 	    case 'n': case 'N':
1127c2fbfb3SApril Chin 		flags &= ((1<<D_FLAG)-1);
113da2e3ebdSchin 		flags |= (r=='n'?N_FLAG:NN_FLAG);
114da2e3ebdSchin 		r = (int)opt_info.num;
115da2e3ebdSchin 		if((unsigned)r > (1<<((8*sizeof(int))-D_FLAG))-1)
1167c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_exit(1),e_overlimit,opt_info.name);
117da2e3ebdSchin 		flags |= (r<< D_FLAG);
118da2e3ebdSchin 		break;
119da2e3ebdSchin 	    case 'r':
120da2e3ebdSchin 		flags |= R_FLAG;
121da2e3ebdSchin 		break;
122da2e3ebdSchin 	    case 's':
123da2e3ebdSchin 		/* save in history file */
124da2e3ebdSchin 		flags |= S_FLAG;
125da2e3ebdSchin 		break;
126da2e3ebdSchin 	    case 'u':
127da2e3ebdSchin 		fd = (int)opt_info.num;
128da2e3ebdSchin 		if(sh_inuse(fd))
129da2e3ebdSchin 			fd = -1;
130da2e3ebdSchin 		break;
131da2e3ebdSchin 	    case 'v':
132da2e3ebdSchin 		flags |= V_FLAG;
133da2e3ebdSchin 		break;
134da2e3ebdSchin 	    case ':':
135da2e3ebdSchin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
136da2e3ebdSchin 		break;
137da2e3ebdSchin 	    case '?':
138da2e3ebdSchin 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
139da2e3ebdSchin 		break;
140da2e3ebdSchin 	}
141da2e3ebdSchin 	argv += opt_info.index;
142da2e3ebdSchin 	if(error_info.errors)
143da2e3ebdSchin 		errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
144da2e3ebdSchin 	if(!((r=shp->fdstatus[fd])&IOREAD)  || !(r&(IOSEEK|IONOSEEK)))
1457c2fbfb3SApril Chin 		r = sh_iocheckfd(shp,fd);
146da2e3ebdSchin 	if(fd<0 || !(r&IOREAD))
147da2e3ebdSchin 		errormsg(SH_DICT,ERROR_system(1),e_file+4);
148da2e3ebdSchin 	/* look for prompt */
149da2e3ebdSchin 	if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
1507c2fbfb3SApril Chin 		r = strlen(name++);
1517c2fbfb3SApril Chin 	else
1527c2fbfb3SApril Chin 		r = 0;
1537c2fbfb3SApril Chin 	if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0)))
154da2e3ebdSchin 	{
1557c2fbfb3SApril Chin 		((Shbltin_t*)extra)->data = (void*)rp;
1567c2fbfb3SApril Chin 		rp->fd = fd;
1577c2fbfb3SApril Chin 		rp->flags = flags;
1587c2fbfb3SApril Chin 		rp->timeout = timeout;
1597c2fbfb3SApril Chin 		rp->argv = argv;
1607c2fbfb3SApril Chin 		rp->prompt = name;
1617c2fbfb3SApril Chin 		rp->plen = r;
1627c2fbfb3SApril Chin 	}
1637c2fbfb3SApril Chin bypass:
164*3e14f97fSRoger A. Faulkner 	shp->prompt = default_prompt;
1657c2fbfb3SApril Chin 	if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)))
166da2e3ebdSchin 	{
167da2e3ebdSchin 		memcpy(shp->prompt,name,r);
168da2e3ebdSchin 		sfwrite(sfstderr,shp->prompt,r-1);
169da2e3ebdSchin 	}
170da2e3ebdSchin 	shp->timeout = 0;
171da2e3ebdSchin 	save_prompt = shp->nextprompt;
172da2e3ebdSchin 	shp->nextprompt = 0;
173da2e3ebdSchin 	r=sh_readline(shp,argv,fd,flags,timeout);
174da2e3ebdSchin 	shp->nextprompt = save_prompt;
175da2e3ebdSchin 	if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd]))))
176da2e3ebdSchin 	{
177da2e3ebdSchin 		if(fd == shp->cpipe[0])
178da2e3ebdSchin 		{
179da2e3ebdSchin 			sh_pclose(shp->cpipe);
180da2e3ebdSchin 			return(1);
181da2e3ebdSchin 		}
182da2e3ebdSchin 	}
183da2e3ebdSchin 	sfclrerr(shp->sftable[fd]);
184da2e3ebdSchin 	return(r);
185da2e3ebdSchin }
186da2e3ebdSchin 
187da2e3ebdSchin /*
188da2e3ebdSchin  * here for read timeout
189da2e3ebdSchin  */
timedout(void * handle)190da2e3ebdSchin static void timedout(void *handle)
191da2e3ebdSchin {
192da2e3ebdSchin 	sfclrlock((Sfio_t*)handle);
193da2e3ebdSchin 	sh_exit(1);
194da2e3ebdSchin }
195da2e3ebdSchin 
196da2e3ebdSchin /*
197da2e3ebdSchin  * This is the code to read a line and to split it into tokens
198da2e3ebdSchin  *  <names> is an array of variable names
199da2e3ebdSchin  *  <fd> is the file descriptor
200da2e3ebdSchin  *  <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
201da2e3ebdSchin  *  <timeout> is number of milli-seconds until timeout
202da2e3ebdSchin  */
203da2e3ebdSchin 
sh_readline(register Shell_t * shp,char ** names,int fd,int flags,long timeout)204da2e3ebdSchin int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout)
205da2e3ebdSchin {
20634f9b3eeSRoland Mainz 	register ssize_t	c;
207da2e3ebdSchin 	register unsigned char	*cp;
208da2e3ebdSchin 	register Namval_t	*np;
209da2e3ebdSchin 	register char		*name, *val;
210da2e3ebdSchin 	register Sfio_t		*iop;
2117c2fbfb3SApril Chin 	Namfun_t		*nfp;
212da2e3ebdSchin 	char			*ifs;
213da2e3ebdSchin 	unsigned char		*cpmax;
214da2e3ebdSchin 	unsigned char		*del;
215da2e3ebdSchin 	char			was_escape = 0;
216da2e3ebdSchin 	char			use_stak = 0;
2177c2fbfb3SApril Chin 	volatile char		was_write = 0;
2187c2fbfb3SApril Chin 	volatile char		was_share = 1;
219da2e3ebdSchin 	int			rel, wrd;
220da2e3ebdSchin 	long			array_index = 0;
221da2e3ebdSchin 	void			*timeslot=0;
222da2e3ebdSchin 	int			delim = '\n';
223da2e3ebdSchin 	int			jmpval=0;
22434f9b3eeSRoland Mainz 	ssize_t			size = 0;
2257c2fbfb3SApril Chin 	int			binary;
226da2e3ebdSchin 	struct	checkpt		buff;
2277c2fbfb3SApril Chin 	if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd)))
228da2e3ebdSchin 		return(1);
2297c2fbfb3SApril Chin 	sh_stats(STAT_READS);
230da2e3ebdSchin 	if(names && (name = *names))
231da2e3ebdSchin 	{
23234f9b3eeSRoland Mainz 		Namval_t *mp;
233da2e3ebdSchin 		if(val= strchr(name,'?'))
234da2e3ebdSchin 			*val = 0;
2357c2fbfb3SApril Chin 		np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
23634f9b3eeSRoland Mainz 		if(np && nv_isarray(np) && (mp=nv_opensub(np)))
23734f9b3eeSRoland Mainz 			np = mp;
238da2e3ebdSchin 		if((flags&V_FLAG) && shp->ed_context)
239da2e3ebdSchin 			((struct edit*)shp->ed_context)->e_default = np;
240da2e3ebdSchin 		if(flags&A_FLAG)
241da2e3ebdSchin 		{
242da2e3ebdSchin 			flags &= ~A_FLAG;
243da2e3ebdSchin 			array_index = 1;
244da2e3ebdSchin 			nv_unset(np);
245da2e3ebdSchin 			nv_putsub(np,NIL(char*),0L);
246da2e3ebdSchin 		}
2477c2fbfb3SApril Chin 		else if(flags&C_FLAG)
2487c2fbfb3SApril Chin 		{
2497c2fbfb3SApril Chin 			delim = -1;
2507c2fbfb3SApril Chin 			nv_unset(np);
2517c2fbfb3SApril Chin 			nv_setvtree(np);
2527c2fbfb3SApril Chin 		}
253da2e3ebdSchin 		else
254da2e3ebdSchin 			name = *++names;
255da2e3ebdSchin 		if(val)
256da2e3ebdSchin 			*val = '?';
257da2e3ebdSchin 	}
258da2e3ebdSchin 	else
259da2e3ebdSchin 	{
260da2e3ebdSchin 		name = 0;
261da2e3ebdSchin 		if(dtvnext(shp->var_tree) || shp->namespace)
262da2e3ebdSchin                 	np = nv_open(nv_name(REPLYNOD),shp->var_tree,0);
263da2e3ebdSchin 		else
264da2e3ebdSchin 			np = REPLYNOD;
265da2e3ebdSchin 	}
266da2e3ebdSchin 	if(flags>>D_FLAG)	/* delimiter not new-line or fixed size read */
267da2e3ebdSchin 	{
268da2e3ebdSchin 		if(flags&(N_FLAG|NN_FLAG))
269da2e3ebdSchin 			size = ((unsigned)flags)>>D_FLAG;
270da2e3ebdSchin 		else
271da2e3ebdSchin 			delim = ((unsigned)flags)>>D_FLAG;
272da2e3ebdSchin 		if(shp->fdstatus[fd]&IOTTY)
273da2e3ebdSchin 			tty_raw(fd,1);
274da2e3ebdSchin 	}
2757c2fbfb3SApril Chin 	binary = nv_isattr(np,NV_BINARY);
2767c2fbfb3SApril Chin 	if(!binary && !(flags&(N_FLAG|NN_FLAG)))
277da2e3ebdSchin 	{
278da2e3ebdSchin 		Namval_t *mp;
279da2e3ebdSchin 		/* set up state table based on IFS */
2807c2fbfb3SApril Chin 		ifs = nv_getval(mp=sh_scoped(shp,IFSNOD));
281da2e3ebdSchin 		if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC)
282da2e3ebdSchin 			shp->ifstable['\\'] = 0;
283da2e3ebdSchin 		else if(!(flags&R_FLAG) && shp->ifstable['\\']==0)
284da2e3ebdSchin 			shp->ifstable['\\'] = S_ESC;
285da2e3ebdSchin 		shp->ifstable[delim] = S_NL;
286da2e3ebdSchin 		if(delim!='\n')
287da2e3ebdSchin 		{
288da2e3ebdSchin 			shp->ifstable['\n'] = 0;
289da2e3ebdSchin 			nv_putval(mp, ifs, NV_RDONLY);
290da2e3ebdSchin 		}
291da2e3ebdSchin 		shp->ifstable[0] = S_EOF;
292da2e3ebdSchin 	}
293da2e3ebdSchin 	sfclrerr(iop);
2947c2fbfb3SApril Chin 	for(nfp=np->nvfun; nfp; nfp = nfp->next)
2957c2fbfb3SApril Chin 	{
2967c2fbfb3SApril Chin 		if(nfp->disc && nfp->disc->readf)
2977c2fbfb3SApril Chin 		{
2987c2fbfb3SApril Chin 			if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0)
2997c2fbfb3SApril Chin 				return(c);
3007c2fbfb3SApril Chin 		}
3017c2fbfb3SApril Chin 	}
3027c2fbfb3SApril Chin 	if(binary && !(flags&(N_FLAG|NN_FLAG)))
3037c2fbfb3SApril Chin 	{
3047c2fbfb3SApril Chin 		flags |= NN_FLAG;
3057c2fbfb3SApril Chin 		size = nv_size(np);
3067c2fbfb3SApril Chin 	}
307da2e3ebdSchin 	was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0;
308da2e3ebdSchin 	if(fd==0)
309da2e3ebdSchin 		was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0;
310da2e3ebdSchin 	if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
311da2e3ebdSchin 	{
312da2e3ebdSchin 		sh_pushcontext(&buff,1);
313da2e3ebdSchin 		jmpval = sigsetjmp(buff.buff,0);
314da2e3ebdSchin 		if(jmpval)
315da2e3ebdSchin 			goto done;
316da2e3ebdSchin 		if(timeout)
317da2e3ebdSchin 	                timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop);
318da2e3ebdSchin 	}
319da2e3ebdSchin 	if(flags&(N_FLAG|NN_FLAG))
320da2e3ebdSchin 	{
32134f9b3eeSRoland Mainz 		char buf[256],*var=buf,*cur,*end,*up,*v;
322da2e3ebdSchin 		/* reserved buffer */
323da2e3ebdSchin 		if((c=size)>=sizeof(buf))
324da2e3ebdSchin 		{
325da2e3ebdSchin 			if(!(var = (char*)malloc(c+1)))
326da2e3ebdSchin 				sh_exit(1);
3277c2fbfb3SApril Chin 			end = var + c;
328da2e3ebdSchin 		}
3297c2fbfb3SApril Chin 		else
3307c2fbfb3SApril Chin 			end = var + sizeof(buf) - 1;
3317c2fbfb3SApril Chin 		up = cur = var;
332da2e3ebdSchin 		if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0)
333da2e3ebdSchin 			was_share = 1;
334da2e3ebdSchin 		if(size==0)
335da2e3ebdSchin 		{
336da2e3ebdSchin 			cp = sfreserve(iop,0,0);
337da2e3ebdSchin 			c = 0;
338da2e3ebdSchin 		}
339da2e3ebdSchin 		else
340da2e3ebdSchin 		{
34134f9b3eeSRoland Mainz 			ssize_t	m;
34234f9b3eeSRoland Mainz 			int	f;
3437c2fbfb3SApril Chin 			for (;;)
3447c2fbfb3SApril Chin 			{
345*3e14f97fSRoger A. Faulkner 				c = size;
3467c2fbfb3SApril Chin 				cp = sfreserve(iop,c,SF_LOCKR);
3477c2fbfb3SApril Chin 				f = 1;
34834f9b3eeSRoland Mainz 				if(cp)
34934f9b3eeSRoland Mainz 					m = sfvalue(iop);
350*3e14f97fSRoger A. Faulkner 				else if(flags&NN_FLAG)
351*3e14f97fSRoger A. Faulkner 				{
352*3e14f97fSRoger A. Faulkner 					c = size;
353*3e14f97fSRoger A. Faulkner 					m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0;
354*3e14f97fSRoger A. Faulkner 					f = 0;
355*3e14f97fSRoger A. Faulkner 				}
35634f9b3eeSRoland Mainz 				else
3577c2fbfb3SApril Chin 				{
358*3e14f97fSRoger A. Faulkner 					c = sfvalue(iop);
359*3e14f97fSRoger A. Faulkner 					m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0;
3607c2fbfb3SApril Chin 				}
3617c2fbfb3SApril Chin 				if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m)))
36234f9b3eeSRoland Mainz 				{
36334f9b3eeSRoland Mainz 					*v++ = 0;
3647c2fbfb3SApril Chin 					m = v-(char*)cp;
3657c2fbfb3SApril Chin 				}
3667c2fbfb3SApril Chin 				if((c=m)>size)
367da2e3ebdSchin 					c = size;
368da2e3ebdSchin 				if(c>0)
369da2e3ebdSchin 				{
3707c2fbfb3SApril Chin 					if(c > (end-cur))
3717c2fbfb3SApril Chin 					{
37234f9b3eeSRoland Mainz 						ssize_t	cx = cur - var, ux = up - var;
37334f9b3eeSRoland Mainz 						m = (end - var) + (c - (end - cur));
3747c2fbfb3SApril Chin 						if (var == buf)
3757c2fbfb3SApril Chin 						{
3767c2fbfb3SApril Chin 							v = (char*)malloc(m+1);
37734f9b3eeSRoland Mainz 							var = memcpy(v, var, cur - var);
378da2e3ebdSchin 						}
3797c2fbfb3SApril Chin 						else
38034f9b3eeSRoland Mainz 							var = newof(var, char, m, 1);
38134f9b3eeSRoland Mainz 						end = var + m;
38234f9b3eeSRoland Mainz 						cur = var + cx;
38334f9b3eeSRoland Mainz 						up = var + ux;
3847c2fbfb3SApril Chin 					}
3857c2fbfb3SApril Chin 					memcpy((void*)cur,cp,c);
3867c2fbfb3SApril Chin 					if(f)
3877c2fbfb3SApril Chin 						sfread(iop,cp,c);
3887c2fbfb3SApril Chin 					cur += c;
3897c2fbfb3SApril Chin #if SHOPT_MULTIBYTE
3907c2fbfb3SApril Chin 					if(!binary && mbwide())
3917c2fbfb3SApril Chin 					{
3927c2fbfb3SApril Chin 						int	x;
3937c2fbfb3SApril Chin 						int	z;
3947c2fbfb3SApril Chin 
3957c2fbfb3SApril Chin 						mbinit();
3967c2fbfb3SApril Chin 						*cur = 0;
3977c2fbfb3SApril Chin 						x = z = 0;
3987c2fbfb3SApril Chin 						while (up < cur && (z = mbsize(up)) > 0)
3997c2fbfb3SApril Chin 						{
4007c2fbfb3SApril Chin 							up += z;
4017c2fbfb3SApril Chin 							x++;
4027c2fbfb3SApril Chin 						}
4037c2fbfb3SApril Chin 						if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c))
4047c2fbfb3SApril Chin 							continue;
4057c2fbfb3SApril Chin 					}
4067c2fbfb3SApril Chin #endif
4077c2fbfb3SApril Chin 				}
4087c2fbfb3SApril Chin #if SHOPT_MULTIBYTE
4097c2fbfb3SApril Chin 				if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size))
4107c2fbfb3SApril Chin 					cur = var;
4117c2fbfb3SApril Chin #endif
4127c2fbfb3SApril Chin 				*cur = 0;
413*3e14f97fSRoger A. Faulkner 				if(c>=size || (flags&N_FLAG) || m==0)
414*3e14f97fSRoger A. Faulkner 				{
415*3e14f97fSRoger A. Faulkner 					if(m)
416da2e3ebdSchin 						sfclrerr(iop);
4177c2fbfb3SApril Chin 					break;
4187c2fbfb3SApril Chin 				}
419*3e14f97fSRoger A. Faulkner 				size -= c;
420*3e14f97fSRoger A. Faulkner 			}
421da2e3ebdSchin 		}
422da2e3ebdSchin 		if(timeslot)
423da2e3ebdSchin 			timerdel(timeslot);
42434f9b3eeSRoland Mainz 		if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size))
425da2e3ebdSchin 		{
42634f9b3eeSRoland Mainz 			if((c==size) && np->nvalue.cp && !nv_isarray(np))
4277c2fbfb3SApril Chin 				memcpy((char*)np->nvalue.cp,var,c);
4287c2fbfb3SApril Chin 			else
4297c2fbfb3SApril Chin 			{
43034f9b3eeSRoland Mainz 				Namval_t *mp;
4317c2fbfb3SApril Chin 				if(var==buf)
432*3e14f97fSRoger A. Faulkner 					var = memdup(var,c+1);
433da2e3ebdSchin 				nv_putval(np,var,NV_RAW);
434da2e3ebdSchin 				nv_setsize(np,c);
43534f9b3eeSRoland Mainz 				if(!nv_isattr(np,NV_IMPORT|NV_EXPORT)  && (mp=(Namval_t*)np->nvenv))
43634f9b3eeSRoland Mainz 					nv_setsize(mp,c);
437da2e3ebdSchin 			}
4387c2fbfb3SApril Chin 		}
439da2e3ebdSchin 		else
440da2e3ebdSchin 		{
441da2e3ebdSchin 			nv_putval(np,var,0);
4427c2fbfb3SApril Chin 			if(var!=buf)
443da2e3ebdSchin 				free((void*)var);
444da2e3ebdSchin 		}
445da2e3ebdSchin 		goto done;
446da2e3ebdSchin 	}
447da2e3ebdSchin 	else if(cp = (unsigned char*)sfgetr(iop,delim,0))
448da2e3ebdSchin 		c = sfvalue(iop);
449da2e3ebdSchin 	else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
450da2e3ebdSchin 		c = sfvalue(iop)+1;
451da2e3ebdSchin 	if(timeslot)
452da2e3ebdSchin 		timerdel(timeslot);
453da2e3ebdSchin 	if((flags&S_FLAG) && !shp->hist_ptr)
454da2e3ebdSchin 	{
4557c2fbfb3SApril Chin 		sh_histinit((void*)shp);
456da2e3ebdSchin 		if(!shp->hist_ptr)
457da2e3ebdSchin 			flags &= ~S_FLAG;
458da2e3ebdSchin 	}
459da2e3ebdSchin 	if(cp)
460da2e3ebdSchin 	{
461da2e3ebdSchin 		cpmax = cp + c;
462da2e3ebdSchin #if SHOPT_CRNL
463da2e3ebdSchin 		if(delim=='\n' && c>=2 && cpmax[-2]=='\r')
464da2e3ebdSchin 			cpmax--;
465da2e3ebdSchin #endif /* SHOPT_CRNL */
466da2e3ebdSchin 		if(*(cpmax-1) != delim)
467da2e3ebdSchin 			*(cpmax-1) = delim;
468da2e3ebdSchin 		if(flags&S_FLAG)
469da2e3ebdSchin 			sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
470da2e3ebdSchin 		c = shp->ifstable[*cp++];
471da2e3ebdSchin #if !SHOPT_MULTIBYTE
472da2e3ebdSchin 		if(!name && (flags&R_FLAG)) /* special case single argument */
473da2e3ebdSchin 		{
474da2e3ebdSchin 			/* skip over leading blanks */
475da2e3ebdSchin 			while(c==S_SPACE)
476da2e3ebdSchin 				c = shp->ifstable[*cp++];
477da2e3ebdSchin 			/* strip trailing delimiters */
478da2e3ebdSchin 			if(cpmax[-1] == '\n')
479da2e3ebdSchin 				cpmax--;
480da2e3ebdSchin 			if(cpmax>cp)
481da2e3ebdSchin 			{
482da2e3ebdSchin 				while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
483da2e3ebdSchin 				cpmax[1] = 0;
484da2e3ebdSchin 			}
485da2e3ebdSchin 			else
486da2e3ebdSchin 				*cpmax =0;
487da2e3ebdSchin 			if(nv_isattr(np, NV_RDONLY))
488da2e3ebdSchin 			{
489da2e3ebdSchin 				errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
490da2e3ebdSchin 				jmpval = 1;
491da2e3ebdSchin 			}
492da2e3ebdSchin 			else
493da2e3ebdSchin 				nv_putval(np,(char*)cp-1,0);
494da2e3ebdSchin 			goto done;
495da2e3ebdSchin 		}
496da2e3ebdSchin #endif /* !SHOPT_MULTIBYTE */
497da2e3ebdSchin 	}
498da2e3ebdSchin 	else
499da2e3ebdSchin 		c = S_NL;
500da2e3ebdSchin 	shp->nextprompt = 2;
501da2e3ebdSchin 	rel= staktell();
502da2e3ebdSchin 	/* val==0 at the start of a field */
503da2e3ebdSchin 	val = 0;
504da2e3ebdSchin 	del = 0;
505da2e3ebdSchin 	while(1)
506da2e3ebdSchin 	{
507da2e3ebdSchin 		switch(c)
508da2e3ebdSchin 		{
509da2e3ebdSchin #if SHOPT_MULTIBYTE
510da2e3ebdSchin 		   case S_MBYTE:
511da2e3ebdSchin 			if(val==0)
512da2e3ebdSchin 				val = (char*)(cp-1);
513da2e3ebdSchin 			if(sh_strchr(ifs,(char*)cp-1)>=0)
514da2e3ebdSchin 			{
515da2e3ebdSchin 				c = mbsize((char*)cp-1);
516da2e3ebdSchin 				if(name)
517da2e3ebdSchin 					cp[-1] = 0;
518da2e3ebdSchin 				if(c>1)
519da2e3ebdSchin 					cp += (c-1);
520da2e3ebdSchin 				c = S_DELIM;
521da2e3ebdSchin 			}
522da2e3ebdSchin 			else
523da2e3ebdSchin 				c = 0;
524da2e3ebdSchin 			continue;
525da2e3ebdSchin #endif /*SHOPT_MULTIBYTE */
526da2e3ebdSchin 		    case S_ESC:
527da2e3ebdSchin 			/* process escape character */
528da2e3ebdSchin 			if((c = shp->ifstable[*cp++]) == S_NL)
529da2e3ebdSchin 				was_escape = 1;
530da2e3ebdSchin 			else
531da2e3ebdSchin 				c = 0;
532da2e3ebdSchin 			if(val)
533da2e3ebdSchin 			{
534da2e3ebdSchin 				stakputs(val);
535da2e3ebdSchin 				use_stak = 1;
536da2e3ebdSchin 				was_escape = 1;
537da2e3ebdSchin 				*val = 0;
538da2e3ebdSchin 			}
539da2e3ebdSchin 			continue;
540da2e3ebdSchin 
541da2e3ebdSchin 		    case S_EOF:
542da2e3ebdSchin 			/* check for end of buffer */
543da2e3ebdSchin 			if(val && *val)
544da2e3ebdSchin 			{
545da2e3ebdSchin 				stakputs(val);
546da2e3ebdSchin 				use_stak = 1;
547da2e3ebdSchin 			}
548da2e3ebdSchin 			val = 0;
549da2e3ebdSchin 			if(cp>=cpmax)
550da2e3ebdSchin 			{
551da2e3ebdSchin 				c = S_NL;
552da2e3ebdSchin 				break;
553da2e3ebdSchin 			}
554da2e3ebdSchin 			/* eliminate null bytes */
555da2e3ebdSchin 			c = shp->ifstable[*cp++];
556da2e3ebdSchin 			if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
557da2e3ebdSchin 				c = 0;
558da2e3ebdSchin 			continue;
559da2e3ebdSchin 		    case S_NL:
560da2e3ebdSchin 			if(was_escape)
561da2e3ebdSchin 			{
562da2e3ebdSchin 				was_escape = 0;
563da2e3ebdSchin 				if(cp = (unsigned char*)sfgetr(iop,delim,0))
564da2e3ebdSchin 					c = sfvalue(iop);
565da2e3ebdSchin 				else if(cp=(unsigned char*)sfgetr(iop,delim,-1))
566da2e3ebdSchin 					c = sfvalue(iop)+1;
567da2e3ebdSchin 				if(cp)
568da2e3ebdSchin 				{
569da2e3ebdSchin 					if(flags&S_FLAG)
570da2e3ebdSchin 						sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
571da2e3ebdSchin 					cpmax = cp + c;
572da2e3ebdSchin 					c = shp->ifstable[*cp++];
573da2e3ebdSchin 					val=0;
574da2e3ebdSchin 					if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
575da2e3ebdSchin 						c = 0;
576da2e3ebdSchin 					continue;
577da2e3ebdSchin 				}
578da2e3ebdSchin 			}
579da2e3ebdSchin 			c = S_NL;
580da2e3ebdSchin 			break;
581da2e3ebdSchin 
582da2e3ebdSchin 		    case S_SPACE:
583da2e3ebdSchin 			/* skip over blanks */
584da2e3ebdSchin 			while((c=shp->ifstable[*cp++])==S_SPACE);
585da2e3ebdSchin 			if(!val)
586da2e3ebdSchin 				continue;
587da2e3ebdSchin #if SHOPT_MULTIBYTE
588da2e3ebdSchin 			if(c==S_MBYTE)
589da2e3ebdSchin 			{
590da2e3ebdSchin 				if(sh_strchr(ifs,(char*)cp-1)>=0)
591da2e3ebdSchin 				{
592da2e3ebdSchin 					if((c = mbsize((char*)cp-1))>1)
593da2e3ebdSchin 						cp += (c-1);
594da2e3ebdSchin 					c = S_DELIM;
595da2e3ebdSchin 				}
596da2e3ebdSchin 				else
597da2e3ebdSchin 					c = 0;
598da2e3ebdSchin 			}
599da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
600da2e3ebdSchin 			if(c!=S_DELIM)
601da2e3ebdSchin 				break;
602da2e3ebdSchin 			/* FALL THRU */
603da2e3ebdSchin 
604da2e3ebdSchin 		    case S_DELIM:
605da2e3ebdSchin 			if(!del)
606da2e3ebdSchin 				del = cp - 1;
607da2e3ebdSchin 			if(name)
608da2e3ebdSchin 			{
609da2e3ebdSchin 				/* skip over trailing blanks */
610da2e3ebdSchin 				while((c=shp->ifstable[*cp++])==S_SPACE);
611da2e3ebdSchin 				break;
612da2e3ebdSchin 			}
613da2e3ebdSchin 			/* FALL THRU */
614da2e3ebdSchin 
615da2e3ebdSchin 		    case 0:
616da2e3ebdSchin 			if(val==0 || was_escape)
617da2e3ebdSchin 			{
618da2e3ebdSchin 				val = (char*)(cp-1);
619da2e3ebdSchin 				was_escape = 0;
620da2e3ebdSchin 			}
621da2e3ebdSchin 			/* skip over word characters */
622da2e3ebdSchin 			wrd = -1;
623da2e3ebdSchin 			while(1)
624da2e3ebdSchin 			{
625da2e3ebdSchin 				while((c=shp->ifstable[*cp++])==0)
626da2e3ebdSchin 					if(!wrd)
627da2e3ebdSchin 						wrd = 1;
628da2e3ebdSchin 				if(!del&&c==S_DELIM)
629da2e3ebdSchin 					del = cp - 1;
630da2e3ebdSchin 				if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
631da2e3ebdSchin 					break;
632da2e3ebdSchin 				if(wrd<0)
633da2e3ebdSchin 					wrd = 0;
634da2e3ebdSchin 			}
635da2e3ebdSchin 			if(wrd>0)
636da2e3ebdSchin 				del = (unsigned char*)"";
637da2e3ebdSchin 			if(c!=S_MBYTE)
638da2e3ebdSchin 				cp[-1] = 0;
639da2e3ebdSchin 			continue;
640da2e3ebdSchin 		}
641da2e3ebdSchin 		/* assign value and advance to next variable */
642da2e3ebdSchin 		if(!val)
643da2e3ebdSchin 			val = "";
644da2e3ebdSchin 		if(use_stak)
645da2e3ebdSchin 		{
646da2e3ebdSchin 			stakputs(val);
647da2e3ebdSchin 			stakputc(0);
648da2e3ebdSchin 			val = stakptr(rel);
649da2e3ebdSchin 		}
650da2e3ebdSchin 		if(!name && *val)
651da2e3ebdSchin 		{
652da2e3ebdSchin 			/* strip off trailing space delimiters */
653da2e3ebdSchin 			register unsigned char	*vp = (unsigned char*)val + strlen(val);
654da2e3ebdSchin 			while(shp->ifstable[*--vp]==S_SPACE);
655da2e3ebdSchin 			if(vp==del)
656da2e3ebdSchin 			{
657da2e3ebdSchin 				if(vp==(unsigned char*)val)
658da2e3ebdSchin 					vp--;
659da2e3ebdSchin 				else
660da2e3ebdSchin 					while(shp->ifstable[*--vp]==S_SPACE);
661da2e3ebdSchin 			}
662da2e3ebdSchin 			vp[1] = 0;
663da2e3ebdSchin 		}
664da2e3ebdSchin 		if(nv_isattr(np, NV_RDONLY))
665da2e3ebdSchin 		{
666da2e3ebdSchin 			errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
667da2e3ebdSchin 			jmpval = 1;
668da2e3ebdSchin 		}
669da2e3ebdSchin 		else
670da2e3ebdSchin 			nv_putval(np,val,0);
671da2e3ebdSchin 		val = 0;
672da2e3ebdSchin 		del = 0;
673da2e3ebdSchin 		if(use_stak)
674da2e3ebdSchin 		{
675da2e3ebdSchin 			stakseek(rel);
676da2e3ebdSchin 			use_stak = 0;
677da2e3ebdSchin 		}
678da2e3ebdSchin 		if(array_index)
679da2e3ebdSchin 		{
680da2e3ebdSchin 			nv_putsub(np, NIL(char*), array_index++);
681da2e3ebdSchin 			if(c!=S_NL)
682da2e3ebdSchin 				continue;
683da2e3ebdSchin 			name = *++names;
684da2e3ebdSchin 		}
685da2e3ebdSchin 		while(1)
686da2e3ebdSchin 		{
687da2e3ebdSchin 			if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT))
688da2e3ebdSchin 			{
689da2e3ebdSchin 				nv_onattr(np,NV_EXPORT);
690da2e3ebdSchin 				sh_envput(sh.env,np);
691da2e3ebdSchin 			}
692da2e3ebdSchin 			if(name)
693da2e3ebdSchin 			{
694da2e3ebdSchin 				nv_close(np);
695da2e3ebdSchin 				np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
696da2e3ebdSchin 				name = *++names;
697da2e3ebdSchin 			}
698da2e3ebdSchin 			else
699da2e3ebdSchin 				np = 0;
700da2e3ebdSchin 			if(c!=S_NL)
701da2e3ebdSchin 				break;
702da2e3ebdSchin 			if(!np)
703da2e3ebdSchin 				goto done;
704da2e3ebdSchin 			if(nv_isattr(np, NV_RDONLY))
705da2e3ebdSchin 			{
706da2e3ebdSchin 				errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
707da2e3ebdSchin 				jmpval = 1;
708da2e3ebdSchin 			}
709da2e3ebdSchin 			else
710da2e3ebdSchin 				nv_putval(np, "", 0);
711da2e3ebdSchin 		}
712da2e3ebdSchin 	}
713da2e3ebdSchin done:
714da2e3ebdSchin 	if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
715da2e3ebdSchin 		sh_popcontext(&buff);
716da2e3ebdSchin 	if(was_write)
717da2e3ebdSchin 		sfset(iop,SF_WRITE,1);
718da2e3ebdSchin 	if(!was_share)
719da2e3ebdSchin 		sfset(iop,SF_SHARE,0);
720da2e3ebdSchin 	nv_close(np);
721da2e3ebdSchin 	if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY))
722da2e3ebdSchin 		tty_cooked(fd);
723da2e3ebdSchin 	if(flags&S_FLAG)
724da2e3ebdSchin 		hist_flush(shp->hist_ptr);
725da2e3ebdSchin 	if(jmpval > 1)
726da2e3ebdSchin 		siglongjmp(*shp->jmplist,jmpval);
727da2e3ebdSchin 	return(jmpval);
728da2e3ebdSchin }
729da2e3ebdSchin 
730