[comp.sources.unix] v16i061: Front end editor program, Part01/05

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

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

Dear moderator,

FEP is a general purpose front end for any line-oriented command on
UNIX. This command was developed on Berkeley UNIX, but will probably
run on most UNIX system which have pseudo tty and the select system
call.

			Kazumasa Utashiro
			Software Research Associates, Inc.
			1-1-1 Hirakawa-cho, Chiyoda-ku, Tokyo 102, Japan
				UUCP:	kddlab!srava.sra.junet!utashiro
				ARPA:	utashiro%sra.junet@uunet.uu.net
				JUNET:	utashiro@sra.junet

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

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

#include <stdio.h>
#include "fep_funcs.h"

/*
 * FunctionNameTable
 */
FunctionTableEnt FunctionNameTable[] = {
	{mark,				"mark",
	 "Mark position"},
	{abort,				"abort",
	 "Abort function"},
	{self_insert,			"self-insert",
	 "Insert the character"},
	{beginning_of_line,		"beginning-of-line",
	 "Jump to beginning of line"},
	{backward_character,		"backward-character",
	 "Backward character"},
	{backward_word,			"backward-word",
	 "Backward word (alpha-numeric)"},
	{backward_Word,			"backward-Word",
	 "Backward word (non-space)"},
	{end_of_line,			"end-of-line",
	 "Jump to end of line"},
	{forward_character,		"forward-character",
	 "Forward character"},
	{forward_word,			"forward-word",
	 "Forward word (alpha-numeric)"},
	{forward_Word,			"forward-Word",
	 "Forward word (non-space)"}, 
	{forward_to_end_of_word,	"forward-to-end-of-word",
	 "Forward to end of word (alpha-numeric)"},
	{forward_to_end_of_Word,	"forward-to-end-of-Word",
	 "Forward to end of word (non-space)"},
	{delete_previous_character,	"delete-previous-character",
	 "Delete previous character"},
	{delete_next_character,		"delete-next-character",
	 "Delete next character"},
	{insert_tab,			"insert-tab",
	 "Insert tab"},
	{new_line,			"new-line",
	 "Insert newline"},
	{insert_and_flush,		"insert-and-flush",
	 "Insert the character and flush buffer"},
	{send_eof,			"send-eof",
	 "Send eof"},
	{kill_to_end_of_line,		"kill-to-end-of-line",
	 "Delete current position to eol"},
	{kill_to_top_of_line,		"kill-to-top-of-line",
	 "Delete tol to current position"},
	{delete_to_kill_buffer,		"delete-to-kill-buffer",
	 "Delete resion to buffer"},
	{yank_from_kill_buffer,		"yank-from-kill-buffer",
	 "Yank from kill buffer"},
	{clear_screen,			"clear-screen",
	 "Clear screen"},
	{next_history,			"next-history",
	 "Get next history"},
	{previous_history,		"previous-history",
	 "Get previous history"},
	{ignore,			"ignore",
	 "Ignore"},
	{delete_line,			"delete-line",
	 "Delete whole line"},
	{literal_next,			"literal-next",
	 "Treat next character as literal"},
	{delete_previous_word,		"delete-previous-word",
	 "Delete previous word (alpha-numeric)"},
	{delete_previous_Word,		"delete-previous-Word",
	 "Delete previous word (non-space)"},
	{delete_next_word,		"delete-next-word",
	 "Delete next word (alpha-numeric)"},
	{delete_next_Word,		"delete-next-Word",
	 "Delete next word (non-space)"},
	{reprint,			"reprint",
	 "Reprint line"},
	{show_history,			"show-history",
	 "Show history"},
	{show_bindings,			"show-bindings",
	 "Show binding table"},
	{expand_file_name,		"expand-file-name",
	 "Expand file name"},
	{list_file_name,		"list-file-name",
	 "List file name"},
	{terminate,			"terminate",
	 "Terminate fep"},
	{suspend,			"suspend",
	 "Suspend fep"},
	{toggle_transparency,		"toggle-transparency",
	 "Change transparency mode"},
	{fix_transparency,		"fix-transparency",
	 "Check tty and change transparency mode"},
	{invoke_shell,			"invoke-shell",
	 "Invoke shell process"},
	{search_reverse,		"search-reverse",
	 "Search backward last !history"},
	{search_forward,		"search-forward",
	 "Search forward last !history"},
	{fep_start_script,		"start-script",
	 "Start script"},
	{fep_end_script,		"end-script",
	 "End script"},
	{fep_repaint,			"repaint",
	 "Repaint screen"},
	{show_help,			"help",
	 "Show help"},

	{vi_c,				"vi-c",
	 "Vi c? commands"},
	{vi_d,				"vi-d",
	 "Vi d? commands"},
	{vi_edit,			"vi-edit",
	 "Vi edit commands"},
	{vi_ins_edit,			"vi-ins-edit",
	 "Vi insert mode"},
	{vi_motion,			"vi-motion",
	 "Vi cursor motion commands"},
	{vi_new_line,			"vi-new-line",
	 "Vi new line"},
	{vi_num,			"vi-num",
	 "Vi prefix number"},

	{NULL,				NULL}
};

/*
 * Table of built-in functions
 */
