コード例 #1
0
ファイル: args.c プロジェクト: att/ast
void sh_applyopts(Shell_t *shp, Shopt_t newflags) {
    // Cannot set -n for interactive shells since there is no way out.
    if (sh_isoption(shp, SH_INTERACTIVE)) off_option(&newflags, SH_NOEXEC);
    if (is_option(&newflags, SH_PRIVILEGED)) on_option(&newflags, SH_NOUSRPROFILE);
    int is_privileged = is_option(&newflags, SH_PRIVILEGED) != sh_isoption(shp, SH_PRIVILEGED);
    int is_privileged_off = is_option(&(shp->arg_context)->sh->offoptions, SH_PRIVILEGED);
    if ((!sh_isstate(shp, SH_INIT) && is_privileged) ||
        (sh_isstate(shp, SH_INIT) && is_privileged_off && shp->gd->userid != shp->gd->euserid)) {
        if (!is_option(&newflags, SH_PRIVILEGED)) {
            if (setuid(shp->gd->userid) < 0) {
                error(ERROR_system(0), "setuid(%d) failed", shp->gd->userid);
                return;
            }
            if (setgid(shp->gd->groupid) < 0) {
                error(ERROR_system(0), "setgid(%d) failed", shp->gd->groupid);
                return;
            }
            if (shp->gd->euserid == 0) {
                shp->gd->euserid = shp->gd->userid;
                shp->gd->egroupid = shp->gd->groupid;
            }
        } else if ((shp->gd->userid != shp->gd->euserid && setuid(shp->gd->euserid) < 0) ||
                   (shp->gd->groupid != shp->gd->egroupid && setgid(shp->gd->egroupid) < 0) ||
                   (shp->gd->userid == shp->gd->euserid && shp->gd->groupid == shp->gd->egroupid)) {
            off_option(&newflags, SH_PRIVILEGED);
        }
    }
#if SHOPT_BASH
    on_option(&newflags, SH_CMDHIST);
    on_option(&newflags, SH_CHECKHASH);
    on_option(&newflags, SH_EXECFAIL);
    on_option(&newflags, SH_EXPAND_ALIASES);
    on_option(&newflags, SH_HISTAPPEND);
    on_option(&newflags, SH_INTERACTIVE_COMM);
    on_option(&newflags, SH_LITHIST);
    on_option(&newflags, SH_NOEMPTYCMDCOMPL);

    if (!is_option(&newflags, SH_XPG_ECHO) && sh_isoption(shp, SH_XPG_ECHO)) {
        astconf("UNIVERSE", 0, "ucb");
    }
    if (is_option(&newflags, SH_XPG_ECHO) && !sh_isoption(shp, SH_XPG_ECHO)) {
        astconf("UNIVERSE", 0, "att");
    }
    if (is_option(&newflags, SH_HISTORY2) && !sh_isoption(shp, SH_HISTORY2)) {
        sh_onstate(shp, SH_HISTORY);
        sh_onoption(shp, SH_HISTORY);
    }
    if (!is_option(&newflags, SH_HISTORY2) && sh_isoption(shp, SH_HISTORY2)) {
        sh_offstate(shp, SH_HISTORY);
        sh_offoption(shp, SH_HISTORY);
    }
#endif
    shp->options = newflags;
}
コード例 #2
0
ファイル: completion.c プロジェクト: att/ast
//
// Enter the fc command on the current history line.
//
int ed_fulledit(Edit_t *ep) {
    char *cp;

    if (!shgd->hist_ptr) return -1;
    // Use EDITOR on current command.
    if (ep->e_hline == ep->e_hismax) {
        if (ep->e_eol < 0) return -1;
        ep->e_inbuf[ep->e_eol + 1] = 0;
        ed_external(ep->e_inbuf, (char *)ep->e_inbuf);
        sfwrite(shgd->hist_ptr->histfp, (char *)ep->e_inbuf, ep->e_eol + 1);
        sh_onstate(ep->sh, SH_HISTORY);
        hist_flush(shgd->hist_ptr);
    }
    cp = stpcpy((char *)ep->e_inbuf, e_runvi);
    cp = stpcpy(cp, fmtbase((long)ep->e_hline, 10, 0));
    ep->e_eol =
        ((unsigned char *)cp - (unsigned char *)ep->e_inbuf) - (sh_isoption(ep->sh, SH_VI) != 0);
    return 0;
}
コード例 #3
0
ファイル: whence.c プロジェクト: ISLEcode/kornshell
/*
 * command is called with argc==0 when checking for -V or -v option
 * In this case return 0 when -v or -V or unknown option, otherwise
 *   the shift count to the command is returned
 */
int	b_command(register int argc,char *argv[],Shbltin_t *context)
{
	register int n, flags=0;
	register Shell_t *shp = context->shp;
	opt_info.index = opt_info.offset = 0;
	while((n = optget(argv,sh_optcommand))) switch(n)
	{
	    case 'p':
		if(sh_isoption(SH_RESTRICTED))
			 errormsg(SH_DICT,ERROR_exit(1),e_restricted,"-p");
		sh_onstate(SH_DEFPATH);
		break;
	    case 'v':
		flags |= X_FLAG;
		break;
	    case 'V':
		flags |= V_FLAG;
		break;
	    case 'x':
		shp->xargexit = 1;
		break;
	    case ':':
		if(argc==0)
			return(0);
		errormsg(SH_DICT,2, "%s", opt_info.arg);
		break;
	    case '?':
		if(argc==0)
			return(0);
		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
		break;
	}
	if(argc==0)
		return(flags?0:opt_info.index);
	argv += opt_info.index;
	if(error_info.errors || !*argv)
		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
	return(whence(shp,argv, flags));
}
コード例 #4
0
ファイル: completion.c プロジェクト: ISLEcode/kornshell
/*
 * Enter the fc command on the current history line
 */
