#ifndef lint
static char Sccsid[] = "@(#)setupkeys.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
#endif

/*	SETUPKEYS.C	     */
/*	This module sets up all terminal specific key sequences.
**	It sets up the a linked list that translates function keys to
**	actions and sets up the label for the function keys.
**
**  It requires definitions of
**	key_right	move cursor right
**	key_left	move cursor left
**	key_backspace	"
**	key_tab		move forward thru fields
**	key_down	"
**	key_btab	move backward thru fields
**	key_up		"
**	key_eol		clear to end of field
**	key_dc		delete character under cursor
**	key_ic		move characters from the cursor on one space right
**	key_f2		same as key_ic
**	key_f3		same as key_dc
**	key_f4		same as key_eol
**	key_f5		next page
**	key_f6		previous page
**/

# include <curses.h>
#ifndef TERMCAP
# include <term.h>
#endif
#ifdef DEBUG
#include <stdio.h>
#endif
#include "cardfile.h"

/*
** Indices into "keys" structure
**/
#define	k_BS	0
#define	k_LEFT	1
#define	k_RIGHT	2
#define	k_EOL	3
#define	k_DC	4
#define	k_IC	5
#define	k_TAB	6
#define	k_UP	7
#define	k_DOWN	8
#define	k_F2	9
#define	k_F3	10
#define	k_F4	11
#define	k_F5	12
#define	k_F6	13
#define	k_BTAB	14

int	sfunct(), goright(), goleft(), nextfield(), prevfield(), ferase();
int	delchar(), inschar(), nextpage(), prevpage();
unsigned sleep();
char	*malloc();
#ifndef NeXT
char	*memset();
#endif
#ifndef AIXV3
char	*strstr();
#endif

/* translation of terminfo/termcap names to action routines */
struct	keys	{
    char    *terminfo_name;
    char    *string;
    int	(*func)();
};
static struct keys keys[20] = {
    {"key_backspace", 0, goleft},
    {"key_left",      0, goleft},
    {"key_right",     0, goright},
    {"key_eol",	      0, ferase},
    {"key_dc",	      0, delchar},
    {"key_ic",	      0, inschar},
    {"tab",	      0, nextfield},
    {"key_up",	      0, prevfield},
    {"key_down",      0, nextfield},
    {"key_f2",	      0, inschar},
    {"key_f3",	      0, delchar},
    {"key_f4",	      0, ferase},
    {"key_f5",	      0, nextpage},
    {"key_f6",	      0, prevpage},
#ifdef key_btab
    {"key_btab",      0, prevfield},
#endif
    { 0, 0, 0}
};

#ifdef TERMCAP
char	*clear_screen,
	*clr_eol,
	*enter_dim_mode,
	*enter_blink_mode,
	*exit_attribute_mode,
	*keypad_xmit,
	*keypad_local,
	*cursor_address,
	*cursor_left,
	*cursor_right;
#endif

struct cchar *cc_head;

char	func_label[256];