FunctionTableEnt BuiltinFuncTable[] = {
	{bind_to_key,			"fep-bind",
	 "Change binding table"},
	{alias,				"fep-alias",
	 "Set or show aliases"},
	{unalias,			"fep-unalias",
	 "Delete alias"},
	{set,				"fep-set",
	 "Set or show variables"},
	{unset,				"fep-unset",
	 "Unset variables"},
	{fep_chdir,			"fep-cd",
	 "Change directory"},
	{fep_chdir,			"fep-chdir",
	 "Change directory"},
	{fep_pwd,			"fep-pwd",
	 "Print working directory"},
	{fep_history,			"fep-history",
	 "Show history"},
	{fep_echo,			"fep-echo",
	 "Print arguments"},
	{fep_source,			"fep-source",
	 "Read and execute file"},
	{fep_command,			"fep-command",
	 "Invoke unix command"},
	{fep_command,			"fep-!",
	 "Same as fep_command"},
	{fep_save_history,		"fep-save-history",
	 "Save history to file"},
	{fep_read_history,		"fep-read-history",
	 "Read history from file"},
	{fep_read_from_file,		"fep-read-from-file",
	 "Send file contens to slave command"},
	{fep_read_from_file,		"fep-<",
	 "Same as fep_read_from_file"},
	{fep_read_from_command,		"fep-read-from-command",
	 "Send output of command to slave command"},
	{fep_read_from_command,		"fep-<!",
	 "Same as fep_read_from_command"},
	{fep_start_script,		"fep-start-script",
	 "Start script"},
	{fep_start_script,		"fep-script",
	 "Start script"},
	{fep_end_script,		"fep-end-script",
	 "End script"},
	{fep_if,			"fep-if",
	 "Operation \"if\""},
	{fep_if,			"fep-elseif",
	 "Operation \"endif\""},
	{fep_else,			"fep-else",
	 "Operation \"else\""},
	{fep_endif,			"fep-endif",
	 "Operation \"endif\""},
	{terminate,			"fep-exit",
	 "Terminate fep"},
	{suspend,			"fep-suspend",
	 "Suspend fep"},
	{show_bindings,			"fep-show-bind",
	 "Print bindings"},
	{show_bindings,			"fep-showbind",
	 "Print bindings"},
	{fep_repaint,			"fep-repaint",
	 "Repaint screen"},
#ifdef STAT
	{fep_showstat,			"fep-showstat",
	 "Show statistical information"},
#endif
	{NULL,				NULL}
};
\End\Of\File\
else
  echo "will not over write ./fep_funcs.c"
fi
if `test ! -s ./fep_set.c`
then
echo "writing ./fep_set.c"
cat > ./fep_set.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

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

#include <stdio.h>
#include "fep_defs.h"
#include "fep_glob.h"

VAR default_set_vars [] = {
	{"expand-tilde",	"",
	 "Expand ~ to home directory name",	(VAR*)0},
	{"ignore-empty-line",	"",
	 "Don't put empty line to history",	(VAR*)0},
	{"ignore-same-line",	"",
	 "Don't put same line to history",	(VAR*)0},
	{"editmode",		"emacs",
	 "Fep command line edit mode",		(VAR*)0},
	{"history-file",	".fephistory",
	 "Name of history file",		(VAR*)0},
	{"shell",		"/bin/sh",
	 "Shell name used by invoke-shell",	(VAR*)0},
	{"auto-tty-fix",	"",
	 "Fix tty mode automatically",		(VAR*)0},
	{"script-file",		"fepscript",
	 "Script file name",			(VAR*)0},
	{"crt",			"24",
	 "Terminal lines",			(VAR*)0},
	{"showhist",		"24",
	 "History length used by show-history",	(VAR*)0},
	{"delimiters",		" \t",
	 "Argument delemiter characters",	(VAR*)0},
	{NULL,			NULL,
	 NULL,					(VAR*)0}
};

VAR default_unset_vars [] = {
	/* below from here is unset by default */
	{"alarm-on-eof",	"",
	 "Alarm once to eof character",		(VAR*)0},
	{"ignore-eof",		"",
	 "Never treat eof character as eof",	(VAR*)0}, 
	{"savehist",		"",
	 "Length of save history",		(VAR*)0},
	{"verbose",		"",
	 NULL,					(VAR*)0}, 
	{"search-string",	"",
	 NULL,					(VAR*)0},
	{"noalias",		"",
	 "Not use alias",			(VAR*)0},
	{"tty-fix-bell",	"",
	 "Ring bell when tty mode changed",	(VAR*)0},
	{"auto-repaint",	"",
	 "Repaint screen when restarting",	(VAR*)0},
	{"clear-repaint",	"",
	 "Clear screen before repaint",		(VAR*)0},
	{NULL,			NULL,
	 NULL,					(VAR*)0}
};

#ifdef HASH
#define HASHNUM	10
VAR *var_htab[HASHNUM];
#else HASH
VAR var_top = {"top", "top", (char *)0, (VAR *)0};
VAR *var_list = &var_top;
#endif HASH

/*
 * Functions
 */
int	set_var		(/* char *name, char *value */);
char	*look_var	(/* char *name */);
int	lookd_var	(/* char *name */);
VAR	*getvp		(/* char *name */);