int ed_fulledit(Edit_t *ep)
{
	register char *cp;
	if(!shgd->hist_ptr)
		return(-1);
	/* use EDITOR on current command */
	if(ep->e_hline == ep->e_hismax)
	{
		if(ep->e_eol<0)
			return(-1);
#if SHOPT_MULTIBYTE
		ep->e_inbuf[ep->e_eol+1] = 0;
		ed_external(ep->e_inbuf, (char *)ep->e_inbuf);
#endif /* SHOPT_MULTIBYTE */
		sfwrite(shgd->hist_ptr->histfp,(char*)ep->e_inbuf,ep->e_eol+1);
		sh_onstate(SH_HISTORY);
		hist_flush(shgd->hist_ptr);
	}
	cp = strcopy((char*)ep->e_inbuf,e_runvi);
	cp = strcopy(cp, fmtbase((long)ep->e_hline,10,0));
	ep->e_eol = ((unsigned char*)cp - (unsigned char*)ep->e_inbuf)-(sh_isoption(SH_VI)!=0);
	return(0);
}
コード例 #5
0
int	b_hist(int argc,char *argv[], void *extra)
{
	register History_t *hp;
	register char *arg;
	register int flag,fdo;
	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
	Sfio_t *outfile;
	char *fname;
	int range[2], incr, index2, indx= -1;
	char *edit = 0;		/* name of editor */
	char *replace = 0;		/* replace old=new */
	int lflag = 0, nflag = 0, rflag = 0;
#if SHOPT_HISTEXPAND
	int pflag = 0;
#endif
	Histloc_t location;
	NOT_USED(argc);
	if(!sh_histinit((void*)shp))
		errormsg(SH_DICT,ERROR_system(1),e_histopen);
	hp = shp->gd->hist_ptr;
	while((flag = optget(argv,sh_opthist))) switch(flag)
	{
	    case 'e':
		edit = opt_info.arg;
		break;
	    case 'n':
		nflag++;
		break;
	    case 'l':
		lflag++;
		break;
	    case 'r':
		rflag++;
		break;
	    case 's':
		edit = "-";
		break;
#if SHOPT_HISTEXPAND
	    case 'p':
		pflag++;
		break;
#endif
	    case 'N':
		if(indx<=0)
		{
			if((flag = hist_max(hp) - opt_info.num-1) < 0)
				flag = 1;
			range[++indx] = flag;
			break;
		}
	    case ':':
		errormsg(SH_DICT,2, "%s", opt_info.arg);
		break;
	    case '?':
		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
		break;
	}
	if(error_info.errors)
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	argv += (opt_info.index-1);
#if SHOPT_HISTEXPAND
	if(pflag)
	{
		hist_cancel(hp);
		pflag = 0;
		while(arg=argv[1])
		{
			flag = hist_expand(arg,&replace);
			if(!(flag & HIST_ERROR))
				sfputr(sfstdout, replace, '\n');
			else
				pflag = 1;
			if(replace)
				free(replace);
			argv++;
		}
		return pflag;
	}
#endif
	flag = indx;
	while(flag<1 && (arg=argv[1]))
	{
		/* look for old=new argument */
		if(!replace && strchr(arg+1,'='))
		{
			replace = arg;
			argv++;
			continue;
		}
		else if(isdigit(*arg) || *arg == '-')
		{
			/* see if completely numeric */
			do	arg++;
			while(isdigit(*arg));
			if(*arg==0)
			{
				arg = argv[1];
				range[++flag] = (int)strtol(arg, (char**)0, 10);
				if(*arg == '-')
					range[flag] += (hist_max(hp)-1);
				argv++;
				continue;
			}
		}
		/* search for last line starting with string */
		location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
		if((range[++flag] = location.hist_command) < 0)
			errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
		argv++;
	}
	if(flag <0)
	{
		/* set default starting range */
		if(lflag)
		{
			flag = hist_max(hp)-16;
			if(flag<1)
				flag = 1;
		}
		else
			flag = hist_max(hp)-2;
		range[0] = flag;
		flag = 0;
	}
	index2 = hist_min(hp);
	if(range[0]<index2)
		range[0] = index2;
	if(flag==0)
		/* set default termination range */
		range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
	if(range[1]>=(flag=(hist_max(hp) - !lflag)))
		range[1] = flag;
	/* check for valid ranges */
	if(range[1]<index2 || range[0]>=flag)
		errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
	if(edit && *edit=='-' && range[0]!=range[1])
		errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
	/* now list commands from range[rflag] to range[1-rflag] */
	incr = 1;
	flag = rflag>0;
	if(range[1-flag] < range[flag])
		incr = -1;
	if(lflag)
	{
		outfile = sfstdout;
		arg = "\n\t";
	}
	else
	{
		if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
			errormsg(SH_DICT,ERROR_exit(1),e_create,"");
		if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
			errormsg(SH_DICT,ERROR_system(1),e_create,fname);
		outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
		arg = "\n";
		nflag++;
	}
	while(1)
	{
		if(nflag==0)
			sfprintf(outfile,"%d\t",range[flag]);
		else if(lflag)
			sfputc(outfile,'\t');
		hist_list(shp->gd->hist_ptr,outfile,hist_tell(shp->gd->hist_ptr,range[flag]),0,arg);
		if(lflag)
			sh_sigcheck(shp);
		if(range[flag] == range[1-flag])
			break;
		range[flag] += incr;
	}
	if(lflag)
		return(0);
	sfclose(outfile);
	hist_eof(hp);
	arg = edit;
	if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
		arg = (char*)e_defedit;
#ifdef apollo
	/*
	 * Code to support the FC using the pad editor.
	 * Exampled of how to use: HISTEDIT=pad
	 */
	if (strcmp (arg, "pad") == 0)
	{
		extern int pad_create(char*);
		sh_close(fdo);
		fdo = pad_create(fname);
		pad_wait(fdo);
		unlink(fname);
		strcat(fname, ".bak");
		unlink(fname);
		lseek(fdo,(off_t)0,SEEK_SET);
	}
	else
	{
#endif /* apollo */
	if(*arg != '-')
	{
		char *com[3];
		com[0] =  arg;
		com[1] =  fname;
		com[2] = 0;
		error_info.errors = sh_eval(sh_sfeval(com),0);
	}
	fdo = sh_chkopen(fname);
	unlink(fname);
	free((void*)fname);
#ifdef apollo
	}
#endif /* apollo */
	/* don't history fc itself unless forked */
	error_info.flags |= ERROR_SILENT;
	if(!sh_isstate(SH_FORKED))
		hist_cancel(hp);
	sh_onstate(SH_HISTORY);
	sh_onstate(SH_VERBOSE);	/* echo lines as read */
	if(replace)
		hist_subst(error_info.id,fdo,replace);
	else if(error_info.errors == 0)
	{
		char buff[IOBSIZE+1];
		Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
		/* read in and run the command */
		if(shp->hist_depth++ > HIST_RECURSE)
			errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
		sh_eval(iop,1);
		shp->hist_depth--;
	}
コード例 #6
0
ファイル: args.c プロジェクト: att/ast
struct argnod *sh_argprocsub(Shell_t *shp, struct argnod *argp) {
    // Argument of the form <(cmd) or >(cmd).
    struct argnod *ap;
    int nn, monitor, fd, pv[3];
    int subshell = shp->subshell;
    pid_t pid0;

    ap = (struct argnod *)stkseek(shp->stk, ARGVAL);
    ap->argflag |= ARG_MAKE;
    ap->argflag &= ~ARG_RAW;
    fd = argp->argflag & ARG_RAW;
    if (fd == 0 && shp->subshell) sh_subtmpfile(shp);
#if has_dev_fd
    sfwrite(shp->stk, e_devfdNN, 8);
    pv[2] = 0;
    sh_pipe(pv);
    sfputr(shp->stk, fmtbase((long)pv[fd], 10, 0), 0);
#else   // has_dev_fd
    pv[0] = -1;
    shp->fifo = ast_temp_path("ksh.fifo");
    if (mkfifo(shp->fifo, S_IRUSR | S_IWUSR)) abort();
    sfputr(shp->stk, shp->fifo, 0);
#endif  // has_dev_fd
    ap = (struct argnod *)stkfreeze(shp->stk, 0);
    shp->inpipe = shp->outpipe = NULL;
    monitor = (sh_isstate(shp, SH_MONITOR) != 0);
    if (monitor) sh_offstate(shp, SH_MONITOR);
    shp->subshell = 0;
#if has_dev_fd
#if USE_SPAWN
    if (shp->vex || (shp->vex = spawnvex_open(0))) {
        spawnvex_add(shp->vex, pv[fd], pv[fd], 0, 0);
    } else
#endif  // USE_SPAWN
        fcntl(pv[fd], F_SETFD, 0);
    shp->fdstatus[pv[fd]] &= ~IOCLEX;
#endif  // has_dev_fd
    pid0 = shp->procsub ? *shp->procsub : 0;
    if (fd) {
        if (!shp->procsub) {
            shp->nprocsub = 4;
            shp->procsub = procsub = calloc(1, shp->nprocsub * sizeof(pid_t));
        } else {
            nn = procsub - shp->procsub;
            if (nn >= shp->nprocsub) {
                shp->nprocsub += 3;
                shp->procsub = realloc(shp->procsub, shp->nprocsub * sizeof(pid_t));
                procsub = shp->procsub + nn;
            }
        }
        if (pid0) *shp->procsub = 0;
        shp->inpipe = pv;
        sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT));
        if (pid0) *shp->procsub = pid0;
        *procsub++ = job.lastpost;
    } else {
        shp->outpipe = pv;
        sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT));
    }
    shp->subshell = subshell;
    if (monitor) sh_onstate(shp, SH_MONITOR);
