/*	Copyright (c) 1990 UNIX System Laboratories, Inc.	*/
/*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF     	*/
/*	UNIX System Laboratories, Inc.                     	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1986 AT&T
 *	All Rights Reserved
 */
#ident	"@(#)fmli:oh/slk.c	1.37"

/* microsecond delay timer not available before SVR4.0   abs k18 */
#ifdef PRE_SVR4_COMPILE
#define DO_NOT_DELAY		
#endif

#include	<stdio.h>
#include	<curses.h>
#include	<term.h>
#include	<string.h>	/* abs k17 */
#include 	<sys/types.h>	/* abs k17 */
#include	<unistd.h>	/* abs k18 */
#include	<stdlib.h>	/* abs k18 */
#ifndef DO_NOT_DELAY
#include 	<sys/time.h>	/* abs k18 */
#endif
#include	"wish.h"
#include	"token.h"
#include	"fm_mn_par.h"
#include	"slk.h"
#include	"ctl.h"
#include	"moremacros.h"
#include	"interrupt.h"

struct slk Moreslk = {
	"CHG-KEYS",	TOK_TOGSLK,	NULL,	NULL,	NULL
};

struct slk Markslk = {
	"MARK",		TOK_MARK,	NULL,	NULL,	NULL
};

struct slk Blankslk = {
	"",		TOK_NOP,	NULL,	NULL,	NULL
};

struct slk Formslk[] = {
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"CHOICES",	TOK_OPTIONS,	NULL,	NULL,	NULL},
	{"SAVE",	TOK_DONE,	NULL,	NULL,	NULL},
	{"PREV-FRM",	TOK_PREV_WDW,	NULL,	NULL,	NULL},
	{"NEXT-FRM",	TOK_NEXT_WDW,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CLOSE,	NULL,	NULL,	NULL},
	{"CMD-MENU",	TOK_CMD,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{NULL, 		TOK_NOP, 	NULL,	NULL,	NULL}
};

#define MARK 1

struct slk Menuslk[] = {
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},/* MARK for mult. selections  */
	{"ENTER",	TOK_RETURN,	NULL,	NULL,	NULL},
	{"PREV-FRM",	TOK_PREV_WDW,	NULL,	NULL,	NULL},
	{"NEXT-FRM",	TOK_NEXT_WDW,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CLOSE,	NULL,	NULL,	NULL},
	{"CMD-MENU",	TOK_CMD,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{NULL,		TOK_NOP,	NULL,	NULL,	NULL}
};

struct slk Textslk[] = {
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"PREVPAGE",	TOK_PPAGE,	NULL,	NULL,	NULL},
	{"NEXTPAGE",	TOK_NPAGE,	NULL,	NULL,	NULL},
	{"PREV-FRM",	TOK_PREV_WDW,	NULL,	NULL,	NULL},
	{"NEXT-FRM",	TOK_NEXT_WDW,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CLOSE,	NULL,	NULL,	NULL},
	{"CMD-MENU",	TOK_CMD,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{NULL,		TOK_NOP,	NULL,	NULL,	NULL}
};

struct slk Echslk[] = {		/* Enter/Cancel/Help slks */
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CANCEL,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{"",		TOK_BADCHAR,	NULL,	NULL,	NULL},
	{NULL,		TOK_NOP,	NULL,	NULL,	NULL}
};


/*
 * FACE user interface Directory SLKS
 */
struct slk Vmslk[] = {
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},	
	{"ENTER",	TOK_RETURN,	NULL,	NULL,	NULL},
	{"PREV-FRM",	TOK_PREV_WDW,	NULL,	NULL,	NULL},
	{"NEXT-FRM",	TOK_NEXT_WDW,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CLOSE,	NULL,	NULL,	NULL},
	{"CMD-MENU",	TOK_CMD,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"COPY",	TOK_COPY,	NULL,	NULL,	NULL},
	{"MOVE",	TOK_MOVE,	NULL,	NULL,	NULL},
	{"DELETE",	TOK_DELETE,	NULL,	NULL,	NULL},
	{"RENAME",	TOK_REPLACE,	NULL,	NULL,	NULL},
	{"CREATE",	TOK_CREATE,	NULL,	NULL,	NULL},
	{"SECURITY",	TOK_SECURITY,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{NULL,		TOK_NOP,	NULL,	NULL,	NULL}
};

extern int Browse_mode;


