Blob Blame History Raw
/*
 * $LynxId: LYEditmap.c,v 1.75 2018/03/10 01:31:27 tom Exp $
 *
 * LYEditMap.c
 * Keybindings for line and form editing.
 */

#include <HTUtils.h>
#include <HTAlert.h>
#include <HTFile.h>
#include <LYGlobalDefs.h>
#include <LYCharUtils.h>
#include <LYStrings.h>
#include <LYKeymap.h>		/* KEYMAP_SIZE, LKC_*, LYK_* - kw */
#include <LYLeaks.h>

#define PUTS(buf)    (*target->isa->put_string)(target, buf)

/* * * * * LynxEditactionCodes * * * * */
#ifdef USE_ALT_BINDINGS

/* Last valid index for the (lynxkeycode+modifier -> lynxeditactioncode)
 * tables.  Currently all three tables are the same.  - kw
 */
#define LAST_MOD1_LKC	0x111
#define LAST_MOD2_LKC	0x111
#define LAST_MOD3_LKC	0x111

/*  Get (lynxkeycode+modifier -> lynxeditactioncode) mapping, intermediate.
 */
#define LKC_TO_LEC_M1(c) ((c)>LAST_MOD1_LKC? (int)LYE_UNMOD: Mod1Binding[c])
#define LKC_TO_LEC_M2(c) ((c)>LAST_MOD2_LKC? (int)LYE_UNMOD: Mod2Binding[c])
#define LKC_TO_LEC_M3(c) ((c)>LAST_MOD3_LKC? (int)LYE_UNMOD: Mod3Binding[c])

#endif /* USE_ALT_BINDINGS */

int current_lineedit = 0;	/* Index into LYLineEditors[]   */

int escape_bound = 0;		/* User wanted Escape to perform actions?  */

/*
 * See LYStrings.h for the LYE definitions.
 */
/* *INDENT-OFF* */
struct emap {
    const char *name;
    const int   code;
    const char *descr;
};

#define SEPARATOR {"", -1, ""}

static struct emap ekmap[] = {
  {"NOP",	LYE_NOP,	"Do Nothing"},
  {"CHAR",	LYE_CHAR,	"Insert printable char"},
  SEPARATOR,
  {"ENTER",	LYE_ENTER,	"Input complete, return char"},
  {"TAB",	LYE_TAB,	"Input complete, return TAB"},
  {"STOP",	LYE_STOP,	"Input deactivated"},
  {"ABORT",	LYE_ABORT,	"Input cancelled"},
  SEPARATOR,
  {"PASS",	LYE_FORM_PASS,  "Fields only: input complete"},
  SEPARATOR,
  {"DELBL",	LYE_DELBL,	"Delete back to BOL"},
  {"DELEL",	LYE_DELEL,	"Delete thru EOL"},
  {"DELN",	LYE_DELN,	"Delete next/curr char"},
  {"DELP",	LYE_DELP,	"Delete prev      char"},
  {"DELNW",	LYE_DELNW,	"Delete next word"},
  {"DELPW",	LYE_DELPW,	"Delete prev word"},
  SEPARATOR,

  {"ERASE",	LYE_ERASE,	"Erase the line"},
  SEPARATOR,
  {"BOL",	LYE_BOL,	"Go to begin of line"},
  {"EOL",	LYE_EOL,	"Go to end   of line"},
  {"FORW",	LYE_FORW,	"Cursor forwards"},
  {"FORW_RL",	LYE_FORW_RL,	"Cursor forwards or right link"},
  {"BACK",	LYE_BACK,	"Cursor backwards"},
  {"BACK_LL",	LYE_BACK_LL,	"Cursor backwards or left link"},
  {"FORWW",	LYE_FORWW,	"Word forward"},
  {"BACKW",	LYE_BACKW,	"Word back"},
  SEPARATOR,
  {"LOWER",	LYE_LOWER,	"Lower case the line"},
  {"UPPER",	LYE_UPPER,	"Upper case the line"},
  SEPARATOR,
  {"LKCMD",	LYE_LKCMD,	"Invoke command prompt"},
  {"SWMAP",	LYE_SWMAP,	"Switch input keymap"},
  SEPARATOR,
  {"C1CHAR",	LYE_C1CHAR,	"Insert C1 char if printable"},
  {"SETM1",	LYE_SETM1,	"Set modifier 1 flag"},
  {"SETM2",	LYE_SETM2,	"Set modifier 2 flag"},
  {"UNMOD",	LYE_UNMOD,	"Fall back to no-modifier command"},
  SEPARATOR,
  {"TPOS",	LYE_TPOS,	"Transpose characters"},
  {"SETMARK",	LYE_SETMARK,	"emacs-like set-mark-command"},
  {"XPMARK",	LYE_XPMARK,	"emacs-like exchange-point-and-mark"},
  {"KILLREG",	LYE_KILLREG,	"emacs-like kill-region"},
  {"YANK",	LYE_YANK,	"emacs-like yank"},
#ifdef CAN_CUT_AND_PASTE
  SEPARATOR,
  {"PASTE",	LYE_PASTE,	"ClipBoard to Lynx"},
#endif
  SEPARATOR,
  {"AIX",	LYE_AIX,	"Hex 97"},
  {0,           -1,             0},
};
#undef SEPARATOR
/* *INDENT-ON* */

static LYEditCode DefaultEditBinding[KEYMAP_SIZE];

#ifdef USE_ALT_BINDINGS
static LYEditCode BetterEditBinding[KEYMAP_SIZE];
static LYEditCode BashlikeEditBinding[KEYMAP_SIZE];

/*
 * If a modifier bit is set in a lynxkeycode, it is first looked up here.
 *
 * Currently this table isn't specific to the current_lineedit value, it is
 * shared by all alternative "Bindings" to save space.  However, if the
 * modifier flag is set only by a LYE_SETMn lynxeditaction, this table can have
 * effect only for those Bindings that map a lynxkeycode to LYE_SETMn.  ( This
 * doesn't apply if the modifier is already being set in LYgetch().  ) - kw
 */
static LYEditCode Mod1Binding[KEYMAP_SIZE];

/*  Two more tables here, but currently they are all the same.
    In other words, we are cheating to save space, until there
    is a need for different tables. - kw */
static LYEditCode *Mod2Binding = Mod1Binding;
static LYEditCode *Mod3Binding = Mod1Binding;