#if has_dev_fd
    sh_close(pv[1 - fd]);
    sh_iosave(shp, -pv[fd], shp->topfd, NULL);
#else
    free(shp->fifo);
    shp->fifo = NULL;
#endif  // has_dev_fd
    return ap;
}
コード例 #7
0
ファイル: edit.c プロジェクト: ISLEcode/kornshell
/*
 * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
 * Use sfpkrd() to poll() or select() to wait for input if possible
 * Unfortunately, systems that get interrupted from slow reads update
 * this access time for for the terminal (in violation of POSIX).
 * The fixtime() macro, resets the time to the time at entry in
 * this case.  This is not necessary for systems that can handle
 * sfpkrd() correctly (i,e., those that support poll() or select()
 */
int ed_read(void *context, int fd, char *buff, int size, int reedit)
{
	register Edit_t *ep = (Edit_t*)context;
	register int rv= -1;
	register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
	Shell_t *shp = ep->sh;
	int mode = -1;
	int (*waitevent)(int,long,int) = shp->gd->waitevent;
	if(ep->e_raw==ALTMODE)
		mode = 1;
	if(size < 0)
	{
		mode = 1;
		size = -size;
	}
	sh_onstate(SH_TTYWAIT);
	errno = EINTR;
	shp->gd->waitevent = 0;
	while(rv<0 && errno==EINTR)
	{
		if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
			goto done;
		if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
		{
			Edpos_t	lastpos;
			int	n, rows, newsize;
			/* move cursor to start of first line */
			ed_putchar(ep,'\r');
			ed_flush(ep);
			astwinsize(2,&rows,&newsize);
			n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
			while(n--)
				ed_putstring(ep,CURSOR_UP);
			if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
			{
				/* clear the current command line */
				n = lastpos.line;
				while(lastpos.line--)
				{
					ed_nputchar(ep,ep->e_winsz,' ');
					ed_putchar(ep,'\n');
				}
				ed_nputchar(ep,ep->e_winsz,' ');
				while(n--)
					ed_putstring(ep,CURSOR_UP);
			}
	                ep->sh->winch = 0;
			ed_flush(ep);
			sh_delay(.05);
			astwinsize(2,&rows,&newsize);
			ep->e_winsz = newsize-1;
			if(ep->e_winsz < MINWINDOW)
				ep->e_winsz = MINWINDOW;
			if(!ep->e_multiline && ep->e_wsize < MAXLINE)
				ep->e_wsize = ep->e_winsz-2;
			ep->e_nocrnl=1;
			if(*ep->e_vi_insert)
			{
				buff[0] = ESC;
				buff[1] = cntl('L');
				buff[2] = 'a';
				return(3);
			}
			if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
				buff[0] = cntl('L');
			return(1);
		}
		else
			ep->sh->winch = 0;
		/* an interrupt that should be ignored */
		errno = 0;
		if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
			rv = sfpkrd(fd,buff,size,delim,-1L,mode);
	}
	if(rv < 0)
	{
#ifdef _hdr_utime
#		define fixtime()	if(isdevtty)utime(ep->e_tty,&utimes)
		int	isdevtty=0;
		struct stat statb;
		struct utimbuf utimes;
	 	if(errno==0 && !ep->e_tty)
		{
			if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
			{
				ep->e_tty_ino = statb.st_ino;
				ep->e_tty_dev = statb.st_dev;
			}
		}
		if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
		{
			utimes.actime = statb.st_atime;
			utimes.modtime = statb.st_mtime;
			isdevtty=1;
		}
#else
#		define fixtime()
#endif /* _hdr_utime */
		while(1)
		{
			rv = read(fd,buff,size);
			if(rv>=0 || errno!=EINTR)
				break;
			if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
				goto done;
			/* an interrupt that should be ignored */
			fixtime();
		}
	}
	else if(rv>=0 && mode>0)
		rv = read(fd,buff,rv>0?rv:1);
done:
	shp->gd->waitevent = waitevent;
	sh_offstate(SH_TTYWAIT);
	return(rv);
}
コード例 #8
0
ファイル: completion.c プロジェクト: ISLEcode/kornshell
int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count)
{
	struct comnod	*comptr;
	struct argnod	*ap;
	register char	*out;
	char 		*av[2], *begin , *dir=0;
	int		addstar=0, rval=0, var=0, strip=1;
	int 		nomarkdirs = !sh_isoption(SH_MARKDIRS);
	sh_onstate(SH_FCOMPLETE);
	if(ep->e_nlist)
	{
		if(mode=='=' && count>0)
		{
			if(count> ep->e_nlist)
				return(-1);
			mode = '?';
			av[0] = ep->e_clist[count-1];
			av[1] = 0;
		}
		else
		{
			stakset(ep->e_stkptr,ep->e_stkoff);
			ep->e_nlist = 0;
		}
	}
	comptr = (struct comnod*)stakalloc(sizeof(struct comnod));
	ap = (struct argnod*)stakseek(ARGVAL);
#if SHOPT_MULTIBYTE
	{
		register int c = *cur;
		register genchar *cp;
		/* adjust cur */
		cp = (genchar *)outbuff + *cur;
		c = *cp;
		*cp = 0;
		*cur = ed_external((genchar*)outbuff,(char*)stakptr(0));
		*cp = c;
		*eol = ed_external((genchar*)outbuff,outbuff);
	}
#endif /* SHOPT_MULTIBYTE */
	out = outbuff + *cur + (sh_isoption(SH_VI)!=0);
	if(out[-1]=='"' || out[-1]=='\'')
	{
		rval = -(sh_isoption(SH_VI)!=0);
		goto done;
	}
	comptr->comtyp = COMSCAN;
	comptr->comarg = ap;
	ap->argflag = (ARG_MAC|ARG_EXP);
	ap->argnxt.ap = 0;
	ap->argchn.cp = 0;
	{
		register int c;
		char *last = out;
		c =  *(unsigned char*)out;
		var = mode;
		begin = out = find_begin(outbuff,last,0,&var);
		/* addstar set to zero if * should not be added */
		if(var=='$')
		{
			stakputs("${!");
			stakwrite(out,last-out);
			stakputs("@}");
			out = last;
		}
		else
		{
			addstar = '*';
			while(out < last)
			{
				c = *(unsigned char*)out;
				if(isexp(c))
					addstar = 0;
				if (c == '/')
				{
					if(addstar == 0)
						strip = 0;
					dir = out+1;
				}
				stakputc(c);
				out++;
			}
		}
		if(mode=='?')
			mode = '*';
		if(var!='$' && mode=='\\' && out[-1]!='*')
			addstar = '*';
		if(*begin=='~' && !strchr(begin,'/'))
			addstar = 0;
		stakputc(addstar);
		ap = (struct argnod*)stakfreeze(1);
	}
	if(mode!='*')
		sh_onoption(SH_MARKDIRS);
	{
		register char	**com;
		char		*cp=begin, *left=0, *saveout=".";
		int	 	nocase=0,narg,cmd_completion=0;
		register 	int size='x';
		while(cp>outbuff && ((size=cp[-1])==' ' || size=='\t'))
			cp--;
		if(!var && !strchr(ap->argval,'/') && (((cp==outbuff&&ep->sh->nextprompt==1) || (strchr(";&|(",size)) && (cp==outbuff+1||size=='('||cp[-2]!='>') && *begin!='~' )))
		{
			cmd_completion=1;
			sh_onstate(SH_COMPLETE);
		}
		if(ep->e_nlist)
		{
			narg = 1;
			com = av;
			if(dir)
				begin += (dir-begin);
		}
		else
		{
			com = sh_argbuild(ep->sh,&narg,comptr,0);
			/* special handling for leading quotes */
			if(begin>outbuff && (begin[-1]=='"' || begin[-1]=='\''))
			begin--;
		}
		sh_offstate(SH_COMPLETE);
                /* allow a search to be aborted */
		if(ep->sh->trapnote&SH_SIGSET)
		{
			rval = -1;
			goto done;
		}
		/*  match? */
		if (*com==0 || (narg <= 1 && (strcmp(ap->argval,*com)==0) || (addstar && com[0][strlen(*com)-1]=='*')))
		{
			rval = -1;
			goto done;
		}
		if(mode=='\\' && out[-1]=='/'  && narg>1)
			mode = '=';
		if(mode=='=')
		{
			if (strip && !cmd_completion)
			{
				register char **ptrcom;
				for(ptrcom=com;*ptrcom;ptrcom++)
					/* trim directory prefix */
					*ptrcom = path_basename(*ptrcom);
			}
			sfputc(sfstderr,'\n');
			sh_menu(sfstderr,narg,com);
			sfsync(sfstderr);
			ep->e_nlist = narg;
			ep->e_clist = com;
			goto done;
		}
		/* see if there is enough room */
		size = *eol - (out-begin);
		if(mode=='\\')
		{
			int c;
			if(dir)
			{
				c = *dir;
				*dir = 0;
				saveout = begin;
			}
			if(saveout=astconf("PATH_ATTRIBUTES",saveout,(char*)0))
				nocase = (strchr(saveout,'c')!=0);
			if(dir)
				*dir = c;
			/* just expand until name is unique */
			size += strlen(*com);
		}
		else
		{
			size += narg;
			{
				char **savcom = com;
				while (*com)
					size += strlen(cp=fmtx(*com++));
				com = savcom;
			}
		}
		/* see if room for expansion */
		if(outbuff+size >= &outbuff[MAXLINE])
		{
			com[0] = ap->argval;
			com[1] = 0;
		}
		/* save remainder of the buffer */
		if(*out)
			left=stakcopy(out);
		if(cmd_completion && mode=='\\')
			out = strcopy(begin,path_basename(cp= *com++));
		else if(mode=='*')
		{
			if(ep->e_nlist && dir && var)
			{
				if(*cp==var)
					cp++;
				else
					*begin++ = var;
				out = strcopy(begin,cp);
				var = 0;
			}
			else
				out = strcopy(begin,fmtx(*com));
			com++;
		}
		else
			out = strcopy(begin,*com++);
		if(mode=='\\')
		{
			saveout= ++out;
			while (*com && *begin)
			{
				if(cmd_completion)
					out = overlaid(begin,path_basename(*com++),nocase);
				else
					out = overlaid(begin,*com++,nocase);
			}
			mode = (out==saveout);
			if(out[-1]==0)
				out--;
			if(mode && out[-1]!='/')
			{
				if(cmd_completion)
				{
					Namval_t *np;
					/* add as tracked alias */
					Pathcomp_t *pp;
					if(*cp=='/' && (pp=path_dirfind(ep->sh->pathlist,cp,'/')) && (np=nv_search(begin,ep->sh->track_tree,NV_ADD)))
						path_alias(np,pp);
					out = strcopy(begin,cp);
				}
				/* add quotes if necessary */
				if((cp=fmtx(begin))!=begin)
					out = strcopy(begin,cp);
				if(var=='$' && begin[-1]=='{')
					*out = '}';
				else
					*out = ' ';
				*++out = 0;
			}
			else if((cp=fmtx(begin))!=begin)
			{
				out = strcopy(begin,cp);
				if(out[-1] =='"' || out[-1]=='\'')
					  *--out = 0;
			}
			if(*begin==0)
				ed_ringbell();
		}
		else
		{
			while (*com)
			{
				*out++  = ' ';
				out = strcopy(out,fmtx(*com++));
			}
		}
		if(ep->e_nlist)
		{
			cp = com[-1];
			if(cp[strlen(cp)-1]!='/')
			{
				if(var=='$' && begin[-1]=='{')
					*out = '}';
				else
					*out = ' ';
				out++;
			}
			else if(out[-1] =='"' || out[-1]=='\'')
				out--;
			*out = 0;
		}
		*cur = (out-outbuff);
		/* restore rest of buffer */
		if(left)
			out = strcopy(out,left);
		*eol = (out-outbuff);
	}
 done:
	sh_offstate(SH_FCOMPLETE);
	if(!ep->e_nlist)
		stakset(ep->e_stkptr,ep->e_stkoff);
	if(nomarkdirs)
		sh_offoption(SH_MARKDIRS);
#if SHOPT_MULTIBYTE
	{
		register int c,n=0;
		/* first re-adjust cur */
		c = outbuff[*cur];
		outbuff[*cur] = 0;
		for(out=outbuff; *out;n++)
			mbchar(out);
		outbuff[*cur] = c;
		*cur = n;
		outbuff[*eol+1] = 0;
		*eol = ed_internal(outbuff,(genchar*)outbuff);
	}
#endif /* SHOPT_MULTIBYTE */
	return(rval);
}
コード例 #9
0
ファイル: main.c プロジェクト: ISLEcode/kornshell
int sh_main(int ac, char *av[], Shinit_f userinit)
{
	register char	*name;
	register int	fdin;
	register Sfio_t  *iop;
	register Shell_t *shp;
	struct stat	statb;
	int i, rshflag;		/* set for restricted shell */
	char *command;
	free(malloc(64*1024));
#ifdef _lib_sigvec
	/* This is to clear mask that may be left on by rlogin */
	clearsigmask(SIGALRM);
	clearsigmask(SIGHUP);
	clearsigmask(SIGCHLD);
#endif /* _lib_sigvec */
#ifdef	_hdr_nc
	_NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
#endif	/* _hdr_nc */
	fixargs(av,0);
	shp = sh_init(ac,av,userinit);
	time(&mailtime);
	if(rshflag=sh_isoption(SH_RESTRICTED))
		sh_offoption(SH_RESTRICTED);
	if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
	{
		/* begin script execution here */
		sh_reinit((char**)0);
		shp->gd->pid = getpid();
		shp->gd->ppid = getppid();
	}
	shp->fn_depth = shp->dot_depth = 0;
	command = error_info.id;
	/* set pidname '$$' */
	srand(shp->gd->pid&0x7fff);
	if(nv_isnull(PS4NOD))
		nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
	path_pwd(shp,1);
	iop = (Sfio_t*)0;
#if SHOPT_BRACEPAT
	sh_onoption(SH_BRACEEXPAND);
#endif
	if((beenhere++)==0)
	{
		sh_onstate(SH_PROFILE);
		((Lex_t*)shp->lex_context)->nonstandard = 0;
		if(shp->gd->ppid==1)
			shp->login_sh++;
		if(shp->login_sh >= 2)
			sh_onoption(SH_LOGIN_SHELL);
		/* decide whether shell is interactive */
		if(!sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) &&
		   sh_isoption(SH_SFLAG) && tty_check(0) && tty_check(ERRIO))
			sh_onoption(SH_INTERACTIVE);
		if(sh_isoption(SH_INTERACTIVE))
		{
			sh_onoption(SH_BGNICE);
			sh_onoption(SH_RC);
		}
		if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)