extern	char	*allocAndCopyThere();
extern	char	*prompt;

/*
 * Set default variables
 */
set_default_vars ()
{
    register VAR *vp;

    for (vp = default_set_vars; vp->v_name; vp++)
	set_only_var (vp->v_name, vp->v_value);
}

/*
 * Set variable
 */
set_var (name, value)
    char *name;
    char *value;
{
    set_only_var (name, value);

    /*
     * Process special variable
     */
    if (eq (name, "history"))
	changeHistorySize (lookd_var ("history"));
    if (eq (name, "prompt")) {
	free (prompt);
	prompt = allocAndCopyThere (value);
    }
    if (eq (name, "editmode")) {
	if (eq (value, "emacs")) {
	    editmode = EMACS;
	    initEmacsBindings (curFuncTab, altFuncTab);
	}
	else if (eq (value, "vi")) {
	    editmode = VI;
	    initViBindings (curFuncTab, altFuncTab);
	}
	else
	    printf ("%s: Unknown editmode\n", value);
    }
    if (eq (name, "auto-tty-fix"))
	auto_tty_fix = ON;
    if (eq (name, "debug"))
	debug = ON;
    if (eq (name, "tty-fix-bell"))
	tty_fix_bell = ON;
    if (eq (name, "delimiters"))
	delimiters = look_var ("delimiters");
    if (eq (name, "crt"))
	lines = atoi (look_var("crt"));

}

set_only_var (name, value)
    char *name, *value;
{
    VAR *vp;

    vp = getvp (name, 1, 0);

    if (vp->v_value)
	free (vp->v_value);

    vp->v_value = allocAndCopyThere (value);
}

/*
 * Unset variable
 */
unset_var (name)
    char *name;
{
    VAR *vp, *prev;

    vp = getvp (name, 0, &prev);

    if (!vp)
	return;

    prev->v_next = vp->v_next;
    free (vp->v_name);
    free (vp->v_value);
    free (vp);

    if (eq (name, "auto-tty-fix"))
	auto_tty_fix = OFF;

    if (eq (name, "debug"))
	debug = OFF;

    if (eq (name, "tty-fix-bell"))
	tty_fix_bell = OFF;

    if (eq (name, "delimiters"))
	delimiters = DEFAULT_DELIMITERS;
    return;
}

/*
 * Look up variable
 */
char *
look_var (name)
    char *name;
{

    VAR *vp;

    vp = getvp (name, 0, 0);

    if (vp && vp->v_value)
	return (vp->v_value);
    else
	return ((char *)0);
}

/*
 * Look up variable and get integer result
 */
int
lookd_var (name)
    char *name;
{
    VAR *vp;

    vp = getvp (name, 0, 0);

    if (vp && vp->v_value)
	return (atoi (vp->v_value));
    else
	return (0);
}

/*
 * Show variable list
 */
show_varlist ()
{
#ifdef HASH
    register int i;

    for (i = 0; i< HASHNUM; i++) {
	register VAR *vp;

	vp = var_htab[i];
	if (vp == (VAR *)0)
	    continue;

	for (; vp != (VAR *)0; vp = vp->v_next)
	    printf ("%-16s %s\n", vp->v_name, vp->v_value);
    }
#else HASH
    register VAR *vp;

    for (vp = var_list->v_next; vp; vp = vp->v_next)
	printf ("%-16s %s\n", vp->v_name, vp->v_value);
#endif HASH
}

#ifdef HASH
/*
 * Get hash index from variable name
 */
static getindex (s)
    register char *s;
{
    register int sum = 0;

    while (*s)
	sum += *s++;

    return (sum % HASHNUM);
}
#endif HASH

/*
 * Get pointer to VAR.
 * If there is no memoly associated to the variable and alloc argument is 1,
 * allocate the area and initialize name field.
 */
VAR *
getvp (name, alloc, lastvp)
    char *name;
    int alloc;
    VAR **lastvp;
{
#ifdef HASH
    register i = getindex (name);
#endif HASH
    VAR *vp, *last = (VAR *)0;

#ifdef HASH
    for (vp = var_htab[i]; vp; last = vp, vp->v_next) {
	if (strcmp (name, vp->v_value) == 0)
	    return (vp);
    }
#else HASH
    for (vp = var_list->v_next, last = var_list; vp; last = vp, vp = vp->v_next) {
	int r;

	r = strcmp (name, vp->v_name);
	if (r == 0) {
	    if (lastvp)
		*lastvp = last;
	    return (vp);
	}
	else if (r < 0)
	    break;
    }
#endif HASH

    if (alloc == 0)
	return (0);

    vp = (VAR *) calloc (sizeof (VAR), 1);
    vp->v_value = (char *)0;
    vp->v_next = (VAR *) 0;
    vp->v_name = allocAndCopyThere (name);

#ifdef HASH
    if (last) {
	vp->v_next = last->v_next;
	last->v_next = vp;
    }
    else {
	var_htab[i] = vp;
    }
#else HASH
    vp->v_next = last->v_next;
    last->v_next = vp;
#endif HASH
    return (vp);
}
\End\Of\File\
else
  echo "will not over write ./fep_set.c"
fi
if `test ! -s ./fep_vi.c`
then
echo "writing ./fep_vi.c"
cat > ./fep_vi.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

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