static const LYEditInit initMod1Binding[] =
{
    {CTL('A'), LYE_BOL},
    {CTL('B'), LYE_BACKW},
    {CTL('C'), LYE_UNMOD},
    {CTL('D'), LYK_NEXT_LINK | LYE_FORM_LAC},
    {CTL('E'), LYK_EDITTEXTAREA | LYE_FORM_LAC},
    {CTL('F'), LYE_FORWW},
    {CTL('G'), LYE_ABORT},
    {CTL('H'), LYE_DELPW},
    {CTL('I'), LYE_UNMOD},
    {CTL('J'), LYE_ENTER},
    {CTL('K'), LYK_LPOS_NEXT_LINK | LYE_FORM_LAC},
    {CTL('L'), LYE_FORM_PASS},
    {CTL('M'), LYE_ENTER},
    {CTL('N'), LYE_FORWW},
    {CTL('O'), LYE_UNMOD},
    {CTL('P'), LYE_BACKW},
    {CTL('R'), LYE_BACKW},
    {CTL('U'), LYE_FORM_PASS},
    {CTL('W'), LYE_KILLREG},
    {CTL('X'), LYE_XPMARK},
    {CTL('Y'), LYE_UNMOD},
    {CTL('Z'), LYE_FORM_PASS},
    {CTL('\\'), LYE_FORM_PASS},
    {CTL(']'), LYE_FORM_PASS},
    {CTL('^'), LYE_UNMOD},
    {' ', LYE_UNMOD},
    {'!', LYE_UNMOD},
    {'"', LYE_UNMOD},
    {'#', LYE_UNMOD},
    {'$', LYE_UNMOD},
    {'%', LYE_UNMOD},
    {'&', LYE_UNMOD},
    {'\'', LYE_UNMOD},
    {'(', LYE_UNMOD},
    {')', LYE_UNMOD},
    {'*', LYE_UNMOD},
    {'+', LYE_UNMOD},
    {',', LYE_UNMOD},
    {'-', LYE_UNMOD},
    {'.', LYE_UNMOD},
    {'/', LYE_FORM_PASS},
    {'0', LYE_UNMOD},
    {'1', LYE_UNMOD},
    {'2', LYE_UNMOD},
    {'3', LYE_UNMOD},
    {'4', LYE_UNMOD},
    {'5', LYE_UNMOD},
    {'6', LYE_UNMOD},
    {'7', LYE_UNMOD},
    {'8', LYE_UNMOD},
    {'9', LYE_UNMOD},
    {':', LYE_UNMOD},
    {';', LYE_UNMOD},
    {'<', LYK_HOME | LYE_FORM_LAC},
    {'=', LYE_UNMOD},
    {'>', LYK_END | LYE_FORM_LAC},
    {'?', LYE_UNMOD},
    {'@', LYE_C1CHAR},
    {'A', LYE_C1CHAR},
    {'B', LYE_C1CHAR},
    {'C', LYE_C1CHAR},
    {'D', LYE_C1CHAR},
    {'E', LYE_C1CHAR},
    {'F', LYE_C1CHAR},
    {'G', LYE_C1CHAR},
    {'H', LYE_C1CHAR},
    {'I', LYE_C1CHAR},
    {'J', LYE_C1CHAR},
    {'K', LYE_C1CHAR},
    {'L', LYE_C1CHAR},
    {'M', LYE_C1CHAR},
    {'N', LYE_C1CHAR},
    {'O', LYE_C1CHAR},
    {'P', LYE_C1CHAR},
    {'Q', LYE_C1CHAR},
    {'R', LYE_C1CHAR},
    {'S', LYE_C1CHAR},
    {'T', LYE_C1CHAR},
    {'U', LYE_C1CHAR},
    {'V', LYE_C1CHAR},
    {'W', LYE_C1CHAR},
    {'X', LYE_C1CHAR},
    {'Y', LYE_C1CHAR},
    {'Z', LYE_C1CHAR},
    {'[', LYE_C1CHAR},
    {'\\', LYE_C1CHAR},
    {']', LYE_C1CHAR},
    {'^', LYE_C1CHAR},
    {'_', LYE_C1CHAR},
    {'`', LYE_UNMOD},
    {'a', LYE_BOL},
    {'b', LYE_BACKW},
    {'c', LYE_UNMOD},
    {'d', LYE_DELNW},
    {'e', LYK_EDITTEXTAREA | LYE_FORM_LAC},
    {'f', LYE_FORWW},
    {'g', LYK_GROWTEXTAREA | LYE_FORM_LAC},
    {'h', LYE_CHAR},
    {'i', LYK_INSERTFILE | LYE_FORM_LAC},
    {'j', LYE_CHAR},
    {'k', LYE_ERASE},
    {'l', LYE_LOWER},
    {'m', LYE_CHAR},
    {'n', LYE_FORM_PASS},
    {'o', LYE_UNMOD},
    {'p', LYE_CHAR},
    {'u', LYE_UPPER},
    {'z', LYE_UNMOD},
    {'{', LYE_UNMOD},
    {'|', LYE_UNMOD},
    {'}', LYE_UNMOD},
    {'~', LYE_UNMOD},
    {DEL_KEY, LYE_DELPW},
    {160, LYE_UNMOD},
    {161, LYE_UNMOD},
    {162, LYE_UNMOD},
    {163, LYE_UNMOD},
    {164, LYE_UNMOD},
    {165, LYE_UNMOD},
    {166, LYE_UNMOD},
    {167, LYE_UNMOD},
    {168, LYE_UNMOD},
    {169, LYE_UNMOD},
    {170, LYE_UNMOD},
    {171, LYE_UNMOD},
    {172, LYE_UNMOD},
    {173, LYE_UNMOD},
    {174, LYE_UNMOD},
    {175, LYE_UNMOD},
    {176, LYE_UNMOD},
    {177, LYE_UNMOD},
    {178, LYE_UNMOD},
    {179, LYE_UNMOD},
    {180, LYE_UNMOD},
    {181, LYE_UNMOD},
    {182, LYE_UNMOD},
    {183, LYE_UNMOD},
    {184, LYE_UNMOD},
    {185, LYE_UNMOD},
    {186, LYE_UNMOD},
    {187, LYE_UNMOD},
    {188, LYE_UNMOD},
    {189, LYE_UNMOD},
    {190, LYE_UNMOD},
    {191, LYE_UNMOD},
    {192, LYE_UNMOD},
    {193, LYE_UNMOD},
    {194, LYE_UNMOD},
    {195, LYE_UNMOD},
    {196, LYE_UNMOD},
    {197, LYE_UNMOD},
    {198, LYE_UNMOD},
    {199, LYE_UNMOD},
    {200, LYE_UNMOD},
    {201, LYE_UNMOD},
    {202, LYE_UNMOD},
    {203, LYE_UNMOD},
    {204, LYE_UNMOD},
    {205, LYE_UNMOD},
    {206, LYE_UNMOD},
    {207, LYE_UNMOD},
    {208, LYE_UNMOD},
    {209, LYE_UNMOD},
    {210, LYE_UNMOD},
    {211, LYE_UNMOD},
    {212, LYE_UNMOD},
    {213, LYE_UNMOD},
    {214, LYE_UNMOD},
    {215, LYE_UNMOD},
    {216, LYE_UNMOD},
    {217, LYE_UNMOD},
    {218, LYE_UNMOD},
    {219, LYE_UNMOD},
    {220, LYE_UNMOD},
    {221, LYE_UNMOD},
    {222, LYE_UNMOD},
    {223, LYE_UNMOD},
    {224, LYE_UNMOD},
    {225, LYE_UNMOD},
    {226, LYE_UNMOD},
    {227, LYE_UNMOD},
    {228, LYE_UNMOD},
    {229, LYE_UNMOD},
    {230, LYE_UNMOD},
    {231, LYE_UNMOD},
    {232, LYE_UNMOD},
    {233, LYE_UNMOD},
    {234, LYE_UNMOD},
    {235, LYE_UNMOD},
    {236, LYE_UNMOD},
    {237, LYE_UNMOD},
    {238, LYE_UNMOD},
    {239, LYE_UNMOD},
    {240, LYE_UNMOD},
    {241, LYE_UNMOD},
    {242, LYE_UNMOD},
    {243, LYE_UNMOD},
    {244, LYE_UNMOD},
    {245, LYE_UNMOD},
    {246, LYE_UNMOD},
    {247, LYE_UNMOD},
    {248, LYE_UNMOD},
    {249, LYE_UNMOD},
    {250, LYE_UNMOD},
    {251, LYE_UNMOD},
    {252, LYE_UNMOD},
    {253, LYE_UNMOD},
    {254, LYE_UNMOD},
    {255, LYE_UNMOD},
    {UPARROW_KEY, LYE_UNMOD},
    {DNARROW_KEY, LYE_UNMOD},
    {RTARROW_KEY, LYE_UNMOD},
    {LTARROW_KEY, LYE_UNMOD},
    {PGDOWN_KEY, LYE_UNMOD},
    {PGUP_KEY, LYE_UNMOD},
    {HOME_KEY, LYE_FORM_PASS},
    {END_KEY, LYE_FORM_PASS},
    {F1_KEY, LYK_DWIMHELP | LYE_FORM_LAC},
    {DO_KEY, LYE_UNMOD},
#if (defined(_WINDOWS) || defined(__DJGPP__))
    {FIND_KEY, LYE_UNMOD},
    {SELECT_KEY, LYE_UNMOD},
#else
    {FIND_KEY, LYK_WHEREIS | LYE_FORM_LAC},
    {SELECT_KEY, LYK_NEXT | LYE_FORM_LAC},
#endif
    {INSERT_KEY, LYE_UNMOD},
    {DO_NOTHING, LYE_UNMOD},
    {BACKTAB_KEY, LYE_UNMOD},
#if (defined(_WINDOWS) || defined(__DJGPP__)) && defined(USE_SLANG) && !defined(DJGPP_KEYHANDLER)
    {272, LYE_DELPW},
#else
    {272, LYE_UNMOD},
#endif
    {273, LYE_UNMOD},
    {-1, LYE_UNKNOWN}
};

LYEditConfig LYModifierBindings[] =
{
    {"Modifier Binding", initMod1Binding, Mod1Binding},
};

#endif /* USE_ALT_BINDINGS */

