Example #1
0
static char *fmtx(const char *string)
{
	register const char	*cp = string;
	register int	 	n,c;
	unsigned char 		*state = (unsigned char*)sh_lexstates[2]; 
	int offset = staktell();
	if(*cp=='#' || *cp=='~')
		stakputc('\\');
	while((c=mbchar(cp)),(c>UCHAR_MAX)||(n=state[c])==0 || n==S_EPAT);
	if(n==S_EOF && *string!='#')
		return((char*)string);
	stakwrite(string,--cp-string);
	for(string=cp;c=mbchar(cp);string=cp)
	{
		if((n=cp-string)==1)
		{
			if((n=state[c]) && n!=S_EPAT)
				stakputc('\\');
			stakputc(c);
		}
		else
			stakwrite(string,n);
	}
	stakputc(0);
	return(stakptr(offset));
}
Example #2
0
static void
addmatch(register glob_t* gp, const char* dir, const char* pat, register const char* rescan, char* endslash, int meta)
{
	register globlist_t*	ap;
	int			offset;
	int			type;

	stakseek(MATCHPATH(gp));
	if (dir)
	{
		stakputs(dir);
		stakputc(gp->gl_delim);
	}
	if (endslash)
		*endslash = 0;
	stakputs(pat);
	if (rescan)
	{
		if ((*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0) != GLOB_DIR)
			return;
		stakputc(gp->gl_delim);
		offset = staktell();
		/* if null, reserve room for . */
		if (*rescan)
			stakputs(rescan);
		else
			stakputc(0);
		stakputc(0);
		rescan = stakptr(offset);
		ap = (globlist_t*)stakfreeze(0);
		ap->gl_begin = (char*)rescan;
		ap->gl_next = gp->gl_rescan;
		gp->gl_rescan = ap;
	}
	else
	{
		if (!endslash && (gp->gl_flags & GLOB_MARK) && (type = (*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0)))
		{
			if ((gp->gl_flags & GLOB_COMPLETE) && type != GLOB_EXE)
			{
				stakseek(0);
				return;
			}
			else if (type == GLOB_DIR && (gp->gl_flags & GLOB_MARK))
				stakputc(gp->gl_delim);
		}
		ap = (globlist_t*)stakfreeze(1);
		ap->gl_next = gp->gl_match;
		gp->gl_match = ap;
		gp->gl_pathc++;
	}
	ap->gl_flags = MATCH_RAW|meta;
	if (gp->gl_flags & GLOB_COMPLETE)
		ap->gl_flags |= MATCH_MAKE;
}
Example #3
0
static int sig_number(Shell_t *shp,const char *string)
{
	const Shtable_t	*tp;
	register int	n,o,sig=0;
	char		*last, *name;
	if(isdigit(*string))
	{
		n = strtol(string,&last,10);
		if(*last)
			n = -1;
	}
	else
	{
		register int c;
		o = staktell();
		do
		{
			c = *string++;
			if(islower(c))
				c = toupper(c);
			stakputc(c);
		}
		while(c);
		stakseek(o);
		if(memcmp(stakptr(o),"SIG",3)==0)
		{
			sig = 1;
			o += 3;
			if(isdigit(*stakptr(o)))
			{
				n = strtol(stakptr(o),&last,10);
				if(!*last)
					return(n);
			}
		}
		tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals));
		n = tp->sh_number;
		if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS)))
		{
			/* sig prefix cannot match internal traps */
			n = 0;
			tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
			if(strcmp(stakptr(o),tp->sh_name)==0)
				n = tp->sh_number;
		}
		if((n>>SH_SIGBITS)&SH_SIGRUNTIME)
			n = shp->gd->sigruntime[(n&((1<<SH_SIGBITS)-1))-1];
		else
		{
			n &= (1<<SH_SIGBITS)-1;
			if(n < SH_TRAP)
				n--;
		}
		if(n<0 && shp->gd->sigruntime[1] && (name=stakptr(o)) && *name++=='R' && *name++=='T')
		{
			if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+')
			{
				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
					n = shp->gd->sigruntime[SH_SIGRTMIN] + sig;
			}
			else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-')
			{
				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
					n = shp->gd->sigruntime[SH_SIGRTMAX] - sig;
			}
			else if((sig=(int)strtol(name,&name,10)) > 0 && !*name)
				n = shp->gd->sigruntime[SH_SIGRTMIN] + sig - 1;
			if(n<shp->gd->sigruntime[SH_SIGRTMIN] || n>shp->gd->sigruntime[SH_SIGRTMAX])
				n = -1;
		}
	}
