[comp.sources.unix] v16i063: Front end editor program, Part03/05

rsalz@uunet.uu.net (Rich Salz) (11/11/88)

Submitted-by: Kazumasa Utashiro <kddlab!sra.junet!utashiro>
Posting-number: Volume 16, Issue 63
Archive-name: fep/part03

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./fep_edit.c`
then
echo "writing ./fep_edit.c"
cat > ./fep_edit.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

#ifndef lint
static char rcsid[]=
"$Header: fep_edit.c,v 4.0 88/08/05 20:22:06 utashiro Rel $ (SRA)";
#endif lint

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sgtty.h>
#include <sys/time.h>
#include <ctype.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <setjmp.h>
#include "fep_defs.h"
#include "fep_glob.h"
#include "fep_funcs.h"

CHAR		*CommandLine;		/* pointer to command line buffer */
CHAR		*KillBuffer;		/* pointer to kill buffer */
int		CurrentPosition;	/* current cursor position */
int		MarkPosition = -1;	/* Marked position */
EDITMODE	editmode = NOTYET;	/* edtimode EMACS, VI */
EDITSTATUS	editstatus;		/* EDITING, NOTEDITING */

int	maxline = MAXCOMLEN;		/* maximum length of command line */
int	NeedNewLine;			/* add new line flag */
int	NeedSave;			/* need to save to history */
int	Transparency = OFF;		/* transparent flag */
int	eof_occured = 0;		/* eof has been occured */
jmp_buf	jbuf;				/* jump buffer */

FUNC	*curFuncTab;			/* current function table */
FUNC	*altFuncTab;			/* alternative function table */

/*
 * Default binding table
 */
BINDENT emacsBindings[] = {
	/* NULL		*/	{"\0",		mark},
	/* ^A		*/	{"\\^A",	beginning_of_line},
	/* ^B		*/	{"\\^B",	backward_character},
	/* ^D		*/	{"\\^D",	delete_next_character},
	/* ^E		*/	{"\\^E",	end_of_line},
	/* ^F		*/	{"\\^F",	forward_character},
	/* ^I		*/	{"\\^I",	insert_tab},
	/* ^J		*/	{"\\^J",	new_line},
	/* ^K		*/	{"\\^K",	kill_to_end_of_line},
	/* ^L		*/	{"\\^L",	clear_screen},
	/* ^M		*/	{"\\^M",	new_line},
	/* ^N		*/	{"\\^N",	next_history},
	/* ^P		*/	{"\\^P",	previous_history},
	/* ^T		*/	{"\\^T",	previous_history},
	/* ^Y		*/	{"\\^Y",	yank_from_kill_buffer},
	/* ^^		*/	{"\\^^",	toggle_transparency},
	/* esc-b	*/	{"\\^[b",	backward_word},
	/* esc-B	*/	{"\\^[B",	backward_Word},
	/* esc-d	*/	{"\\^[d",	delete_next_word},
	/* esc-D	*/	{"\\^[D",	delete_next_Word},
	/* esc-f	*/	{"\\^[f",	forward_word},
	/* esc-F	*/	{"\\^[F",	forward_Word},
	/* esc-h	*/	{"\\^[h",	delete_previous_word},
	/* esc-H	*/	{"\\^[H",	delete_previous_Word},
	/* esc-l	*/	{"\\^[l",	list_file_name},
	/* esc-L	*/	{"\\^[L",	list_file_name},
    	/* esc-esc	*/	{"\\^[\\^[",	expand_file_name},
	/* esc-"-"	*/	{"\\^[-",	toggle_transparency},
	/* esc-_	*/	{"\\^[_",	invoke_shell},
	/* esc-<	*/	{"\\^[<",	search_reverse},
	/* esc->	*/	{"\\^[>",	search_forward},
	/* esc-?	*/	{"\\^[?",	show_help},
	/* ^X-^B	*/	{"\\^X\\^B",	show_bindings},
	/* ^X-B		*/	{"\\^XB",	show_bindings},
	/* ^X-b		*/	{"\\^Xb",	show_bindings},
	/* ^X-^H	*/	{"\\^X\\^H",	show_history},
	/* ^X-H		*/	{"\\^XH",	show_history},
	/* ^X-h		*/	{"\\^Xh",	show_history},
	/* ^X-^K	*/	{"\\^X\\^K",	kill_to_top_of_line},
	/* ^X-^L	*/	{"\\^X\\^L",	fep_repaint},
	/* ^X-^C	*/	{"\\^X\\^C",	terminate},
	/* ^X-^D	*/	{"\\^X\\^D",	send_eof},
	/* ^X-(		*/	{"\\^X(",	fep_start_script},
	/* ^X-)		*/	{"\\^X)",	fep_end_script},
	/*		*/	{NULL,		NULL}
};

/*
 * Initialize function table buffer
 */
init_bind_table ()
{

    curFuncTab = (FUNC *) calloc (sizeof (FUNC), 256);
    altFuncTab = (FUNC *) calloc (sizeof (FUNC), 256);
    if (curFuncTab == 0 || altFuncTab == 0) {
	printf ("Can't allocate space for function table\n");
	exit (1);
    }
}

/*
 * Initialize function table
 */
char strspace [256], *strspace_addr = strspace;

init_edit_params ()
{
    struct indirect *idp;
    char *cp, *getenv();
    char sbuf[2048], *term, *tgetstr();

    if (term = look_var ("term")) {
	if (tgetent (sbuf, term) == 1) {
	    if (lines == 0)
		lines = tgetnum ("li");
	    if (columns == 0)
		columns = tgetnum ("co");
	    term_clear = tgetstr ("cl", &strspace_addr);
	}
    }

    if (lines == 0)
	lines = 24;
    if (columns == 0)
	columns = 80;

    sprintf (sbuf, "%d", lines);
    set_var ("crt", sbuf);

    if (editmode == NOTYET) {
	if (look_var ("editmode"))
	    set_var ("editmode", look_var ("editmode"));
	else
	    set_var ("editmode", "emacs");
    }

    set_var ("showhist", itoa (lines - 1));

    /*
     * Read startup file
     */
    sourceRcFile ();

    /*
     * Read history if 'history-file' is set
     */
    {
	char *cp, *mk_home_relative ();

	if (look_var ("savehist") && (cp = look_var ("history-file"))) {
	    cp = mk_home_relative (cp);

	    if (access (cp, R_OK) == 0)
		read_history (cp);
	}
    }

    /*
     * Initialize command line buffer
     */
    CommandLine = (CHAR *) calloc (maxline, 1);
    KillBuffer = (CHAR *) calloc (maxline, 1);
    if (CommandLine == 0 || KillBuffer == 0) {
	perror ("Edit line buffer");
	exit (1);
    }
    (void) strcpy (CommandLine, "");
    (void) strcpy (KillBuffer, "");
    CurrentPosition = 0;
}

/*
 * Initialize emacs bindings
 */
initEmacsBindings (cft, aft)
    FUNC cft[], aft[];
{
    register int i;
    BINDENT *ftp;

    for (i = 0; i < 256; i++)
	cft[i] = self_insert;
    for (ftp = emacsBindings; ftp->bt_s; ftp++) {
	bind_key (cft, ftp->bt_func, ftp->bt_s, abort);
    }

    /* Now, using cbreak mode
    cft[(int) tchars_buf.t_startc] = ignore;
    cft[(int) tchars_buf.t_stopc] = ignore;
    */
    cft[(int) tchars_buf.t_intrc] = insert_and_flush;
    cft[(int) tchars_buf.t_quitc] = insert_and_flush;
    /* Now, EOF will be sent on empty line.
    cft[(int) tchars_buf.t_eofc] = send_eof;
    */
    cft[(int) tchars_buf.t_brkc] = insert_and_flush;
    cft[(int) ltchars_buf.t_suspc] = insert_and_flush;
    /* ^Y is used for yank-from-kill-buffer
    cft[(int) ltchars_buf.t_dsuspc] = self_insert;
    */
    cft[(int) ltchars_buf.t_rprntc] = reprint;
    cft[(int) ltchars_buf.t_flushc] = self_insert;
    cft[(int) ltchars_buf.t_werasc] = delete_previous_word;
    cft[(int) ltchars_buf.t_lnextc] = literal_next;
    cft[(int) initial_ttymode.sg_erase] = delete_previous_character;
    cft[(int) initial_ttymode.sg_kill] = delete_line;
}

/*
 * Main function of front end program
 */
CHAR *
getline()
{
    int c;
    CHAR *execute_command, *check_alias();

    (void) strcpy (CommandLine, "");
    CurrentPosition = 0;
    resetCurrentHistory ();

RETRY:
    (void) fflush (stdout);
    NeedNewLine = 0;
    NeedSave = 0;
    editstatus = EDITING;
    setjmp (jbuf);

    /*
     * If there is file pointer for I/O redirection,
     * read input from the pointer and return
     */
    if (redirect_fp) {

	/*
	 * Check output from sub-process
	 */
	swallow_output();

	if (fgets (CommandLine, MAXCOMLEN, redirect_fp)) {
	    ++redirect_line;
	    execute_command = CommandLine;
	    goto RETURN;	    
	}
	else {
	    if (look_var ("verbose"))
		printf ("%d lines redirected\n", redirect_line);
	    errorBell ();
	    if (redirect_pid) {
		pclose (redirect_fp);
		redirect_pid = 0;
	    }
	    else
		fclose (redirect_fp);
	    redirect_fp = NULL;
	}
    }

    while ((c = getcharacter ()) >= (CHAR) 0) {
	int status;

	/*
	 * In transparet mode
	 */
	if (Transparency == ON) {
	    if (*curFuncTab[(int) c] == toggle_transparency ||
	        *curFuncTab[(int) c] == fix_transparency) {
		(*curFuncTab[(int) c])();
		goto RETRY;
	    }
	    else {
		CommandLine[CurrentPosition] = c;
		CommandLine[CurrentPosition + 1] = '\0';
		return (CommandLine);
	    }
	}

	/*
	 * If find EOF character on top of empty line
	 * and the variable "send-eof-on-empty-line" is set
	 * call send_eof
	 */
	if (
	    c == tchars_buf.t_eofc
	    && curFuncTab[c] != send_eof
	    && ! look_var ("ignore-eof")
	    && CommandLine [0] == '\0'
	) {
	    if (!eof_occured && look_var ("alarm-on-eof")) {
		eof_occured = 1;
		status = alarm_on_eof (c);		
	    }
	    else
		status = send_eof (c);
	}
	else {
	    eof_occured = 0;
	    status = callfunc (curFuncTab, c);
	}

	(void) fflush (stdout);
	if (status == 1)	/* end of line editing */
	    break;
	else			/* continue line editing */
	    continue;
    }
    editstatus = NOTEDITING;

    /*
     * Check command line refer history or not
     */
    if (refer_history () == PROCESSED)
	goto RETRY;

    /*
     * Check alias list
     */
    if (!look_var ("noalias")
	&& (execute_command = check_alias (CommandLine))
    ) {
	if (look_var ("verbose"))
	    printf ("%s\n", execute_command);
    }
    else
	execute_command = CommandLine;
	

    /*
     * Check builtin function, and execute it.
     */
    if (executeBuiltInFunction (execute_command) == PROCESSED) {
	addHistory (CommandLine);
	CommandLine[0] = '\0';
	CurrentPosition = 0;
	if (!redirect_fp)
	    fputs (prompt, stdout);
	goto RETRY;
    }

    if (NeedSave) {
	if (!is_empty_line (CommandLine) || !look_var ("ignore-empty-line"))
	    addHistory (CommandLine);
	/*
	 * put string to buffer
	 */
	buf_put (output_buffer, CommandLine);
	if (NeedNewLine == 1)
	    buf_put (output_buffer, "\n");
    }

    if (NeedNewLine == 1)
	(void) strcat (execute_command, "\n");

RETURN:
    return (execute_command);
}

/*
 * Invoke appropliate function according to fucntion table
 * Return value 1 means exit from line editing
 */
callfunc (ft, c)
    FUNC ft[];
    int c;
{

    if (isIndirect(ft[(int) c])) {
	FUNC *nft = maskIndirect (ft[(int)c]);
	char nc;

	nc = (CHAR) getcharacter();
	return (callfunc (nft, nc));
    }
    else
	return ((*ft[(int) c]) (c));
}

/*
 * Beep and do nothing
 */
abort()
{
    (void) errorBell ();
    return (0);
}

/*
 * Insert the character self
 */
self_insert(c)
    CHAR c;
{
    register int i, nbyte = 1, currentNull;
#ifdef KANJI
    CHAR byte2;
#endif KANJI

    currentNull = strlen (CommandLine);

    if (currentNull >= maxline) {
        errorBell();
	return (0);
    }

    if (isctlchar(CommandLine[CurrentPosition]))
	(void) putchar (BS);
#ifdef KANJI
    if (iskanji (c)) {
	byte2 = (CHAR) getcharacter ();
	putchar (c);
	putchar (byte2);
	nbyte = 2;
    }
    else
#endif KANJI
	putChar (c);
    reverse_strcpy (
	&CommandLine[CurrentPosition] + nbyte,
	&CommandLine[CurrentPosition]
    );
    CurrentPosition += nbyte;
    CommandLine[CurrentPosition - nbyte] = c;
#ifdef KANJI
    if (nbyte > 1) {
	CommandLine[CurrentPosition - 1] = byte2;
    }
#endif KANJI
    printS (&CommandLine [CurrentPosition]);

    if (CommandLine[CurrentPosition] != '\0') {
	repeat (BS, howlong (&CommandLine[CurrentPosition + 1], 0));
	(void) putchar (BS);
    }
    return (0);
}

/*
 * Insert string in current position
 */
insert_string (s)
    CHAR *s;
{
    register int i, nbyte = strlen (s), currentNull;

    currentNull = strlen (CommandLine);

    if (currentNull + nbyte >= maxline - 1) {
        errorBell();
	return (0);
    }

    if (isctlchar(CommandLine[CurrentPosition]))
	(void) putchar (BS);
    printS (s);
    reverse_strcpy (
	&CommandLine[CurrentPosition] + nbyte,	/* to */ 
	&CommandLine[CurrentPosition]		/* from */
    );
    bcopy (s, &CommandLine[CurrentPosition], nbyte);
    CurrentPosition += nbyte;

    if (CommandLine[CurrentPosition] != '\0') {
	printS (&CommandLine[CurrentPosition]);
	repeat (BS, howlong (&CommandLine[CurrentPosition], 0));
    }
    return (0);
}

/*
 * Yank string from kill buffer.
 */
yank_from_kill_buffer ()
{
    insert_string (KillBuffer);
}

/*
 * Set mark to current position
 */
mark ()
{
    set_mark (CurrentPosition);
    return (0);
}

/*
 * Set mark to specified position
 */
set_mark (pos)
    int pos;
{
    MarkPosition = pos;
    return (0);
}

/*
 * Delete area from mark to current position to kill buffer
 */
delete_to_kill_buffer ()
{
    int n = abs (CurrentPosition - MarkPosition);

    if (MarkPosition < 0) {
	errorBell();
	return (0);
    }

    if (CurrentPosition == MarkPosition)
	return;

    if (CurrentPosition > MarkPosition) {
	(void) moveto (MarkPosition);
    }

    return (delete_next_n_character (n));
}

/*
 * Move to specified position.
 */
moveto (position)
{
    if (position < CurrentPosition)
	while (position < CurrentPosition)
	    (void) backward_n_character (1);
    else
	while (position > CurrentPosition
#ifdef KANJI
	    && !(CurrentPosition + 1 == position
		    && iskanji (CommandLine[CurrentPosition]))
#endif KANJI
	)
	    (void) forward_n_character (1);
}

/*
 * Move cursor to top of line
 */
beginning_of_line()
{
    register int i;

    for (i = CurrentPosition; i > 0; i--) {
	if (isctlchar (CommandLine[i]))
	    (void) putchar (BS);
	(void) putchar (BS);
    }
    CurrentPosition = 0;
    return (0);
}

#ifdef KANJI
#define INC(i) if(iskanji(CommandLine[i])) i+=2; else i++;
#define DEC(i) if(i>=2 && iskanji_in_string(CommandLine, i-2)) i-=2; else i--;
#else KANJI
#define INC(i) i++
#define DEC(i) i--
#endif KANJI

/*
 * Move cursor to end of line
 */
end_of_line()
{
    register int    i;

    for (i = CurrentPosition; CommandLine[i]; i++) {
	if (isctlchar (CommandLine[i]))
	    (void) putchar (unctl(CommandLine[i]));
	else
	    (void) putchar (CommandLine[i]);
	if (isctlchar(CommandLine[i+1]))
	    (void) putchar ('^');
    }
    CurrentPosition = i;
    return (0);
}

/*
 * Move cursor left one space
 */
backward_character()
{

    return (backward_n_character (1));
}

/*
 * Move cursor left "n" space
 */
backward_n_character(n)
    int n;
{
    int space;
    int i = CurrentPosition;

    if (n == 0)
	return (0);
    else if (n < 0)
	return (forward_n_character (-n));
    else if (n > CurrentPosition) {
	errorBell ();
	return (0);
    }

    while (n-- && i >= 0) {
	if (isctlchar (CommandLine[i]))
	    putchar (BS);
#ifdef KANJI
	if (i > 0 && iskanji_in_string (CommandLine, i-2)) {
	    (void) putchar (BS);
	    (void) putchar (BS);
	    i--;
	}
	else
#endif KANJI
	putchar (BS);
	i--;
    }
    CurrentPosition = i;
    return (0);
}

/*
 * Move cursor backward one word
 */
backward_word ()
{

    return (backward_n_word (1));
}

/*
 * Move cursor backward n word
 */
backward_n_word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (i == 0) {
	errorBell ();
	return (0);
    }

#ifdef KANJI
    while (n--) {
	DEC(i);
	nchars++;

	while (1) {
	    if (i >= 2 && iskanji_in_string (CommandLine, i-2))
		break;
	    else if (i > 0 && !iswordchar (CommandLine[i]))
		i -= 1;
	    else
		break;
	    
	    nchars++;
	}
	while (1) {
	    if (i >= 2 && iskanji_in_string (CommandLine, i - 2))
		i -= 2;
	    else if (i > 0 && iswordchar (CommandLine [i -1]))
		i -= 1;
	    else
		break;
	    nchars++;
	}
    }
#else KANJI
    while (n--) {
	i--, nchars++;
	while (i > 0 && !iswordchar (CommandLine [i])) {
	    i--, nchars++;
	}
	while (i > 0 && iswordchar (CommandLine [i - 1])) {
	    i--, nchars++;
	}
    }
#endif KANJI
    return (backward_n_character (nchars));
}

/*
 * Move cursor backward one Word
 */
backward_Word ()
{

    return (backward_n_Word (1));
}

/*
 * Move cursor backward n Word
 */
backward_n_Word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (i == 0) {
	errorBell ();
	return (0);
    }

#ifdef KANJI
    while (n--) {
	DEC(i);
	nchars++;

	while (1) {
	    if (i > 1 && iskanji_in_string (CommandLine, i - 2))
		break;
	    else if (i > 0 && !iswordchar (CommandLine[i]))
		i -= 1;
	    else
		break;
	    
	    nchars++;
	}
	while (1) {
	    if (i > 2 && iskanji_in_string (CommandLine, i - 2))
		i -= 2;
	    else if (i > 0 && iswordchar (CommandLine [i - 1]))
		i -= 1;
	    else
		break;
	    nchars++;
	}
    }
#else KANJI
    while (n--) {
	i--, nchars++;
	while (i > 0 && !isWordchar (CommandLine [i]))
	    i--, nchars++;
	while (i > 0 && isWordchar (CommandLine [i - 1]))
	    i--, nchars++;
    }
#endif KANJI
    return (backward_n_character (nchars));
}

/*
 * Move cursor forward one character
 */
forward_character()
{

    return (forward_n_character (1));
}

/*
 * Move cursor forward n character
 */
forward_n_character(n)
    int n;
{
    int space;
    register int i = CurrentPosition;

    if (n == 0)
	return (0);
    else if (n < 0)
	return (backward_n_character (-n));

    if (CommandLine [CurrentPosition] == '\0') {
	errorBell ();
	return (0);
    }

#ifdef KANJI
    if (iskanji (CommandLine[i])) {
	(void) putchar (CommandLine[i++]);
	(void) putchar (CommandLine[i++]);
    }
    else
#endif KANJI
    if (isctlchar(CommandLine[i]))
	(void) putchar (unctl (CommandLine [i++]));
    else
	(void) putchar (CommandLine[i++]);

    while (--n && CommandLine [i]) {
#ifdef KANJI
	if (iskanji (CommandLine[i])) {
	    (void) putchar (CommandLine[i++]);
	    (void) putchar (CommandLine[i++]);
	}
	else
#endif KANJI
	putChar (CommandLine [i++]);
    }

    if (isctlchar (CommandLine [i]))
	putchar ('^');

    CurrentPosition = i;

    return (0);
}

/*
 * Move cursor forward one word
 */
forward_word ()
{
    return (forward_n_word (1));
}

/*
 * Move cursor forward n word
 */
forward_n_word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    while (n--) {
	while (CommandLine [i] && iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
	while (CommandLine [i] && !iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
    }
    return (forward_n_character (nchars));
}

/*
 * Move cursor forward one word
 */
forward_Word ()
{
    return (forward_n_Word (1));
}

/*
 * Move cursor forward n word
 */
forward_n_Word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    while (n--) {
	while (CommandLine [i] && isWordchar (CommandLine [i])) {
	    INC(i);
	     nchars++;
	}
	while (CommandLine [i] && !isWordchar (CommandLine [i])) {
	    INC(i);
	     nchars++;
	}
    }
    return (forward_n_character (nchars));
}

/*
 * Forward to end of word
 */
forward_to_end_of_word ()
{

    return (forward_to_end_of_n_word (1));
}

/*
 * Forward to end of n word
 */
forward_to_end_of_n_word (n)
{    
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    INC(i);
    while (n--) {
	while (CommandLine [i] && !iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
	while (CommandLine [i] && iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
    }
    DEC(i);
    return (forward_n_character (nchars));
}

/*
 * Forward to end of word
 */
forward_to_end_of_Word ()
{

    return (forward_to_end_of_n_Word (1));
}

/*
 * Forward to end of n word
 */
forward_to_end_of_n_Word (n)
{    
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    INC(i);
    while (n--) {
	while (CommandLine [i] && !isWordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
	while (CommandLine [i] && isWordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
    }
    DEC(i);
    return (forward_n_character (nchars));
}

/*
 * Delete previous one character
 */
delete_previous_character()
{

    return (delete_previous_n_character (1));
}

/*
 * Delete previous n characters
 */
delete_previous_n_character(n)
    int n;
{
    register int i, nbyte;
    int deleteArea, restArea;

    if (CurrentPosition < n) {
	errorBell ();
	return (0);
    }

#ifdef KANJI
    for (nbyte = 0, i = CurrentPosition; n-- > 0 && i;)
	if (i > 1 && iskanji_in_string (CommandLine, i - 2))
	    i -= 2, nbyte += 2;
	else
	    i -= 1, nbyte += 1;
#else KANJI
    nbyte = n;
#endif KANJI

    deleteArea = howlong (&CommandLine[CurrentPosition - nbyte], nbyte);
    restArea = howlong (&CommandLine[CurrentPosition], 0);
    if (isctlchar(CommandLine[CurrentPosition]))
	(void) putchar (BS);
    repeat(BS, deleteArea);
    CurrentPosition -= nbyte;
    strcpy (KillBuffer, &CommandLine [CurrentPosition]);
    KillBuffer [nbyte] = '\0';
    for (i = CurrentPosition; CommandLine[i + nbyte]; i++) {
	CommandLine[i] = CommandLine[i + nbyte];
	putChar (CommandLine[i]);
    }
    CommandLine[i] = '\0';
    repeat(SP, deleteArea);
    repeat(BS, deleteArea);
    if (isctlchar (CommandLine[CurrentPosition]))
	repeat(BS, restArea - 1);
    else
	repeat(BS, restArea);
    
    return (0);
}

/*
 * Delete previous one word
 */
delete_previous_word()
{
    
    return (delete_previous_n_word (1));
}

/*
 * Delete previous n word
 */
delete_previous_n_word(n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (i == 0) {
	errorBell();
	return (0);
    }

#ifdef KANJI
    while (n--) {
	if (i>1 && iskanji_in_string (CommandLine, i-2))
	    i--;
	i--, nchars++;

	while (1) {
	    if (i > 1 && iskanji_in_string (CommandLine, i-2))
		break;
	    else if (i > 0 && !iswordchar (CommandLine[i]))
		i -= 1;
	    else
		break;
	    
	    nchars++;
	}
	while (1) {
	    if (i > 2 && iskanji_in_string (CommandLine, i - 2))
		i -= 2;
	    else if (i > 0 && iswordchar (CommandLine [i -1]))
		i -= 1;
	    else
		break;
	    nchars++;
	}
    }
#else KANJI
    while (n--) {
	i--, nchars++;
	while (i > 0 && !iswordchar (CommandLine [i]))
	    i--, nchars++;
	while (i > 0 && iswordchar (CommandLine [i - 1]))
	    i--, nchars++;
    }
#endif KANJI

    return (delete_previous_n_character (nchars));
}

/*
 * Delete previous one word
 */
delete_previous_Word()
{
    
    return (delete_previous_n_Word (1));
}

/*
 * Delete previous n word
 */
delete_previous_n_Word(n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (i == 0) {
	errorBell();
	return (0);
    }

#ifdef KANJI
    while (n--) {
	if (i>1 && iskanji_in_string (CommandLine, i-2))
	    i--;
	i--, nchars++;

	while (1) {
	    if (i > 1 && iskanji_in_string (CommandLine, i-2))
		break;
	    else if (i > 0 && !isWordchar (CommandLine[i]))
		i -= 1;
	    else
		break;
	    
	    nchars++;
	}
	while (1) {
	    if (i > 2 && iskanji_in_string (CommandLine, i - 2))
		i -= 2;
	    else if (i > 0 && isWordchar (CommandLine [i -1]))
		i -= 1;
	    else
		break;
	    nchars++;
	}
    }
#else KANJI
    while (n--) {
	i--, nchars++;
	while (i > 0 && !isWordchar (CommandLine [i]))
	    i--, nchars++;
	while (i > 0 && isWordchar (CommandLine [i - 1]))
	    i--, nchars++;
    }
#endif KANJI

    return (delete_previous_n_character (nchars));
}

/*
 * Delete next one character
 */
delete_next_character ()
{

    return (delete_next_n_character (1));
}

/*
 * Delete next n character
 */
delete_next_n_character (n)
    int n;
{
    register int i, nbyte;
    int deleteArea, restArea;

    if (strlen (&CommandLine [CurrentPosition]) < n) {
	errorBell ();
	return (0);
    }

#ifdef KANJI
    {
	register CHAR *cp = &CommandLine[CurrentPosition];

	nbyte = 0;
	while (n-- > 0 && *cp)
	    if (iskanji (*cp))
		cp += 2, nbyte += 2;
	    else
		cp++, nbyte++;
    }
#else KANJI
    nbyte = n;
#endif KANJI

    deleteArea = howlong (&CommandLine[CurrentPosition], nbyte);
    restArea = howlong (&CommandLine[CurrentPosition + nbyte], 0);
    if (isctlchar(CommandLine[CurrentPosition]))
	(void) putchar (BS);
    strcpy (KillBuffer, CommandLine + CurrentPosition);
    KillBuffer [nbyte] = '\0';
    for (i = CurrentPosition; CommandLine[i + nbyte]; i++) {
	CommandLine[i] = CommandLine[i + nbyte];
	putChar (CommandLine[i]);
    }
    CommandLine[i] = '\0';
    repeat(SP, deleteArea);
    repeat(BS, deleteArea);
    if (isctlchar (CommandLine[CurrentPosition]))
	repeat(BS, restArea - 1);
    else
	repeat(BS, restArea);
    
    return (0);
}

/*
 * Delete next one word
 */
delete_next_word ()
{
    return (delete_next_n_word (1));
}

/*
 * Delete next n word
 */
delete_next_n_word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    while (n--) {
	while (CommandLine [i] && iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
	while (CommandLine [i] && !iswordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
    }
    return (delete_next_n_character (nchars));
}

/*
 * Delete next one word
 */
delete_next_Word ()
{
    return (delete_next_n_Word (1));
}

/*
 * Delete next n word
 */
delete_next_n_Word (n)
    int n;
{
    register int i = CurrentPosition, nchars = 0;

    if (CommandLine [i] == '\0') {
	errorBell ();
	return (0);
    }

    while (n--) {
	while (CommandLine [i] && isWordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
	while (CommandLine [i] && !isWordchar (CommandLine [i])) {
	    INC(i);
	    nchars++;
	}
    }
    return (delete_next_n_character (nchars));
}

/*
 * Erase whole line
 */
delete_line()
{
    register int i = CurrentPosition;
    register int len;

    len = howlong (CommandLine, 0);

    /*
     * If cursor is there right part of line, move it to end of line
     * and erase character by character from end
     */
    if (howlong (CommandLine, CurrentPosition + 1) > len / 2) {
	(void) end_of_line ();
	repeat_string ("\b \b", len);
    }
    /*
     * If cursor is there on left part of line, move it to top of line
     * and erase line at once
     */
    else {
	(void) beginning_of_line ();
	if (isctlchar (CommandLine[0]))
	    putchar (BS);
	repeat (SP, len);
	repeat (BS, len);
    }
    strcpy (KillBuffer, CommandLine);
    CurrentPosition = 0;
    CommandLine [0] = '\0';
    return (0);
}

/*
 * Delete characters from current position to top of line
 */
kill_to_top_of_line()
{
    int i = CurrentPosition;

    (void) beginning_of_line();
    return (delete_next_n_character (i));
}

/*
 * Delete characters from current position to end of line
 */
kill_to_end_of_line()
{
    register int    i, backCnt = 0;

    if (isctlchar(CommandLine[CurrentPosition])) {
        (void) putchar(BS);
    }
    for (i = CurrentPosition; CommandLine[i]; i++) {
	if (isctlchar(CommandLine[i])) {
	    fputs("  ", stdout);
	    backCnt++;
	}
	else
	    (void) putchar (SP);
	backCnt++;
    }
    for (; backCnt; backCnt--)
	(void) putchar (BS);
    strcpy (KillBuffer, CommandLine + CurrentPosition);
    CommandLine[CurrentPosition] = '\0';
    return (0);
}

/*
 * Insert tab to current cursor position
 */
insert_tab()
{

    /* sorry, not implemented */
    return (self_insert ('\t'));
}

/*
 * Process new line
 */
new_line()
{

    (void) end_of_line;
    fputs ("\r\n", stdout);
    NeedNewLine = 1;
    NeedSave = 1;

    return (1);
}

/*
 * Check current position is top-of-line
 */
is_tol()
{
    return (CurrentPosition == 0);
}

/*
 * Check current position is end-of-line
 */
is_eol()
{
    return (CommandLine [CurrentPosition] == '\0');
}

/*
 * Check command line if it refer history or not
 */
refer_history()
{
    char   *historyExtract ();
    char   *his;

    if (CommandLine[0] != '!')
	return (NOT_PROCESSED);

    if (his = historyExtract (CommandLine)) {
	(void) strcpy (CommandLine, his);
	CurrentPosition = strlen (CommandLine);
    }
    else {
	fputs (CommandLine, stdout);
	fputs (" : Event not found.\r\n", stdout);
	(void) strcpy (CommandLine, "");
	CurrentPosition = 0;
    }
    fputs (prompt, stdout);
    print_com_line ();
    return (PROCESSED);
}

#define FORWARD	    1
#define REVERSE	    2

search_reverse ()
{
    return (search_history (REVERSE));
}

search_forward ()
{
    return (search_history (FORWARD));
}

search_history (direct)
    int direct;
{
    char *his, *search_reverse_history(), *search_forward_history();
    char *(*func)();

    if (direct == FORWARD)
	func = search_forward_history;
    else
	func = search_reverse_history;

AGAIN:
    if (his = (*func) (0)) {
	if (eq (his, CommandLine))
	    goto AGAIN;

	(void) delete_line ();
	(void) insert_string (his);
	CurrentPosition = strlen (CommandLine);
    }
    else {
	(void) errorBell ();

	if (look_var ("verbose")) {
	    char *cp;

	    if ((cp = look_var ("search-string")) == NULL)
		cp = "";
	    (void) clear_edit_line ();
	    fprintf (stdout, "\"%s\": No match.\r\n", cp);
	    (void) recover_edit_line ();
	}
    }

    return 0;
}


/*
 * Insert the character and flush buffer
 */
insert_and_flush(c)
    char c;
{
    (void) self_insert (c);
    return (1);
}

/*
 * Insert the character, but it means EOL. Therefore move cursor backward and
 * flush buffer
 */
send_eof()
{
    char c = tchars_buf.t_eofc;

    (void) self_insert (c);
    if (isctlchar (c))
	fputs ("\b\b", stdout);
    else
	fputs ("\b", stdout);
    return (1);
}

/*
 * Alarm for EOF on only the first time finding eof character
 */
alarm_on_eof ()
{

    errorBell ();
    (void) clear_edit_line ();
    printf ("EOF -- one more eof character to send eof to the process.\n");
    (void) recover_edit_line ();
}

/*
 * Clear screen
 */
clear_screen()
{


    if (term_clear) {
	(void) clear_edit_line ();
	fputs (term_clear, stdout);
	(void) recover_edit_line ();
    }
    else
	errorBell ();

    return (0);
}

/*
 * Get next history entry
 */
next_history()
{
    register char  *cp;
    char   *getNextHistory ();
    int diff;

    if ((cp = getNextHistory ()) == (char *)0) {
	errorBell ();
	return (0);
    }
    diff = howlong (CommandLine, 0) - howlong (cp, 0);
    (void) beginning_of_line ();
    if (isctlchar (CommandLine[0]))
	putchar (BS);
    printS (cp);
    if (diff > 0) {
	repeat (SP, diff);
	repeat (BS, diff);
    }
    (void) strcpy (CommandLine, cp);
    CurrentPosition = strlen (CommandLine);
    return (0);
}

/*
 * Get previous history
 */
previous_history()
{
    register char *cp;
    char *getPreviousHistory ();
    int diff;

    if ((cp = getPreviousHistory ()) == (char *)0) {
	errorBell ();
	return (0);
    }

    diff = howlong (CommandLine, 0) - howlong (cp, 0);
    (void) beginning_of_line ();
    if (isctlchar (CommandLine[0]))
	putchar (BS);
    printS (cp);
    if (diff > 0) {
	repeat (SP, diff);
	repeat (BS, diff);
    }
    (void) strcpy (CommandLine, cp);
    CurrentPosition = strlen (CommandLine);
    return (0);
}

/*
 * Show history
 */
show_history()
{
    int saveCP = CurrentPosition;
    char *cp;
    char *getHistory ();
    int showhist;
    
    (void) end_of_line ();
    CurrentPosition = saveCP;
    fputs("\r\n", stdout);

    hist_showHistory (lookd_var ("showhist"));

    fputs (prompt, stdout);
    (void) print_com_line();
}

/*
 * Do nothing
 */
ignore()
{
    return(0);
}

/*
 * Next character is literal
 */
literal_next()
{

    return (self_insert (getcharacter ()));
}

/*
 * Reprint command line
 */
reprint()
{

    (void) clear_edit_line ();
    (void) recover_edit_line ();
    return (0);
}

/*
 * Print whole command line and move cursor to the current position
 */
print_com_line()
{

    printS (CommandLine);
    if (CommandLine[CurrentPosition] != '\0') {
	repeat (BS, howlong(&CommandLine[CurrentPosition + 1], 0));
	(void) putchar (BS);
    }
}

/*
 * Calcurate space of string using "^" for control character
 */
howlong(s, n)
    char *s;
    int n;
{
    register char *sp;
    register int area = 0;

    if (n == 0)
	n = -1;
    for (sp = s; *sp && n; sp++, n--) {
	if (isctlchar(*sp))
	    area += 2;
	else
	    area += 1;
    }
    return (area);
}

/*
 * Repeat puting character n times
 */
repeat(c, n)
    char c;
    register int n;
{
    for (n = n; n; n--)
	(void) putchar(c);
}

/*
 * Repeat putting string n times
 */
repeat_string(s, n)
    char *s;
    register int n;
{
    for (n = n; n; n--)
	fputs(s, stdout);
}

/*
 * Expand file name
 */
expand_file_name ()
{
    CHAR *cp, *start_expand;
    char *x_dirname();
    char dir[256];
    char *fileList[256];
    CHAR line[256];
    DIR *dirp, *x_opendir();
    struct direct *dp;
    int found = 0;
    int i;
    int tilde_expanded = 0;
    CHAR *index(), *rindex();
    
    if (delimiters == NULL)
        delimiters = DEFAULT_DELIMITERS;
    strcpy (line, CommandLine);
    for (cp = &line[CurrentPosition] - 1; cp > line ; --cp) {
        if (index (delimiters, *(cp - 1)))
	    break;
    }
    start_expand = cp;
    if (any ('/', cp)) {
	(void) strcpy (dir, cp);
	*(rindex (dir, '/') + 1) = '\0';
	cp = (CHAR *) (rindex (cp, '/') + 1);
    }
    else
	strcpy (dir, ".");

    if ((dirp = x_opendir (dir)) == NULL) {
	errorBell ();
	return (0);
    }

    for (dp = readdir(dirp), i = 0; dp != NULL; dp = readdir(dirp)) {

	if (*cp == '\0')
	    break;

	if (*cp != '.' && *(dp->d_name) == '.')
	    continue;

	if (prefix (cp, dp->d_name)) {
	    char *fcp;

# ifdef ALLOCA
  	    fcp = (char *) alloca (strlen (dp->d_name) + 1);
# else ALLOCA
  	    fcp = (char *) malloc (strlen (dp->d_name) + 1);
# endif ALLOCA
	    if (fcp == 0) {
		fputs ("\r\n", stdout);
		perror ("alloca:");
		reprint ();
		longjmp (jbuf);
	    }
	    strcpy (fcp, dp->d_name);
	    fileList [i++] = fcp;
	}
    }
    fileList [i] = (char *) 0;

    if (*start_expand == '~' && look_var ("expand-tilde")) {
	char *buf [256], *p;

	strcpy (buf, start_expand);
	p = x_dirname (buf);
	if (!eq (p, buf)) {
	    (void) moveto (start_expand - line);
	    (void) kill_to_end_of_line ();
	    (void) insert_string (x_dirname (buf));
	    tilde_expanded = 1;
	}
    }

    switch (i) {

	case 0:
	    if (tilde_expanded == 0)
		errorBell ();
	    break;

	case 1:
	    (void) end_of_line ();
	    (void) insert_string (fileList[0] + strlen (cp));
	    break;

	default:
	    {
		char *one, *other;
		char *c1, *c2;
		int i;

		one = fileList [0];
		for (i = 1; other = fileList [i]; i++) {
		    for (c1 = one, c2 = other; *c1 && *c2; c1++, c2++)
			if (*c1 != *c2)
			    break;
		    *c1 = '\0';
		}
		errorBell ();
		(void) end_of_line ();
		(void) insert_string (fileList[0] + strlen (cp));
	    }
	    break;
    }

# ifndef ALLOCA
    for (i = 0; fileList [i]; i++)
	free (fileList [i]);
# endif ALLOCA

    closedir(dirp);
    return (0);
}

/*
 * List file name
 */
list_file_name ()
{
    CHAR *cp;
    char dir[256];
    DIR *dirp, *x_opendir();
    CHAR *index(), *rindex();

    if (delimiters == NULL)
        delimiters = DEFAULT_DELIMITERS;
    for (cp = (CHAR *) index (CommandLine, '\0'); cp > CommandLine ; --cp) {
        if (index (delimiters, *(cp - 1))) {
	    break;
	}
    }
#ifdef RINFO
    /*
     * This is an experimental code for rinfod, which serves remote
     * information about file, process, etc.
     */
    if (any (':', cp)) {
	char *host, *pattern;

	(void) strcpy (dir, cp);
	host = dir;
	*(index (host, ':')) = '\0';
	pattern = (index (cp, ':') + 1);;

	(void) clear_edit_line();
	list_remote_file (host, pattern);
	(void) recover_edit_line();
	return;
    }
#endif
    if (any ('/', cp)) {
	(void) strcpy (dir, cp);
	*(rindex (dir, '/') + 1) = '\0';
	cp = (CHAR *) (rindex (cp, '/') + 1);
    }
    else
	strcpy (dir, ".");


    if ((dirp = x_opendir (dir)) == NULL) {
	errorBell ();
	return (0);
    }

    (void) clear_edit_line();
    ls (dirp, cp);
    closedir(dirp);
    (void) recover_edit_line();

    return (0);
}

int	rememberPosition;

clear_edit_line ()
{

    if (editstatus == NOTEDITING)
	return;

    rememberPosition = CurrentPosition;
    (void) end_of_line ();
    (void) fputs ("\r\n", stdout);
}

recover_edit_line ()
{

    if (editstatus == NOTEDITING)
	return;

    if (rememberPosition < 0)
	return;
    CurrentPosition = rememberPosition;
    rememberPosition = -1;
    if (prompt)
	fputs (prompt, stdout);
    (void) print_com_line();
}

#define MAXFILES 256

/*
 * Do ls
 */
ls (dirp, prefixstring)
    DIR *dirp;
    char *prefixstring;
{
    struct direct *dp;
    char *fileList[MAXFILES + 1];
    int i, j;
    int maxlen = 0;
    int files;		/* number of file */
    int fpl;		/* file par line */
    int cpf;		/* column par file */
    int fpc;		/* file par column */
    int COL = 80;
    char format[10];
    int scmp();
    
    for (dp = readdir(dirp), i = 0; dp != NULL; dp = readdir(dirp)) {
	char *fcp;

	if (i >= MAXFILES) {
	    printf ("Too many files\n");
	    break;
	}

	if (dp->d_ino == (unsigned long) 0
    		|| (prefixstring[0] != '.' && dp->d_name[0] == '.'))
	    continue;
	if (prefix (prefixstring, dp->d_name)) {
# ifdef ALLOCA
  	    fcp = (char *) alloca (strlen (dp->d_name) + 1);
# else ALLOCA
  	    fcp = (char *) malloc (strlen (dp->d_name) + 1);
# endif ALLOCA
	    if (fcp == 0) {
		fputs ("\r\n", stdout);
		perror ("alloca:");
		reprint ();
		longjmp (jbuf);
	    }
	    strcpy (fcp, dp->d_name);
	    fileList [i++] = fcp;
	    maxlen = max (maxlen, strlen (dp->d_name));
	}
    }
    fileList [i] = (char *) 0;

    if (i == 0)
	goto BACK;

    files = i;

    qsort (fileList, i, sizeof (char *), scmp);

    if (debug)
	printf ("%d files\n", files);

    cpf = maxlen + 1;
    fpl = COL / cpf;
    if (fpl == 0) fpl = 1;
    fpc = (files + fpl - 1) / fpl;

    sprintf (format, "%%-%ds", cpf);
    for (i = 0; i < fpc; i++) {
	for (j = 0; j < fpl - 1; j++)
	    if (i + j * fpc < files)
		printf (format, fileList[i + (j * fpc)]);
	if (i + (fpc * (fpl - 1)) < files)
	    printf ("%s", fileList[i + (fpc * (fpl - 1))]);
	fputs ("\n", stdout);
    }

BACK:

# ifndef ALLOCA
    for (i = 0; fileList [i]; i++)
	free (fileList [i]);
# endif ALLOCA
    return;
}

#ifdef RINFO

#include "../rinfo/rinfo.h"

list_remote_file (host, pattern)
    char *host, *pattern;
{
    struct slist *slp, *getfilelist();
    int i, j;
    char format [64];
    int COL = 80;
    int  maxlen, cpf, fpl, fpc;
    int files;

    slp = getfilelist (host, pattern);
    files = slp->s_cnt;

    COL = 80;
    maxlen = 0;
    for (i = 0; i < files; i++) {
	int len;

	if ((len = strlen (*(slp->s_list + i))) > maxlen)
	    maxlen = len;
    }

    cpf = maxlen + 1;
    fpl = COL / cpf;
    if (fpl == 0)
	fpl = 1;
    fpc = (files + fpl - 1) / fpl;

    sprintf (format, "%%-%ds", cpf);
    for (i = 0; i < fpc; i++) {
	for (j = 0; j < fpl - 1; j++) {
	    if (i + j * fpc < slp->s_cnt)
		printf (format, *(slp->s_list + (i + (j * fpc))));
	}
	if (i + (fpc * (fpl - 1)) < files)
	    printf ("%s", slp->s_list[i + (fpc * (fpl - 1))]);
	fputs ("\n", stdout);
    }
}
#endif RINFO

bind_key (ft, func, s, dfunc)
    FUNC ft[];		/* Function table */
    FUNC func;		/* Function to be binded */
    char *s;		/* String to bind */
    FUNC dfunc;		/* Default function for table allocating */
{
    char tmps[16];

    if (s[0] == '\\' && s[1] == '^' && s[2] != NULL) {
	tmps[0] = toctrl (s[2]);
	strcpy (&tmps[1], &s[3]);
	s = tmps;
    }

    /*
     * If the string contain only one character, put the function to
     * appropriate position in the table.
     */
    if (*(s+1) == NULL) {
	if (isIndirect (ft[(int) *s]))
	    free (maskIndirect (ft[(int) *s]));

	ft[(int) *s] = func;
	return (1);
    }
    else {
	FUNC *nft = (FUNC *) 0;
	int status;

	/*
	 * If the entry doesn't have indirect function table, allocate it.
	 */
	if (! (isIndirect (ft[(int) *s]))) {
	    register int i;

	    nft = (FUNC *) calloc (sizeof (FUNC), 256);
	    /*
	     * If failed in allocating, return 0.
	     */
	    if (nft == 0)
		return (0);

	    /*
	     * Initialize the table with default function
	     */
	    for (i = 0; i < 256; i++)
		nft [i] = dfunc;
	    ft[(int) *s] = setIndirect (nft);
	}

	status = bind_key (maskIndirect (ft[(int) *s]), func, s+1, dfunc);
	/*
	 * If the binding failed and the table was allocated in this function
	 * free the table and return with same status.
	 */
	if (status == 0 && nft)
	    free (nft);
	return (status);
    }
}
\End\Of\File\
else
  echo "will not over write ./fep_edit.c"
fi
echo "Finished archive 3 of 5"
exit

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.