static const LYEditInit initDefaultEditor[] =
{
    {CTL('A'), LYE_BOL},
    {CTL('B'), LYE_DELPW},
    {CTL('C'), LYE_ABORT},
    {CTL('D'), LYE_DELN},
    {CTL('E'), LYE_EOL},
    {CTL('F'), LYE_DELNW},
    {CTL('G'), LYE_ABORT},
    {CTL('H'), LYE_DELP},
    {CTL('I'), LYE_TAB},
    {CTL('J'), LYE_ENTER},
    {CTL('K'), LYE_LOWER},
    {CTL('M'), LYE_ENTER},
    {CTL('N'), LYE_FORWW},
    {CTL('O'), LYE_ABORT},
    {CTL('P'), LYE_BACKW},
    {CTL('R'), LYE_DELN},
    {CTL('T'), LYE_UPPER},
    {CTL('U'), LYE_ERASE},
    {CTL('V'), LYE_LKCMD},
#ifdef CAN_CUT_AND_PASTE
    {CTL('W'), LYE_PASTE},
#endif
    {CTL('X'), LYE_SETM1},
    {CTL('^'), LYE_SWMAP},
    {CTL('_'), LYE_DELEL},
    {' ', LYE_CHAR},
    {'!', LYE_CHAR},
    {'"', LYE_CHAR},
    {'#', LYE_CHAR},
    {'$', LYE_CHAR},
    {'%', LYE_CHAR},
    {'&', LYE_CHAR},
    {'\'', LYE_CHAR},
    {'(', LYE_CHAR},
    {')', LYE_CHAR},
    {'*', LYE_CHAR},
    {'+', LYE_CHAR},
    {',', LYE_CHAR},
    {'-', LYE_CHAR},
    {'.', LYE_CHAR},
    {'/', LYE_CHAR},
    {'0', LYE_CHAR},
    {'1', LYE_CHAR},
    {'2', LYE_CHAR},
    {'3', LYE_CHAR},
    {'4', LYE_CHAR},
    {'5', LYE_CHAR},
    {'6', LYE_CHAR},
    {'7', LYE_CHAR},
    {'8', LYE_CHAR},
    {'9', LYE_CHAR},
    {':', LYE_CHAR},
    {';', LYE_CHAR},
    {'<', LYE_CHAR},
    {'=', LYE_CHAR},
    {'>', LYE_CHAR},
    {'?', LYE_CHAR},
    {'@', LYE_CHAR},
    {'A', LYE_CHAR},
    {'B', LYE_CHAR},
    {'C', LYE_CHAR},
    {'D', LYE_CHAR},
    {'E', LYE_CHAR},
    {'F', LYE_CHAR},
    {'G', LYE_CHAR},
    {'H', LYE_CHAR},
    {'I', LYE_CHAR},
    {'J', LYE_CHAR},
    {'K', LYE_CHAR},
    {'L', LYE_CHAR},
    {'M', LYE_CHAR},
    {'N', LYE_CHAR},
    {'O', LYE_CHAR},
    {'P', LYE_CHAR},
    {'Q', LYE_CHAR},
    {'R', LYE_CHAR},
    {'S', LYE_CHAR},
    {'T', LYE_CHAR},
    {'U', LYE_CHAR},
    {'V', LYE_CHAR},
    {'W', LYE_CHAR},
    {'X', LYE_CHAR},
    {'Y', LYE_CHAR},
    {'Z', LYE_CHAR},
    {'[', LYE_CHAR},
    {'\\', LYE_CHAR},
    {']', LYE_CHAR},
    {'^', LYE_CHAR},
    {'_', LYE_CHAR},
    {'`', LYE_CHAR},
    {'a', LYE_CHAR},
    {'b', LYE_CHAR},
    {'c', LYE_CHAR},
    {'d', LYE_CHAR},
    {'e', LYE_CHAR},
    {'f', LYE_CHAR},
    {'g', LYE_CHAR},
    {'h', LYE_CHAR},
    {'i', LYE_CHAR},
    {'j', LYE_CHAR},
    {'k', LYE_CHAR},
    {'l', LYE_CHAR},
    {'m', LYE_CHAR},
    {'n', LYE_CHAR},
    {'o', LYE_CHAR},
    {'p', LYE_CHAR},
    {'q', LYE_CHAR},
    {'r', LYE_CHAR},
    {'s', LYE_CHAR},
    {'t', LYE_CHAR},
    {'u', LYE_CHAR},
    {'v', LYE_CHAR},
    {'w', LYE_CHAR},
    {'x', LYE_CHAR},
    {'y', LYE_CHAR},
    {'z', LYE_CHAR},
    {'{', LYE_CHAR},
    {'|', LYE_CHAR},
    {'}', LYE_CHAR},
    {'~', LYE_CHAR},
    {DEL_KEY, LYE_DELP},
    {128, LYE_CHAR},
    {129, LYE_CHAR},
    {130, LYE_CHAR},
    {131, LYE_CHAR},
    {132, LYE_CHAR},
    {133, LYE_CHAR},
    {134, LYE_CHAR},
    {135, LYE_CHAR},
    {136, LYE_CHAR},
    {137, LYE_CHAR},
    {138, LYE_CHAR},
    {139, LYE_CHAR},
    {140, LYE_CHAR},
    {141, LYE_CHAR},
#ifdef CJK_EX			/* 1997/11/03 (Mon) 20:30:54 */
    {142, LYE_CHAR},
#else
    {142, LYE_AIX},
#endif
    {143, LYE_CHAR},
    {144, LYE_CHAR},
    {145, LYE_CHAR},
    {146, LYE_CHAR},
    {147, LYE_CHAR},
    {148, LYE_CHAR},
    {149, LYE_CHAR},
    {150, LYE_CHAR},
    {151, LYE_CHAR},
    {152, LYE_CHAR},
    {153, LYE_CHAR},
    {154, LYE_CHAR},
    {155, LYE_CHAR},
    {156, LYE_CHAR},
    {157, LYE_CHAR},
    {158, LYE_CHAR},
    {159, LYE_CHAR},
    {160, LYE_CHAR},
    {161, LYE_CHAR},
    {162, LYE_CHAR},
    {163, LYE_CHAR},
    {164, LYE_CHAR},
    {165, LYE_CHAR},
    {166, LYE_CHAR},
    {167, LYE_CHAR},
    {168, LYE_CHAR},
    {169, LYE_CHAR},
    {170, LYE_CHAR},
    {171, LYE_CHAR},
    {172, LYE_CHAR},
    {173, LYE_CHAR},
    {174, LYE_CHAR},
    {175, LYE_CHAR},
    {176, LYE_CHAR},
    {177, LYE_CHAR},
    {178, LYE_CHAR},
    {179, LYE_CHAR},
    {180, LYE_CHAR},
    {181, LYE_CHAR},
    {182, LYE_CHAR},
    {183, LYE_CHAR},
    {184, LYE_CHAR},
    {185, LYE_CHAR},
    {186, LYE_CHAR},
    {187, LYE_CHAR},
    {188, LYE_CHAR},
    {189, LYE_CHAR},
    {190, LYE_CHAR},
    {191, LYE_CHAR},
    {192, LYE_CHAR},
    {193, LYE_CHAR},
    {194, LYE_CHAR},
    {195, LYE_CHAR},
    {196, LYE_CHAR},
    {197, LYE_CHAR},
    {198, LYE_CHAR},
    {199, LYE_CHAR},
    {200, LYE_CHAR},
    {201, LYE_CHAR},
    {202, LYE_CHAR},
    {203, LYE_CHAR},
    {204, LYE_CHAR},
    {205, LYE_CHAR},
    {206, LYE_CHAR},
    {207, LYE_CHAR},
    {208, LYE_CHAR},
    {209, LYE_CHAR},
    {210, LYE_CHAR},
    {211, LYE_CHAR},
    {212, LYE_CHAR},
    {213, LYE_CHAR},
    {214, LYE_CHAR},
    {215, LYE_CHAR},
    {216, LYE_CHAR},
    {217, LYE_CHAR},
    {218, LYE_CHAR},
    {219, LYE_CHAR},
    {220, LYE_CHAR},
    {221, LYE_CHAR},
    {222, LYE_CHAR},
    {223, LYE_CHAR},
    {224, LYE_CHAR},
    {225, LYE_CHAR},
    {226, LYE_CHAR},
    {227, LYE_CHAR},
    {228, LYE_CHAR},
    {229, LYE_CHAR},
    {230, LYE_CHAR},
    {231, LYE_CHAR},
    {232, LYE_CHAR},
    {233, LYE_CHAR},
    {234, LYE_CHAR},
    {235, LYE_CHAR},
    {236, LYE_CHAR},
    {237, LYE_CHAR},
    {238, LYE_CHAR},
    {239, LYE_CHAR},
    {240, LYE_CHAR},
    {241, LYE_CHAR},
    {242, LYE_CHAR},
    {243, LYE_CHAR},
    {244, LYE_CHAR},
    {245, LYE_CHAR},
    {246, LYE_CHAR},
    {247, LYE_CHAR},
    {248, LYE_CHAR},
    {249, LYE_CHAR},
    {250, LYE_CHAR},
    {251, LYE_CHAR},
    {252, LYE_CHAR},
    {253, LYE_CHAR},
    {254, LYE_CHAR},
    {255, LYE_CHAR},
    {UPARROW_KEY, LYE_FORM_PASS},
    {DNARROW_KEY, LYE_FORM_PASS},
    {RTARROW_KEY, LYE_FORW},
    {LTARROW_KEY, LYE_BACK},
    {PGDOWN_KEY, LYE_FORM_PASS},
    {PGUP_KEY, LYE_FORM_PASS},
    {HOME_KEY, LYE_BOL},
    {END_KEY, LYE_EOL},
    {F1_KEY, LYE_FORM_PASS},
#if !(defined(_WINDOWS) || defined(__DJGPP__))
    {DO_KEY, LYE_TAB},
    {FIND_KEY, LYE_BOL},
    {SELECT_KEY, LYE_EOL},
#endif
    {REMOVE_KEY, LYE_DELP},
    {BACKTAB_KEY, LYE_FORM_PASS},
#if (defined(_WINDOWS) || defined(__DJGPP__)) && defined(USE_SLANG) && !defined(DJGPP_KEYHANDLER)
    {272, LYE_DELP},
    {273, LYE_ENTER},
#endif
    {-1, LYE_UNKNOWN}
};