Example #4
0
void	ed_setup(register Edit_t *ep, int fd, int reedit)
{
	Shell_t *shp = ep->sh;
	register char *pp;
	register char *last, *prev;
	char *ppmax;
	int myquote = 0, n;
	register int qlen = 1, qwid;
	char inquote = 0;
	ep->e_fd = fd;
	ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
#ifdef SIGWINCH
	if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
	{
		signal(SIGWINCH,sh_fault);
		shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
	}
	pp = shp->st.trapcom[SIGWINCH];
	shp->st.trapcom[SIGWINCH] = 0;
	sh_fault(SIGWINCH);
	shp->st.trapcom[SIGWINCH] = pp;
	ep->sh->winch = 0;
#endif
#if SHOPT_EDPREDICT
	ep->hlist = 0;
	ep->nhlist = 0;
	ep->hoff = 0;
#endif /* SHOPT_EDPREDICT */
#if KSHELL
	ep->e_stkptr = stakptr(0);
	ep->e_stkoff = staktell();
	if(!(last = shp->prompt))
		last = "";
	shp->prompt = 0;
#else
	last = ep->e_prbuff;
#endif /* KSHELL */
	if(shp->gd->hist_ptr)
	{
		register History_t *hp = shp->gd->hist_ptr;
		ep->e_hismax = hist_max(hp);
		ep->e_hismin = hist_min(hp);
	}
	else
	{
		ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
	}
	ep->e_hline = ep->e_hismax;
	if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
		ep->e_wsize = MAXLINE;
	else
		ep->e_wsize = ed_window()-2;
	ep->e_winsz = ep->e_wsize+2;
	ep->e_crlf = 1;
	ep->e_plen = 0;
	pp = ep->e_prompt;
	ppmax = pp+PRSIZE-1;
	*pp++ = '\r';
	{
		register int c;
		while(prev = last, c = mbchar(last)) switch(c)
		{
			case ESC:
			{
				int skip=0;
				ep->e_crlf = 0;
				*pp++ = c;
				for(n=1; c = *last++; n++)
				{
					if(pp < ppmax)
						*pp++ = c;
					if(c=='\a' || c==ESC || c=='\r')
						break;
					if(skip || (c>='0' && c<='9'))
					{
						skip = 0;
						continue;
					}
					if(n>1 && c==';')
						skip = 1;
					else if(n>2 || (c!= '[' &&  c!= ']'))
						break;
				}
				if(c==0 || c==ESC || c=='\r')
					last--;
				qlen += (n+1);
				break;
			}
			case '\b':
				if(pp>ep->e_prompt+1)
					pp--;
				break;
			case '\r':
				if(pp == (ep->e_prompt+2)) /* quote char */
					myquote = *(pp-1);
				/*FALLTHROUGH*/

			case '\n':
				/* start again */
				ep->e_crlf = 1;
				qlen = 1;
				inquote = 0;
				pp = ep->e_prompt+1;
				break;

			case '\t':
				/* expand tabs */
				while((pp-ep->e_prompt)%TABSIZE)
				{
					if(pp >= ppmax)
						break;
					*pp++ = ' ';
				}
				break;

			case '\a':
				/* cut out bells */
				break;

			default:
				if(c==myquote)
				{
					qlen += inquote;
					inquote ^= 1;
				}
				if(pp < ppmax)
				{
					if(inquote)
						qlen++;
					else if(!is_print(c))
						ep->e_crlf = 0;
					if((qwid = last - prev) > 1)
						qlen += qwid - mbwidth(c);
					while(prev < last && pp < ppmax)
						*pp++ = *prev++;
				}
				break;
		}
	}
	if(pp-ep->e_prompt > qlen)
		ep->e_plen = pp - ep->e_prompt - qlen;
	*pp = 0;
	if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
	{
		register int shift = 7-ep->e_wsize;
		ep->e_wsize = 7;
		pp = ep->e_prompt+1;
		strcpy(pp,pp+shift);
		ep->e_plen -= shift;
		last[-ep->e_plen-2] = '\r';
	}
	sfsync(sfstderr);
	if(fd == sffileno(sfstderr))
	{
		/* can't use output buffer when reading from stderr */
		static char *buff;
		if(!buff)
			buff = (char*)malloc(MAXLINE);
		ep->e_outbase = ep->e_outptr = buff;
		ep->e_outlast = ep->e_outptr + MAXLINE;
		return;
	}
	qlen = sfset(sfstderr,SF_READ,0);
	/* make sure SF_READ not on */
	ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
	ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
	if(qlen)
		sfset(sfstderr,SF_READ,1);
	sfwrite(sfstderr,ep->e_outptr,0);
	ep->e_eol = reedit;
	if(ep->e_multiline)
	{
#ifdef _cmd_tput
		char *term;
		if(!ep->e_term)
			ep->e_term = nv_search("TERM",shp->var_tree,0);
		if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
		{
			sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
			if(pp=nv_getval(SH_SUBSCRNOD))
				strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
			nv_unset(SH_SUBSCRNOD);
			strcpy(ep->e_termname,term);
		}
#endif
		ep->e_wsize = MAXLINE - (ep->e_plen+1);
	}
	if(ep->e_default && (pp = nv_getval(ep->e_default)))
	{
		n = strlen(pp);
		if(n > LOOKAHEAD)
			n = LOOKAHEAD;
		ep->e_lookahead = n;
		while(n-- > 0)
			ep->e_lbuf[n] = *pp++;
		ep->e_default = 0;
	}
}
Example #5
0
/*
 * open the history file
 * if HISTNAME is not given and userid==0 then no history file.
 * if login_sh and HISTFILE is longer than HIST_MAX bytes then it is
 * cleaned up.
 * hist_open() returns 1, if history file is open
 */