#if SHOPT_REMOTE
		   || !fstat(0, &statb) && REMOTE(statb.st_mode)
#endif
		  ))
			sh_onoption(SH_RC);
		for(i=0; i<elementsof(shp->offoptions.v); i++)
			shp->options.v[i] &= ~shp->offoptions.v[i];
		if(sh_isoption(SH_INTERACTIVE))
		{
#ifdef SIGXCPU
			signal(SIGXCPU,SIG_DFL);
#endif /* SIGXCPU */
#ifdef SIGXFSZ
			signal(SIGXFSZ,SIG_DFL);
#endif /* SIGXFSZ */
			sh_onoption(SH_MONITOR);
		}
		job_init(shp,sh_isoption(SH_LOGIN_SHELL));
		if(sh_isoption(SH_LOGIN_SHELL))
		{
			/*	system profile	*/
			sh_source(shp, iop, e_sysprofile);
			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED))
			{
				char **files = shp->gd->login_files;
				while ((name = *files++) && !sh_source(shp, iop, sh_mactry(shp,name)));
			}
		}
		/* make sure PWD is set up correctly */
		path_pwd(shp,1);
		if(!sh_isoption(SH_NOEXEC))
		{
			if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC))
			{
#if SHOPT_BASH
				if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX))
				{
#if SHOPT_SYSRC
					sh_source(shp, iop, e_bash_sysrc);
#endif
					sh_source(shp, iop, shp->gd->rcfile ? shp->gd->rcfile : sh_mactry(shp,(char*)e_bash_rc));
				}
				else