#ifdef USE_ALT_BINDINGS
static const LYEditInit initBetterEditor[] =
{
    {CTL('A'), LYE_BOL},
    {CTL('B'), LYE_BACK},
    {CTL('C'), LYE_ABORT},
    {CTL('D'), LYE_DELN},
    {CTL('E'), LYE_EOL},
    {CTL('F'), LYE_FORW},
    {CTL('G'), LYE_ABORT},
    {CTL('H'), LYE_DELP},
    {CTL('I'), LYE_ENTER},
    {CTL('J'), LYE_ENTER},
    {CTL('K'), LYE_DELEL},
    {CTL('M'), LYE_ENTER},
    {CTL('N'), LYE_FORWW},
    {CTL('O'), LYE_ABORT},
    {CTL('P'), LYE_BACKW},
    {CTL('R'), LYE_DELPW},
    {CTL('T'), LYE_DELNW},
    {CTL('U'), LYE_ERASE},
    {CTL('V'), LYE_LKCMD},
#ifdef CAN_CUT_AND_PASTE
    {CTL('W'), LYE_PASTE},
#endif
    {CTL('X'), LYE_SETM1},
    {CTL('^'), LYE_UPPER},
    {CTL('_'), LYE_LOWER},
    {' ', LYE_CHAR},
    {'!', LYE_CHAR},
    {'"', LYE_CHAR},
    {'#', LYE_CHAR},
    {'$', LYE_CHAR},
    {'%', LYE_CHAR},
    {'&', LYE_CHAR},
    {'\'', LYE_CHAR},
    {'(', LYE_CHAR},
    {')', LYE_CHAR},
    {'*', LYE_CHAR},
    {'+', LYE_CHAR},
    {',', LYE_CHAR},
    {'-', LYE_CHAR},
    {'.', LYE_CHAR},
    {'/', LYE_CHAR},
    {'0', LYE_CHAR},
    {'1', LYE_CHAR},
    {'2', LYE_CHAR},
    {'3', LYE_CHAR},
    {'4', LYE_CHAR},
    {'5', LYE_CHAR},
    {'6', LYE_CHAR},
    {'7', LYE_CHAR},
    {'8', LYE_CHAR},
    {'9', LYE_CHAR},
    {':', LYE_CHAR},
    {';', LYE_CHAR},
    {'<', LYE_CHAR},
    {'=', LYE_CHAR},
    {'>', LYE_CHAR},
    {'?', LYE_CHAR},
    {'@', LYE_CHAR},
    {'A', LYE_CHAR},
    {'B', LYE_CHAR},
    {'C', LYE_CHAR},
    {'D', LYE_CHAR},
    {'E', LYE_CHAR},
    {'F', LYE_CHAR},
    {'G', LYE_CHAR},
    {'H', LYE_CHAR},
    {'I', LYE_CHAR},
    {'J', LYE_CHAR},
    {'K', LYE_CHAR},
    {'L', LYE_CHAR},
    {'M', LYE_CHAR},
    {'N', LYE_CHAR},
    {'O', LYE_CHAR},
    {'P', LYE_CHAR},
    {'Q', LYE_CHAR},
    {'R', LYE_CHAR},
    {'S', LYE_CHAR},
    {'T', LYE_CHAR},
    {'U', LYE_CHAR},
    {'V', LYE_CHAR},
    {'W', LYE_CHAR},
    {'X', LYE_CHAR},
    {'Y', LYE_CHAR},
    {'Z', LYE_CHAR},
    {'[', LYE_CHAR},
    {'\\', LYE_CHAR},
    {']', LYE_CHAR},
    {'^', LYE_CHAR},
    {'_', LYE_CHAR},
    {'`', LYE_CHAR},
    {'a', LYE_CHAR},
    {'b', LYE_CHAR},
    {'c', LYE_CHAR},
    {'d', LYE_CHAR},
    {'e', LYE_CHAR},
    {'f', LYE_CHAR},
    {'g', LYE_CHAR},
    {'h', LYE_CHAR},
    {'i', LYE_CHAR},
    {'j', LYE_CHAR},
    {'k', LYE_CHAR},
    {'l', LYE_CHAR},
    {'m', LYE_CHAR},
    {'n', LYE_CHAR},
    {'o', LYE_CHAR},
    {'p', LYE_CHAR},
    {'q', LYE_CHAR},
    {'r', LYE_CHAR},
    {'s', LYE_CHAR},
    {'t', LYE_CHAR},
    {'u', LYE_CHAR},
    {'v', LYE_CHAR},
    {'w', LYE_CHAR},
    {'x', LYE_CHAR},
    {'y', LYE_CHAR},
    {'z', LYE_CHAR},
    {'{', LYE_CHAR},
    {'|', LYE_CHAR},
    {'}', LYE_CHAR},
    {'~', LYE_CHAR},
    {DEL_KEY, LYE_DELP},
    {128, LYE_CHAR},
    {129, LYE_CHAR},
    {130, LYE_CHAR},
    {131, LYE_CHAR},
    {132, LYE_CHAR},
    {133, LYE_CHAR},
    {134, LYE_CHAR},
    {135, LYE_CHAR},
    {136, LYE_CHAR},
    {137, LYE_CHAR},
    {138, LYE_CHAR},
    {139, LYE_CHAR},
    {140, LYE_CHAR},
    {141, LYE_CHAR},
#ifdef CJK_EX			/* 1997/11/03 (Mon) 20:30:54 */
    {142, LYE_CHAR},
#else
    {142, LYE_AIX},
#endif
    {143, LYE_CHAR},
    {144, LYE_CHAR},
    {145, LYE_CHAR},
    {146, LYE_CHAR},
    {147, LYE_CHAR},
    {148, LYE_CHAR},
    {149, LYE_CHAR},
    {150, LYE_CHAR},
    {151, LYE_CHAR},
    {152, LYE_CHAR},
    {153, LYE_CHAR},
    {154, LYE_CHAR},
    {155, LYE_CHAR},
    {156, LYE_CHAR},
    {157, LYE_CHAR},
    {158, LYE_CHAR},
    {159, LYE_CHAR},
    {160, LYE_CHAR},
    {161, LYE_CHAR},
    {162, LYE_CHAR},
    {163, LYE_CHAR},
    {164, LYE_CHAR},
    {165, LYE_CHAR},
    {166, LYE_CHAR},
    {167, LYE_CHAR},
    {168, LYE_CHAR},
    {169, LYE_CHAR},
    {170, LYE_CHAR},
    {171, LYE_CHAR},
    {172, LYE_CHAR},
    {173, LYE_CHAR},
    {174, LYE_CHAR},
    {175, LYE_CHAR},
    {176, LYE_CHAR},
    {177, LYE_CHAR},
    {178, LYE_CHAR},
    {179, LYE_CHAR},
    {180, LYE_CHAR},
    {181, LYE_CHAR},
    {182, LYE_CHAR},
    {183, LYE_CHAR},
    {184, LYE_CHAR},
    {185, LYE_CHAR},
    {186, LYE_CHAR},
    {187, LYE_CHAR},
    {188, LYE_CHAR},
    {189, LYE_CHAR},
    {190, LYE_CHAR},
    {191, LYE_CHAR},
    {192, LYE_CHAR},
    {193, LYE_CHAR},
    {194, LYE_CHAR},
    {195, LYE_CHAR},
    {196, LYE_CHAR},
    {197, LYE_CHAR},
    {198, LYE_CHAR},
    {199, LYE_CHAR},
    {200, LYE_CHAR},
    {201, LYE_CHAR},
    {202, LYE_CHAR},
    {203, LYE_CHAR},
    {204, LYE_CHAR},
    {205, LYE_CHAR},
    {206, LYE_CHAR},
    {207, LYE_CHAR},
    {208, LYE_CHAR},
    {209, LYE_CHAR},
    {210, LYE_CHAR},
    {211, LYE_CHAR},
    {212, LYE_CHAR},
    {213, LYE_CHAR},
    {214, LYE_CHAR},
    {215, LYE_CHAR},
    {216, LYE_CHAR},
    {217, LYE_CHAR},
    {218, LYE_CHAR},
    {219, LYE_CHAR},
    {220, LYE_CHAR},
    {221, LYE_CHAR},
    {222, LYE_CHAR},
    {223, LYE_CHAR},
    {224, LYE_CHAR},
    {225, LYE_CHAR},
    {226, LYE_CHAR},
    {227, LYE_CHAR},
    {228, LYE_CHAR},
    {229, LYE_CHAR},
    {230, LYE_CHAR},
    {231, LYE_CHAR},
    {232, LYE_CHAR},
    {233, LYE_CHAR},
    {234, LYE_CHAR},
    {235, LYE_CHAR},
    {236, LYE_CHAR},
    {237, LYE_CHAR},
    {238, LYE_CHAR},
    {239, LYE_CHAR},
    {240, LYE_CHAR},
    {241, LYE_CHAR},
    {242, LYE_CHAR},
    {243, LYE_CHAR},
    {244, LYE_CHAR},
    {245, LYE_CHAR},
    {246, LYE_CHAR},
    {247, LYE_CHAR},
    {248, LYE_CHAR},
    {249, LYE_CHAR},
    {250, LYE_CHAR},
    {251, LYE_CHAR},
    {252, LYE_CHAR},
    {253, LYE_CHAR},
    {254, LYE_CHAR},
    {255, LYE_CHAR},
    {UPARROW_KEY, LYE_FORM_PASS},
    {DNARROW_KEY, LYE_FORM_PASS},
    {RTARROW_KEY, LYE_FORW},
    {LTARROW_KEY, LYE_BACK},
    {PGDOWN_KEY, LYE_FORM_PASS},
    {PGUP_KEY, LYE_FORM_PASS},
    {HOME_KEY, LYE_BOL},
    {END_KEY, LYE_EOL},
    {F1_KEY, LYE_FORM_PASS},
#if !(defined(_WINDOWS) || defined(__DJGPP__))
    {DO_KEY, LYE_TAB},
    {FIND_KEY, LYE_BOL},
    {SELECT_KEY, LYE_EOL},
#endif
    {REMOVE_KEY, LYE_DELP},
    {BACKTAB_KEY, LYE_FORM_PASS},
#if (defined(_WINDOWS) || defined(__DJGPP__)) && defined(USE_SLANG) && !defined(DJGPP_KEYHANDLER)
    {272, LYE_DELP},
    {273, LYE_ENTER},
#endif
    {-1, LYE_UNKNOWN}
};