setupkeys()
{
    register struct keys    *kp;
    register char   *so_on, *so_off;
    register char   *cp;
    register struct cchar    *ccp;
    int    slen;
#ifdef TERMCAP
    static	char	tc_buf[1024];
    static	char	*tc_ptr = tc_buf;
    static	char	tc_out[256];
    static	char	*out_ptr = tc_out;
    extern	char	*tgetstr(), *tgoto();
    extern	char	*getenv();
#endif

#ifdef TERMCAP
    if (tgetent(tc_buf, (cp = getenv("TERM"))) != 1) {
	printf(stderr, "Unable to get terminal settings for %s\n",
	    (cp ? cp : "<NULL>"));
	exit(1);
    }
    if ((keys[k_BS].string = tgetstr("kb", &out_ptr)) == 0) {
	keys[k_BS].string = "\b";
    }
    if ((keys[k_LEFT].string = tgetstr("kl", &out_ptr)) == 0) {
	keys[k_LEFT].string = "";
    }
    if ((keys[k_RIGHT].string = tgetstr("kr", &out_ptr)) == 0) {
	keys[k_RIGHT].string = "";
    }
    if ((keys[k_EOL].string = tgetstr("kE", &out_ptr)) == 0) {
	keys[k_EOL].string = "";
    }
    if ((keys[k_DC].string = tgetstr("kD", &out_ptr)) == 0) {
	keys[k_DC].string = "";
    }
    if ((keys[k_IC].string = tgetstr("kI", &out_ptr)) == 0) {
	keys[k_IC].string = "";
    }
    if ((keys[k_TAB].string = tgetstr("ta", &out_ptr)) == 0) {
	keys[k_TAB].string = "\t";
    }
    if ((keys[k_UP].string = tgetstr("ku", &out_ptr)) == 0) {
	keys[k_UP].string = "";
    }
    if ((keys[k_DOWN].string = tgetstr("kd", &out_ptr)) == 0) {
	keys[k_DOWN].string = "";
    }
    if ((keys[k_F2].string = tgetstr("k2", &out_ptr)) == 0) {
	keys[k_F2].string = "";
    }
    if ((keys[k_F3].string = tgetstr("k3", &out_ptr)) == 0) {
	keys[k_F3].string = "";
    }
    if ((keys[k_F4].string = tgetstr("k4", &out_ptr)) == 0) {
	keys[k_F4].string = "";
    }
    if ((keys[k_F5].string = tgetstr("k5", &out_ptr)) == 0) {
	keys[k_F5].string = "";
    }
    if ((keys[k_F6].string = tgetstr("k6", &out_ptr)) == 0) {
	keys[k_F6].string = "";
    }
    if ((keys[k_BTAB].string = tgetstr("kB", &out_ptr)) == 0) {
	keys[k_BTAB].string = "";
    }

    if ((clear_screen = tgetstr("cl", &out_ptr)) == 0) {
	clear_screen = "";
    }
    if ((cursor_address = tgetstr("cm", &out_ptr)) == 0) {
	cursor_address = "";
    }
    if ((enter_dim_mode = tgetstr("mh", &out_ptr)) == 0) {
	enter_dim_mode = "";
    }
    if ((exit_attribute_mode = tgetstr("me", &out_ptr)) == 0) {
	exit_attribute_mode = "";
    }
    if ((cursor_right = tgetstr("nd", &out_ptr)) == 0) {
	cursor_right = "";
    }
    if ((cursor_left = tgetstr("le", &out_ptr)) == 0) {
	cursor_left = "\b";
    }
    if ((keypad_xmit = tgetstr("ks", &out_ptr)) == 0) {
	keypad_xmit = "";
    }
    if ((keypad_local = tgetstr("ke", &out_ptr)) == 0) {
	keypad_local = "";
    }
    if ((clr_eol = tgetstr("ce", &out_ptr)) == 0) {
	clr_eol = "";
    }
    if ((enter_blink_mode = tgetstr("mb", &out_ptr)) == 0) {
	if ((enter_blink_mode = tgetstr("so", &out_ptr)) == 0)
	    enter_blink_mode = "";
    }
#else	/* TERMCAP */
    setupterm((char*)0, 1, (int*)0);
    keys[k_BS].string = key_backspace;
    keys[k_LEFT].string = key_left;
    keys[k_RIGHT].string = key_right;
    keys[k_EOL].string = key_eol;
    keys[k_DC].string = key_dc;
    keys[k_IC].string = key_ic;
    keys[k_TAB].string = tab;
    keys[k_UP].string = key_up;
    keys[k_DOWN].string = key_down;
    keys[k_F2].string = key_f2;
    keys[k_F3].string = key_f3;
    keys[k_F4].string = key_f4;
    keys[k_F5].string = key_f5;
    keys[k_F6].string = key_f6;
# ifdef key_btab
    keys[k_BTAB].string = key_btab;
# endif
#endif	/* TERMCAP */

/*
 * Set up function key label string
 */
#ifdef TERMCAP
    so_on = tgetstr("mr", &out_ptr);
    so_off = tgetstr("me", &out_ptr);
    if (so_on == 0 || strlen(so_on) == 0) {
	so_on = tgetstr("se", &out_ptr);
	so_off = tgetstr("so", &out_ptr);
    }
#else	/* TERMCAP */
    so_on = enter_reverse_mode;
    so_off = exit_attribute_mode;
    if (so_on == 0 || strlen(so_on) == 0) {
	so_on = enter_standout_mode;
	so_off = exit_standout_mode;
    }
#endif	/* TERMCAP */
    sprintf(func_label, "%s%8s%s %s%8s%s %s%8s%s %s%8s%s         ",
	so_on, "", so_off,
	so_on, (keys[k_F2].string[0]?"insert ":""), so_off,
	so_on, (keys[k_F3].string[0]?"delete ":""), so_off,
	so_on, (keys[k_F4].string[0]?"clr fld ":""), so_off);
    sprintf(func_label+strlen(func_label), "%s%8s%s %s%8s%s %s%8s%s %s%8s%s",
	so_on, (keys[k_F5].string[0]?"next pg":""), so_off,
	so_on, (keys[k_F6].string[0]?"prev pg":""), so_off,
	so_on, "", so_off,
	so_on, "", so_off);

/*
** Set defaults for some keys
**/
    if (keys[k_BS].string == 0 || strlen(keys[k_BS].string) == 0)
	keys[k_BS].string = "\b";
    if (keys[k_TAB].string == 0 || strlen(keys[k_TAB].string) == 0)
	keys[k_TAB].string = "\t";

    cc_head = (struct cchar*)malloc(sizeof(struct cchar));
    memset(cc_head, '\0', sizeof(struct cchar));

    for (kp = keys; kp->terminfo_name; ++kp) {
#ifdef DEBUG
	fprintf(stderr, "Capname=%s,string='", kp->terminfo_name);
	for (cp=kp->string ;  cp != 0 && *cp ; cp++)
	    fputs(unctrl(*cp), stderr);
	fprintf(stderr,"'\n");
#endif
	if (kp->string == 0 || strlen(kp->string) == 0) {
#ifdef DEBUG
	    fprintf(stderr, "Control sequence for \"%s\" doesn't exist\n",
		kp->terminfo_name);
#endif
	    continue;
	}
	/*
	 * Throw away pad string '$<nn>'
	 */
	if ((cp = strstr(kp->string, "$<")) != NULL) {
	    /* num of chars to delete */
	    slen = strchr(cp, '>') - cp + 1;
	    if (slen > 0) {
		strcpy(cp, cp+slen);
	    }
	}

	for (cp = kp->string, ccp = cc_head; *cp; ) {
	    if (ccp->ch == '\0')
		ccp->ch = *cp;
	    if (ccp->ch == *cp) {
		if (*(cp+1) == '\0') {	/* end of string, add action */
		    if (ccp->action != NULL) {
			fprintf(stderr, "Control string conflict\n");
			break;
		    } else {	/* add it */
			ccp->action = kp->func;
			break;
		    }
		}
		/* not end of string */
		if (ccp->next == NULL) {
		    ccp->next = (struct cchar*)malloc(sizeof(struct cchar));
		    memset(ccp->next, '\0', sizeof(struct cchar));
		}
		ccp = ccp->next;
		++cp;
		continue;
	    }
	    if (ccp->alt != NULL) {
		ccp = ccp->alt;
		continue;
	    }
	    /* allocate new alternate */
	    ccp->alt = (struct cchar*)malloc(sizeof(struct cchar));
	    memset(ccp->alt, '\0', sizeof(struct cchar));
	    ccp = ccp->alt;
	}

#if DEBUG > 1
	dumptables(cc_head);
#endif
    }
#if DEBUG == 1
    dumptables(cc_head);
    dumpcmd();
#endif
}