#include <stdio.h>
#include <sgtty.h>
#include <ctype.h>
#include "fep_defs.h"
#include "fep_glob.h"
#include "fep_funcs.h"

enum {INSERTMODE, COMMANDMODE} vi_mode = COMMANDMODE;
int vi_count;

extern char *CommandLine;
extern int CurrentPosition;

/*
 * Default binding table
 */
BINDENT viComBindings[] = {
	/* 1       */	{"1",		vi_num},
	/* 2       */	{"2",		vi_num},
	/* 3       */	{"3",		vi_num},
	/* 4       */	{"4",		vi_num},
	/* 5       */	{"5",		vi_num},
	/* 6       */	{"6",		vi_num},
	/* 7       */	{"7",		vi_num},
	/* 8       */	{"8",		vi_num},
	/* 9       */	{"9",		vi_num},

	/* ~       */	{"~",		vi_edit},
	/* A       */	{"A",		vi_edit},
	/* C       */	{"C",		vi_edit},
	/* D       */	{"D",		vi_edit},
	/* P       */	{"P",		vi_edit},
	/* S       */	{"S",		vi_edit},
	/* I       */	{"I",		vi_edit},
	/* a       */	{"a",		vi_edit},
	/* i       */	{"i",		vi_edit},
	/* p       */	{"p",		vi_edit},
	/* r       */	{"r",		vi_edit},
	/* s       */	{"s",		vi_edit},
	/* x       */	{"x",		vi_edit},
	/* X       */	{"X",		vi_edit},
	/* ^U      */	{"\\^U",	vi_edit},

	/*         */	{" ",		vi_motion},
	/* ^H      */	{"\b",		vi_motion},
	/* l       */	{"l",		vi_motion},
	/* h       */	{"h",		vi_motion},
	/* k       */	{"k",		vi_motion},
	/* j       */	{"j",		vi_motion},
	/* b       */	{"b",		vi_motion},
	/* B       */	{"B",		vi_motion},
	/* e       */	{"e",		vi_motion},
	/* E       */	{"E",		vi_motion},
	/* w       */	{"w",		vi_motion},
	/* W       */	{"W",		vi_motion},
	/* n       */	{"n",		vi_motion},
	/* N       */	{"N",		vi_motion},
	/* 0       */	{"0",		vi_motion},
	/* ^       */	{"^",		vi_motion},
	/* $       */	{"$",		vi_motion},
	/* |       */	{"|",		vi_motion},
	/* -       */	{"-",		vi_motion},
	/* +       */	{"+",		vi_motion},

	/* cb      */	{"cb",		vi_c},
	/* cB      */	{"cb",		vi_c},
	/* cw      */	{"cw",		vi_c},
	/* cW      */	{"cW",		vi_c},
	/* c0      */	{"c0",		vi_c},
	/* c^      */	{"c^",		vi_c},
	/* c$      */	{"c$",		vi_c},
	/* cc      */	{"cc",		vi_c},

	/* db      */	{"db",		vi_d},
	/* dB      */	{"dB",		vi_d},
	/* dw      */	{"dw",		vi_d},
	/* dW      */	{"dW",		vi_d},
	/* d0      */	{"d0",		vi_d},
	/* d^      */	{"d^",		vi_d},
	/* d$      */	{"d$",		vi_d},
	/* dd      */	{"dd",		vi_d},

	/* ^E      */	{"\\^E",	expand_file_name},
	/* ^J      */	{"\\^J",	vi_new_line},
	/* ^L      */	{"\\^L",	list_file_name},
	/* ^M      */	{"\\^M",	vi_new_line},
	/* ^P      */	{"\\^P",	previous_history},
	/* ^N      */	{"\\^N",	next_history},
	/* ^R      */	{"\\^R",	reprint},
	/* ^^      */	{"\\^^",	toggle_transparency},
	/* ^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-l    */	{"\\^Xl",	list_file_name},
	/* ^X-L    */	{"\\^XL",	list_file_name},
	/* ^X-^L   */	{"\\^X\\^L",	fep_repaint},
	/* ^X-^X   */	{"\\^X\\^X",	expand_file_name},
	/* ^X-?    */	{"\\^X?",	show_bindings},
	/* ^X-^C   */	{"\\^X\\^C",	terminate},
	/* ^X-^D   */	{"\\^X\\^D",	send_eof},
	/* ^X-(	   */	{"\\^X(",	fep_start_script},
	/* ^X-)	   */	{"\\^X)",	fep_end_script},
	/*         */	{NULL,		NULL}
};