static const LYEditInit initBashlikeEditor[] =
{
    {CTL('@'), LYE_SETMARK},
    {CTL('A'), LYE_BOL},
    {CTL('B'), LYE_BACK},
    {CTL('C'), LYE_ABORT},
    {CTL('D'), LYE_DELN},
    {CTL('E'), LYE_EOL | LYE_DF},
    {CTL('F'), LYE_FORW},
    {CTL('G'), LYE_ABORT},
    {CTL('H'), LYE_DELP},
    {CTL('I'), LYE_TAB},
    {CTL('J'), LYE_ENTER},
    {CTL('K'), LYE_DELEL | LYE_DF},
    {CTL('L'), LYE_FORM_PASS},
    {CTL('M'), LYE_ENTER},
    {CTL('N'), LYE_FORM_PASS},
    {CTL('O'), LYE_FORM_PASS},
    {CTL('P'), LYE_FORM_PASS},
    {CTL('R'), LYE_BACKW},
    {CTL('S'), LYE_FORWW},
    {CTL('T'), LYE_TPOS},
    {CTL('U'), LYE_DELBL},
    {CTL('V'), LYE_LKCMD},
    {CTL('W'), LYE_DELPW},
    {CTL('X'), LYE_SETM1},
    {CTL('Y'), LYE_YANK},
    {CTL('Z'), LYE_FORM_PASS},
    {CTL('['), LYE_SETM2},
    {CTL('\\'), LYE_FORM_PASS},
    {CTL(']'), LYE_FORM_PASS},
    {CTL('^'), LYE_SWMAP},
    {CTL('_'), LYE_ABORT},
    {' ', LYE_CHAR},
    {'!', LYE_CHAR},
    {'"', LYE_CHAR},
    {'#', LYE_CHAR},
    {'$', LYE_CHAR},
    {'%', LYE_CHAR},
    {'&', LYE_CHAR},
    {'\'', LYE_CHAR},
    {'(', LYE_CHAR},
    {')', LYE_CHAR},
    {'*', LYE_CHAR},
    {'+', LYE_CHAR},
    {',', LYE_CHAR},
    {'-', LYE_CHAR},
    {'.', LYE_CHAR},
    {'/', LYE_CHAR},
    {'0', LYE_CHAR},
    {'1', LYE_CHAR},
    {'2', LYE_CHAR},
    {'3', LYE_CHAR},
    {'4', LYE_CHAR},
    {'5', LYE_CHAR},
    {'6', LYE_CHAR},
    {'7', LYE_CHAR},
    {'8', LYE_CHAR},
    {'9', LYE_CHAR},
    {':', LYE_CHAR},
    {';', LYE_CHAR},
    {'<', LYE_CHAR},
    {'=', LYE_CHAR},
    {'>', LYE_CHAR},
    {'?', LYE_CHAR},
    {'@', LYE_CHAR},
    {'A', LYE_CHAR},
    {'B', LYE_CHAR},
    {'C', LYE_CHAR},
    {'D', LYE_CHAR},
    {'E', LYE_CHAR},
    {'F', LYE_CHAR},
    {'G', LYE_CHAR},
    {'H', LYE_CHAR},
    {'I', LYE_CHAR},
    {'J', LYE_CHAR},
    {'K', LYE_CHAR},
    {'L', LYE_CHAR},
    {'M', LYE_CHAR},
    {'N', LYE_CHAR},
    {'O', LYE_CHAR},
    {'P', LYE_CHAR},
    {'Q', LYE_CHAR},
    {'R', LYE_CHAR},
    {'S', LYE_CHAR},
    {'T', LYE_CHAR},
    {'U', LYE_CHAR},
    {'V', LYE_CHAR},
    {'W', LYE_CHAR},
    {'X', LYE_CHAR},
    {'Y', LYE_CHAR},
    {'Z', LYE_CHAR},
    {'[', LYE_CHAR},
    {'\\', LYE_CHAR},
    {']', LYE_CHAR},
    {'^', LYE_CHAR},
    {'_', LYE_CHAR},
    {'`', LYE_CHAR},
    {'a', LYE_CHAR},
    {'b', LYE_CHAR},
    {'c', LYE_CHAR},
    {'d', LYE_CHAR},
    {'e', LYE_CHAR},
    {'f', LYE_CHAR},
    {'g', LYE_CHAR},
    {'h', LYE_CHAR},
    {'i', LYE_CHAR},
    {'j', LYE_CHAR},
    {'k', LYE_CHAR},
    {'l', LYE_CHAR},
    {'m', LYE_CHAR},
    {'n', LYE_CHAR},
    {'o', LYE_CHAR},
    {'p', LYE_CHAR},
    {'q', LYE_CHAR},
    {'r', LYE_CHAR},
    {'s', LYE_CHAR},
    {'t', LYE_CHAR},
    {'u', LYE_CHAR},
    {'v', LYE_CHAR},
    {'w', LYE_CHAR},
    {'x', LYE_CHAR},
    {'y', LYE_CHAR},
    {'z', LYE_CHAR},
    {'{', LYE_CHAR},
    {'|', LYE_CHAR},
    {'}', LYE_CHAR},
    {'~', LYE_CHAR},
    {DEL_KEY, LYE_DELP},
    {128, LYE_CHAR},
    {129, LYE_CHAR},
    {130, LYE_CHAR},
    {131, LYE_CHAR},
    {132, LYE_CHAR},
    {133, LYE_CHAR},
    {134, LYE_CHAR},
    {135, LYE_CHAR},
    {136, LYE_CHAR},
    {137, LYE_CHAR},
    {138, LYE_CHAR},
    {139, LYE_CHAR},
    {140, LYE_CHAR},
    {141, LYE_CHAR},
    {142, LYE_CHAR},
    {143, LYE_CHAR},
    {144, LYE_CHAR},
    {145, LYE_CHAR},
    {146, LYE_CHAR},
    {147, LYE_CHAR},
    {148, LYE_CHAR},
    {149, LYE_CHAR},
    {150, LYE_CHAR},
    {151, LYE_AIX},
    {152, LYE_CHAR},
    {153, LYE_CHAR},
    {154, LYE_CHAR},
    {155, LYE_CHAR},
    {156, LYE_CHAR},
    {157, LYE_CHAR},
    {158, LYE_CHAR},
    {159, LYE_CHAR},
    {160, LYE_CHAR},
    {161, LYE_CHAR},
    {162, LYE_CHAR},
    {163, LYE_CHAR},
    {164, LYE_CHAR},
    {165, LYE_CHAR},
    {166, LYE_CHAR},
    {167, LYE_CHAR},
    {168, LYE_CHAR},
    {169, LYE_CHAR},
    {170, LYE_CHAR},
    {171, LYE_CHAR},
    {172, LYE_CHAR},
    {173, LYE_CHAR},
    {174, LYE_CHAR},
    {175, LYE_CHAR},
    {176, LYE_CHAR},
    {177, LYE_CHAR},
    {178, LYE_CHAR},
    {179, LYE_CHAR},
    {180, LYE_CHAR},
    {181, LYE_CHAR},
    {182, LYE_CHAR},
    {183, LYE_CHAR},
    {184, LYE_CHAR},
    {185, LYE_CHAR},
    {186, LYE_CHAR},
    {187, LYE_CHAR},
    {188, LYE_CHAR},
    {189, LYE_CHAR},
    {190, LYE_CHAR},
    {191, LYE_CHAR},
    {192, LYE_CHAR},
    {193, LYE_CHAR},
    {194, LYE_CHAR},
    {195, LYE_CHAR},
    {196, LYE_CHAR},
    {197, LYE_CHAR},
    {198, LYE_CHAR},
    {199, LYE_CHAR},
    {200, LYE_CHAR},
    {201, LYE_CHAR},
    {202, LYE_CHAR},
    {203, LYE_CHAR},
    {204, LYE_CHAR},
    {205, LYE_CHAR},
    {206, LYE_CHAR},
    {207, LYE_CHAR},
    {208, LYE_CHAR},
    {209, LYE_CHAR},
    {210, LYE_CHAR},
    {211, LYE_CHAR},
    {212, LYE_CHAR},
    {213, LYE_CHAR},
    {214, LYE_CHAR},
    {215, LYE_CHAR},
    {216, LYE_CHAR},
    {217, LYE_CHAR},
    {218, LYE_CHAR},
    {219, LYE_CHAR},
    {220, LYE_CHAR},
    {221, LYE_CHAR},
    {222, LYE_CHAR},
    {223, LYE_CHAR},
    {224, LYE_CHAR},
    {225, LYE_CHAR},
    {226, LYE_CHAR},
    {227, LYE_CHAR},
    {228, LYE_CHAR},
    {229, LYE_CHAR},
    {230, LYE_CHAR},
    {231, LYE_CHAR},
    {232, LYE_CHAR},
    {233, LYE_CHAR},
    {234, LYE_CHAR},
    {235, LYE_CHAR},
    {236, LYE_CHAR},
    {237, LYE_CHAR},
    {238, LYE_CHAR},
    {239, LYE_CHAR},
    {240, LYE_CHAR},
    {241, LYE_CHAR},
    {242, LYE_CHAR},
    {243, LYE_CHAR},
    {244, LYE_CHAR},
    {245, LYE_CHAR},
    {246, LYE_CHAR},
    {247, LYE_CHAR},
    {248, LYE_CHAR},
    {249, LYE_CHAR},
    {250, LYE_CHAR},
    {251, LYE_CHAR},
    {252, LYE_CHAR},
    {253, LYE_CHAR},
    {254, LYE_CHAR},
    {255, LYE_CHAR},
    {UPARROW_KEY, LYE_FORM_PASS},
    {DNARROW_KEY, LYE_FORM_PASS},
    {RTARROW_KEY, LYE_FORW},
    {LTARROW_KEY, LYE_BACK},
    {PGDOWN_KEY, LYE_FORM_PASS},
    {PGUP_KEY, LYE_FORM_PASS},
    {HOME_KEY, LYE_BOL},
    {END_KEY, LYE_EOL},
    {F1_KEY, LYE_FORM_PASS},
#if !(defined(_WINDOWS) || defined(__DJGPP__))
    {DO_KEY, LYE_TAB},
    {FIND_KEY, LYE_BOL},
    {SELECT_KEY, LYE_EOL},
#endif
    {REMOVE_KEY, LYE_DELN},
    {BACKTAB_KEY, LYE_FORM_PASS},
#if (defined(_WINDOWS) || defined(__DJGPP__)) && defined(USE_SLANG) && !defined(DJGPP_KEYHANDLER)
    {272, LYE_DELP},
    {273, LYE_ENTER},
#endif
    {-1, LYE_UNKNOWN}
};
#endif /* USE_ALT_BINDINGS */

