xref: /onnv-gate/usr/src/lib/libshell/common/bltins/read.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
228462SApril.Chin@Sun.COM  * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...]
234887Schin  *
244887Schin  *   David Korn
254887Schin  *   AT&T Labs
264887Schin  *
274887Schin  */
284887Schin 
294887Schin #include	<ast.h>
304887Schin #include	<error.h>
314887Schin #include	"defs.h"
324887Schin #include	"variables.h"
334887Schin #include	"lexstates.h"
344887Schin #include	"io.h"
354887Schin #include	"name.h"
364887Schin #include	"builtins.h"
374887Schin #include	"history.h"
384887Schin #include	"terminal.h"
394887Schin #include	"edit.h"
404887Schin 
414887Schin #define	R_FLAG	1	/* raw mode */
424887Schin #define	S_FLAG	2	/* save in history file */
434887Schin #define	A_FLAG	4	/* read into array */
444887Schin #define N_FLAG	8	/* fixed size read at most */
454887Schin #define NN_FLAG	0x10	/* fixed size read exact */
464887Schin #define V_FLAG	0x20	/* use default value */
478462SApril.Chin@Sun.COM #define	C_FLAG	0x40	/* read into compound variable */
484887Schin #define D_FLAG	8	/* must be number of bits for all flags */
494887Schin 
508462SApril.Chin@Sun.COM struct read_save
518462SApril.Chin@Sun.COM {
528462SApril.Chin@Sun.COM         char	**argv;
538462SApril.Chin@Sun.COM 	char	*prompt;
548462SApril.Chin@Sun.COM         short	fd;
558462SApril.Chin@Sun.COM         short	plen;
568462SApril.Chin@Sun.COM 	int	flags;
578462SApril.Chin@Sun.COM         long	timeout;
588462SApril.Chin@Sun.COM };
598462SApril.Chin@Sun.COM 
b_read(int argc,char * argv[],void * extra)604887Schin int	b_read(int argc,char *argv[], void *extra)
614887Schin {
624887Schin 	Sfdouble_t sec;
634887Schin 	register char *name;
644887Schin 	register int r, flags=0, fd=0;
658462SApril.Chin@Sun.COM 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
664887Schin 	long timeout = 1000*shp->st.tmout;
678462SApril.Chin@Sun.COM 	int save_prompt, fixargs=((Shbltin_t*)extra)->invariant;
688462SApril.Chin@Sun.COM 	struct read_save *rp;
694887Schin 	static char default_prompt[3] = {ESC,ESC};
7010898Sroland.mainz@nrubsig.org 	rp = (struct read_save*)(((Shbltin_t*)extra)->data);
718462SApril.Chin@Sun.COM 	if(argc==0)
7210898Sroland.mainz@nrubsig.org 	{
7310898Sroland.mainz@nrubsig.org 		if(rp)
7410898Sroland.mainz@nrubsig.org 			free((void*)rp);
758462SApril.Chin@Sun.COM 		return(0);
7610898Sroland.mainz@nrubsig.org 	}
7710898Sroland.mainz@nrubsig.org 	if(rp)
788462SApril.Chin@Sun.COM 	{
798462SApril.Chin@Sun.COM 		flags = rp->flags;
808462SApril.Chin@Sun.COM 		timeout = rp->timeout;
818462SApril.Chin@Sun.COM 		fd = rp->fd;
828462SApril.Chin@Sun.COM 		argv = rp->argv;
838462SApril.Chin@Sun.COM 		name = rp->prompt;
848462SApril.Chin@Sun.COM 		r = rp->plen;
858462SApril.Chin@Sun.COM 		goto bypass;
868462SApril.Chin@Sun.COM 	}
874887Schin 	while((r = optget(argv,sh_optread))) switch(r)
884887Schin 	{
894887Schin 	    case 'A':
904887Schin 		flags |= A_FLAG;
914887Schin 		break;
928462SApril.Chin@Sun.COM 	    case 'C':
938462SApril.Chin@Sun.COM 		flags |= C_FLAG;
948462SApril.Chin@Sun.COM 		break;
954887Schin 	    case 't':
964887Schin 		sec = sh_strnum(opt_info.arg, (char**)0,1);
974887Schin 		timeout = sec ? 1000*sec : 1;
984887Schin 		break;
994887Schin 	    case 'd':
1004887Schin 		if(opt_info.arg && *opt_info.arg!='\n')
1014887Schin 		{
1024887Schin 			char *cp = opt_info.arg;
1034887Schin 			flags &= ~((1<<D_FLAG)-1);
1044887Schin 			flags |= (mbchar(cp)<< D_FLAG);
1054887Schin 		}
1064887Schin 		break;
1074887Schin 	    case 'p':
1084887Schin 		if((fd = shp->cpipe[0])<=0)
1094887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_query);
1104887Schin 		break;
1114887Schin 	    case 'n': case 'N':
1128462SApril.Chin@Sun.COM 		flags &= ((1<<D_FLAG)-1);
1134887Schin 		flags |= (r=='n'?N_FLAG:NN_FLAG);
1144887Schin 		r = (int)opt_info.num;
1154887Schin 		if((unsigned)r > (1<<((8*sizeof(int))-D_FLAG))-1)
1168462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_exit(1),e_overlimit,opt_info.name);
1174887Schin 		flags |= (r<< D_FLAG);
1184887Schin 		break;
1194887Schin 	    case 'r':
1204887Schin 		flags |= R_FLAG;
1214887Schin 		break;
1224887Schin 	    case 's':
1234887Schin 		/* save in history file */
1244887Schin 		flags |= S_FLAG;
1254887Schin 		break;
1264887Schin 	    case 'u':
1274887Schin 		fd = (int)opt_info.num;
1284887Schin 		if(sh_inuse(fd))
1294887Schin 			fd = -1;
1304887Schin 		break;
1314887Schin 	    case 'v':
1324887Schin 		flags |= V_FLAG;
1334887Schin 		break;
1344887Schin 	    case ':':
1354887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
1364887Schin 		break;
1374887Schin 	    case '?':
1384887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1394887Schin 		break;
1404887Schin 	}
1414887Schin 	argv += opt_info.index;
1424887Schin 	if(error_info.errors)
1434887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
1444887Schin 	if(!((r=shp->fdstatus[fd])&IOREAD)  || !(r&(IOSEEK|IONOSEEK)))
1458462SApril.Chin@Sun.COM 		r = sh_iocheckfd(shp,fd);
1464887Schin 	if(fd<0 || !(r&IOREAD))
1474887Schin 		errormsg(SH_DICT,ERROR_system(1),e_file+4);
1484887Schin 	/* look for prompt */
1494887Schin 	if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
1508462SApril.Chin@Sun.COM 		r = strlen(name++);
1518462SApril.Chin@Sun.COM 	else
1528462SApril.Chin@Sun.COM 		r = 0;
1538462SApril.Chin@Sun.COM 	if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0)))
1544887Schin 	{
1558462SApril.Chin@Sun.COM 		((Shbltin_t*)extra)->data = (void*)rp;
1568462SApril.Chin@Sun.COM 		rp->fd = fd;
1578462SApril.Chin@Sun.COM 		rp->flags = flags;
1588462SApril.Chin@Sun.COM 		rp->timeout = timeout;
1598462SApril.Chin@Sun.COM 		rp->argv = argv;
1608462SApril.Chin@Sun.COM 		rp->prompt = name;
1618462SApril.Chin@Sun.COM 		rp->plen = r;
1628462SApril.Chin@Sun.COM 	}
1638462SApril.Chin@Sun.COM bypass:
164*12068SRoger.Faulkner@Oracle.COM 	shp->prompt = default_prompt;
1658462SApril.Chin@Sun.COM 	if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)))
1668462SApril.Chin@Sun.COM 	{
1678462SApril.Chin@Sun.COM 		memcpy(shp->prompt,name,r);
1688462SApril.Chin@Sun.COM 		sfwrite(sfstderr,shp->prompt,r-1);
1694887Schin 	}
1704887Schin 	shp->timeout = 0;
1714887Schin 	save_prompt = shp->nextprompt;
1724887Schin 	shp->nextprompt = 0;
1734887Schin 	r=sh_readline(shp,argv,fd,flags,timeout);
1744887Schin 	shp->nextprompt = save_prompt;
1754887Schin 	if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd]))))
1764887Schin 	{
1774887Schin 		if(fd == shp->cpipe[0])
1784887Schin 		{
1794887Schin 			sh_pclose(shp->cpipe);
1804887Schin 			return(1);
1814887Schin 		}
1824887Schin 	}
1834887Schin 	sfclrerr(shp->sftable[fd]);
1844887Schin 	return(r);
1854887Schin }
1864887Schin 
1874887Schin /*
1884887Schin  * here for read timeout
1894887Schin  */
timedout(void * handle)1904887Schin static void timedout(void *handle)
1914887Schin {
1924887Schin 	sfclrlock((Sfio_t*)handle);
1934887Schin 	sh_exit(1);
1944887Schin }
1954887Schin 
1964887Schin /*
1974887Schin  * This is the code to read a line and to split it into tokens
1984887Schin  *  <names> is an array of variable names
1994887Schin  *  <fd> is the file descriptor
2004887Schin  *  <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
2014887Schin  *  <timeout> is number of milli-seconds until timeout
2024887Schin  */
2034887Schin 
sh_readline(register Shell_t * shp,char ** names,int fd,int flags,long timeout)2044887Schin int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout)
2054887Schin {
20610898Sroland.mainz@nrubsig.org 	register ssize_t	c;
2074887Schin 	register unsigned char	*cp;
2084887Schin 	register Namval_t	*np;
2094887Schin 	register char		*name, *val;
2108462SApril.Chin@Sun.COM 	register Sfio_t		*iop;
2118462SApril.Chin@Sun.COM 	Namfun_t		*nfp;
2124887Schin 	char			*ifs;
2134887Schin 	unsigned char		*cpmax;
2144887Schin 	unsigned char		*del;
2154887Schin 	char			was_escape = 0;
2164887Schin 	char			use_stak = 0;
2178462SApril.Chin@Sun.COM 	volatile char		was_write = 0;
2188462SApril.Chin@Sun.COM 	volatile char		was_share = 1;
2194887Schin 	int			rel, wrd;
2204887Schin 	long			array_index = 0;
2214887Schin 	void			*timeslot=0;
2224887Schin 	int			delim = '\n';
2234887Schin 	int			jmpval=0;
22410898Sroland.mainz@nrubsig.org 	ssize_t			size = 0;
2258462SApril.Chin@Sun.COM 	int			binary;
2264887Schin 	struct	checkpt		buff;
2278462SApril.Chin@Sun.COM 	if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd)))
2284887Schin 		return(1);
2298462SApril.Chin@Sun.COM 	sh_stats(STAT_READS);
2304887Schin 	if(names && (name = *names))
2314887Schin 	{
23210898Sroland.mainz@nrubsig.org 		Namval_t *mp;
2334887Schin 		if(val= strchr(name,'?'))
2344887Schin 			*val = 0;
2358462SApril.Chin@Sun.COM 		np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
23610898Sroland.mainz@nrubsig.org 		if(np && nv_isarray(np) && (mp=nv_opensub(np)))
23710898Sroland.mainz@nrubsig.org 			np = mp;
2384887Schin 		if((flags&V_FLAG) && shp->ed_context)
2394887Schin 			((struct edit*)shp->ed_context)->e_default = np;
2404887Schin 		if(flags&A_FLAG)
2414887Schin 		{
2424887Schin 			flags &= ~A_FLAG;
2434887Schin 			array_index = 1;
2444887Schin 			nv_unset(np);
2454887Schin 			nv_putsub(np,NIL(char*),0L);
2464887Schin 		}
2478462SApril.Chin@Sun.COM 		else if(flags&C_FLAG)
2488462SApril.Chin@Sun.COM 		{
2498462SApril.Chin@Sun.COM 			delim = -1;
2508462SApril.Chin@Sun.COM 			nv_unset(np);
2518462SApril.Chin@Sun.COM 			nv_setvtree(np);
2528462SApril.Chin@Sun.COM 		}
2534887Schin 		else
2544887Schin 			name = *++names;
2554887Schin 		if(val)
2564887Schin 			*val = '?';
2574887Schin 	}
2584887Schin 	else
2594887Schin 	{
2604887Schin 		name = 0;
2614887Schin 		if(dtvnext(shp->var_tree) || shp->namespace)
2624887Schin                 	np = nv_open(nv_name(REPLYNOD),shp->var_tree,0);
2634887Schin 		else
2644887Schin 			np = REPLYNOD;
2654887Schin 	}
2664887Schin 	if(flags>>D_FLAG)	/* delimiter not new-line or fixed size read */
2674887Schin 	{
2684887Schin 		if(flags&(N_FLAG|NN_FLAG))
2694887Schin 			size = ((unsigned)flags)>>D_FLAG;
2704887Schin 		else
2714887Schin 			delim = ((unsigned)flags)>>D_FLAG;
2724887Schin 		if(shp->fdstatus[fd]&IOTTY)
2734887Schin 			tty_raw(fd,1);
2744887Schin 	}
2758462SApril.Chin@Sun.COM 	binary = nv_isattr(np,NV_BINARY);
2768462SApril.Chin@Sun.COM 	if(!binary && !(flags&(N_FLAG|NN_FLAG)))
2774887Schin 	{
2784887Schin 		Namval_t *mp;
2794887Schin 		/* set up state table based on IFS */
2808462SApril.Chin@Sun.COM 		ifs = nv_getval(mp=sh_scoped(shp,IFSNOD));
2814887Schin 		if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC)
2824887Schin 			shp->ifstable['\\'] = 0;
2834887Schin 		else if(!(flags&R_FLAG) && shp->ifstable['\\']==0)
2844887Schin 			shp->ifstable['\\'] = S_ESC;
2854887Schin 		shp->ifstable[delim] = S_NL;
2864887Schin 		if(delim!='\n')
2874887Schin 		{
2884887Schin 			shp->ifstable['\n'] = 0;
2894887Schin 			nv_putval(mp, ifs, NV_RDONLY);
2904887Schin 		}
2914887Schin 		shp->ifstable[0] = S_EOF;
2924887Schin 	}
2934887Schin 	sfclrerr(iop);
2948462SApril.Chin@Sun.COM 	for(nfp=np->nvfun; nfp; nfp = nfp->next)
2958462SApril.Chin@Sun.COM 	{
2968462SApril.Chin@Sun.COM 		if(nfp->disc && nfp->disc->readf)
2978462SApril.Chin@Sun.COM 		{
2988462SApril.Chin@Sun.COM 			if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0)
2998462SApril.Chin@Sun.COM 				return(c);
3008462SApril.Chin@Sun.COM 		}
3018462SApril.Chin@Sun.COM 	}
3028462SApril.Chin@Sun.COM 	if(binary && !(flags&(N_FLAG|NN_FLAG)))
3038462SApril.Chin@Sun.COM 	{
3048462SApril.Chin@Sun.COM 		flags |= NN_FLAG;
3058462SApril.Chin@Sun.COM 		size = nv_size(np);
3068462SApril.Chin@Sun.COM 	}
3074887Schin 	was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0;
3084887Schin 	if(fd==0)
3094887Schin 		was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0;
3104887Schin 	if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
3114887Schin 	{
3124887Schin 		sh_pushcontext(&buff,1);
3134887Schin 		jmpval = sigsetjmp(buff.buff,0);
3144887Schin 		if(jmpval)
3154887Schin 			goto done;
3164887Schin 		if(timeout)
3174887Schin 	                timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop);
3184887Schin 	}
3194887Schin 	if(flags&(N_FLAG|NN_FLAG))
3204887Schin 	{
32110898Sroland.mainz@nrubsig.org 		char buf[256],*var=buf,*cur,*end,*up,*v;
3224887Schin 		/* reserved buffer */
3234887Schin 		if((c=size)>=sizeof(buf))
3244887Schin 		{
3254887Schin 			if(!(var = (char*)malloc(c+1)))
3264887Schin 				sh_exit(1);
3278462SApril.Chin@Sun.COM 			end = var + c;
3284887Schin 		}
3298462SApril.Chin@Sun.COM 		else
3308462SApril.Chin@Sun.COM 			end = var + sizeof(buf) - 1;
3318462SApril.Chin@Sun.COM 		up = cur = var;
3324887Schin 		if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0)
3334887Schin 			was_share = 1;
3344887Schin 		if(size==0)
3354887Schin 		{
3364887Schin 			cp = sfreserve(iop,0,0);
3374887Schin 			c = 0;
3384887Schin 		}
3394887Schin 		else
3404887Schin 		{
34110898Sroland.mainz@nrubsig.org 			ssize_t	m;
34210898Sroland.mainz@nrubsig.org 			int	f;
3438462SApril.Chin@Sun.COM 			for (;;)
3444887Schin 			{
345*12068SRoger.Faulkner@Oracle.COM 				c = size;
3468462SApril.Chin@Sun.COM 				cp = sfreserve(iop,c,SF_LOCKR);
3478462SApril.Chin@Sun.COM 				f = 1;
34810898Sroland.mainz@nrubsig.org 				if(cp)
34910898Sroland.mainz@nrubsig.org 					m = sfvalue(iop);
350*12068SRoger.Faulkner@Oracle.COM 				else if(flags&NN_FLAG)
351*12068SRoger.Faulkner@Oracle.COM 				{
352*12068SRoger.Faulkner@Oracle.COM 					c = size;
353*12068SRoger.Faulkner@Oracle.COM 					m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0;
354*12068SRoger.Faulkner@Oracle.COM 					f = 0;
355*12068SRoger.Faulkner@Oracle.COM 				}
35610898Sroland.mainz@nrubsig.org 				else
3578462SApril.Chin@Sun.COM 				{
358*12068SRoger.Faulkner@Oracle.COM 					c = sfvalue(iop);
359*12068SRoger.Faulkner@Oracle.COM 					m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0;
36010898Sroland.mainz@nrubsig.org 				}
36110898Sroland.mainz@nrubsig.org 				if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m)))
36210898Sroland.mainz@nrubsig.org 				{
36310898Sroland.mainz@nrubsig.org 					*v++ = 0;
36410898Sroland.mainz@nrubsig.org 					m = v-(char*)cp;
3658462SApril.Chin@Sun.COM 				}
3668462SApril.Chin@Sun.COM 				if((c=m)>size)
3678462SApril.Chin@Sun.COM 					c = size;
3688462SApril.Chin@Sun.COM 				if(c>0)
3698462SApril.Chin@Sun.COM 				{
3708462SApril.Chin@Sun.COM 					if(c > (end-cur))
3718462SApril.Chin@Sun.COM 					{
37210898Sroland.mainz@nrubsig.org 						ssize_t	cx = cur - var, ux = up - var;
37310898Sroland.mainz@nrubsig.org 						m = (end - var) + (c - (end - cur));
3748462SApril.Chin@Sun.COM 						if (var == buf)
3758462SApril.Chin@Sun.COM 						{
3768462SApril.Chin@Sun.COM 							v = (char*)malloc(m+1);
37710898Sroland.mainz@nrubsig.org 							var = memcpy(v, var, cur - var);
3788462SApril.Chin@Sun.COM 						}
3798462SApril.Chin@Sun.COM 						else
38010898Sroland.mainz@nrubsig.org 							var = newof(var, char, m, 1);
38110898Sroland.mainz@nrubsig.org 						end = var + m;
38210898Sroland.mainz@nrubsig.org 						cur = var + cx;
38310898Sroland.mainz@nrubsig.org 						up = var + ux;
3848462SApril.Chin@Sun.COM 					}
3858462SApril.Chin@Sun.COM 					memcpy((void*)cur,cp,c);
3868462SApril.Chin@Sun.COM 					if(f)
3878462SApril.Chin@Sun.COM 						sfread(iop,cp,c);
3888462SApril.Chin@Sun.COM 					cur += c;
3898462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE
3908462SApril.Chin@Sun.COM 					if(!binary && mbwide())
3918462SApril.Chin@Sun.COM 					{
3928462SApril.Chin@Sun.COM 						int	x;
3938462SApril.Chin@Sun.COM 						int	z;
3948462SApril.Chin@Sun.COM 
3958462SApril.Chin@Sun.COM 						mbinit();
3968462SApril.Chin@Sun.COM 						*cur = 0;
3978462SApril.Chin@Sun.COM 						x = z = 0;
3988462SApril.Chin@Sun.COM 						while (up < cur && (z = mbsize(up)) > 0)
3998462SApril.Chin@Sun.COM 						{
4008462SApril.Chin@Sun.COM 							up += z;
4018462SApril.Chin@Sun.COM 							x++;
4028462SApril.Chin@Sun.COM 						}
4038462SApril.Chin@Sun.COM 						if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c))
4048462SApril.Chin@Sun.COM 							continue;
4058462SApril.Chin@Sun.COM 					}
4068462SApril.Chin@Sun.COM #endif
4078462SApril.Chin@Sun.COM 				}
4088462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE
4098462SApril.Chin@Sun.COM 				if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size))
4108462SApril.Chin@Sun.COM 					cur = var;
4118462SApril.Chin@Sun.COM #endif
4128462SApril.Chin@Sun.COM 				*cur = 0;
413*12068SRoger.Faulkner@Oracle.COM 				if(c>=size || (flags&N_FLAG) || m==0)
414*12068SRoger.Faulkner@Oracle.COM 				{
415*12068SRoger.Faulkner@Oracle.COM 					if(m)
416*12068SRoger.Faulkner@Oracle.COM 						sfclrerr(iop);
417*12068SRoger.Faulkner@Oracle.COM 					break;
418*12068SRoger.Faulkner@Oracle.COM 				}
419*12068SRoger.Faulkner@Oracle.COM 				size -= c;
4204887Schin 			}
4214887Schin 		}
4224887Schin 		if(timeslot)
4234887Schin 			timerdel(timeslot);
42410898Sroland.mainz@nrubsig.org 		if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size))
4254887Schin 		{
42610898Sroland.mainz@nrubsig.org 			if((c==size) && np->nvalue.cp && !nv_isarray(np))
4278462SApril.Chin@Sun.COM 				memcpy((char*)np->nvalue.cp,var,c);
4288462SApril.Chin@Sun.COM 			else
4298462SApril.Chin@Sun.COM 			{
43010898Sroland.mainz@nrubsig.org 				Namval_t *mp;
4318462SApril.Chin@Sun.COM 				if(var==buf)
432*12068SRoger.Faulkner@Oracle.COM 					var = memdup(var,c+1);
4338462SApril.Chin@Sun.COM 				nv_putval(np,var,NV_RAW);
4348462SApril.Chin@Sun.COM 				nv_setsize(np,c);
43510898Sroland.mainz@nrubsig.org 				if(!nv_isattr(np,NV_IMPORT|NV_EXPORT)  && (mp=(Namval_t*)np->nvenv))
43610898Sroland.mainz@nrubsig.org 					nv_setsize(mp,c);
4378462SApril.Chin@Sun.COM 			}
4384887Schin 		}
4394887Schin 		else
4404887Schin 		{
4414887Schin 			nv_putval(np,var,0);
4428462SApril.Chin@Sun.COM 			if(var!=buf)
4434887Schin 				free((void*)var);
4444887Schin 		}
4454887Schin 		goto done;
4464887Schin 	}
4474887Schin 	else if(cp = (unsigned char*)sfgetr(iop,delim,0))
4484887Schin 		c = sfvalue(iop);
4494887Schin 	else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
4504887Schin 		c = sfvalue(iop)+1;
4514887Schin 	if(timeslot)
4524887Schin 		timerdel(timeslot);
4534887Schin 	if((flags&S_FLAG) && !shp->hist_ptr)
4544887Schin 	{
4558462SApril.Chin@Sun.COM 		sh_histinit((void*)shp);
4564887Schin 		if(!shp->hist_ptr)
4574887Schin 			flags &= ~S_FLAG;
4584887Schin 	}
4594887Schin 	if(cp)
4604887Schin 	{
4614887Schin 		cpmax = cp + c;
4624887Schin #if SHOPT_CRNL
4634887Schin 		if(delim=='\n' && c>=2 && cpmax[-2]=='\r')
4644887Schin 			cpmax--;
4654887Schin #endif /* SHOPT_CRNL */
4664887Schin 		if(*(cpmax-1) != delim)
4674887Schin 			*(cpmax-1) = delim;
4684887Schin 		if(flags&S_FLAG)
4694887Schin 			sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
4704887Schin 		c = shp->ifstable[*cp++];
4714887Schin #if !SHOPT_MULTIBYTE
4724887Schin 		if(!name && (flags&R_FLAG)) /* special case single argument */
4734887Schin 		{
4744887Schin 			/* skip over leading blanks */
4754887Schin 			while(c==S_SPACE)
4764887Schin 				c = shp->ifstable[*cp++];
4774887Schin 			/* strip trailing delimiters */
4784887Schin 			if(cpmax[-1] == '\n')
4794887Schin 				cpmax--;
4804887Schin 			if(cpmax>cp)
4814887Schin 			{
4824887Schin 				while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
4834887Schin 				cpmax[1] = 0;
4844887Schin 			}
4854887Schin 			else
4864887Schin 				*cpmax =0;
4874887Schin 			if(nv_isattr(np, NV_RDONLY))
4884887Schin 			{
4894887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
4904887Schin 				jmpval = 1;
4914887Schin 			}
4924887Schin 			else
4934887Schin 				nv_putval(np,(char*)cp-1,0);
4944887Schin 			goto done;
4954887Schin 		}
4964887Schin #endif /* !SHOPT_MULTIBYTE */
4974887Schin 	}
4984887Schin 	else
4994887Schin 		c = S_NL;
5004887Schin 	shp->nextprompt = 2;
5014887Schin 	rel= staktell();
5024887Schin 	/* val==0 at the start of a field */
5034887Schin 	val = 0;
5044887Schin 	del = 0;
5054887Schin 	while(1)
5064887Schin 	{
5074887Schin 		switch(c)
5084887Schin 		{
5094887Schin #if SHOPT_MULTIBYTE
5104887Schin 		   case S_MBYTE:
5114887Schin 			if(val==0)
5124887Schin 				val = (char*)(cp-1);
5134887Schin 			if(sh_strchr(ifs,(char*)cp-1)>=0)
5144887Schin 			{
5154887Schin 				c = mbsize((char*)cp-1);
5164887Schin 				if(name)
5174887Schin 					cp[-1] = 0;
5184887Schin 				if(c>1)
5194887Schin 					cp += (c-1);
5204887Schin 				c = S_DELIM;
5214887Schin 			}
5224887Schin 			else
5234887Schin 				c = 0;
5244887Schin 			continue;
5254887Schin #endif /*SHOPT_MULTIBYTE */
5264887Schin 		    case S_ESC:
5274887Schin 			/* process escape character */
5284887Schin 			if((c = shp->ifstable[*cp++]) == S_NL)
5294887Schin 				was_escape = 1;
5304887Schin 			else
5314887Schin 				c = 0;
5324887Schin 			if(val)
5334887Schin 			{
5344887Schin 				stakputs(val);
5354887Schin 				use_stak = 1;
5364887Schin 				was_escape = 1;
5374887Schin 				*val = 0;
5384887Schin 			}
5394887Schin 			continue;
5404887Schin 
5414887Schin 		    case S_EOF:
5424887Schin 			/* check for end of buffer */
5434887Schin 			if(val && *val)
5444887Schin 			{
5454887Schin 				stakputs(val);
5464887Schin 				use_stak = 1;
5474887Schin 			}
5484887Schin 			val = 0;
5494887Schin 			if(cp>=cpmax)
5504887Schin 			{
5514887Schin 				c = S_NL;
5524887Schin 				break;
5534887Schin 			}
5544887Schin 			/* eliminate null bytes */
5554887Schin 			c = shp->ifstable[*cp++];
5564887Schin 			if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
5574887Schin 				c = 0;
5584887Schin 			continue;
5594887Schin 		    case S_NL:
5604887Schin 			if(was_escape)
5614887Schin 			{
5624887Schin 				was_escape = 0;
5634887Schin 				if(cp = (unsigned char*)sfgetr(iop,delim,0))
5644887Schin 					c = sfvalue(iop);
5654887Schin 				else if(cp=(unsigned char*)sfgetr(iop,delim,-1))
5664887Schin 					c = sfvalue(iop)+1;
5674887Schin 				if(cp)
5684887Schin 				{
5694887Schin 					if(flags&S_FLAG)
5704887Schin 						sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
5714887Schin 					cpmax = cp + c;
5724887Schin 					c = shp->ifstable[*cp++];
5734887Schin 					val=0;
5744887Schin 					if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
5754887Schin 						c = 0;
5764887Schin 					continue;
5774887Schin 				}
5784887Schin 			}
5794887Schin 			c = S_NL;
5804887Schin 			break;
5814887Schin 
5824887Schin 		    case S_SPACE:
5834887Schin 			/* skip over blanks */
5844887Schin 			while((c=shp->ifstable[*cp++])==S_SPACE);
5854887Schin 			if(!val)
5864887Schin 				continue;
5874887Schin #if SHOPT_MULTIBYTE
5884887Schin 			if(c==S_MBYTE)
5894887Schin 			{
5904887Schin 				if(sh_strchr(ifs,(char*)cp-1)>=0)
5914887Schin 				{
5924887Schin 					if((c = mbsize((char*)cp-1))>1)
5934887Schin 						cp += (c-1);
5944887Schin 					c = S_DELIM;
5954887Schin 				}
5964887Schin 				else
5974887Schin 					c = 0;
5984887Schin 			}
5994887Schin #endif /* SHOPT_MULTIBYTE */
6004887Schin 			if(c!=S_DELIM)
6014887Schin 				break;
6024887Schin 			/* FALL THRU */
6034887Schin 
6044887Schin 		    case S_DELIM:
6054887Schin 			if(!del)
6064887Schin 				del = cp - 1;
6074887Schin 			if(name)
6084887Schin 			{
6094887Schin 				/* skip over trailing blanks */
6104887Schin 				while((c=shp->ifstable[*cp++])==S_SPACE);
6114887Schin 				break;
6124887Schin 			}
6134887Schin 			/* FALL THRU */
6144887Schin 
6154887Schin 		    case 0:
6164887Schin 			if(val==0 || was_escape)
6174887Schin 			{
6184887Schin 				val = (char*)(cp-1);
6194887Schin 				was_escape = 0;
6204887Schin 			}
6214887Schin 			/* skip over word characters */
6224887Schin 			wrd = -1;
6234887Schin 			while(1)
6244887Schin 			{
6254887Schin 				while((c=shp->ifstable[*cp++])==0)
6264887Schin 					if(!wrd)
6274887Schin 						wrd = 1;
6284887Schin 				if(!del&&c==S_DELIM)
6294887Schin 					del = cp - 1;
6304887Schin 				if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
6314887Schin 					break;
6324887Schin 				if(wrd<0)
6334887Schin 					wrd = 0;
6344887Schin 			}
6354887Schin 			if(wrd>0)
6364887Schin 				del = (unsigned char*)"";
6374887Schin 			if(c!=S_MBYTE)
6384887Schin 				cp[-1] = 0;
6394887Schin 			continue;
6404887Schin 		}
6414887Schin 		/* assign value and advance to next variable */
6424887Schin 		if(!val)
6434887Schin 			val = "";
6444887Schin 		if(use_stak)
6454887Schin 		{
6464887Schin 			stakputs(val);
6474887Schin 			stakputc(0);
6484887Schin 			val = stakptr(rel);
6494887Schin 		}
6504887Schin 		if(!name && *val)
6514887Schin 		{
6524887Schin 			/* strip off trailing space delimiters */
6534887Schin 			register unsigned char	*vp = (unsigned char*)val + strlen(val);
6544887Schin 			while(shp->ifstable[*--vp]==S_SPACE);
6554887Schin 			if(vp==del)
6564887Schin 			{
6574887Schin 				if(vp==(unsigned char*)val)
6584887Schin 					vp--;
6594887Schin 				else
6604887Schin 					while(shp->ifstable[*--vp]==S_SPACE);
6614887Schin 			}
6624887Schin 			vp[1] = 0;
6634887Schin 		}
6644887Schin 		if(nv_isattr(np, NV_RDONLY))
6654887Schin 		{
6664887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
6674887Schin 			jmpval = 1;
6684887Schin 		}
6694887Schin 		else
6704887Schin 			nv_putval(np,val,0);
6714887Schin 		val = 0;
6724887Schin 		del = 0;
6734887Schin 		if(use_stak)
6744887Schin 		{
6754887Schin 			stakseek(rel);
6764887Schin 			use_stak = 0;
6774887Schin 		}
6784887Schin 		if(array_index)
6794887Schin 		{
6804887Schin 			nv_putsub(np, NIL(char*), array_index++);
6814887Schin 			if(c!=S_NL)
6824887Schin 				continue;
6834887Schin 			name = *++names;
6844887Schin 		}
6854887Schin 		while(1)
6864887Schin 		{
6874887Schin 			if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT))
6884887Schin 			{
6894887Schin 				nv_onattr(np,NV_EXPORT);
6904887Schin 				sh_envput(sh.env,np);
6914887Schin 			}
6924887Schin 			if(name)
6934887Schin 			{
6944887Schin 				nv_close(np);
6954887Schin 				np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
6964887Schin 				name = *++names;
6974887Schin 			}
6984887Schin 			else
6994887Schin 				np = 0;
7004887Schin 			if(c!=S_NL)
7014887Schin 				break;
7024887Schin 			if(!np)
7034887Schin 				goto done;
7044887Schin 			if(nv_isattr(np, NV_RDONLY))
7054887Schin 			{
7064887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
7074887Schin 				jmpval = 1;
7084887Schin 			}
7094887Schin 			else
7104887Schin 				nv_putval(np, "", 0);
7114887Schin 		}
7124887Schin 	}
7134887Schin done:
7144887Schin 	if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
7154887Schin 		sh_popcontext(&buff);
7164887Schin 	if(was_write)
7174887Schin 		sfset(iop,SF_WRITE,1);
7184887Schin 	if(!was_share)
7194887Schin 		sfset(iop,SF_SHARE,0);
7204887Schin 	nv_close(np);
7214887Schin 	if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY))
7224887Schin 		tty_cooked(fd);
7234887Schin 	if(flags&S_FLAG)
7244887Schin 		hist_flush(shp->hist_ptr);
7254887Schin 	if(jmpval > 1)
7264887Schin 		siglongjmp(*shp->jmplist,jmpval);
7274887Schin 	return(jmpval);
7284887Schin }
7294887Schin 
730