BINDENT viInsertBindings[] = {
	/* ^H      */	{"\\^H",	vi_ins_edit},
	/* ^W      */	{"\\^W",	vi_ins_edit},
	/* ^U      */	{"\\^U",	vi_ins_edit},
	/* ^V      */	{"\\^V",	vi_ins_edit},
	/* ^J      */	{"\\^J",	vi_new_line},
	/* ^L      */	{"\\^L",	list_file_name},
	/* ^M      */	{"\\^M",	vi_new_line},
	/* ^P      */	{"\\^P",	previous_history},
	/* ^N      */	{"\\^N",	next_history},
	/* ESC     */	{"\\^[",	vi_ins_edit},
	/* ^E      */	{"\\^E",	expand_file_name},
	/* ^^      */	{"\\^^",	toggle_transparency},
	/* ^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-l    */	{"\\^Xl",	list_file_name},
	/* ^X-L    */	{"\\^XL",	list_file_name},
	/* ^X-^L   */	{"\\^X\\^L",	fep_repaint},
	/* ^X-^X   */	{"\\^X\\^X",	expand_file_name},
	/* ^X-?    */	{"\\^X?",	show_bindings},
	/* ^X-^C   */	{"\\^X\\^C",	terminate},
	/* ^X-^D   */	{"\\^X\\^D",	send_eof},
	/* ^X-(	   */	{"\\^X(",	fep_start_script},
	/* ^X-)	   */	{"\\^X)",	fep_end_script},
	/*         */	{NULL,		NULL}
};

FUNC *viComTable;
FUNC *viInsTable;

initViBindings (cft, aft)
FUNC cft[], aft[];
{
    register int i;
    BINDENT *ftp;

    for (i = 0; i < 256; i++)
	aft[i] = abort;
    for (i = 0; i < 256; i++)
	cft[i] = self_insert;

    for (ftp = viComBindings; ftp->bt_s; ftp++) {
	bind_key (aft, ftp->bt_func, ftp->bt_s, abort);
    }
    for (ftp = viInsertBindings; ftp->bt_s; ftp++) {
	bind_key (cft, ftp->bt_func, ftp->bt_s, abort);
    }

    /* Now, using cbreak mode
    cft[(int) tchars_buf.t_startx] = ignore;
    cft[(int) tchars_buf.t_stopc] = ignore;
    */
    cft[(int) tchars_buf.t_intrc] = insert_and_flush;
    aft[(int) tchars_buf.t_intrc] = insert_and_flush;
    cft[(int) tchars_buf.t_quitc] = insert_and_flush;
    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;
    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;

    viInsTable = cft;
    viComTable = aft;
    vi_mode = INSERTMODE;
}

vi_edit (c)
    int c;
{
    int count = vi_count ? vi_count : 1;

    switch (c) {
	case '~':
	    {
		char c = CommandLine [CurrentPosition];

		if (isalpha (c)) {
		    (void) delete_next_character (c);
		    c ^= 0040;
		    (void) self_insert (c);
		}
		else
		    (void) forward_character (c);
	    }
	    break;

	case 'a':
	    if (!is_eol())
		(void) forward_character (c);
	case 'i':
	    (void) altenateEditmode (c);
	    break;

	case 'A':
	    (void) end_of_line (c);
	    (void) altenateEditmode ();
	    break;

	case 'I':
	    (void) beginning_of_line (c);
	    (void) altenateEditmode ();
	    break;

	case 'C':
	    (void) kill_to_end_of_line (c);
	    (void) altenateEditmode (c);
	    break;

	case 'D':
	    (void) kill_to_end_of_line (c);
	    break;

	case 'S':
	    (void) delete_line (c);
	    (void) altenateEditmode ();
	    break;

	case 'r':
	    (void) delete_next_character (c);
	    (void) self_insert (getcharacter ());
	    break;

	case 's':
	    (void) delete_next_n_character (count);
	    (void) altenateEditmode ();
	    break;

	case 'x':
	    (void) delete_next_n_character (count);
	    break;

	case 'X':
	    (void) delete_previous_n_character (count);
	    break;

	case 'p':
	    (void) forward_character ();
	case 'P':
	    (void) yank_from_kill_buffer ();
	    (void) backward_character ();
	    break;

	case CTRL(U):
	    (void) delete_line (c);
	    (void) altenateEditmode ();
	    break;
    }
    vi_count = 0;
    return (0);
}

altenateEditmode ()
{
    FUNC *tmp;

    tmp = curFuncTab;
    curFuncTab = altFuncTab;
    altFuncTab = tmp;
    vi_mode = (vi_mode == INSERTMODE) ? COMMANDMODE : INSERTMODE;

    return (0);
}

vi_num (c)
    int c;
{
    vi_count = vi_count * 10 + ((int)c - (int)'0');
    return (0);
}

vi_motion (c)
    int c;
{
    int count = vi_count ? vi_count : 1;

    switch (c) {

	case 'w':
	    (void) forward_n_word (count);
	    break;

	case 'W':
	    (void) forward_n_Word (count);
	    break;

	case 'e':
	    (void) forward_to_end_of_n_word (count);
	    break;

	case 'E':
	    (void) forward_to_end_of_n_Word (count);
	    break;

	case 'b':
	    (void) backward_n_word (count);
	    break;

	case 'B':
	    (void) backward_n_Word (count);
	    break;

	case 'l':
	case ' ':
	    (void) forward_n_character (count);
	    break;

	case 'h':
	case '\b':
	    (void) backward_n_character (count);
	    break;

	case 'k':
	case '-':
	    (void) previous_history (c);
	    break;

	case 'j':
	case '+':
	    (void) next_history (c);
	    break;

	case 'n':
	    (void) search_reverse (c);
	    break;

	case 'N':
	    (void) search_forward (c);
	    break;

	case '0':
	    if (vi_count)
		return (vi_num (c));
	    /* falling down */

	case '^':
	    (void) beginning_of_line (c);
	    break;

	case '$':
	    (void) end_of_line (c);
	    break;

	case '|':
	    (void) moveto (count - 1);
	    /***
	    if (strlen (CommandLine) >= count) {
		(void) beginning_of_line (c);
		(void) forward_n_character (count - 1);
	    }
	    else
		(void) end_of_line (c);
	    ***/
	    break;

	default:
	    (void) abort (c);
	    break; 
    }
    vi_count = 0;
    return (0);
}