LYEditConfig LYLineEditors[] =
{
    {"Default Binding", initDefaultEditor, DefaultEditBinding},
#ifdef USE_ALT_BINDINGS
    {"Alternate Bindings", initBetterEditor, BetterEditBinding},
    {"Bash-like Bindings", initBashlikeEditor, BashlikeEditBinding},
#endif
};

const char *LYEditorNames[TABLESIZE(LYLineEditors) + 1];

/*
 * Add the URL (relative to helpfilepath) used for context-dependent
 * help on form field editing.
 *
 * The order must correspond to that of LYLineditNames.
 */
const char *LYLineeditHelpURLs[] =
{
    EDIT_HELP,
#ifdef USE_ALT_BINDINGS
    ALT_EDIT_HELP,
    BASHLIKE_EDIT_HELP,
#endif
    (char *) 0
};

static struct emap *name2emap(const char *name)
{
    struct emap *mp;
    struct emap *result = 0;

    if (non_empty(name)) {
	for (mp = ekmap; mp->name != NULL; mp++) {
	    if (strcasecomp(mp->name, name) == 0) {
		result = mp;
		break;
	    }
	}
    }
    return result;
}

static struct emap *code2emap(int code)
{
    struct emap *mp;
    struct emap *result = 0;

    for (mp = ekmap; mp->name != NULL; mp++) {
	if (mp->code == code) {
	    result = mp;
	    break;
	}
    }
    return result;
}

/*
 * Return editactioncode whose name is the string func.  func must be present
 * in the ekmap table.  returns -1 if not found.  - kw
 */
int lecname_to_lec(const char *func)
{
    struct emap *mp;
    int result = -1;

    if ((mp = name2emap(func)) != 0) {
	result = mp->code;
    }
    return result;
}

const char *lec_to_lecname(int code)
{
    struct emap *mp;
    const char *result = 0;

    if ((mp = code2emap(code)) != 0) {
	result = mp->name;
    }
    return result;
}

int EditBinding(int xlkc)
{
    int editaction, xleac = LYE_UNMOD;
    int c = xlkc & LKC_MASK;

    if (xlkc == -1)
	return LYE_NOP;		/* maybe LYE_ABORT? or LYE_FORM_LAC|LYK_UNKNOWN? */
#ifdef NOT_ASCII
    if (c < 256) {
	c = TOASCII(c);
    }
#endif
#ifdef USE_ALT_BINDINGS
    /*
     * Get intermediate code from one of the lynxkeycode+modifier tables if
     * applicable, otherwise get the lynxeditactioncode directly.  If we have
     * more than one modifier bits, the first currently wins.  - kw
     */
    if (xlkc & LKC_ISLECLAC) {
	return LKC2_TO_LEC(xlkc);
    } else if (xlkc & LKC_MOD1) {
	xleac = LKC_TO_LEC_M1(c);
    } else if (xlkc & LKC_MOD2) {
	xleac = LKC_TO_LEC_M2(c);
    } else if (xlkc & LKC_MOD3) {
	xleac = LKC_TO_LEC_M3(c);
    } else {
	xleac = UCH(CurrentLineEditor()[c]);
    }
#endif
    /*
     * If we have an intermediate code that says "same as without modifier",
     * look that up now; otherwise we are already done.  - kw
     */
    if (xleac == LYE_UNMOD) {
	editaction = CurrentLineEditor()[c];
    } else {
	editaction = xleac;
    }
    return editaction;
}

/*
 * Install lec as the lynxeditaction for lynxkeycode xlkc.  func must be
 * present in the revmap table.  For normal (non-modifier) lynxkeycodes,
 * select_edi selects which of the alternative line-editor binding tables is
 * modified.  If select_edi is positive, only the table given by it is modified
 * (the DefaultEditBinding table is numbered 1).  If select_edi is 0, all
 * tables are modified.  If select_edi is negative, all tables except the one
 * given by abs(select_edi) are modified.  returns TRUE if the mapping was
 * made, FALSE if not.  Note that this remapping cannot be undone (as might be
 * desirable as a result of re-parsing lynx.cfg), we don't remember the
 * original editaction from the Bindings tables anywhere.  - kw
 */