#endif
				{
					if(name = sh_mactry(shp,nv_getval(ENVNOD)))
						name = *name ? strdup(name) : (char*)0;
#if SHOPT_SYSRC
					if(!strmatch(name, "?(.)/./*"))
						sh_source(shp, iop, e_sysrc);
#endif
					if(name)
					{
						sh_source(shp, iop, name);
						free(name);
					}
				}
			}
			else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED))
				sh_source(shp, iop, e_suidprofile);
		}
		shp->st.cmdname = error_info.id = command;
		sh_offstate(SH_PROFILE);
		if(rshflag)
			sh_onoption(SH_RESTRICTED);
		/* open input file if specified */
		if(shp->comdiv)
		{
		shell_c:
			iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
		}
コード例 #10
0
ファイル: print.c プロジェクト: nathanmkaya/ksh-arch
int    b_print(int argc, char *argv[], Shbltin_t *context)
{
	register Sfio_t *outfile;
	register int exitval=0,n, fd = 1;
	register Shell_t *shp = context->shp;
	const char *options, *msg = e_file+4;
	char *format = 0, *fmttype=0;
	int sflag = 0, nflag=0, rflag=0, vflag=0;
	Namval_t *vname=0;
	Optdisc_t disc;
	disc.version = OPT_VERSION;
	disc.infof = infof;
	opt_info.disc = &disc;
	if(argc>0)
	{
		options = sh_optprint;
		nflag = rflag = 0;
		format = 0;
	}
	else
	{
		struct print *pp = (struct print*)context;
		shp = pp->sh;
		options = pp->options;
		if(argc==0)
		{
			nflag = pp->echon;
			rflag = pp->raw;
			argv++;
			goto skip;
		}
	}
	while((n = optget(argv,options))) switch(n)
	{
		case 'n':
			nflag++;
			break;
		case 'p':
			fd = shp->coutpipe;
			msg = e_query;
			break;
		case 'f':
			format = opt_info.arg;
			break;
		case 's':
			/* print to history file */
			if(!sh_histinit((void*)shp))
				errormsg(SH_DICT,ERROR_system(1),e_history);
			fd = sffileno(shp->gd->hist_ptr->histfp);
			sh_onstate(shp,SH_HISTORY);
			sflag++;
			break;
		case 'e':
			rflag = 0;
			break;
		case 'r':
			rflag = 1;
			break;
		case 'u':
			if(opt_info.arg[0]=='p' && opt_info.arg[1]==0)
			{
				fd = shp->coutpipe;
				msg = e_query;
				break;
			}
			fd = (int)strtol(opt_info.arg,&opt_info.arg,10);
			if(*opt_info.arg)
				fd = -1;
			else if(!sh_iovalidfd(shp,fd))
				fd = -1;
			else if(!(shp->inuse_bits&(1<<fd)) && (sh_inuse(shp,fd) || (shp->gd->hist_ptr && fd==sffileno(shp->gd->hist_ptr->histfp))))

				fd = -1;
			break;
		case 'j':
			fmttype = "json";
		case 'v':
			if(argc < 0)
			{
				if(!(vname = nv_open(opt_info.arg, shp->var_tree,NV_VARNAME|NV_NOARRAY)))
					errormsg(SH_DICT,2, "Cannot create variable %s", opt_info.arg);
			}
			else
				vflag='v';
			break;
		case 'C':
			vflag='C';
			break;
		case ':':
			/* The following is for backward compatibility */
#if OPT_VERSION >= 19990123
			if(strcmp(opt_info.name,"-R")==0)
#else
			if(strcmp(opt_info.option,"-R")==0)
#endif
			{
				rflag = 1;
				if(error_info.errors==0)
				{
					argv += opt_info.index+1;
					/* special case test for -Rn */
					if(strchr(argv[-1],'n'))
						nflag++;
					if(*argv && strcmp(*argv,"-n")==0)
					{

						nflag++;
						argv++;
					}
					goto skip2;
				}
			}
			else
				errormsg(SH_DICT,2, "%s", opt_info.arg);
			break;
		case '?':
			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
			break;
	}
	argv += opt_info.index;
	if(error_info.errors || (argc<0 && !(format = *argv++)))
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	if(vflag && format)
		errormsg(SH_DICT,ERROR_usage(2),"-%c and -f are mutually exclusive",vflag);
skip:
	if(format)
		format = genformat(shp,format);
	/* handle special case of '-' operand for print */
	if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--"))
		argv++;
	if(vname)
	{
		if(!shp->strbuf2)
			shp->strbuf2 = sfstropen();
		outfile = shp->strbuf2;
		goto printv;
	}
skip2:
	if(fd < 0)
	{
		errno = EBADF;
		n = 0;
	}
	else if(!(n=shp->fdstatus[fd]))
		n = sh_iocheckfd(shp,fd,fd);
	if(!(n&IOWRITE))
	{
		/* don't print error message for stdout for compatibility */
		if(fd==1)
			return(1);
		errormsg(SH_DICT,ERROR_system(1),msg);
	}
	if(!(outfile=shp->sftable[fd]))
	{
		sh_onstate(shp,SH_NOTRACK);
		n = SF_WRITE|((n&IOREAD)?SF_READ:0);
		shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n);
		sh_offstate(shp,SH_NOTRACK);
		sfpool(outfile,shp->outpool,SF_WRITE);
	}