vi_c (c)
    int c;
{
    int count = vi_count ? vi_count : 1;

    switch (c) {
	case '0':
	case '^':
	    (void) kill_to_top_of_line (c);
	    break;

	case 'c':
	    delete_line(c);
	    break;

	case 'w':
	    (void) delete_next_n_word (count);
	    break;

	case 'W':
	    (void) delete_next_n_Word (count);
	    break;

	case 'b':
	    (void) delete_previous_n_word (count);
	    break;

	case 'B':
	    (void) delete_previous_n_Word (count);
	    break;

	case '$':
	    (void) kill_to_end_of_line(c);
	    break;

	default:
	    return (abort (c));
    }
    vi_count = 0;
    altenateEditmode ();
    return (0);
}

vi_d (c)
    int c;
{
    int count = vi_count ? vi_count : 1;

    switch (c) {
	case '0':
	case '^':
	    (void) kill_to_top_of_line (c);
	    break;

	case 'd':
	    delete_line(c);
	    break;

	case 'w':
	    (void) delete_next_n_word (count);
	    break;

	case 'W':
	    (void) delete_next_n_Word (count);
	    break;

	case 'b':
	    (void) delete_previous_n_word (count);
	    break;

	case 'B':
	    (void) delete_previous_n_Word (count);
	    break;

	case '$':
	    (void) kill_to_end_of_line(c);
	    break;

	default:
	    return (abort (c));
    }
    vi_count = 0;
    return (0);
}

vi_new_line (c)
    int c;
{
    int count = vi_count ? vi_count : 1;

    vi_count = 0;

    (void) new_line (c);
    if (vi_mode == COMMANDMODE)
	altenateEditmode ();

    return (1);
}

vi_ins_edit (c)
    int c;
{
    switch (c) {

	case CTRL(H):
	    (void) delete_previous_character (c);
	    break;

	case CTRL(W):
	    (void) delete_previous_word (c);
	    break;

	case CTRL(U):
	    (void) delete_line (c);
	    break;

	case CTRL(V):
	    (void) literal_next (c);
	    break;

	case '\033':
	    (void) altenateEditmode ();
	    (void) backward_character ();
	    break;
    }
    return (0);
}
\End\Of\File\
else
  echo "will not over write ./fep_vi.c"
fi
if `test ! -s ./fep_util.c`
then
echo "writing ./fep_util.c"
cat > ./fep_util.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

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

#ifndef MKARGDEBUG

#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <ctype.h>
#include "fep_defs.h"

message(messageString)
    char *messageString;
{
    write (2, messageString, strlen (messageString));
}

errorBell()
{
    write (2, "\007", 1);
}

ctlprint(string)
    char *string;
{
    register char  *cp;

    for (cp = string; *cp; cp++) {
	if (isctlchar (*cp)) {
	    putchar ('^');
	    putchar (unctl (*cp));
	}
	else
	    putchar (*cp);
    }
    fputs ("\r\n", stdout);
    fflush (stdout);
}

/*
 * Print string using "^" for control characters
 */
printS (string)
    char *string;
{
    char *cp;

    for (cp = string; *cp; cp++)
	putChar (*cp);
}

/*
 * Check the line is empty or not
 */
is_empty_line(line)
    char *line;
{
    register char *cp;

    for (cp = line; *cp; cp++) {
        if (!isspace(*cp)) {
	    return(0);
	}
    }
    return(1);
}

/*
 * Put character using "^" for control characters
 */
putChar(c)
    char c;
{
    if (isctlchar(c)) {
	(void) putchar('^');
	(void) putchar(unctl(c));
    }
    else
	(void) putchar(c);
}

char *
x_dirname (dir)
    char *dir;
{
    static char dirname [256];
    char *index();

    if (*dir != '~')
	strcpy (dirname, dir);
    else {
	struct passwd *pw;

	if (*(dir+1) == '/' || *(dir+1) == '\0') {
	    pw = getpwuid (getuid ());
	}
	else {
	    char user [64], *sp, *dp;

	    for (sp = dir+1, dp = user; *sp && *sp != '/'; sp++, dp++)
		*dp = *sp;
	    *dp = '\0';
	    pw = getpwnam (user);
	}

	if (pw) {
	    strcpy (dirname, pw->pw_dir);
	    if (any ('/', dir))
		strcat (dirname, index (dir, '/'));
	}
	else {
	    strcpy (dirname, dir);
	}    
    }

    return (dirname);
}

DIR *
x_opendir (dir)
    char *dir;
{
    return (opendir (x_dirname (dir)));
}

/*
 * Strring compare for qsort
 */
scmp (a, b)
    char **a, **b;
{

    return (strcmp (*a, *b));
}

/*
 * Return 1 if "str" is prefixed by "sub"
 */