BOOL LYRemapEditBinding(int xlkc,
			int lec,
			int select_edi)
{
    int j;
    int c = xlkc & LKC_MASK;
    BOOLEAN success = FALSE;

    if (xlkc >= 0 && !(xlkc & LKC_ISLAC) && (c < KEYMAP_SIZE)) {
	LYEditCode code = (LYEditCode) lec;

#ifdef USE_ALT_BINDINGS
	if (xlkc & LKC_MOD1) {
	    if (c <= LAST_MOD1_LKC) {
		Mod1Binding[c] = code;
		success = TRUE;
	    }
	} else if (xlkc & LKC_MOD2) {
	    if (c <= LAST_MOD2_LKC) {
		Mod2Binding[c] = code;
		success = TRUE;
	    }
	} else if (xlkc & LKC_MOD3) {
	    if (c <= LAST_MOD3_LKC) {
		Mod3Binding[c] = code;
		success = TRUE;
	    }
	} else
#endif /* USE_ALT_BINDINGS */
	{
#ifndef UCHAR_MAX
#define UCHAR_MAX 255
#endif
	    if ((unsigned int) lec <= UCHAR_MAX) {
		if (select_edi > 0) {
		    if ((unsigned int) select_edi < TABLESIZE(LYLineEditors)) {
			LYLineEditors[select_edi - 1].used[c] = code;
			success = TRUE;
		    }
		} else {
		    for (j = 0; j < (int) TABLESIZE(LYLineEditors); j++) {
			success = TRUE;
			if ((select_edi < 0) && ((j + 1 + select_edi) == 0))
			    continue;
			LYLineEditors[j].used[c] = code;
		    }
		}
	    }
	}
    }
    return success;
}

/*
 * Macro to walk through lkc-indexed tables up to imax, in the (ASCII) order
 *     97 - 122  ('a' - 'z'),
 *     32 -  96  (' ' - '`', includes 'A' - 'Z'),
 *    123 - 126  ('{' - '~'),
 *      0 -  31  (^@  - ^_),
 *    256 - imax,
 *    127 - 255
 */
#define NEXT_I(i,imax) ((i==122) ? 32 : (i==96) ? 123 : (i==126) ? 0 :\
			(i==31) ? 256 : (i==imax) ? 127 :\
			(i==255) ? (-1) :i+1)
#define FIRST_I 97

int LYKeyForEditAction(int lec)
{
    int editaction, i;

    for (i = FIRST_I; i >= 0; i = NEXT_I(i, KEYMAP_SIZE - 1)) {
	editaction = CurrentLineEditor()[i];
	if (editaction == lec) {
#ifdef NOT_ASCII
	    if (i < 256) {
		return FROMASCII(i);
	    } else
#endif
		return i;
	}
    }
    return (-1);
}

/*
 * Given a lynxactioncode, return a key (lynxkeycode) or sequence of two keys
 * that results in the given action while forms-editing.  The main keycode is
 * returned as function value, possibly with modifier bits set; in addition, if
 * applicable, a key that sets the required modifier flag is returned in
 * *pmodkey if (pmodkey!=NULL).  Non-lineediting bindings that would require
 * typing LYE_LKCMD (default ^V) to activate are not checked here, the caller
 * should do that separately if required.  If no key is bound by current
 * line-editor bindings to the action, -1 is returned.
 *
 * This is all a bit long - it is general enough to continue to work should the
 * three Mod<N>Binding[] become different tables.  - kw
 */
int LYEditKeyForAction(int lac,
		       int *pmodkey)
{
    int editaction, i, c;
    int mod1found = -1, mod2found = -1, mod3found = -1;

    if (pmodkey)
	*pmodkey = -1;
    for (i = FIRST_I; i >= 0; i = NEXT_I(i, KEYMAP_SIZE - 1)) {
	editaction = CurrentLineEditor()[i];
#ifdef NOT_ASCII
	if (i < 256) {
	    c = FROMASCII(i);
	} else
#endif
	    c = i;
	if (editaction == (lac | LYE_FORM_LAC))
	    return c;
	if (editaction == LYE_FORM_PASS) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
	    if (lynx_edit_mode && !no_dired_support && lac &&
		LKC_TO_LAC(key_override, c) == lac)
		return c;
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
	    if (LKC_TO_LAC(keymap, c) == lac)
		return c;
	}
	if (editaction == LYE_TAB) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
	    if (lynx_edit_mode && !no_dired_support && lac &&
		LKC_TO_LAC(key_override, '\t') == lac)
		return c;
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
	    if (LKC_TO_LAC(keymap, '\t') == lac)
		return c;
	}
	if (editaction == LYE_SETM1 && mod1found < 0)
	    mod1found = i;
	if (editaction == LYE_SETM2 && mod2found < 0)
	    mod2found = i;
	if ((editaction & LYE_DF) && mod3found < 0)
	    mod3found = i;
    }
#ifdef USE_ALT_BINDINGS
    if (mod3found >= 0) {
	for (i = mod3found; i >= 0; i = NEXT_I(i, LAST_MOD3_LKC)) {
	    editaction = CurrentLineEditor()[i];
	    if (!(editaction & LYE_DF))
		continue;
	    editaction = Mod3Binding[i];
#ifdef NOT_ASCII
	    if (i < 256) {
		c = FROMASCII(i);
	    } else
#endif
		c = i;
	    if (pmodkey)
		*pmodkey = c;
	    if (editaction == (lac | LYE_FORM_LAC))
		return (c | LKC_MOD3);
	    if (editaction == LYE_FORM_PASS) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, c) == lac)
		    return (c | LKC_MOD3);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, c) == lac)
		    return (c | LKC_MOD3);
	    }
	    if (editaction == LYE_TAB) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, '\t') == lac)
		    return (c | LKC_MOD3);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, '\t') == lac)
		    return (c | LKC_MOD3);
	    }
	}
    }
    if (mod1found >= 0) {
	if (pmodkey) {
#ifdef NOT_ASCII
	    if (mod1found < 256) {
		*pmodkey = FROMASCII(mod1found);
	    } else
#endif
		*pmodkey = mod1found;
	}
	for (i = FIRST_I; i >= 0; i = NEXT_I(i, LAST_MOD1_LKC)) {
	    editaction = Mod1Binding[i];
#ifdef NOT_ASCII
	    if (i < 256) {
		c = FROMASCII(i);
	    } else
#endif
		c = i;
	    if (editaction == (lac | LYE_FORM_LAC))
		return (c | LKC_MOD1);
	    if (editaction == LYE_FORM_PASS) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, c) == lac)
		    return (c | LKC_MOD1);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, c) == lac)
		    return (c | LKC_MOD1);
	    }
	    if (editaction == LYE_TAB) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, '\t') == lac)
		    return (c | LKC_MOD1);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, '\t') == lac)
		    return (c | LKC_MOD1);
	    }
	}
    }
    if (mod2found >= 0) {
	if (pmodkey) {
#ifdef NOT_ASCII
	    if (mod1found < 256) {
		*pmodkey = FROMASCII(mod1found);
	    } else
#endif
		*pmodkey = mod1found;
	}
	for (i = FIRST_I; i >= 0; i = NEXT_I(i, LAST_MOD2_LKC)) {
	    editaction = Mod2Binding[i];
#ifdef NOT_ASCII
	    if (i < 256) {
		c = FROMASCII(i);
	    } else
#endif
		c = i;
	    if (editaction == (lac | LYE_FORM_LAC))
		return (c | LKC_MOD2);
	    if (editaction == LYE_FORM_PASS) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, c) == lac)
		    return (c | LKC_MOD2);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, c) == lac)
		    return (c | LKC_MOD2);
	    }
	    if (editaction == LYE_TAB) {
#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
		if (lynx_edit_mode && !no_dired_support && lac &&
		    LKC_TO_LAC(key_override, '\t') == lac)
		    return (c | LKC_MOD2);
#endif /* DIRED_SUPPORT && OK_OVERRIDE */
		if (LKC_TO_LAC(keymap, '\t') == lac)
		    return (c | LKC_MOD2);
	    }
	}
    }
#endif /* USE_ALT_BINDINGS */
    if (pmodkey)
	*pmodkey = -1;
    return (-1);
}

#if 0
/*
 * This function was useful in converting the hand-crafted key-bindings to
 * their reusable form in 2.8.8 -TD
 */