int  sh_histinit(void *sh_context)
{
	Shell_t *shp = (Shell_t*)sh_context;
	register int fd;
	register History_t *hp;
	register char *histname;
	char *fname=0;
	int histmask, maxlines, hist_start=0;
	register char *cp;
	register off_t hsize = 0;

	if(shgd->hist_ptr=hist_ptr)
		return(1);
	if(!(histname = nv_getval(HISTFILE)))
	{
		int offset = staktell();
		if(cp=nv_getval(HOME))
			stakputs(cp);
		stakputs(hist_fname);
		stakputc(0);
		stakseek(offset);
		histname = stakptr(offset);
	}
#ifdef future
	if(hp=wasopen)
	{
		/* reuse history file if same name */
		wasopen = 0;
		shgd->hist_ptr = hist_ptr = hp;
		if(strcmp(histname,hp->histname)==0)
			return(1);
		else
			hist_free();
	}
#endif
retry:
	cp = path_relative(shp,histname);
	if(!histinit)
		histmode = S_IRUSR|S_IWUSR;
	if((fd=open(cp,O_BINARY|O_APPEND|O_RDWR|O_CREAT,histmode))>=0)
	{
		hsize=lseek(fd,(off_t)0,SEEK_END);
	}
	if((unsigned)fd <=2)
	{
		int n;
		if((n=fcntl(fd,F_DUPFD,10))>=0)
		{
			close(fd);
			fd=n;
		}
	}
	/* make sure that file has history file format */
	if(hsize && hist_check(fd))
	{
		close(fd);
		hsize = 0;
		if(unlink(cp)>=0)
			goto retry;
		fd = -1;
	}
	if(fd < 0)
	{
#if KSHELL
		/* don't allow root a history_file in /tmp */
		if(shgd->userid)
#endif	/* KSHELL */
		{
			if(!(fname = pathtmp(NIL(char*),0,0,NIL(int*))))
				return(0);
			fd = open(fname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
		}
	}
	if(fd<0)
		return(0);
	/* set the file to close-on-exec */
	fcntl(fd,F_SETFD,FD_CLOEXEC);
	if(cp=nv_getval(HISTSIZE))
		maxlines = (unsigned)strtol(cp, (char**)0, 10);
	else
		maxlines = HIST_DFLT;
	for(histmask=16;histmask <= maxlines; histmask <<=1 );
	if(!(hp=new_of(History_t,(--histmask)*sizeof(off_t))))
	{
		close(fd);
		return(0);
	}
	shgd->hist_ptr = hist_ptr = hp;
	hp->histshell = (void*)shp;
	hp->histsize = maxlines;
	hp->histmask = histmask;
	hp->histfp= sfnew(NIL(Sfio_t*),hp->histbuff,HIST_BSIZE,fd,SF_READ|SF_WRITE|SF_APPENDWR|SF_SHARE);
	memset((char*)hp->histcmds,0,sizeof(off_t)*(hp->histmask+1));
	hp->histind = 1;
	hp->histcmds[1] = 2;
	hp->histcnt = 2;
	hp->histname = strdup(histname);
	hp->histdisc = hist_disc;
	if(hsize==0)
	{
		/* put special characters at front of file */
		sfwrite(hp->histfp,(char*)hist_stamp,2);
		sfsync(hp->histfp);
	}
	/* initialize history list */
	else
	{
		int first,last;
		off_t mark,size = (HIST_MAX/4)+maxlines*HIST_LINE;
		hp->histind = first = hist_nearend(hp,hp->histfp,hsize-size);
		histinit = 1;
		hist_eof(hp);	 /* this sets histind to last command */
		if((hist_start = (last=(int)hp->histind)-maxlines) <=0)
			hist_start = 1;
		mark = hp->histmarker;
		while(first > hist_start)
		{
			size += size;
			first = hist_nearend(hp,hp->histfp,hsize-size);
			hp->histind = first;
		}
		histinit = hist_start;
		hist_eof(hp);
		if(!histinit)
		{
			sfseek(hp->histfp,hp->histcnt=hsize,SEEK_SET);
			hp->histind = last;
			hp->histmarker = mark;
		}
		histinit = 0;
	}
	if(fname)
	{
		unlink(fname);
		free((void*)fname);
	}
	if(hist_clean(fd) && hist_start>1 && hsize > HIST_MAX)
	{
#ifdef DEBUG
		sfprintf(sfstderr,"%d: hist_trim hsize=%d\n",getpid(),hsize);
		sfsync(sfstderr);
#endif /* DEBUG */
		hp = hist_trim(hp,(int)hp->histind-maxlines);
	}
	sfdisc(hp->histfp,&hp->histdisc);
#if KSHELL
	(HISTCUR)->nvalue.lp = (&hp->histind);
#endif /* KSHELL */
	sh_timeradd(1000L*(HIST_RECENT-30), 1, hist_touch, (void*)hp->histname);
#if SHOPT_ACCTFILE
	if(sh_isstate(SH_INTERACTIVE))
		acctinit(hp);
#endif /* SHOPT_ACCTFILE */
#if SHOPT_AUDIT
	{
		char buff[SF_BUFSIZE];
		hp->auditfp = 0;
		if(sh_isstate(SH_INTERACTIVE) && (hp->auditmask=sh_checkaudit(hp,SHOPT_AUDITFILE, buff, sizeof(buff))))
		{
			if((fd=sh_open(buff,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && fd < 10)
			{
				int n;
				if((n = sh_fcntl(fd,F_DUPFD, 10)) >= 0)
				{
					sh_close(fd);
					fd = n;
				}
			}
			if(fd>=0)
			{
				fcntl(fd,F_SETFD,FD_CLOEXEC);
				hp->tty = strdup(ttyname(2));
				hp->auditfp = sfnew((Sfio_t*)0,NULL,-1,fd,SF_WRITE);
			}
		}
	}
#endif
	return(1);
}
Example #6
0
int	wordexp(const char *string, wordexp_t *wdarg, register int flags)
{
	register Sfio_t *iop;
	register char *cp=(char*)string;
	register int c,quoted=0,literal=0,ac=0;
	int offset;
	char *savebase,**av;
	if(offset=staktell())
		savebase = stakfreeze(0);
	if(flags&WRDE_REUSE)
		wordfree(wdarg);
	else if(!(flags&WRDE_APPEND))
	{
		wdarg->we_wordv = 0;
		wdarg->we_wordc = 0;
	}
	if(flags&WRDE_UNDEF)
		stakwrite("set -u\n",7);
	if(!(flags&WRDE_SHOWERR))
		stakwrite("exec 2> /dev/null\n",18);
	stakwrite("print -f \"%q\\n\" ",16);
	if(*cp=='#')
		stakputc('\\');
	while(c = *cp++)
	{
		if(c=='\'' && !quoted)
			literal = !literal;
		else if(!literal)
		{
			if(c=='\\' && (!quoted || strchr("\\\"`\n$",c)))
			{
				stakputc('\\');
				if(c= *cp)
					cp++;
				else
					c = '\\';
			}
			else if(c=='"')
				quoted = !quoted;
			else if(c=='`' || (c=='$' && *cp=='('))
			{
				if(flags&WRDE_NOCMD)
				{
					c=WRDE_CMDSUB;
					goto err;
				}
				/* only the shell can parse the rest */
				stakputs(cp-1);
				break;
			}
			else if(!quoted && strchr("|&\n;<>"+ac,c))
			{
				c=WRDE_BADCHAR;
				goto err;
			}
			else if(c=='(') /* allow | and & inside pattern */
				ac=2;
		}
		stakputc(c);
	}
	stakputc(0);
	if(!(iop = sfpopen((Sfio_t*)0,stakptr(0),"r")))
	{
		c = WRDE_NOSHELL;
		goto err;
	}
	stakseek(0);
	ac = 0;
	while((c=sfgetc(iop)) != EOF)
	{
		if(c=='\'')
			quoted = ! quoted;
		else if(!quoted && (c==' ' || c=='\n'))
		{
			ac++;
			c = 0;
		}
		stakputc(c);
	}
	if(c=sfclose(iop))
	{
		if(c==3 || !(flags&WRDE_UNDEF))
			c=WRDE_SYNTAX;
		else
			c=WRDE_BADVAL;
		goto err;
	}
	c = ac+2;
	if(flags&WRDE_DOOFFS)
		c += wdarg->we_offs;
	if(flags&WRDE_APPEND)
		av = (char**)realloc((void*)&wdarg->we_wordv[-1], (wdarg->we_wordc+c)*sizeof(char*));
	else if(av = (char**)malloc(c*sizeof(char*)))
	{
		if(flags&WRDE_DOOFFS)
			memset((void*)av,0,(wdarg->we_offs+1)*sizeof(char*));
		else
			av[0] = 0;
	}
	if(!av)
		return(WRDE_NOSPACE);
	c = staktell();
	if(!(cp = (char*)malloc(sizeof(char*)+c)))
	{
		c=WRDE_NOSPACE;
		goto err;
	}
	((struct list*)cp)->next = (struct list*)(*av);
	*av++ = (char*)cp;
	cp += sizeof(char*);
	wdarg->we_wordv = av;
	if(flags&WRDE_APPEND)
		av += wdarg->we_wordc;
	wdarg->we_wordc += ac;
	if(flags&WRDE_DOOFFS)
		av += wdarg->we_offs;
	memcpy((void*)cp,stakptr(offset),c);
	while(ac-- > 0)
	{
		*av++ = cp;
		sh_unquote(cp);
		while(c= *cp++);
	}
	*av = 0;
	c=0;
err:
	if(offset)
		stakset(savebase,offset);
	else
		stakseek(0);
	return(c);
}
Example #7
0
int test_unop(Shell_t *shp,register int op,register const char *arg)
{
	struct stat statb;
	int f;
	switch(op)
	{
	    case 'r':
		return(permission(arg, R_OK));
	    case 'w':
		return(permission(arg, W_OK));
	    case 'x':
		return(permission(arg, X_OK));
	    case 'V':
#if SHOPT_FS_3D
	    {
		register int offset = staktell();
		if(stat(arg,&statb)<0 || !S_ISREG(statb.st_mode))
			return(0);
		/* add trailing / */
		stakputs(arg);
		stakputc('/');
		stakputc(0);
		arg = (const char*)stakptr(offset);
		stakseek(offset);
		/* FALL THRU */
	    }
#else
		return(0);
#endif /* SHOPT_FS_3D */
	    case 'd':
		return(test_stat(arg,&statb)>=0 && S_ISDIR(statb.st_mode));
	    case 'c':
		return(test_stat(arg,&statb)>=0 && S_ISCHR(statb.st_mode));
	    case 'b':
		return(test_stat(arg,&statb)>=0 && S_ISBLK(statb.st_mode));
	    case 'f':
		return(test_stat(arg,&statb)>=0 && S_ISREG(statb.st_mode));
	    case 'u':
		return(test_mode(arg)&S_ISUID);
	    case 'g':
		return(test_mode(arg)&S_ISGID);
	    case 'k':
#ifdef S_ISVTX
		return(test_mode(arg)&S_ISVTX);
#else
		return(0);
#endif /* S_ISVTX */
#if SHOPT_TEST_L
	    case 'l':
#endif
	    case 'L':
	    case 'h': /* undocumented, and hopefully will disappear */
		if(*arg==0 || arg[strlen(arg)-1]=='/' || lstat(arg,&statb)<0)
			return(0);
		return(S_ISLNK(statb.st_mode));

	    case 'C':
#ifdef S_ISCTG
		return(test_stat(arg,&statb)>=0 && S_ISCTG(statb.st_mode));
#else
		return(0);
#endif	/* S_ISCTG */
	    case 'H':
#ifdef S_ISCDF
	    {
		register int offset = staktell();
		if(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode))
			return(1);
		stakputs(arg);
		stakputc('+');
		stakputc(0);
		arg = (const char*)stakptr(offset);
		stakseek(offset);
		return(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode));
	    }
#else
		return(0);
#endif	/* S_ISCDF */

	    case 'S':
		return(isasock(arg,&statb));
	    case 'N':
		return(test_stat(arg,&statb)>=0 && tmxgetmtime(&statb) > tmxgetatime(&statb));
	    case 'p':
		return(isapipe(arg,&statb));
	    case 'n':
		return(*arg != 0);
	    case 'z':
		return(*arg == 0);
	    case 's':
		sfsync(sfstdout);
	    case 'O':
	    case 'G':
		if(*arg==0 || test_stat(arg,&statb)<0)
			return(0);
		if(op=='s')
			return(statb.st_size>0);
		else if(op=='O')
			return(statb.st_uid==shp->gd->userid);
		return(statb.st_gid==shp->gd->groupid);
	    case 'a':
	    case 'e':
		if(memcmp(arg,"/dev/",5)==0 && sh_open(arg,O_NONBLOCK))
			return(1);
		return(permission(arg, F_OK));
	    case 'o':
		f=1;
		if(*arg=='?')
			return(sh_lookopt(arg+1,&f)>0);
		op = sh_lookopt(arg,&f);
		return(op && (f==(sh_isoption(op)!=0)));
	    case 't':
	    {
		char *last;
		op = strtol(arg,&last, 10);
		return(*last?0:tty_check(op));
	    }
	    case 'v':
	    case 'R':
	    {
		Namval_t *np;
		Namarr_t *ap;
		int isref;
		if(!(np = nv_open(arg,shp->var_tree,NV_VARNAME|NV_NOFAIL|NV_NOADD|NV_NOREF)))
			return(0);
		isref = nv_isref(np);
		if(op=='R')
			return(isref);
		if(isref)
		{
			if(np->nvalue.cp)
				np = nv_refnode(np);
			else
				return(0);
			
		}
		if(ap = nv_arrayptr(np))
			return(nv_arrayisset(np,ap));
		return(!nv_isnull(np) || nv_isattr(np,NV_INTEGER));
	    }
	    default:
	    {
		static char a[3] = "-?";
		a[1]= op;
		errormsg(SH_DICT,ERROR_exit(2),e_badop,a);
		/* NOTREACHED  */
		return(0);
	    }
	}
}
Example #8
0
static int
intercept(Sfio_t* sp, int level, int flags)
{
	register Rule_t*	r;
	char*			m;
	char*			s;
	char*			t;
	char*			e;
	int			n;
	int			i;
	Sfio_t*			tmp;

	NoP(sp);
	NoP(flags);
	if ((state.mam.level = level) > 0 && !state.hold && (r = internal.error) && (r->property & (P_functional|P_target)) == (P_functional|P_target) && !state.compileonly && !state.interrupt && (m = stakptr(0)) && (n = staktell()) > 0)
	{
		/*
		 * make the error trap
		 */

		state.hold = m;
		while (*m && *m != ':')
			m++;
		while (isspace(*++m));
		n -= m - state.hold;
		tmp = sfstropen();
		sfprintf(tmp, "%d %-.*s", level, n, m);
		s = sfstruse(tmp);

		/*
		 * return [ level | - ] [ message ]
		 * level is new level or - to retain old
		 * omitted message means it has been printed
		 */

		if (t = call(r, s))
		{
			i = strtol(t, &e, 0);
			if (e > t)
			{
				t = e;
				level = i;
			}
			else if (*t == '-')
				t++;
			while (isspace(*t))
				t++;
		}
		if (!t || !*t)
		{
			level |= ERROR_OUTPUT;
			message((-1, "suppressed %s message: `%-.*s'", level == 1 ? "warning" : "error", n, m));
		}
		sfstrclose(tmp);
		state.hold = 0;
	}
	return level;
}
Example #9
0
static char *parse_subst(const char *s, struct subst *sb)
{
	char	*cp,del;
	int	off,n = 0;

	/* build the strings on the stack, mainly for '&' substition in "new" */
	off = staktell();

	/* init "new" with empty string */
	if(sb->str[1])
		free(sb->str[1]);
	sb->str[1] = strdup("");

	/* get delimiter */
	del = *s;

	cp = (char*) s + 1;

	while(n < 2)
	{
		if(*cp == del || *cp == '\n' || *cp == '\0')
		{
			/* delimiter or EOL */
			if(staktell() != off)
			{
				/* dupe string on stack and rewind stack */
				stakputc('\0');
				if(sb->str[n])
					free(sb->str[n]);
				sb->str[n] = strdup(stakptr(off));
				stakseek(off);
			}
			n++;

			/* if not delimiter, we've reached EOL. Get outta here. */
			if(*cp != del)
				break;
		}
		else if(*cp == '\\')
		{
			if(*(cp+1) == del)	/* quote delimiter */
			{
				stakputc(del);
				cp++;
			}
			else if(*(cp+1) == '&' && n == 1)
			{		/* quote '&' only in "new" */
				stakputc('&');
				cp++;
			}
			else
				stakputc('\\');
		}
		else if(*cp == '&' && n == 1 && sb->str[0])
			/* substitute '&' with "old" in "new" */
			stakputs(sb->str[0]);
		else
			stakputc(*cp);
		cp++;
	}

	/* rewind stack */
	stakseek(off);

	return cp;
}
Example #10
0
int hist_expand(const char *ln, char **xp)
{
	int	off,	/* stack offset */
		q,	/* quotation flags */
		p,	/* flag */
		c,	/* current char */
		flag=0;	/* HIST_* flags */
	Sfoff_t	n,	/* history line number, counter, etc. */
		i,	/* counter */
		w[2];	/* word range */
	char	*sp,	/* stack pointer */
		*cp,	/* current char in ln */
		*str,	/* search string */
		*evp,	/* event/word designator string, for error msgs */
		*cc=0,	/* copy of current line up to cp; temp ptr */
		hc[3],	/* default histchars */
		*qc="\'\"`";	/* quote characters */
	Sfio_t	*ref=0,	/* line referenced by event designator */
		*tmp=0,	/* temporary line buffer */
		*tmp2=0;/* temporary line buffer */
	Histloc_t hl;	/* history location */
	static Namval_t *np = 0;	/* histchars variable */
	static struct subst	sb = {0,0};	/* substition strings */
	static Sfio_t	*wm=0;	/* word match from !?string? event designator */

	if(!wm)
		wm = sfopen(NULL, NULL, "swr");

	hc[0] = '!';
	hc[1] = '^';
	hc[2] = 0;
	if((np = nv_open("histchars",sh.var_tree,0)) && (cp = nv_getval(np)))
	{
		if(cp[0])
		{
			hc[0] = cp[0];
			if(cp[1])
			{
				hc[1] = cp[1];
				if(cp[2])
					hc[2] = cp[2];
			}
		}
	}

	/* save shell stack */
	if(off = staktell())
		sp = stakfreeze(0);

	cp = (char*)ln;

	while(cp && *cp)
	{
		/* read until event/quick substitution/comment designator */
		if((*cp != hc[0] && *cp != hc[1] && *cp != hc[2]) 
		   || (*cp == hc[1] && cp != ln))
		{
			if(*cp == '\\')	/* skip escaped designators */
				stakputc(*cp++);
			else if(*cp == '\'') /* skip quoted designators */
			{
				do
					stakputc(*cp);				
				while(*++cp && *cp != '\'');
			}
			stakputc(*cp++);
			continue;
		}

		if(hc[2] && *cp == hc[2]) /* history comment designator, skip rest of line */
		{
			stakputc(*cp++);
			stakputs(cp);
			DONE();
		}

		n = -1;
		str = 0;
		flag &= HIST_EVENT; /* save event flag for returning later */
		evp = cp;
		ref = 0;

		if(*cp == hc[1]) /* shortcut substitution */
		{
			flag |= HIST_QUICKSUBST;
			goto getline;
		}

		if(*cp == hc[0] && *(cp+1) == hc[0]) /* refer to line -1 */
		{
			cp += 2;
			goto getline;
		}

		switch(c = *++cp) {
		case ' ':
		case '\t':
		case '\n':
		case '\0':
		case '=':
		case '(':
			stakputc(hc[0]);
			continue;
		case '#': /* the line up to current position */
			flag |= HIST_HASH;
			cp++;
			n = staktell(); /* terminate string and dup */
			stakputc('\0');
			cc = strdup(stakptr(0));
			stakseek(n); /* remove null byte again */
			ref = sfopen(ref, cc, "s"); /* open as file */
			n = 0; /* skip history file referencing */
			break;
		case '-': /* back reference by number */
			if(!isdigit(*(cp+1)))
				goto string_event;
			cp++;
		case '0': /* reference by number */
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			n = 0;
			while(isdigit(*cp))
				n = n * 10 + (*cp++) - '0';
			if(c == '-')
				n = -n;
			break;
		case '$':
			n = -1;
		case ':':
			break;
		case '?':
			cp++;
			flag |= HIST_QUESTION;
		string_event:
		default:
			/* read until end of string or word designator/modifier */
			str = cp;
			while(*cp)
			{
				cp++;
				if((!(flag&HIST_QUESTION) &&
				   (*cp == ':' || isspace(*cp)
				    || *cp == '^' || *cp == '$'
				    || *cp == '*' || *cp == '-'
				    || *cp == '%')
				   )
				   || ((flag&HIST_QUESTION) && (*cp == '?' || *cp == '\n')))
				{
					c = *cp;
					*cp = '\0';
				}
			}
			break;
		}

getline:
		flag |= HIST_EVENT;
		if(str)	/* !string or !?string? event designator */
		{

			/* search history for string */
			hl = hist_find(shgd->hist_ptr, str,
				       shgd->hist_ptr->histind,
				       flag&HIST_QUESTION, -1);
			if((n = hl.hist_command) == -1)
				n = 0;	/* not found */
		}
		if(n)
		{
			if(n < 0) /* determine index for backref */
				n = shgd->hist_ptr->histind + n;
			/* search and use history file if found */
			if(n > 0 && hist_seek(shgd->hist_ptr, n) != -1)
				ref = shgd->hist_ptr->histfp;

		}
		if(!ref)
		{
			/* string not found or command # out of range */
			c = *cp;
			*cp = '\0';
			errormsg(SH_DICT, ERROR_ERROR, "%s: event not found", evp);
			*cp = c;
			DONE();
		}

		if(str) /* string search: restore orig. line */
		{
			if(flag&HIST_QUESTION)
				*cp++ = c; /* skip second question mark */
			else
				*cp = c;
		}

		/* colon introduces either word designators or modifiers */
		if(*(evp = cp) == ':')
			cp++;

		w[0] = 0; /* -1 means last word, -2 means match from !?string? */
		w[1] = -1; /* -1 means last word, -2 means suppress last word */

		if(flag & HIST_QUICKSUBST) /* shortcut substitution */
			goto getsel;

		n = 0;
		while(n < 2)
		{
			switch(c = *cp++) {
			case '^': /* first word */
				if(n == 0)
				{
					w[0] = w[1] = 1;
					goto skip;
				}
				else
					goto skip2;
			case '$': /* last word */
				w[n] = -1;
				goto skip;
			case '%': /* match from !?string? event designator */
				if(n == 0)
				{
					if(!str)
					{
						w[0] = 0;
						w[1] = -1;
						ref = wm;
					}
					else
					{
						w[0] = -2;
						w[1] = sftell(ref) + hl.hist_char;
					}
					sfseek(wm, 0, SEEK_SET);
					goto skip;
				}
			default:
			skip2:
				cp--;
				n = 2;
				break;
			case '*': /* until last word */
				if(n == 0)
					w[0] = 1;
				w[1] = -1;
			skip:
				flag |= HIST_WORDDSGN;
				n = 2;
				break;
			case '-': /* until last word or specified index */
				w[1] = -2;
				flag |= HIST_WORDDSGN;
				n = 1;
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9': /* specify index */
				if((*evp == ':') || w[1] == -2)
				{
					w[n] = c - '0';
					while(isdigit(c=*cp++))
						w[n] = w[n] * 10 + c - '0';
					flag |= HIST_WORDDSGN;
					if(n == 0)
						w[1] = w[0];
					n++;
				}
				else
					n = 2;
				cp--;
				break;
			}
		}

		if(w[0] != -2 && w[1] > 0 && w[0] > w[1])
		{
			c = *cp;
			*cp = '\0';
			errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
			*cp = c;
			DONE();
		}

		/* no valid word designator after colon, rewind */
		if(!(flag & HIST_WORDDSGN) && (*evp == ':'))
			cp = evp;

getsel:
		/* open temp buffer, let sfio do the (re)allocation */
		tmp = sfopen(NULL, NULL, "swr");

		/* push selected words into buffer, squash 
		   whitespace into single blank or a newline */
		n = i = q = 0;

		while((c = sfgetc(ref)) > 0)
		{
			if(isspace(c))
			{
				flag |= (c == '\n' ? HIST_NEWLINE : 0);
				continue;
			}

			if(n >= w[0] && ((w[0] != -2) ? (w[1] < 0 || n <= w[1]) : 1))
			{
				if(w[0] < 0)
					sfseek(tmp, 0, SEEK_SET);
				else
					i = sftell(tmp);

				if(i > 0)
					sfputc(tmp, flag & HIST_NEWLINE ? '\n' : ' ');

				flag &= ~HIST_NEWLINE;
				p = 1;
			}
			else
				p = 0;

			do
			{
				cc = strchr(qc, c);
				q ^= cc ? 1<<(int)(cc - qc) : 0;
				if(p)
					sfputc(tmp, c);
			}
			while((c = sfgetc(ref)) > 0  && (!isspace(c) || q));

			if(w[0] == -2 && sftell(ref) > w[1])
				break;

			flag |= (c == '\n' ? HIST_NEWLINE : 0);
			n++;
		}
		if(w[0] != -2 && w[1] >= 0 && w[1] >= n)
		{
			c = *cp;
			*cp = '\0';
			errormsg(SH_DICT, ERROR_ERROR, "%s: bad word specifier", evp);
			*cp = c;
			DONE();
		}
		else if(w[1] == -2)	/* skip last word */
			sfseek(tmp, i, SEEK_SET);

		/* remove trailing newline */
		if(sftell(tmp))
		{
			sfseek(tmp, -1, SEEK_CUR);
			if(sfgetc(tmp) == '\n')
				sfungetc(tmp, '\n');
		}

		sfputc(tmp, '\0');

		if(str)
		{
			if(wm)
				sfclose(wm);
			wm = tmp;
		}

		if(cc && (flag&HIST_HASH))
		{
			/* close !# temp file */
			sfclose(ref);
			flag &= ~HIST_HASH;
			free(cc);
			cc = 0;
		}

		evp = cp;

		/* selected line/words are now in buffer, now go for the modifiers */
		while(*cp == ':' || (flag & HIST_QUICKSUBST))
		{
			if(flag & HIST_QUICKSUBST)
			{
				flag &= ~HIST_QUICKSUBST;
				c = 's';
				cp--;
			}
			else
				c = *++cp;

			sfseek(tmp, 0, SEEK_SET);
			tmp2 = sfopen(tmp2, NULL, "swr");

			if(c == 'g') /* global substitution */
			{
				flag |= HIST_GLOBALSUBST;
				c = *++cp;
			}

			if(cc = strchr(modifiers, c))
				flag |= mod_flags[cc - modifiers];
			else
			{
				errormsg(SH_DICT, ERROR_ERROR, "%c: unrecognized history modifier", c);
				DONE();
			}

			if(c == 'h' || c == 'r') /* head or base */
			{
				n = -1;
				while((c = sfgetc(tmp)) > 0)
				{	/* remember position of / or . */
					if((c == '/' && *cp == 'h') || (c == '.' && *cp == 'r'))
						n = sftell(tmp2);
					sfputc(tmp2, c);
				}
				if(n > 0)
				{	 /* rewind to last / or . */
					sfseek(tmp2, n, SEEK_SET);
					/* end string there */
					sfputc(tmp2, '\0');
				}
			}
			else if(c == 't' || c == 'e') /* tail or suffix */
			{
				n = 0;
				while((c = sfgetc(tmp)) > 0)
				{	/* remember position of / or . */
					if((c == '/' && *cp == 't') || (c == '.' && *cp == 'e'))
						n = sftell(tmp);
				}
				/* rewind to last / or . */
				sfseek(tmp, n, SEEK_SET);
				/* copy from there on */
				while((c = sfgetc(tmp)) > 0)
					sfputc(tmp2, c);
			}
			else if(c == 's' || c == '&')
			{
				cp++;

				if(c == 's')
				{
					/* preset old with match from !?string? */
					if(!sb.str[0] && wm)
						sb.str[0] = strdup(sfsetbuf(wm, (Void_t*)1, 0));
					cp = parse_subst(cp, &sb);
				}

				if(!sb.str[0] || !sb.str[1])
				{
					c = *cp;
					*cp = '\0';
					errormsg(SH_DICT, ERROR_ERROR, 
						 "%s%s: no previous substitution", 
						(flag & HIST_QUICKSUBST) ? ":s" : "",
						evp);
					*cp = c;
					DONE();
				}

				/* need pointer for strstr() */
				str = sfsetbuf(tmp, (Void_t*)1, 0);

				flag |= HIST_SUBSTITUTE;
				while(flag & HIST_SUBSTITUTE)
				{
					/* find string */
					if(cc = strstr(str, sb.str[0]))
					{	/* replace it */
						c = *cc;
						*cc = '\0';
						sfputr(tmp2, str, -1);
						sfputr(tmp2, sb.str[1], -1);
						*cc = c;
						str = cc + strlen(sb.str[0]);
					}
					else if(!sftell(tmp2))
					{	/* not successfull */
						c = *cp;
						*cp = '\0';
						errormsg(SH_DICT, ERROR_ERROR,
							 "%s%s: substitution failed",
							(flag & HIST_QUICKSUBST) ? ":s" : "",
							evp);
						*cp = c;
						DONE();
					}
					/* loop if g modifier specified */
					if(!cc || !(flag & HIST_GLOBALSUBST))
						flag &= ~HIST_SUBSTITUTE;
				}
				/* output rest of line */
				sfputr(tmp2, str, -1);
				if(*cp)
					cp--;
			}

			if(sftell(tmp2))
			{ /* if any substitions done, swap buffers */
				if(wm != tmp)
					sfclose(tmp);
				tmp = tmp2;
				tmp2 = 0;
			}
			cc = 0;
			if(*cp)
				cp++;
		}

		/* flush temporary buffer to stack */
		if(tmp)
		{
			sfseek(tmp, 0, SEEK_SET);

			if(flag & HIST_QUOTE)
				stakputc('\'');

			while((c = sfgetc(tmp)) > 0)
			{
				if(isspace(c))
				{
					flag = flag & ~HIST_NEWLINE;

					/* squash white space to either a 
					   blank or a newline */
					do
						flag |= (c == '\n' ? HIST_NEWLINE : 0);
					while((c = sfgetc(tmp)) > 0 && isspace(c));

					sfungetc(tmp, c);

					c = (flag & HIST_NEWLINE) ? '\n' : ' ';

					if(flag & HIST_QUOTE_BR)
					{
						stakputc('\'');
						stakputc(c);
						stakputc('\'');
					}
					else
						stakputc(c);
				}
				else if((c == '\'') && (flag & HIST_QUOTE))
				{
					stakputc('\'');
					stakputc('\\');
					stakputc(c);
					stakputc('\'');
				}
				else
					stakputc(c);
			}
			if(flag & HIST_QUOTE)
				stakputc('\'');
		}
	}

	stakputc('\0');

done:
	if(cc && (flag&HIST_HASH))
	{
		/* close !# temp file */
		sfclose(ref);
		free(cc);
		cc = 0;
	}

	/* error? */
	if(staktell() && !(flag & HIST_ERROR))
		*xp = strdup(stakfreeze(1));

	/* restore shell stack */
	if(off)
		stakset(sp,off);
	else
		stakseek(0);

	/* drop temporary files */

	if(tmp && tmp != wm)
		sfclose(tmp);
	if(tmp2)
		sfclose(tmp2);

	return (flag & HIST_ERROR ? HIST_ERROR : flag & HIST_FLAG_RETURN_MASK);
}
Example #11
0
/*
 * print <str> quoting chars so that it can be read by the shell
 * puts null terminated result on stack, but doesn't freeze it
 * single!=0 limits quoting to '...'
 * fold>0 prints raw newlines and inserts appropriately
 * escaped newlines every (fold-x) chars
 */
char	*sh_fmtqf(const char *string, int single, int fold)
{
	register const char *cp = string;
	register const char *bp;
	register const char *vp;
	register int c;
	register int n;
	register int q;
	register int a;
	int offset;

	if (--fold < 8)
		fold = 0;
	if (!cp || !*cp || !single && !fold || fold && strlen(string) < fold)
		return sh_fmtq(cp);
	offset = staktell();
	single = single ? 1 : 3;
	c = mbchar(string);
	a = isaletter(c) ? '=' : 0;
	vp = cp + 1;
	do
	{
		q = 0;
		n = fold;
		bp = cp;
		while ((!n || n-- > 0) && (c = mbchar(cp)))
		{
			if (a && !isaname(c))
				a = 0;
#if SHOPT_MULTIBYTE
			if (c >= 0x200)
				continue;
			if (c == '\'' || !iswprint(c))
#else
			if (c == '\'' || !isprint(c))
#endif /* SHOPT_MULTIBYTE */
			{
				q = single;
				break;
			}
			if (c == '\n')
				q = 1;
			else if (c == a)
			{
				stakwrite(bp, cp - bp);
				bp = cp;
				vp = cp + 1;
				a = 0;
			}
			else if ((c == '#' || c == '~') && cp == vp || c == ']' || c != ':' && (c = sh_lexstates[ST_NORM][c]) && c != S_EPAT)
				q = 1;
		}
		if (q & 2)
		{
			stakputc('$');
			stakputc('\'');
			cp = bp;
			n = fold - 3;
			q = 1;
			while (c = mbchar(cp))
			{
				switch (c)
				{
		    		case ('a'==97?'\033':39):
					c = 'E';
					break;
		    		case '\n':
					q = 0;
					n = fold - 1;
					break;
		    		case '\r':
					c = 'r';
					break;
		    		case '\t':
					c = 't';
					break;
		    		case '\f':
					c = 'f';
					break;
		    		case '\b':
					c = 'b';
					break;
		    		case '\a':
					c = 'a';
					break;
		    		case '\\':
					if (*cp == 'n')
					{
						c = '\n';
						q = 0;
						n = fold - 1;
						break;
					}
				case '\'':
					break;
		    		default:
#if SHOPT_MULTIBYTE
					if(!iswprint(c))
#else
					if(!isprint(c))
#endif
					{
						if ((n -= 4) <= 0)
						{
							stakwrite("'\\\n$'", 5);
							n = fold - 7;
						}
						sfprintf(staksp, "\\%03o", c);
						continue;
					}
					q = 0;
					break;
				}
				if ((n -= q + 1) <= 0)
				{
					if (!q)
					{
						stakputc('\'');
						cp = bp;
						break;
					}
					stakwrite("'\\\n$'", 5);
					n = fold - 5;
				}
				if (q)
					stakputc('\\');
				else
					q = 1;
				stakputc(c);
				bp = cp;
			}
			if (!c)
				stakputc('\'');
		}
		else if (q & 1)
		{
			stakputc('\'');
			cp = bp;
			n = fold ? (fold - 2) : 0;
			while (c = mbchar(cp))
			{
				if (c == '\n')
					n = fold - 1;
				else if (n && --n <= 0)
				{
					n = fold - 2;
					stakwrite(bp, --cp - bp);
					bp = cp;
					stakwrite("'\\\n'", 4);
				}
				else if (n == 1 && *cp == '\'')
				{
					n = fold - 5;
					stakwrite(bp, --cp - bp);
					bp = cp;
					stakwrite("'\\\n\\''", 6);
				}
				else if (c == '\'')
				{
					stakwrite(bp, cp - bp - 1);
					bp = cp;
					if (n && (n -= 4) <= 0)
					{
						n = fold - 5;
						stakwrite("'\\\n\\''", 6);
					}
					else
						stakwrite("'\\''", 4);
				}
			}
			stakwrite(bp, cp - bp - 1);
			stakputc('\'');
		}
		else if (n = fold)
		{
			cp = bp;
			while (c = mbchar(cp))
			{
				if (--n <= 0)
				{
					n = fold;
					stakwrite(bp, --cp - bp);
					bp = cp;
					stakwrite("\\\n", 2);
				}
			}
			stakwrite(bp, cp - bp - 1);
		}
		else
			stakwrite(bp, cp - bp);
		if (c)
		{
			stakputc('\\');
			stakputc('\n');
		}
	} while (c);
	stakputc(0);
	return(stakptr(offset));
}
Example #12
0
/*
 * print <str> quoting chars so that it can be read by the shell
 * puts null terminated result on stack, but doesn't freeze it
 */
char	*sh_fmtq(const char *string)
{
	register const char *cp = string, *op;
	register int c, state;
	int offset;
	if(!cp)
		return((char*)0);
	offset = staktell();
#if SHOPT_MULTIBYTE
	state = ((c= mbchar(cp))==0);
#else
	state = ((c= *(unsigned char*)cp++)==0);
#endif
	if(isaletter(c))
	{
#if SHOPT_MULTIBYTE
		while((c=mbchar(cp)),isaname(c));
#else
		while((c = *(unsigned char*)cp++),isaname(c));
#endif
		if(c==0)
			return((char*)string);
		if(c=='=')
		{
			if(*cp==0)
				return((char*)string);
			c = cp - string;
			stakwrite(string,c);
			string = cp;
#if SHOPT_MULTIBYTE
			c = mbchar(cp);
#else
			c = *(unsigned char*)cp++;
#endif
		}
	}
	if(c==0 || c=='#' || c=='~')
		state = 1;
#if SHOPT_MULTIBYTE
	for(;c;c= mbchar(cp))
#else
	for(;c; c= *(unsigned char*)cp++)
#endif
	{
#if SHOPT_MULTIBYTE
		if(c=='\'' || !iswprint(c))
#else
		if(c=='\'' || !isprint(c))
#endif /* SHOPT_MULTIBYTE */
			state = 2;
		else if(c==']' || (c!=':' && c<=0xff && (c=sh_lexstates[ST_NORM][c]) && c!=S_EPAT))
			state |=1;
	}
	if(state<2)
	{
		if(state==1)
			stakputc('\'');
		if(c = --cp - string)
			stakwrite(string,c);
		if(state==1)
			stakputc('\'');
	}
	else
	{
		stakwrite("$'",2);
		cp = string;
#if SHOPT_MULTIBYTE
		while(op = cp, c= mbchar(cp))
#else
		while(op = cp, c= *(unsigned char*)cp++)
#endif
		{
			state=1;
			switch(c)
			{
			    case ('a'==97?'\033':39):
				c = 'E';
				break;
			    case '\n':
				c = 'n';
				break;
			    case '\r':
				c = 'r';
				break;
			    case '\t':
				c = 't';
				break;
			    case '\f':
				c = 'f';
				break;
			    case '\b':
				c = 'b';
				break;
			    case '\a':
				c = 'a';
				break;
			    case '\\':	case '\'':
				break;
			    default:
#if SHOPT_MULTIBYTE
				if(!iswprint(c))
				{
					while(op<cp)
						sfprintf(staksp,"\\%.3o",*(unsigned char*)op++);
					continue;
				}
#else
				if(!isprint(c))
				{
					sfprintf(staksp,"\\%.3o",c);
					continue;
				}
#endif
				state=0;
				break;
			}
			if(state)
			{
				stakputc('\\');
				stakputc(c);
			}
			else
				stakwrite(op, cp-op);
		}
		stakputc('\'');
	}
	stakputc(0);
	return(stakptr(offset));
}