/*
 * FACE user interface Browse Mode SLKS 
 */
struct slk Browslk[] = {	/* slks when browsing */
	{"HELP",	TOK_HELP,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{"",		TOK_NOP,	NULL,	NULL,	NULL},
	{"PREV-FRM",	TOK_PREV_WDW,	NULL,	NULL,	NULL},
	{"NEXT-FRM",	TOK_NEXT_WDW,	NULL,	NULL,	NULL},
	{"CANCEL",	TOK_CANCEL,	NULL,	NULL,	NULL},
	{"CMD-MENU",	TOK_CMD,	NULL,	NULL,	NULL},
	{"SELECT",	TOK_SELECT,	NULL,	NULL,	NULL},
	{NULL,		TOK_NOP,	NULL,	NULL,	NULL}
};

#define CHG_KEYS	7	/* SLK number of first level CHG_KEYS */
#define SECOND_LEVEL	8	/* number of slks displayable */
#define ALT_CHG_KEYS	15	/* SLK number of second level CHG_KEYS */
#define MAX_SLKS	16	/* total number of slks */	

struct slk No_slks[1];
struct slk SLK_array[MAX_SLKS];
struct slk Defslk[MAX_SLKS];
struct slk *Curslk = &Defslk[0];
static int SLK_level = 0;

static void showslks();
static bool sfk_prompt();

extern int Vflag;

/*
 * init_sfk tries to initialize the screen function keys for terminals
 * (like the att630) which do not have pre-defined screen function keys
 * It will not do anything if:
 * 1) the environment variable LOADPFK is set to anything other than
 *    yes, true, or the null string (case insensitive) or
 * 2) the terminal does not support software downloading of these strings or
 * 3) if the terminal has predefined strings sent by the function keys.
 * 4) if, when prompted, the user responds with anything other than
 *    "yes", "y", or "" (whitespace & extra words ignored.)  Prompt only occurs 
 *    once per session and only if LOADPFK is not defined.
 *
 * NOTE:       if the terminfo entry indicates a mandatory delay is needed
 *             and there is no pad char then FMLI will insert the delay.
 *             For some terminals (ex dmd 5620) this delay is appreciable
 *             and should be avoided, when feasable, by downloading once then
 *             setting LOADPFK=no.
 * IMPORTANT:  remove the delay code (ifdef'd by DO_NOT_DELAY)
 *	       when curses gets smart enough to do delays right for
 *             terminals like the dmd 5620 which do not have pad characters
 */


init_sfk(do_prompt)
bool do_prompt;				/* abs k18 */
{
    char    sequence[3];
    int     i;
#ifndef DO_NOT_DELAY
    char   *sub_str;
    char   *end_str;			/* abs k18 */
    unsigned time_left;			/* abs k18 */
    static struct itimerval delay_time; /* abs k18 */
    static long Mandatory_delay = 0L; 	/* abs k18 */
    static bool First_time = TRUE;    	/* abs k18 */
#endif
    static bool Said_no = FALSE;    	/* abs k18 */
    char   *load;		 	/* abs k18 */

    sequence[0] = 'F' & 037;		/* <control f> */
    sequence[2] = '\0';
        
    /* if we already prompted user and they said no then don't do anything */

    if (Said_no == TRUE)		/* abs k18 */
	return;				/* abs k18 */

    /* if LOADPFK is set in the environment, don't download function keys,
     * unless it is set to yes, true, or the null string. abs k18
     */

    if ( (load = getenv("LOADPFK")) && *load &&
         strCcmp(load, "yes") && strCcmp(load, "true"))	/* abs k18 */
	   return; 	     /* user says don't mess with my keys! */

    if (load)
	do_prompt = FALSE;	/* don't prompt if LOADPFK is set. abs k18 */

    if (!pkey_xmit || pkey_xmit == NULL)   /* term can't transmit fn keys */
	   return;
#ifndef DO_NOT_DELAY
    if (First_time == TRUE)	/* this block added k18 abs. */
    {
	First_time = FALSE;
	if (no_pad_char)	/* can't create delay by sending pads */
	{
	    /* look for mandatory delay 
	     * delays are coded $<nnn/> where n is a digit and 
	     * the slash, if present, means the delay is mandatory.
             */

	    sub_str = pkey_xmit;
	    while (sub_str = strchr(sub_str, '$'))
		if (*(++sub_str) == '<')
		{
		    Mandatory_delay = strtol(&sub_str[1], &end_str, 10);
		    if (end_str[0] != '/' || end_str[1] != '>')
			Mandatory_delay = 0L;
		}
	    if (Mandatory_delay)
	    {
		/* convert milliseconds to microseconds and seconds.
		 * tv_usec must be less than 1,000,000.  abs k18.2 
		 */
		delay_time.it_value.tv_usec = (Mandatory_delay % 1000L) * 1000L;
		delay_time.it_value.tv_sec = Mandatory_delay  / 1000L;
		delay_time.it_interval.tv_sec = 0L;
		delay_time.it_interval.tv_usec = 0L;
	    }

	}
    }
    
    /* don't want mailcheck to intefere with timer. abs k18 */
    time_left = alarm((unsigned)0);	
#endif
    if (!key_f1 || *key_f1 == NULL) /* if no pre-defined key 1 then assume
				     * keys 2 - 8 not pre-defined either */
    {
	if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)  /* abs k18 */
	    return;						/* abs k18 */

/*      The following line was moved from below.  This is where it belongs,
**      unfortunately the doupdate() to make the indicator visible
**      interferes with downloading 5620 pfk's (somehow?!) depending on whats
**      in the curses screen buffer.  abs k18.2
**      working(TRUE);	
*/
	for (i = 1; i < 9; i++)
	{
	    sequence[1] = '0' + i;
	    putp(tparm(pkey_xmit, i, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
    }
    else
    {
	if (!key_f2 || *key_f2 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '2';
	    putp(tparm(pkey_xmit, 2, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f3 || *key_f3 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '3';
	    putp(tparm(pkey_xmit, 3, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f4 || *key_f4 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '4';
	    putp(tparm(pkey_xmit, 4, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f5 || *key_f5 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '5';
	    putp(tparm(pkey_xmit, 5, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f6 || *key_f6 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '6';
	    putp(tparm(pkey_xmit, 6, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f7 || *key_f7 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '7';
	    putp(tparm(pkey_xmit, 7, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	if (!key_f8 || *key_f8 == NULL)
	{
	    if (do_prompt == TRUE && (Said_no = sfk_prompt()) == TRUE)   /* abs k18 */
		return;						/* abs k18 */
	    else						/* abs k18 */
		do_prompt = FALSE;				/* abs k18 */
	    sequence[1] = '8';
	    putp(tparm(pkey_xmit, 8, sequence));
	    fflush(stdout);
#ifndef DO_NOT_DELAY
 	    if (Mandatory_delay) 				/* abs k18 */
	    {
		setitimer(ITIMER_REAL, &delay_time, NULL); 	/* abs k18 */
		pause();					/* abs k18 */
	    }
#endif
	}
	    
    }
#ifndef DO_NOT_DELAY
    alarm(time_left);		/* reset alarm. abs k18 */
#endif
}


static bool
sfk_prompt()
{
    char raw_input[80];
    char *response, *word_end;
    WINDOW *win;
    int cursor, x, y;

    win = newwin(0,0,1,0);	/* almost full screen window */
    getmaxyx(win, y, x);
    wmove(win, y/2-6, 0);	/* go to about the center row */
    cursor = curs_set(1);	/* make cursor visible */
    flushinp();

    wprintw(win, "This terminal does not have usable default settings for its function keys;\nhowever, this application can download usable settings.\n\nIf you reply yes, function keys will work, BUT any values you may already \nhave programmed into them will be overwritten.\n\n");
    wprintw(win, "If you reply no,  function keys may not work, and you must use CTRL-f1 \nthru CTRL-f8 to simulate the function keys.\n\nThis prompt will not occur if you set LOADPFK=YES or LOADPFK=NO in \nyour environment.\n\nDownload usable settings into the function keys [default is yes]? ");

    wrefresh(win);
    echo();
    wgetnstr(win, raw_input, 79);
    noecho();
    werase(win);
    wrefresh(win);
    delwin(win);
    (void)curs_set(cursor);

    response = raw_input;
    while (isspace(*response))
	response++;
    word_end = response;				/* abs k18.2 */
    while (!isspace(*word_end) && *word_end !=  '\0') 	/* abs k18.2 */
	word_end++;					/* abs k18.2 */
    *word_end = '\0';					/* abs k18.2 */
    
    if (*response && strCcmp(response, "y") && strCcmp(response, "yes"))
    {
	putenv("LOADPFK=NO");	/* so child fmli's don't prompt. abs k18.2 */
	return(TRUE);		/* said no */
    }
    else
    {
	putenv("LOADPFK=YES");	/* so child fmli's don't prompt. abs k18.2 */
	return(FALSE);		/* said yes */
    }
}




/*
 * SETUP_SLK_ARRAY will initialize defaults for the SLKS
 */
setup_slk_array()
{
	register int i, j;

	for (i = 0; i < SECOND_LEVEL; i++)
		Defslk[i] = Menuslk[i];

	for (i = SECOND_LEVEL; i < MAX_SLKS; i++) {
		Defslk[i].label = nil; 
		Defslk[i].tok = TOK_NOP;
		Defslk[i].tokstr = NULL;
		Defslk[i].intr   = NULL;
		Defslk[i].onintr = NULL;
	}
}

#define REDEFINED(x)	 ((x).label && (*((x).label) != '\0' || (x).tok < 0))

/*
 * SETSLKS will make "slks" the currently displayed SLKS
 */
void
setslks(slks, flag)
struct slk	slks[];
int flag;
{
	register int	i, more_slks;
	static  void	showslks();

#ifdef _DEBUG
	_debug(stderr, "in setslk!\n");
#endif
	if (slks == NULL) {	/* e.g., directory object */
		if (Vflag) {	/* FACE specific slks */
			if (Browse_mode)
				setslks(Browslk, 0);
			else
				setslks(Vmslk, 0);
		}
		else {	/* use menu slks by default */
			set_top_slks(Menuslk);
			setslks(Defslk, 0);
		}
		return;
	}
	else if (slks == No_slks) {
#ifdef _DEBUG
		_debug(stderr, "slks are history\n");
#endif
		SLK_level = -1;
		slk_clear();
		return;
	}
	more_slks = 0;
	for (i = 0; slks[i].label && i < MAX_SLKS; i++) {
		if (i >= SECOND_LEVEL && *(slks[i].label) != '\0')
			more_slks++;
#ifdef _DEBUG
		_debug(stderr, "SLK_array[%d] = '%s'\n", i, slks[i].label);
#endif
		SLK_array[i] = slks[i];
	}
#ifdef _DEBUG
	if (slks[i].label)
		_debug(stderr, "setslks was passed an array without a NULL terminator\n");
#endif
	while (i < MAX_SLKS)
		SLK_array[i++].label = nil;
	if (more_slks && !(REDEFINED(SLK_array[CHG_KEYS]) ||
			 REDEFINED(SLK_array[ALT_CHG_KEYS]))) 
		SLK_array[CHG_KEYS] = SLK_array[ALT_CHG_KEYS] = Moreslk;
	showslks(flag);
}

int Refresh_slks = 0;

/*
 * SHOWSLKS will do the actial displaying
 */
static void
showslks(flag)
int flag;
{
	register int	i;
	register int	j;

	if (SLK_level < 0) {
		Refresh_slks++;
		/*slk_restore();    defer to vt_flush() */
	}
	if (flag)
		SLK_level = j = SECOND_LEVEL;
	else
		SLK_level = j = 0;
	for (i = 1; i <= SECOND_LEVEL; i++)
		slk_set(i, SLK_array[j++].label, 1);
	slk_noutrefresh();
}

/*
 * SLK_TOKEN will determine the token action for a given SLK
 */
token
slk_token(t)
token	t;
{
    register int	n;
    int flags;
    char **arglist, **eval_string();
    char  *intr, *onintr;

    n = t - TOK_SLK1 + SLK_level;
#ifdef _DEBUG
    _debug(stderr, "slk %d is labeled '%s' and returns token %d\n", t, n, SLK_array[n].label,SLK_array[n].tok);
#endif
    if (SLK_array[n].label && SLK_array[n].label[0])
    {
	if (SLK_array[n].tok >= 0)	/* internally-defined */
	    return(SLK_array[n].tok);
	else
	{

	    /* 	update the interrupt structures based on 
		the values for the current slk, if defined
		else with the inherited values.
	    */
	    Cur_intr.skip_eval =  FALSE;
	    if ((intr = SLK_array[n].intr) == NULL)
		intr = (char *)ar_ctl(AR_cur, CTGETINTR);
	    flags = RET_BOOL;
	    Cur_intr.interrupt = FALSE;	/* dont intrupt eval of intr */
	    Cur_intr.interrupt = (bool)eval_string(intr, &flags);

	    if ((onintr = SLK_array[n].onintr) == NULL)
		onintr = (char *)ar_ctl(AR_cur, CTGETONINTR);
	    Cur_intr.oninterrupt = onintr;

	    flags = RET_ARGS;
	    arglist = eval_string(SLK_array[n].tokstr, &flags);
	    return(make_action(arglist));
	}
    }
	return TOK_BADCHAR;
}

set_top_slks(slks)
struct slk slks[];
{
	register int i;

	for (i = 0; i < SECOND_LEVEL; i++)
		Defslk[i] = slks[i];
}

/*
 * SET_OBJ_SLK is called by objects that wish to redefine the
 * GLOBAL default SLKS ... 
 * The object will pass a "slktok" in the range SLK1 - SLK16.
 * If a token in this range is "caught" by the object,
 * the object itself will determine the appropriate action.
 */ 
set_obj_slk(slk, label, slktok, intr, onintr)
struct slk *slk;
char *label;
int slktok;
char *intr, *onintr;
{
	int slknum;

	if (label && (*label == '\0')) {     /* disable any SLK */
		slk->label = "";
		slk->tok = -1;
		slk->tokstr = NULL;
		slk->intr   = NULL;
		slk->onintr = NULL;
	}
	else {
		slknum = slktok - TOK_SLK1;  /* (adjust for array offset) */
		if (slknum >= CHG_KEYS) {    /* redefine certain SLKS */ 
			slk->label = strsave(label);
			/*
			 * unfortunately this test needs to be made ...
			 * (if odsh gets prevpage or nextpage its too late)
			 * We must search for a better way !!!
			 */
			if (strCcmp(label, "prevpage") == 0)
				slk->tok = TOK_PPAGE;
			else if (strCcmp(label, "nextpage") == 0)
				slk->tok = TOK_NPAGE;
			else if (strCcmp(label, "prev-frm") == 0)
				slk->tok = TOK_PREV_WDW;
			else if (strCcmp(label, "next-frm") == 0)
				slk->tok = TOK_NEXT_WDW;
			else if (strCcmp(label, "enter") == 0)
				slk->tok = TOK_RETURN;
			else
				slk->tok = slktok;
			slk->tokstr = NULL;
			slk->intr   = strsave(intr);
			slk->onintr = strsave(onintr);
		}
		else {			     /* must use the defaults! */ 
			slk->label = Defslk[slknum].label;
			slk->tok = Defslk[slknum].tok;
			slk->tokstr = Defslk[slknum].tokstr;
			slk->tokstr = Defslk[slknum].intr;
			slk->tokstr = Defslk[slknum].onintr;
		}
	}
}


/*
 * SET_DEF_SLK will over-write the GLOBAL default SLKS 
 */
set_def_slk(slknum, label, action, intr, onintr)
int slknum;
char *label;
char *action;
char *intr, *onintr;
{
	/*
	 * if less then CHG_KEYS do nothing (can't redefine first level)
	 */
	if (label && (*label == '\0')) {	/* disable any SLK */
		Defslk[slknum].label = "";
		Defslk[slknum].tok = -1;
		Defslk[slknum].tokstr = NULL;
		Defslk[slknum].intr   = NULL;
		Defslk[slknum].onintr = NULL;
	}
	else if (slknum >= CHG_KEYS) {		/* redefine certain SLKS */
		Defslk[slknum].label = strsave(label);
		Defslk[slknum].tok = -1;
		Defslk[slknum].tokstr = strsave(action);
		Defslk[slknum].intr   = strsave(intr);
		Defslk[slknum].onintr = strsave(onintr);
	}
	/*
	 * if SLK is at the first level, then change the object
	 * SLKS to reflect the redefined or disabled SLK 
	 */
	if (slknum <= CHG_KEYS) {	
		Formslk[slknum] = Defslk[slknum];
		Textslk[slknum] = Defslk[slknum];
		Menuslk[slknum] = Defslk[slknum];
	}
}

/*
 * SLK_TOGGLE will toggle the currently displayed SLKS
 */
slk_toggle()
{
	showslks(!SLK_level);
}

set_slk_mark(flag)
int flag;
{
	if (flag == TRUE)
		Menuslk[MARK] = Markslk;
	else
		Menuslk[MARK] = Blankslk;
	Defslk[MARK] = Menuslk[MARK];
}