prefix (sub, str)
    register char *sub, *str;
{

    for (;;) {
	if (*sub == 0)
	    return (1);
	if (*str == 0)
	    return (0);
	if (*sub++ != *str++)
	    return (0);
    }
}

/*
 * Return 1 if s includes character c
 */
any (c, s)
    register int c;
    register char *s;
{

    while (*s)
	if (*s++ == c)
	    return(1);
    return(0);
}

#ifndef max
/*
 * Return maximum number of d1 and d2
 */
max (d1, d2)
    int d1, d2;
{
    return (d1 > d2 ? d1 : d2);
}
#endif max

#else MKARGDEBUG

#include <stdio.h>
#include <ctype.h>

#define MAXARGS	64

main()
{
    char s[128];
    char *argv[MAXARGS];

    while (gets (s)) {
	register int c;

	showArgs (s);
    }
}
#endif MKARGDEBUG

showArgs (comline)
    char *comline;
{
    char *argv[MAXARGS];
    register int c;
    register char **argp;
    register int i;

    c = mkargv (comline, argv, MAXARGS);
    if (c < 0) {
	printf ("%s\n", argv[0]);
	return;
    }
    printf ("argc = %d\n", c);
    for (i = 0, argp = argv; *argp; argp++, i++) {
	printf ("\"%s\" ", *argp);
    }
    printf ("\n");
}

mkargv (s, argv, maxarg)
    char *s;
    char *argv[];
    int maxarg;
{
    register char *cp;
    register int argc = 0;
    int insquot = 0, indquot = 0, ignorenext = 0;
    enum {STRING, SPACE} status = SPACE;
    static char buf[1024], *bp;

    for (cp = s, bp = buf; *cp; cp++) {

	if (argc > maxarg)
	    return (argc);

	/*
	 * Found white space
	 */
	if (isspace (*cp)) {
	    /*
	     * In outside of quotation
	     */
	    if (!ignorenext && !insquot && !indquot) {
		/*
		 * If status was in string, go next arg
		 */
		if (status == STRING) {
		    status = SPACE;
		    *bp++ = '\0';
		    continue;
		}
		else
		    continue;
	    }
	}

#	define SPECIALCHARS "\"\'\\"
	if (!ignorenext && index (SPECIALCHARS, *cp)) {
	    switch (*cp) {

		/*
		 * Literal next character
		 */
		case '\\':
		    if (indquot || insquot)
			goto THROUGH;
		    else {
			ignorenext = 1;
			continue;
		    }

		/*
		 * Double quotation
		 */
		case '\"':
		    if (insquot)
			goto THROUGH;
		    if (indquot && *(bp-1) == '\\') {
			bp--;
			goto THROUGH;
		    }
		    indquot = !indquot;
		    break;

		/*
		 * Single quotation
		 */
		case '\'':
		    if (indquot)
			goto THROUGH;
		    if (insquot && *(bp-1) == '\\') {
			bp--;
			goto THROUGH;
		    }
		    insquot = !insquot;
		    break;
    	    }

	    /*
	     * Only in " or ' case.
	     */
	    if (status == SPACE) {
		status = STRING;
		argc++;
		argv[argc-1] = bp;
		*bp = 0;
	    }
	    continue;
	}

THROUGH:
	/*
	 * Found non-space character
	 */
	ignorenext = 0;
	if (status == SPACE) {
	    status = STRING;
	    argc++;
	    argv[argc-1] = bp;
	}
	*bp++ = *cp;
    }

    if (indquot || insquot) {
	argv[0] = indquot ? "Unmatched \"." : "Unmatched \'.";
	return (-1);
    }

    *bp = '\0';
    argv[argc] = (char *)0;
    return (argc);
}

reverse_strcpy (to, from)
    register char *to, *from;
{
    register int len;

    for (len = strlen (from); len >= 0; len--)
	*(to + len) = *(from + len);
}

#ifdef KANJI
/*
 * Uuuuuuuum. I hate search kanji in Shift-JIS code from the end of string
 * This function check if i'th character is first byte of KANJI code
 * in string starting from s.
 * It is assumed that first byte of strint s can't be second byte of KANJI
 * code.
 */
iskanji_in_string (s, i)
    char *s;
    int i;
{
    register char *cp = s, *target = s + i;

    if (i < 0)
	return (0);

    while (cp < target) {
	if (iskanji (*cp))
	    cp += 2;
	else
	    cp++;
    }

    if (cp != target)
	return (0);
    else
	return (iskanji (*cp));
}
#endif KANJI
\End\Of\File\
else
  echo "will not over write ./fep_util.c"
fi
if `test ! -s ./fep_alias.c`
then
echo "writing ./fep_alias.c"
cat > ./fep_alias.c << '\End\Of\File\'
/*	Copyright (c) 1987, 1988 by Software Research Associates, Inc.	*/

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

#include <stdio.h>
#include <ctype.h>
#include "fep_defs.h"
#include "fep_glob.h"

typedef struct _alias {
	char *al_name;
	char *al_value;
	struct _alias *al_next;
} ALIAS;

ALIAS	alias_top = {"top", "top", (ALIAS *)0};
ALIAS	*alias_list = &alias_top;
CHAR	aliased_line[MAXCOMLEN+1];