コード例 #11
0
ファイル: completion.c プロジェクト: att/ast
//
// File name generation for edit modes.
// Non-zero exit for error, <0 ring bell.
// Don't search back past beginning of the buffer.
// Mode is '*' for inline expansion.
// Mode is '\' for filename completion.
// Mode is '=' cause files to be listed in select format.
//
int ed_expand(Edit_t *ep, char outbuff[], int *cur, int *eol, int mode, int count) {
    struct comnod *comptr;
    struct argnod *ap;
    char *out;
    char *av[2], *begin;
    char *dir = NULL;
    int addstar = 0, rval = 0, var = 0, strip = 1, narg = 0;
    int nomarkdirs = !sh_isoption(ep->sh, SH_MARKDIRS);
    Shell_t *shp = ep->sh;
    char **com = NULL;

    sh_onstate(shp, SH_FCOMPLETE);
    if (ep->e_nlist) {
        if (mode == '=' && count > 0) {
            if (count > ep->e_nlist) return -1;
            mode = '?';
            av[0] = ep->e_clist[count - 1];
            av[1] = 0;
        } else {
            stkset(shp->stk, ep->e_stkptr, ep->e_stkoff);
            ep->e_nlist = 0;
        }
    }
    comptr = stkalloc(shp->stk, sizeof(struct comnod));
    ap = (struct argnod *)stkseek(shp->stk, ARGVAL);

    {
        // Adjust cur.
        int c;
        genchar *cp;
        cp = (genchar *)outbuff + *cur;
        c = *cp;
        *cp = 0;
        *cur = ed_external((genchar *)outbuff, (char *)stkptr(shp->stk, 0));
        *cp = c;
        *eol = ed_external((genchar *)outbuff, outbuff);
    }

    out = outbuff + *cur + (sh_isoption(shp, SH_VI) != 0);
#if 0
        if(out[-1]=='"' || out[-1]=='\'')
        {
                rval = -(sh_isoption(shp,SH_VI)!=0);
                goto done;
        }
#endif
    comptr->comtyp = COMSCAN;
    comptr->comarg = ap;
    ap->argflag = (ARG_MAC | ARG_EXP);
    ap->argnxt.ap = NULL;
    ap->argchn.cp = NULL;

    {
        char *last = out;
        Namval_t *np = nv_search("COMP_KEY", shp->var_tree, 0);
        if (np) STORE_VT(np->nvalue, i16, '\t');
        np = nv_search("COMP_TYPE", shp->var_tree, 0);
        if (np) STORE_VT(np->nvalue, i16, mode == '\\' ? '\t' : '?');
        var = mode;
        begin = out = find_begin(outbuff, last, 0, &var);
        if (ep->compdict && mode != '?' &&
            (com = prog_complete(ep->compdict, outbuff, out, *cur))) {
            char **av;
            for (av = com; *av; av++) {
                ;  // empty loop
            }
            narg = av - com;
        }
        // Addstar set to zero if * should not be added.
        if (var == '$') {
            sfwrite(shp->stk, "${!", 3);
            sfwrite(shp->stk, out, last - out);
            sfwrite(shp->stk, "$@}", 2);
            out = last;
        } else {
            addstar = '*';
            while (out < last) {
                char c = *out;
                if (c == 0) break;
                if (isexp(c)) addstar = 0;
                if (c == '/') {
                    if (addstar == 0) strip = 0;
                    dir = out + 1;
                }
                sfputc(shp->stk, c);
                out++;
            }
        }
        if (mode == '?') mode = '*';
        if (var != '$' && mode == '\\' && out[-1] != '*') addstar = '*';
        if (*begin == '~' && !strchr(begin, '/')) addstar = 0;
        sfputc(shp->stk, addstar);
        ap = (struct argnod *)stkfreeze(shp->stk, 1);
    }

    if (mode != '*') sh_onoption(shp, SH_MARKDIRS);

    {
        char *cp = begin, *left = NULL;
        int cmd_completion = 0;
        int size = 'x';
        while (cp > outbuff && ((size = cp[-1]) == ' ' || size == '\t')) cp--;
        if (!var && !strchr(ap->argval, '/') &&
            ((cp == outbuff && shp->nextprompt == 1) ||
             (strchr(";&|(", size) && (cp == outbuff + 1 || size == '(' || cp[-2] != '>') &&
              *begin != '~'))) {
            cmd_completion = 1;
            sh_onstate(shp, SH_COMPLETE);
        }
        if (ep->e_nlist) {
            narg = 1;
            com = av;
            if (dir) begin += (dir - begin);
        } else {
            if (!com) com = sh_argbuild(shp, &narg, comptr, 0);
            // Special handling for leading quotes.
            if (begin > outbuff && (begin[-1] == '"' || begin[-1] == '\'')) begin--;
        }
        sh_offstate(shp, SH_COMPLETE);
        // Allow a search to be aborted.
        if (shp->trapnote & SH_SIGSET) {
            rval = -1;
            goto done;
        }
        // Match?
        if (*com == 0 || ((narg <= 1 && (strcmp(ap->argval, *com) == 0)) ||
                          (addstar && com[0][strlen(*com) - 1] == '*'))) {
            rval = -1;
            goto done;
        }
        if (mode == '\\' && out[-1] == '/' && narg > 1) mode = '=';
        if (mode == '=') {
            if (strip && !cmd_completion) {
                char **ptrcom;
                for (ptrcom = com; *ptrcom; ptrcom++) {  // trim directory prefix
                    *ptrcom = path_basename(*ptrcom);
                }
            }
            sfputc(sfstderr, '\n');
            sh_menu(shp, sfstderr, narg, com);
            sfsync(sfstderr);
            ep->e_nlist = narg;
            ep->e_clist = com;
            goto done;
        }
        // See if there is enough room.
        size = *eol - (out - begin);
        if (mode == '\\') {
            int c;
            if (dir) {
                c = *dir;
                *dir = 0;
            }
            if (dir) *dir = c;
            // Just expand until name is unique.
            size += strlen(*com);
        } else {
            char **tmpcom = com;
            size += narg;
            while (*tmpcom) {
                cp = fmtx(shp, *tmpcom++);
                size += strlen(cp);
            }
        }
        // See if room for expansion.
        if (outbuff + size >= &outbuff[MAXLINE]) {
            com[0] = ap->argval;
            com[1] = 0;
        }
        // Save remainder of the buffer.
        if (*out) left = stkcopy(shp->stk, out);
        if (cmd_completion && mode == '\\') {
            cp = *com++;
            out = stpcpy(begin, path_basename(cp));
        } else if (mode == '*') {
            if (ep->e_nlist && dir && var) {
                if (*cp == var) {
                    cp++;
                } else {
                    *begin++ = var;
                }
                out = stpcpy(begin, cp);
                var = 0;
            } else {
                out = stpcpy(begin, fmtx(shp, *com));
            }
            com++;
        } else {
            out = stpcpy(begin, *com++);
        }
        if (mode == '\\') {
            char *saveout = ++out;
            while (*com && *begin) {
                if (cmd_completion) {
                    out = overlaid(begin, path_basename(*com++), false);
                } else {
                    out = overlaid(begin, *com++, false);
                }
            }
            mode = (out == saveout);
            if (out[-1] == 0) out--;
            if (mode && out[-1] != '/') {
                if (cmd_completion) {
                    Namval_t *np;
                    // Add as tracked alias.
                    Pathcomp_t *pp;
                    if (*cp == '/' && (pp = path_dirfind(shp->pathlist, cp, '/')) &&
                        (np = nv_search(begin, shp->track_tree, NV_ADD))) {
                        path_alias(np, pp);
                    }
                    out = stpcpy(begin, cp);
                }
                // Add quotes if necessary.
                if ((cp = fmtx(shp, begin)) != begin) out = stpcpy(begin, cp);
                if (var == '$' && begin[-1] == '{') {
                    *out = '}';
                } else {
                    *out = ' ';
                }
                *++out = 0;
            } else if ((cp = fmtx(shp, begin)) != begin) {
                out = stpcpy(begin, cp);
                if (out[-1] == '"' || out[-1] == '\'') *--out = 0;
            }
            if (*begin == 0 && begin[-1] != ' ') ed_ringbell();
        } else {
            while (*com) {
                *out++ = ' ';
                out = stpcpy(out, fmtx(shp, *com++));
            }
        }
        if (ep->e_nlist) {
            cp = com[-1];
            if (cp[strlen(cp) - 1] != '/') {
                if (var == '$' && begin[-1] == '{') {
                    *out = '}';
                } else {
                    *out = ' ';
                }
                out++;
            } else if (out[-1] == '"' || out[-1] == '\'') {
                out--;
            }
            *out = 0;
        }
        *cur = (out - outbuff);
        // Restore rest of buffer.
        if (left) out = stpcpy(out, left);
        *eol = (out - outbuff);
    }

done:
    sh_offstate(shp, SH_FCOMPLETE);
    if (!ep->e_nlist) stkset(shp->stk, ep->e_stkptr, ep->e_stkoff);
    if (nomarkdirs) sh_offoption(shp, SH_MARKDIRS);

    {
        // First re-adjust cur.
        int c, n = 0;
        c = outbuff[*cur];
        outbuff[*cur] = 0;
        for (out = outbuff; *out; n++) mb1char(&out);
        outbuff[*cur] = c;
        *cur = n;
        outbuff[*eol + 1] = 0;
        *eol = ed_internal(outbuff, (genchar *)outbuff);
    }

    return rval;
}