xref: /onnv-gate/usr/src/lib/libshell/common/edit/completion.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 /*
224887Schin  *  completion.c - command and file completion for shell editors
234887Schin  *
244887Schin  */
254887Schin 
264887Schin #include	"defs.h"
274887Schin #include	<ast_wchar.h>
284887Schin #include	"lexstates.h"
294887Schin #include	"path.h"
304887Schin #include	"io.h"
314887Schin #include	"edit.h"
324887Schin #include	"history.h"
334887Schin 
3410898Sroland.mainz@nrubsig.org #if !SHOPT_MULTIBYTE
3510898Sroland.mainz@nrubsig.org #define mbchar(p)       (*(unsigned char*)p++)
3610898Sroland.mainz@nrubsig.org #endif
3710898Sroland.mainz@nrubsig.org 
fmtx(const char * string)3810898Sroland.mainz@nrubsig.org static char *fmtx(const char *string)
3910898Sroland.mainz@nrubsig.org {
4010898Sroland.mainz@nrubsig.org 	register const char	*cp = string;
4110898Sroland.mainz@nrubsig.org 	register int	 	n,c;
4210898Sroland.mainz@nrubsig.org 	unsigned char 		*state = (unsigned char*)sh_lexstates[2];
4310898Sroland.mainz@nrubsig.org 	int offset;
4410898Sroland.mainz@nrubsig.org 	while((c=mbchar(cp)),(c>UCHAR_MAX)||(n=state[c])==0);
4510898Sroland.mainz@nrubsig.org 	if(n==S_EOF)
4610898Sroland.mainz@nrubsig.org 		return((char*)string);
4710898Sroland.mainz@nrubsig.org 	offset = staktell();
4810898Sroland.mainz@nrubsig.org 	stakwrite(string,--cp-string);
4910898Sroland.mainz@nrubsig.org 	while(c=mbchar(cp))
5010898Sroland.mainz@nrubsig.org 	{
5110898Sroland.mainz@nrubsig.org 		if(state[c])
5210898Sroland.mainz@nrubsig.org 			stakputc('\\');
5310898Sroland.mainz@nrubsig.org 		stakputc(c);
5410898Sroland.mainz@nrubsig.org 	}
5510898Sroland.mainz@nrubsig.org 	stakputc(0);
5610898Sroland.mainz@nrubsig.org 	return(stakptr(offset));
5710898Sroland.mainz@nrubsig.org }
5810898Sroland.mainz@nrubsig.org 
charcmp(int a,int b,int nocase)594887Schin static int charcmp(int a, int b, int nocase)
604887Schin {
614887Schin 	if(nocase)
624887Schin 	{
634887Schin 		if(isupper(a))
644887Schin 			a = tolower(a);
654887Schin 		if(isupper(b))
664887Schin 			b = tolower(b);
674887Schin 	}
684887Schin 	return(a==b);
694887Schin }
704887Schin 
714887Schin /*
724887Schin  *  overwrites <str> to common prefix of <str> and <newstr>
734887Schin  *  if <str> is equal to <newstr> returns  <str>+strlen(<str>)+1
744887Schin  *  otherwise returns <str>+strlen(<str>)
754887Schin  */
overlaid(register char * str,register const char * newstr,int nocase)764887Schin static char *overlaid(register char *str,register const char *newstr,int nocase)
774887Schin {
784887Schin 	register int c,d;
794887Schin 	while((c= *(unsigned char *)str) && ((d= *(unsigned char*)newstr++),charcmp(c,d,nocase)))
804887Schin 		str++;
814887Schin 	if(*str)
824887Schin 		*str = 0;
834887Schin 	else if(*newstr==0)
844887Schin 		str++;
854887Schin 	return(str);
864887Schin }
874887Schin 
884887Schin 
894887Schin /*
904887Schin  * returns pointer to beginning of expansion and sets type of expansion
914887Schin  */
find_begin(char outbuff[],char * last,int endchar,int * type)924887Schin static char *find_begin(char outbuff[], char *last, int endchar, int *type)
934887Schin {
944887Schin 	register char	*cp=outbuff, *bp, *xp;
958462SApril.Chin@Sun.COM 	register int 	c,inquote = 0, inassign=0;
968462SApril.Chin@Sun.COM 	int		mode=*type;
974887Schin 	bp = outbuff;
984887Schin 	*type = 0;
994887Schin 	while(cp < last)
1004887Schin 	{
1014887Schin 		xp = cp;
1024887Schin 		switch(c= mbchar(cp))
1034887Schin 		{
1044887Schin 		    case '\'': case '"':
1054887Schin 			if(!inquote)
1064887Schin 			{
1074887Schin 				inquote = c;
1084887Schin 				bp = xp;
1094887Schin 				break;
1104887Schin 			}
1114887Schin 			if(inquote==c)
1124887Schin 				inquote = 0;
1134887Schin 			break;
1144887Schin 		    case '\\':
1154887Schin 			if(inquote != '\'')
1164887Schin 				mbchar(cp);
1174887Schin 			break;
1184887Schin 		    case '$':
1194887Schin 			if(inquote == '\'')
1204887Schin 				break;
1214887Schin 			c = *(unsigned char*)cp;
1228462SApril.Chin@Sun.COM 			if(mode!='*' && (isaletter(c) || c=='{'))
1234887Schin 			{
1244887Schin 				int dot = '.';
1254887Schin 				if(c=='{')
1264887Schin 				{
1274887Schin 					xp = cp;
1284887Schin 					mbchar(cp);
1294887Schin 					c = *(unsigned char*)cp;
1304887Schin 					if(c!='.' && !isaletter(c))
1314887Schin 						break;
1324887Schin 				}
1334887Schin 				else
1344887Schin 					dot = 'a';
1354887Schin 				while(cp < last)
1364887Schin 				{
1374887Schin 					if((c= mbchar(cp)) , c!=dot && !isaname(c))
1384887Schin 						break;
1394887Schin 				}
1408462SApril.Chin@Sun.COM 				if(cp>=last && c!= '}')
1414887Schin 				{
1424887Schin 					*type='$';
1434887Schin 					return(++xp);
1444887Schin 				}
1454887Schin 			}
1464887Schin 			else if(c=='(')
1474887Schin 			{
1488462SApril.Chin@Sun.COM 				*type = mode;
1494887Schin 				xp = find_begin(cp,last,')',type);
1504887Schin 				if(*(cp=xp)!=')')
1514887Schin 					bp = xp;
1524887Schin 				else
1534887Schin 					cp++;
1544887Schin 			}
1554887Schin 			break;
1564887Schin 		    case '=':
1574887Schin 			if(!inquote)
1588462SApril.Chin@Sun.COM 			{
1598462SApril.Chin@Sun.COM 				bp = cp;
1608462SApril.Chin@Sun.COM 				inassign = 1;
1618462SApril.Chin@Sun.COM 			}
1628462SApril.Chin@Sun.COM 			break;
1638462SApril.Chin@Sun.COM 		    case ':':
1648462SApril.Chin@Sun.COM 			if(!inquote && inassign)
1654887Schin 				bp = cp;
1664887Schin 			break;
1674887Schin 		    case '~':
1684887Schin 			if(*cp=='(')
1694887Schin 				break;
1704887Schin 			/* fall through */
1714887Schin 		    default:
1724887Schin 			if(c && c==endchar)
1734887Schin 				return(xp);
1744887Schin 			if(!inquote && ismeta(c))
1758462SApril.Chin@Sun.COM 			{
1764887Schin 				bp = cp;
1778462SApril.Chin@Sun.COM 				inassign = 0;
1788462SApril.Chin@Sun.COM 			}
1794887Schin 			break;
1804887Schin 		}
1814887Schin 	}
1824887Schin 	if(inquote && *bp==inquote)
1834887Schin 		*type = *bp++;
1844887Schin 	return(bp);
1854887Schin }
1864887Schin 
1874887Schin /*
1884887Schin  * file name generation for edit modes
1894887Schin  * non-zero exit for error, <0 ring bell
1904887Schin  * don't search back past beginning of the buffer
1914887Schin  * mode is '*' for inline expansion,
1924887Schin  * mode is '\' for filename completion
1934887Schin  * mode is '=' cause files to be listed in select format
1944887Schin  */
1954887Schin 
ed_expand(Edit_t * ep,char outbuff[],int * cur,int * eol,int mode,int count)1964887Schin int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count)
1974887Schin {
1984887Schin 	struct comnod	*comptr;
1994887Schin 	struct argnod	*ap;
2004887Schin 	register char	*out;
2014887Schin 	char 		*av[2], *begin , *dir=0;
2024887Schin 	int		addstar=0, rval=0, var=0, strip=1;
2034887Schin 	int 		nomarkdirs = !sh_isoption(SH_MARKDIRS);
2044887Schin 	sh_onstate(SH_FCOMPLETE);
2054887Schin 	if(ep->e_nlist)
2064887Schin 	{
2074887Schin 		if(mode=='=' && count>0)
2084887Schin 		{
2094887Schin 			if(count> ep->e_nlist)
2104887Schin 				return(-1);
2118462SApril.Chin@Sun.COM 			mode = '?';
2124887Schin 			av[0] = ep->e_clist[count-1];
2134887Schin 			av[1] = 0;
2144887Schin 		}
2154887Schin 		else
2164887Schin 		{
2174887Schin 			stakset(ep->e_stkptr,ep->e_stkoff);
2184887Schin 			ep->e_nlist = 0;
2194887Schin 		}
2204887Schin 	}
2214887Schin 	comptr = (struct comnod*)stakalloc(sizeof(struct comnod));
2224887Schin 	ap = (struct argnod*)stakseek(ARGVAL);
2234887Schin #if SHOPT_MULTIBYTE
2244887Schin 	{
2254887Schin 		register int c = *cur;
2264887Schin 		register genchar *cp;
2274887Schin 		/* adjust cur */
2284887Schin 		cp = (genchar *)outbuff + *cur;
2294887Schin 		c = *cp;
2304887Schin 		*cp = 0;
2314887Schin 		*cur = ed_external((genchar*)outbuff,(char*)stakptr(0));
2324887Schin 		*cp = c;
2334887Schin 		*eol = ed_external((genchar*)outbuff,outbuff);
2344887Schin 	}
2354887Schin #endif /* SHOPT_MULTIBYTE */
2364887Schin 	out = outbuff + *cur + (sh_isoption(SH_VI)!=0);
2374887Schin 	comptr->comtyp = COMSCAN;
2384887Schin 	comptr->comarg = ap;
2394887Schin 	ap->argflag = (ARG_MAC|ARG_EXP);
2404887Schin 	ap->argnxt.ap = 0;
2414887Schin 	ap->argchn.cp = 0;
2424887Schin 	{
2434887Schin 		register int c;
2444887Schin 		char *last = out;
2454887Schin 		c =  *(unsigned char*)out;
2468462SApril.Chin@Sun.COM 		var = mode;
2474887Schin 		begin = out = find_begin(outbuff,last,0,&var);
2484887Schin 		/* addstar set to zero if * should not be added */
2494887Schin 		if(var=='$')
2504887Schin 		{
2514887Schin 			stakputs("${!");
2524887Schin 			stakwrite(out,last-out);
2534887Schin 			stakputs("@}");
2544887Schin 			out = last;
2554887Schin 		}
2564887Schin 		else
2574887Schin 		{
2584887Schin 			addstar = '*';
2594887Schin 			while(out < last)
2604887Schin 			{
2614887Schin 				c = *(unsigned char*)out;
2624887Schin 				if(isexp(c))
2634887Schin 					addstar = 0;
2644887Schin 				if (c == '/')
2654887Schin 				{
2664887Schin 					if(addstar == 0)
2674887Schin 						strip = 0;
2684887Schin 					dir = out+1;
2694887Schin 				}
2704887Schin 				stakputc(c);
2714887Schin 				out++;
2724887Schin 			}
2734887Schin 		}
2748462SApril.Chin@Sun.COM 		if(mode=='?')
2758462SApril.Chin@Sun.COM 			mode = '*';
2764887Schin 		if(var!='$' && mode=='\\' && out[-1]!='*')
2774887Schin 			addstar = '*';
2784887Schin 		if(*begin=='~' && !strchr(begin,'/'))
2794887Schin 			addstar = 0;
2804887Schin 		stakputc(addstar);
2814887Schin 		ap = (struct argnod*)stakfreeze(1);
2824887Schin 	}
2834887Schin 	if(mode!='*')
2844887Schin 		sh_onoption(SH_MARKDIRS);
2854887Schin 	{
2864887Schin 		register char	**com;
2874887Schin 		char		*cp=begin, *left=0, *saveout=".";
2884887Schin 		int	 	nocase=0,narg,cmd_completion=0;
2894887Schin 		register 	int size='x';
2904887Schin 		while(cp>outbuff && ((size=cp[-1])==' ' || size=='\t'))
2914887Schin 			cp--;
2924887Schin 		if(!var && !strchr(ap->argval,'/') && (((cp==outbuff&&sh.nextprompt==1) || (strchr(";&|(",size)) && (cp==outbuff+1||size=='('||cp[-2]!='>') && *begin!='~' )))
2934887Schin 		{
2944887Schin 			cmd_completion=1;
2954887Schin 			sh_onstate(SH_COMPLETE);
2964887Schin 		}
2974887Schin 		if(ep->e_nlist)
2984887Schin 		{
2994887Schin 			narg = 1;
3004887Schin 			com = av;
3014887Schin 			if(dir)
3024887Schin 				begin += (dir-begin);
3034887Schin 		}
3044887Schin 		else
3054887Schin 		{
3068462SApril.Chin@Sun.COM 			com = sh_argbuild(ep->sh,&narg,comptr,0);
3074887Schin 			/* special handling for leading quotes */
3084887Schin 			if(begin>outbuff && (begin[-1]=='"' || begin[-1]=='\''))
3094887Schin 			begin--;
3104887Schin 		}
3114887Schin 		sh_offstate(SH_COMPLETE);
3124887Schin                 /* allow a search to be aborted */
3134887Schin 		if(sh.trapnote&SH_SIGSET)
3144887Schin 		{
3154887Schin 			rval = -1;
3164887Schin 			goto done;
3174887Schin 		}
3184887Schin 		/*  match? */
3194887Schin 		if (*com==0 || (narg <= 1 && (strcmp(ap->argval,*com)==0) || (addstar && com[0][strlen(*com)-1]=='*')))
3204887Schin 		{
3214887Schin 			rval = -1;
3224887Schin 			goto done;
3234887Schin 		}
3244887Schin 		if(mode=='=')
3254887Schin 		{
3264887Schin 			if (strip && !cmd_completion)
3274887Schin 			{
3284887Schin 				register char **ptrcom;
3294887Schin 				for(ptrcom=com;*ptrcom;ptrcom++)
3304887Schin 					/* trim directory prefix */
3314887Schin 					*ptrcom = path_basename(*ptrcom);
3324887Schin 			}
3334887Schin 			sfputc(sfstderr,'\n');
3344887Schin 			sh_menu(sfstderr,narg,com);
3354887Schin 			sfsync(sfstderr);
3364887Schin 			ep->e_nlist = narg;
3374887Schin 			ep->e_clist = com;
3384887Schin 			goto done;
3394887Schin 		}
3404887Schin 		/* see if there is enough room */
3414887Schin 		size = *eol - (out-begin);
3424887Schin 		if(mode=='\\')
3434887Schin 		{
3444887Schin 			int c;
3454887Schin 			if(dir)
3464887Schin 			{
3474887Schin 				c = *dir;
3484887Schin 				*dir = 0;
3494887Schin 				saveout = begin;
3504887Schin 			}
3514887Schin 			if(saveout=astconf("PATH_ATTRIBUTES",saveout,(char*)0))
3524887Schin 				nocase = (strchr(saveout,'c')!=0);
3534887Schin 			if(dir)
3544887Schin 				*dir = c;
3554887Schin 			/* just expand until name is unique */
3564887Schin 			size += strlen(*com);
3574887Schin 		}
3584887Schin 		else
3594887Schin 		{
3604887Schin 			size += narg;
3614887Schin 			{
3624887Schin 				char **savcom = com;
3634887Schin 				while (*com)
36410898Sroland.mainz@nrubsig.org 					size += strlen(cp=fmtx(*com++));
3654887Schin 				com = savcom;
3664887Schin 			}
3674887Schin 		}
3684887Schin 		/* see if room for expansion */
3694887Schin 		if(outbuff+size >= &outbuff[MAXLINE])
3704887Schin 		{
3714887Schin 			com[0] = ap->argval;
3724887Schin 			com[1] = 0;
3734887Schin 		}
3744887Schin 		/* save remainder of the buffer */
3754887Schin 		if(*out)
3764887Schin 			left=stakcopy(out);
3774887Schin 		if(cmd_completion && mode=='\\')
3784887Schin 			out = strcopy(begin,path_basename(cp= *com++));
3794887Schin 		else if(mode=='*')
3804887Schin 		{
3814887Schin 			if(ep->e_nlist && dir && var)
3824887Schin 			{
3834887Schin 				if(*cp==var)
3844887Schin 					cp++;
3854887Schin 				else
3864887Schin 					*begin++ = var;
3874887Schin 				out = strcopy(begin,cp);
3884887Schin 				var = 0;
3894887Schin 			}
3904887Schin 			else
39110898Sroland.mainz@nrubsig.org 				out = strcopy(begin,fmtx(*com));
3924887Schin 			com++;
3934887Schin 		}
3944887Schin 		else
3954887Schin 			out = strcopy(begin,*com++);
3964887Schin 		if(mode=='\\')
3974887Schin 		{
3984887Schin 			saveout= ++out;
3994887Schin 			while (*com && *begin)
4004887Schin 			{
4014887Schin 				if(cmd_completion)
4024887Schin 					out = overlaid(begin,path_basename(*com++),nocase);
4034887Schin 				else
4044887Schin 					out = overlaid(begin,*com++,nocase);
4054887Schin 			}
4064887Schin 			mode = (out==saveout);
4074887Schin 			if(out[-1]==0)
4084887Schin 				out--;
4094887Schin 			if(mode && out[-1]!='/')
4104887Schin 			{
4114887Schin 				if(cmd_completion)
4124887Schin 				{
4134887Schin 					Namval_t *np;
4144887Schin 					/* add as tracked alias */
4154887Schin 					Pathcomp_t *pp;
4164887Schin 					if(*cp=='/' && (pp=path_dirfind(sh.pathlist,cp,'/')) && (np=nv_search(begin,sh.track_tree,NV_ADD)))
4174887Schin 						path_alias(np,pp);
4184887Schin 					out = strcopy(begin,cp);
4194887Schin 				}
4204887Schin 				/* add quotes if necessary */
42110898Sroland.mainz@nrubsig.org 				if((cp=fmtx(begin))!=begin)
4224887Schin 					out = strcopy(begin,cp);
4234887Schin 				if(var=='$' && begin[-1]=='{')
4244887Schin 					*out = '}';
4254887Schin 				else
4264887Schin 					*out = ' ';
4274887Schin 				*++out = 0;
4284887Schin 			}
42910898Sroland.mainz@nrubsig.org 			else if((cp=fmtx(begin))!=begin)
4304887Schin 			{
4314887Schin 				out = strcopy(begin,cp);
4324887Schin 				if(out[-1] =='"' || out[-1]=='\'')
43310898Sroland.mainz@nrubsig.org 					  *--out = 0;
4344887Schin 			}
4354887Schin 			if(*begin==0)
4364887Schin 				ed_ringbell();
4374887Schin 		}
4384887Schin 		else
4394887Schin 		{
4404887Schin 			while (*com)
4414887Schin 			{
4424887Schin 				*out++  = ' ';
44310898Sroland.mainz@nrubsig.org 				out = strcopy(out,fmtx(*com++));
4444887Schin 			}
4454887Schin 		}
4464887Schin 		if(ep->e_nlist)
4474887Schin 		{
4484887Schin 			cp = com[-1];
4494887Schin 			if(cp[strlen(cp)-1]!='/')
4504887Schin 			{
4514887Schin 				if(var=='$' && begin[-1]=='{')
4524887Schin 					*out = '}';
4534887Schin 				else
4544887Schin 					*out = ' ';
4554887Schin 				out++;
4564887Schin 			}
4574887Schin 			else if(out[-1] =='"' || out[-1]=='\'')
4584887Schin 				out--;
4594887Schin 			*out = 0;
4604887Schin 		}
4614887Schin 		*cur = (out-outbuff);
4624887Schin 		/* restore rest of buffer */
4634887Schin 		if(left)
4644887Schin 			out = strcopy(out,left);
4654887Schin 		*eol = (out-outbuff);
4664887Schin 	}
4674887Schin  done:
4684887Schin 	sh_offstate(SH_FCOMPLETE);
4694887Schin 	if(!ep->e_nlist)
4704887Schin 		stakset(ep->e_stkptr,ep->e_stkoff);
4714887Schin 	if(nomarkdirs)
4724887Schin 		sh_offoption(SH_MARKDIRS);
4734887Schin #if SHOPT_MULTIBYTE
4744887Schin 	{
4754887Schin 		register int c,n=0;
4764887Schin 		/* first re-adjust cur */
4774887Schin 		c = outbuff[*cur];
4784887Schin 		outbuff[*cur] = 0;
4794887Schin 		for(out=outbuff; *out;n++)
4804887Schin 			mbchar(out);
4814887Schin 		outbuff[*cur] = c;
4824887Schin 		*cur = n;
4834887Schin 		outbuff[*eol+1] = 0;
4844887Schin 		*eol = ed_internal(outbuff,(genchar*)outbuff);
4854887Schin 	}
4864887Schin #endif /* SHOPT_MULTIBYTE */
4874887Schin 	return(rval);
4884887Schin }
4894887Schin 
4904887Schin /*
4914887Schin  * look for edit macro named _i
4924887Schin  * if found, puts the macro definition into lookahead buffer and returns 1
4934887Schin  */
ed_macro(Edit_t * ep,register int i)4944887Schin int ed_macro(Edit_t *ep, register int i)
4954887Schin {
4964887Schin 	register char *out;
4974887Schin 	Namval_t *np;
4984887Schin 	genchar buff[LOOKAHEAD+1];
4994887Schin 	if(i != '@')
5004887Schin 		ep->e_macro[1] = i;
5014887Schin 	/* undocumented feature, macros of the form <ESC>[c evoke alias __c */
5024887Schin 	if(i=='_')
5034887Schin 		ep->e_macro[2] = ed_getchar(ep,1);
5044887Schin 	else
5054887Schin 		ep->e_macro[2] = 0;
5064887Schin 	if (isalnum(i)&&(np=nv_search(ep->e_macro,sh.alias_tree,HASH_SCOPE))&&(out=nv_getval(np)))
5074887Schin 	{
5084887Schin #if SHOPT_MULTIBYTE
5094887Schin 		/* copy to buff in internal representation */
5104887Schin 		int c = 0;
5114887Schin 		if( strlen(out) > LOOKAHEAD )
5124887Schin 		{
5134887Schin 			c = out[LOOKAHEAD];
5144887Schin 			out[LOOKAHEAD] = 0;
5154887Schin 		}
5164887Schin 		i = ed_internal(out,buff);
5174887Schin 		if(c)
5184887Schin 			out[LOOKAHEAD] = c;
5194887Schin #else
5204887Schin 		strncpy((char*)buff,out,LOOKAHEAD);
5214887Schin 		buff[LOOKAHEAD] = 0;
5224887Schin 		i = strlen((char*)buff);
5234887Schin #endif /* SHOPT_MULTIBYTE */
5244887Schin 		while(i-- > 0)
5254887Schin 			ed_ungetchar(ep,buff[i]);
5264887Schin 		return(1);
5274887Schin 	}
5284887Schin 	return(0);
5294887Schin }
5304887Schin 
5314887Schin /*
5324887Schin  * Enter the fc command on the current history line
5334887Schin  */
ed_fulledit(Edit_t * ep)5344887Schin int ed_fulledit(Edit_t *ep)
5354887Schin {
5364887Schin 	register char *cp;
5374887Schin 	if(!sh.hist_ptr)
5384887Schin 		return(-1);
5394887Schin 	/* use EDITOR on current command */
5404887Schin 	if(ep->e_hline == ep->e_hismax)
5414887Schin 	{
5424887Schin 		if(ep->e_eol<0)
5434887Schin 			return(-1);
5444887Schin #if SHOPT_MULTIBYTE
5454887Schin 		ep->e_inbuf[ep->e_eol+1] = 0;
5464887Schin 		ed_external(ep->e_inbuf, (char *)ep->e_inbuf);
5474887Schin #endif /* SHOPT_MULTIBYTE */
5484887Schin 		sfwrite(sh.hist_ptr->histfp,(char*)ep->e_inbuf,ep->e_eol+1);
5494887Schin 		sh_onstate(SH_HISTORY);
5504887Schin 		hist_flush(sh.hist_ptr);
5514887Schin 	}
5524887Schin 	cp = strcopy((char*)ep->e_inbuf,e_runvi);
5534887Schin 	cp = strcopy(cp, fmtbase((long)ep->e_hline,10,0));
5544887Schin 	ep->e_eol = ((unsigned char*)cp - (unsigned char*)ep->e_inbuf)-(sh_isoption(SH_VI)!=0);
5554887Schin 	return(0);
5564887Schin }
557