/*
 * Functions
 */
int	set_alias	(/* char *name, char *value */);
char	*look_alias	(/* char *name */);
ALIAS	*getap		(/* char *name */);

extern	char	*allocAndCopyThere();
extern	char	*prompt;

/*
 * Check alias list, and if found alias change command by its value
 */
CHAR *
check_alias (comline)
    char *comline;
{
    char *argv[MAXARGS];
    int argc;
    char *av;

    while (isspace (*comline))
	++comline;
    if (*comline == NULL)
	return ((CHAR *)0);

    argc = mkargv (comline, argv, MAXARGS);

    if (av = look_alias (argv[0])) {
	int len = strlen (argv[0]);

	strcpy (aliased_line, av);
	strcat (aliased_line, comline + len);
	return (aliased_line);
    }
    else
	return ((CHAR *)0);
}

/*
 * Set alias
 */
set_alias (name, value)
    char *name, *value;
{
    ALIAS *vp;

    vp = getap (name, 1, 0);

    if (vp->al_value)
	free (vp->al_value);

    vp->al_value = allocAndCopyThere (value);
}

/*
 * Unset alias
 */
unset_alias (name)
    char *name;
{
    ALIAS *vp, *prev;

    vp = getap (name, 0, &prev);

    if (!vp)
	return;

    prev->al_next = vp->al_next;
    free (vp->al_name);
    free (vp->al_value);
    free (vp);
    return;
}

/*
 * Look up alias
 */
char *
look_alias (name)
    char *name;
{

    ALIAS *vp;

    vp = getap (name, 0, 0);

    if (vp && vp->al_value)
	return (vp->al_value);
    else
	return ((char *)0);
}

/*
 * Show alias list
 */
show_aliaslist (a)
    char *a;
{
    register ALIAS *vp;

    for (vp = alias_list->al_next; vp; vp = vp->al_next) {
	if (a && strcmp (a, vp->al_name))
	    continue;
	printf ("%-16s %s\n", vp->al_name, vp->al_value);
    }
}


/*
 * Get pointer to ALIAS.
 * If there is no memoly associated to the alias and alloc argument is 1,
 * allocate the area and initialize name field.
 */
ALIAS *
getap (name, alloc, lastvp)
    char *name;
    int alloc;
    ALIAS **lastvp;
{
    ALIAS *vp, *last = (ALIAS *)0;

    for (vp = alias_list->al_next, last = alias_list; vp; last = vp, vp = vp->al_next) {
	int r;

	r = strcmp (name, vp->al_name);
	if (r == 0) {
	    if (lastvp)
		*lastvp = last;
	    return (vp);
	}
	else if (r < 0)
	    break;
    }

    if (alloc == 0)
	return (0);

    vp = (ALIAS *) calloc (sizeof (ALIAS), 1);
    vp->al_value = (char *)0;
    vp->al_next = (ALIAS *) 0;
    vp->al_name = allocAndCopyThere (name);

    vp->al_next = last->al_next;
    last->al_next = vp;
    return (vp);
}
\End\Of\File\
else
  echo "will not over write ./fep_alias.c"
fi
if `test ! -s ./feprc.sample`
then
echo "writing ./feprc.sample"
cat > ./feprc.sample << '\End\Of\File\'
#
# This is a sample .feprc file.
#

set alarm-on-eof
set savehist=50

echo "Welcome to fep! Editmode is" $editmode
echo "I'm a front end processor for" $command

if $editmode == emacs
	fep-bind delete-to-kill-buffer "\^X\^W"
endif

if $command == sh
	set ignore-eof
	set history-file .fephistdir/sh
	set delimiters=" 	\"';&<>()|^%"
	set auto-repaint
	set clear-repaint

	if $editmode == vi
		fep-bind list-file-name "\^D"
	endif

elseif $command == adb
	set history-file .fephistdir/adb

elseif $command == bc
	unset alarm-on-eof
	unset alarm-on-eof

elseif $command == dbx
	set history-file .fephistdir/dbx

else
	echo "History will be saved to" $history-file
endif
\End\Of\File\
else
  echo "will not over write ./feprc.sample"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\File\'
Copyright (c) 1987,1988 by Software Research Associates, Inc.

FEP is a general purpose front end for any line-oriented command on
UNIX. This command was developed on Berkeley UNIX, but will probably
run on most UNIX system which have pseudo tty and the select system
call.

Making FEP

	Just type 'make'.
	If your system is running ASCII UNIX or some compatible system,
	the -DKANJI flag makes fep handle kanji character input.

Using FEP

	See man page fep.1 for detail.
	The help command (ESC-?) and show-bindings command (^X-^B) are
	very convenient when running fep.

Distribution

	Distribution without fee is permitted as long as all
	copyright notices are included.

Any comments will be greatly appreciated. Have fun.

			Kazumasa Utashiro
			Software Research Associates, Inc.
			1-1-1 Hirakawa-cho, Chiyoda-ku, Tokyo 102, Japan
				UUCP:	kddlab!srava.sra.junet!utashiro
				ARPA:	utashiro%sra.junet@uunet.uu.net
				JUNET:	utashiro@sra.junet
\End\Of\File\
else
  echo "will not over write ./README"
fi
echo "Finished archive 1 of 5"
exit

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