#ifndef AIXV3		/* GLAH!!!!  this *must* lose on something else... */

/*	strstr		String version of strchr			*/
/*			Return pointer to 1st occurance of s2 in s1	*/
/*			Return NULL if not found			*/
char
*strstr(s1, s2)
register char *s1, *s2;
{
	register int	len;

	len = strlen(s2);
	while (*s1)
	{
		if (strncmp(s1, s2, len) == 0)
			return(s1);
		else
			++s1;
	}
	return(NULL);
}
#endif /* AIXV3 */

#ifdef DEBUG
static
dumptables(head)
struct cchar	*head;
{
    dtable(head);
    if (head->alt)
	dumptables(head->alt);
    if (head->next)
	dumptables(head->next);
}


static
dtable(ccp)
register struct	cchar	*ccp;
{

    fprintf(stderr, "%d:\tch='%s'\n", ccp-cc_head+1, unctrl(ccp->ch));
    fprintf(stderr, "\tnext=%d", ccp->next?ccp->next-cc_head+1:0);
    fprintf(stderr, "\talt=%d", ccp->alt?ccp->alt-cc_head+1:0);
    if (ccp->action == goright) {
	fprintf(stderr, "\taction=goright\n");
    } else if (ccp->action == goleft) {
	fprintf(stderr, "\taction=goleft\n");
    } else if (ccp->action == nextfield) {
	fprintf(stderr, "\taction=nfield\n");
    } else if (ccp->action == prevfield) {
	fprintf(stderr, "\taction=pfield\n");
    } else if (ccp->action == ferase) {
	fprintf(stderr, "\taction=ferase\n");
    } else if (ccp->action == delchar) {
	fprintf(stderr, "\taction=delchar\n");
    } else if (ccp->action == inschar) {
	fprintf(stderr, "\taction=inschar\n");
    } else if (ccp->action == nextpage) {
	fprintf(stderr, "\taction=nextpage\n");
    } else if (ccp->action == prevpage) {
	fprintf(stderr, "\taction=prevpage\n");
    } else {
	fprintf(stderr, "\n");
    }
}

static
dumpcmd()
{

    fprintf(stderr, "clear_screen='");
    putctlstr(clear_screen);
    fprintf(stderr,"'\n");
    fprintf(stderr, "cursor_address='");
    putctlstr(cursor_address);
    fprintf(stderr,"'\n");
    fprintf(stderr, "enter_dim_mode='");
    putctlstr(enter_dim_mode);
    fprintf(stderr,"'\n");
    fprintf(stderr, "exit_attribute_mode='");
    putctlstr(exit_attribute_mode);
    fprintf(stderr,"'\n");
    fprintf(stderr, "cursor_right='");
    putctlstr(cursor_right);
    fprintf(stderr,"'\n");
    fprintf(stderr, "cursor_left='");
    putctlstr(cursor_left);
    fprintf(stderr,"'\n");
    fprintf(stderr, "keypad_xmit='");
    putctlstr(keypad_xmit);
    fprintf(stderr,"'\n");
    fprintf(stderr, "keypad_local='");
    putctlstr(keypad_local);
    fprintf(stderr,"'\n");
    fprintf(stderr, "clr_eol='");
    putctlstr(clr_eol);
    fprintf(stderr,"'\n");
    fprintf(stderr, "enter_blink_mode='");
    putctlstr(enter_blink_mode);
    fprintf(stderr,"'\n");
}


static
putctlstr(str)
register char	*str;
{

    for ( ;  str != 0 && *str ; str++)
	fputs(unctrl(*str), stderr);
}
#endif