static void checkEditMap(LYEditConfig * table)
{
    unsigned j, k;
    char comment[80];
    int first = TRUE;

    for (j = 0; table->init[j].code >= 0; ++j) {
	int code = table->init[j].code;

	if (table->init[j].edit != table->used[code]) {
	    if (first) {
		printf("TABLE %s\n", table->name);
		first = FALSE;
	    }
	    printf("%u: init %d vs used %d\n",
		   j,
		   table->init[j].edit,
		   table->used[code]);
	}
    }
    for (j = 0; j < KEYMAP_SIZE; ++j) {
	int code = (int) j;
	BOOL found = FALSE;

	for (k = 0; table->init[k].code >= 0; ++k) {
	    if (code == table->init[k].code) {
		found = TRUE;
		break;
	    }
	}
	if (!found) {
	    if (table->used[j] != 0) {
		int edit = table->used[j];
		int has_DF = (edit & LYE_DF);
		int has_LAC = (edit & LYE_FORM_LAC);
		const char *prefix = "LYE_";
		const char *name = 0;

		edit &= 0x7f;
		if (has_LAC) {
		    Kcmd *cmd = LYKeycodeToKcmd(edit);

		    if (cmd != 0) {
			prefix = "LYK_";
			name = cmd->name;
		    }
		} else {
		    name = lec_to_lecname(edit);
		}

		if (j < 32) {
		    char temp[80];
		    const char *what = 0;

		    switch (j) {
		    case 0:
			what = "nul";
			break;
		    case 17:
			what = "XON";
			break;
		    case 19:
			what = "XOFF";
			break;
		    default:
			sprintf(temp, "^%c", j + 'A');
			what = temp;
			break;
		    }
		    sprintf(comment, "\t/* %s */", what);
		} else if (j < 127) {
		    sprintf(comment, "\t/* %c */", j);
		} else {
		    const char *what = LYextraKeysToName(j);

		    if (Non_Empty(what)) {
			sprintf(comment, "\t/* %s%s */", what,
				((StrChr(what, '_') != 0)
				 ? ""
				 : "_KEY"));
		    } else {
			strcpy(comment, "");
		    }
		}
		if (name == 0) {
		    name = "XXX";
		} else if (!strcasecomp(name, "PASS")) {
		    name = "FORM_PASS";
		}
		if (first) {
		    printf("TABLE %s\n", table->name);
		    first = FALSE;
		}
		printf("\t{ %d, %s%s%s%s },%s\n", code, prefix, name,
		       has_DF ? "|LYE_DF" : "",
		       has_LAC ? "|LYE_FORM_LAC" : "",
		       comment);
	    }
	}
    }
}

#else
#define checkEditMap(table)	/* nothing */
#endif

static void initLineEditor(LYEditConfig * table)
{
    unsigned k;
    LYEditCode *used = table->used;
    const LYEditInit *init = table->init;

    memset(used, 0, sizeof(LYEditCode) * KEYMAP_SIZE);
    for (k = 0; init[k].code >= 0; ++k) {
	int code = init[k].code;

	used[code] = init[k].edit;
    }
    checkEditMap(table);
}

/*
 * Reset the editor bindings to their default values.
 */
void LYinitEditmap(void)
{
    unsigned j;

    for (j = 0; j < TABLESIZE(LYLineEditors); ++j) {
	LYEditorNames[j] = LYLineEditors[j].name;
	initLineEditor(&LYLineEditors[j]);
    }
#ifdef USE_ALT_BINDINGS
    for (j = 0; j < TABLESIZE(LYModifierBindings); ++j) {
	initLineEditor(&LYModifierBindings[j]);
    }
#endif
}

static char *showRanges(int *state)
{
    char *result = 0;
    int range[2];
    int i;

    range[0] = range[1] = -1;
    for (i = 0; i < KEYMAP_SIZE; ++i) {
	if (!state[i]) {
	    int code = CurrentLineEditor()[i];

	    if (code == LYE_CHAR) {
		if (range[0] < 0)
		    range[0] = i;
		range[1] = i;
		state[i] = 3;
	    } else if (range[0] >= 0) {
		if (non_empty(result))
		    StrAllocCat(result, ", ");
		HTSprintf(&result, "%d-%d", range[0], range[1]);
		range[0] = range[1] = -1;
	    }
	}
    }
    return result;
}

static int LYLoadEditmap(const char *arg GCC_UNUSED,
			 HTParentAnchor *anAnchor,
			 HTFormat format_out,
			 HTStream *sink)
{
#define FORMAT "  %-*s  %-*s  -  %s\n"
    HTFormat format_in = WWW_HTML;
    HTStream *target;
    int state[KEYMAP_SIZE];
    int width[2];
    char *buf = 0;
    char *ranges = 0;
    struct emap *mp;
    int i;
    int hanging;
    int wrapped;
    int had_output = FALSE;
    int result;

    if ((target = HTStreamStack(format_in, format_out, sink, anAnchor)) != 0) {
	anAnchor->no_cache = TRUE;

	HTSprintf0(&buf,
		   "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
		   CURRENT_EDITMAP_TITLE);
	PUTS(buf);
	HTSprintf0(&buf, "<pre>\n");
	PUTS(buf);

	/* determine the column-widths we will use for showing bindings */
	width[0] = 0;
	width[1] = 0;
	for (i = 0; i < KEYMAP_SIZE; ++i) {
	    int code = CurrentLineEditor()[i];

	    if (code == LYE_NOP) {
		state[i] = 1;
	    } else {
		int need;

		if ((mp = code2emap(code)) != 0) {
		    state[i] = 0;
		    if ((need = (int) strlen(mp->name)) > width[0])
			width[0] = need;
		    if ((need = (int) strlen(mp->descr)) > width[1])
			width[1] = need;
		} else {
		    state[i] = 2;
		}
	    }
	}
	hanging = 2 + width[0] + 2 + width[1] + 5;
	wrapped = hanging;

	/*
	 * Tell which set of bindings we are showing, and link to the
	 * handcrafted page, which adds explanations.
	 */
	PUTS(gettext("These are the current edit-bindings:"));
	HTSprintf0(&buf,
		   " <a href=\"%s\">%s</a>\n\n",
		   LYLineeditHelpURL(),
		   LYEditorNames[current_lineedit]);
	PUTS(buf);

	/* Show by groups to match the arrangement in the handmade files. */
	for (mp = ekmap; mp->name != 0; ++mp) {
	    if (isEmpty(mp->name)) {
		if (had_output) {
		    PUTS("\n");
		    had_output = FALSE;
		}
	    } else if (mp->code == LYE_CHAR) {
		ranges = showRanges(state);
		HTSprintf0(&buf, FORMAT,
			   width[0], mp->name,
			   width[1], mp->descr,
			   ranges);
		FREE(ranges);
		PUTS(buf);
		had_output = TRUE;
	    } else {
		for (i = 0; i < KEYMAP_SIZE; ++i) {
		    int code = CurrentLineEditor()[i];

		    if ((code == mp->code) && !state[i]) {
			char *value = LYKeycodeToString(i, (i >= 160 &&
							    i <= 255));
			int before = wrapped + (ranges ? ((int)
							  strlen(ranges)) : 0);
			int after = before;

			if (non_empty(ranges)) {
			    StrAllocCat(ranges, ", ");
			    after += 2;
			}
			after += (int) strlen(value) + 2;
			if ((before / LYcols) != (after / LYcols)) {
			    wrapped += (LYcols - (before % LYcols));
			    HTSprintf(&ranges, "\n%-*s", hanging, " ");
			}
			StrAllocCat(ranges, value);
		    }
		}
		if (non_empty(ranges)) {
		    LYEntify(&ranges, TRUE);
		    HTSprintf0(&buf, FORMAT,
			       width[0], mp->name,
			       width[1], mp->descr,
			       ranges);
		    PUTS(buf);
		    FREE(ranges);
		    had_output = TRUE;
		}
	    }
	}

	HTSprintf0(&buf, "</pre>\n</body>\n</html>\n");
	PUTS(buf);

	(*target->isa->_free) (target);
	result = HT_LOADED;
    } else {
	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
		   HTAtom_name(format_in), HTAtom_name(format_out));
	HTAlert(buf);
	result = HT_NOT_LOADED;
    }
    FREE(ranges);
    FREE(buf);
    return result;
#undef FORMAT
}

#ifdef GLOBALDEF_IS_MACRO
#define _LYEDITMAP_C_GLOBALDEF_1_INIT { "LYNXEDITMAP", LYLoadEditmap, 0}
GLOBALDEF(HTProtocol, LYLynxEditmap, _LYEDITMAP_C_GLOBALDEF_1_INIT);
#else
GLOBALDEF HTProtocol LYLynxEditmap =
{
    "LYNXEDITMAP", LYLoadEditmap, 0
};
#endif /* GLOBALDEF_IS_MACRO */