home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / keymap.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  22KB  |  1,010 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Keyboard (re)mapping
  5.  */
  6.  
  7. #include "config.h"
  8. #include "keymap.h"
  9. #include "nn_term.h"
  10.  
  11. import int data_bits;
  12.  
  13. /*
  14.  * KEY MAP LAYOUT:
  15.  *    128 normal ASCII chars
  16.  *    0200 -- unused
  17.  *    4 arrow keys #up/down/left/right
  18.  *    10 multi keys #0-#9
  19.  *    17 spare keys
  20.  *    95 national 8-bit characters (8859/x)
  21.  *    0377 is unused (since we must be able to test c<KEY_MAP_SIZE)
  22.  *
  23.  *    The encoding of the keymap arrays are performed in
  24.  *    keymap.c (initialization + key_name/parse_key)
  25.  */
  26.  
  27. /* in keymap.h, MULTI_KEYS include ARROW_KEYS for term.c */
  28. #undef MULTI_KEYS
  29.  
  30. #define NORMAL_KEYS    129    /* include 0200 for convenience */
  31. #define ARROW_KEYS    4
  32. #define MULTI_KEYS    16
  33. #define SPARE_KEYS    11
  34. #define NATIONAL_KEYS    96
  35. #define KEY_MAP_SIZE    255
  36.  
  37. /*
  38.  * standard keyboard mapping for more()
  39.  *
  40.  *    redraw            ^L, ^R
  41.  *    continue        space
  42.  *    repeat message        ^P
  43.  *    help            ?
  44.  *    shell escape        !
  45.  *    version            V
  46.  *    extended command    :
  47.  *    quit            Q
  48.  *
  49.  *    save            S, O
  50.  *    save, no header        W
  51.  *    reply            R
  52.  *    follow up        F
  53.  *    mail (forward)        M
  54.  *    cancel            C
  55.  *    unsubscribe        U
  56.  *    group overview        Y
  57.  *    print article        P
  58.  *    kill handling        K
  59.  *
  60.  *    update, goto next group    X
  61.  *    no update, next group    q, Z
  62.  *    return to menu        =
  63.  *    prev article        p
  64.  *    goto group        G
  65.  *
  66.  *    line forward        CR/NL
  67.  *    half page forward    d/^D
  68.  *    half page back        u/^U
  69.  *    full page back        BS, DEL, (up arrow)
  70.  *    goto line        g
  71.  *    goto match        /
  72.  *    next match        .
  73.  *
  74.  *    select subject        N, *
  75.  *
  76.  *    header            h
  77.  *    digest header        H
  78.  *    top            t
  79.  *    last page        $
  80.  *    leave article        l
  81.  *    leave article to next    L
  82.  *    next article        n
  83.  *    kill subject        k
  84.  *
  85.  *    rot13            D
  86.  *    compress        c
  87.  */
  88.  
  89. export int more_key_map[KEY_MAP_SIZE] = {
  90.  
  91. /* NUL ^@ */    K_UNBOUND,
  92. /* SOH ^A */    K_UNBOUND,
  93. /* STX ^B */    K_UNBOUND,
  94. /* ETX ^C */    K_UNBOUND,
  95. /* EOT ^D */        K_NEXT_HALF_PAGE,
  96. /* ENQ ^E */    K_UNBOUND,
  97. /* ACK ^F */    K_UNBOUND,
  98. /* BEL ^G */        K_INVALID,
  99. /* BS  ^H */        K_PREV_PAGE,
  100. /* TAB ^I */        K_SKIP_LINES,
  101. /* NL  ^J */        K_NEXT_LINE,
  102. /* VT  ^K */    K_UNBOUND,
  103. /* FF  ^L */        K_REDRAW,
  104. /* CR  ^M */        K_NEXT_LINE,
  105. /* SO  ^N */    K_UNBOUND,
  106. /* SI  ^O */    K_UNBOUND,
  107. /* DLE ^P */        K_LAST_MESSAGE,
  108. /* DC1 ^Q */    K_UNBOUND,
  109. /* DC2 ^R */        K_REDRAW,
  110. /* DC3 ^S */    K_UNBOUND,
  111. /* DC4 ^T */    K_UNBOUND,
  112. /* NAK ^U */        K_PREV_HALF_PAGE,
  113. /* SYN ^V */        K_NEXT_PAGE,
  114. /* ETB ^W */    K_UNBOUND,
  115. /* CAN ^X */    K_UNBOUND,
  116. /* EM  ^Y */    K_UNBOUND,
  117. /* SUB ^Z */    K_UNBOUND,
  118. /* ESC ^[ */    K_UNBOUND,
  119. /* FS  ^\ */    K_UNBOUND,
  120. /* GS  ^] */    K_UNBOUND,
  121. /* RS  ^^ */    K_UNBOUND,
  122. /* US  ^_ */    K_UNBOUND,
  123. /* SP  */        K_CONTINUE,
  124. /* !   */        K_SHELL,
  125. /* "   */    K_UNBOUND,
  126. /* #   */    K_UNBOUND,
  127. /* $   */        K_LAST_PAGE,
  128. /* %   */        K_PREVIEW,
  129. /* &   */    K_UNBOUND,
  130. /* '   */    K_UNBOUND,
  131. /* (   */    K_UNBOUND,
  132. /* )   */    K_UNBOUND,
  133. /* *   */        K_SELECT_SUBJECT,
  134. /* +   */    K_UNBOUND,
  135. /* ,   */    K_UNBOUND,
  136. /* -   */    K_UNBOUND,
  137. /* .   */        K_NEXT_MATCH,
  138. /* /   */        K_GOTO_MATCH,
  139. /* 0   */    K_UNBOUND,
  140. /* 1   */    K_UNBOUND,
  141. /* 2   */    K_UNBOUND,
  142. /* 3   */    K_UNBOUND,
  143. /* 4   */    K_UNBOUND,
  144. /* 5   */    K_UNBOUND,
  145. /* 6   */    K_UNBOUND,
  146. /* 7   */    K_UNBOUND,
  147. /* 8   */    K_UNBOUND,
  148. /* 9   */    K_UNBOUND,
  149. /* :   */         K_EXTENDED_CMD,
  150. /* ;   */    K_UNBOUND,
  151. /* <   */    K_UNBOUND,
  152. /* =   */        K_BACK_TO_MENU,
  153. /* >   */    K_UNBOUND,
  154. /* ?   */        K_HELP,
  155. /* @   */    K_UNBOUND,
  156. /* A   */    K_UNBOUND,
  157. /* B   */    K_UNBOUND,
  158. /* C   */        K_CANCEL,
  159. /* D   */        K_ROT13,
  160. /* E   */    K_UNBOUND,
  161. /* F   */        K_FOLLOW_UP,
  162. /* G   */        K_GOTO_GROUP,
  163. /* H   */        K_FULL_DIGEST,
  164. /* I   */    K_UNBOUND,
  165. /* J   */    K_UNBOUND,
  166. /* K   */        K_KILL_HANDLING,
  167. /* L   */        K_LEAVE_NEXT,
  168. /* M   */        K_MAIL_OR_FORWARD,
  169. /* N   */        K_NEXT_GROUP_NO_UPDATE,
  170. /* O   */        K_SAVE_SHORT_HEADER,
  171. /* P   */        K_PRINT,
  172. /* Q   */         K_QUIT,
  173. /* R   */        K_REPLY,
  174. /* S   */        K_SAVE_FULL_HEADER,
  175. /* T   */    K_UNBOUND,
  176. /* U   */        K_UNSUBSCRIBE,
  177. /* V   */         K_VERSION,
  178. /* W   */        K_SAVE_NO_HEADER,
  179. /* X   */        K_READ_GROUP_UPDATE,
  180. /* Y   */        K_GROUP_OVERVIEW,
  181. /* Z   */        K_BACK_TO_MENU,
  182. /* [   */    K_UNBOUND,
  183. /* \   */    K_UNBOUND,
  184. /* ]   */    K_UNBOUND,
  185. /* ^   */        K_FIRST_PAGE,
  186. /* _   */    K_UNBOUND,
  187. /* `   */    K_UNBOUND,
  188. /* a   */        K_FORW_ARTICLE,
  189. /* b   */        K_BACK_ARTICLE,
  190. /* c   */        K_COMPRESS,
  191. /* d   */        K_NEXT_HALF_PAGE,
  192. /* e   */    K_UNBOUND,
  193. /* f   */        K_FOLLOW_UP,
  194. /* g   */        K_GOTO_LINE,
  195. /* h   */        K_HEADER_PAGE,
  196. /* i   */    K_UNBOUND,
  197. /* j   */    K_UNBOUND,
  198. /* k   */        K_NEXT_SUBJECT,
  199. /* l   */        K_LEAVE_ARTICLE,
  200. /* m   */        K_MAIL_OR_FORWARD,
  201. /* n   */        K_NEXT_ARTICLE,
  202. /* o   */        K_SAVE_SHORT_HEADER,
  203. /* p   */        K_PREVIOUS /* article */,
  204. /* q   */        K_NEXT_GROUP_NO_UPDATE,
  205. /* r   */        K_REPLY,
  206. /* s   */        K_SAVE_FULL_HEADER,
  207. /* t   */        K_FIRST_PAGE,
  208. /* u   */        K_PREV_HALF_PAGE,
  209. /* v   */    K_UNBOUND,
  210. /* w   */        K_SAVE_NO_HEADER,
  211. /* x   */    K_UNBOUND,
  212. /* y   */    K_UNBOUND,
  213. /* z   */    K_UNBOUND,
  214. /* {   */    K_UNBOUND,
  215. /* |   */    K_UNBOUND,
  216. /* }   */    K_UNBOUND,
  217. /* ~   */    K_UNBOUND,
  218. /* DEL */        K_PREV_PAGE,
  219. /* 200 */    K_UNBOUND,
  220. /* up  */        K_PREV_PAGE,
  221. /* down */        K_NEXT_PAGE,
  222. /* left */    K_UNBOUND,
  223. /* right */    K_UNBOUND,
  224. /* #0  */    K_UNBOUND,
  225. /* #1  */    K_UNBOUND,
  226. /* #2  */    K_UNBOUND,
  227. /* #3  */    K_UNBOUND,
  228. /* #4  */    K_UNBOUND,
  229. /* #5  */    K_UNBOUND,
  230. /* #6  */    K_UNBOUND,
  231. /* #7  */    K_UNBOUND,
  232. /* #8  */    K_UNBOUND,
  233. /* #9  */    K_UNBOUND,
  234. /* mouse d1 */   K_M_CONTINUE,
  235. /* mouse d2 */   K_NEXT_SUBJECT,
  236. /* mouse d3 */   K_BACK_TO_MENU,
  237. /* mouse u1 */   K_INVALID,
  238. /* mouse u2 */   K_INVALID,
  239. /* mouse u3 */   K_INVALID
  240. };
  241.  
  242.  
  243.  
  244. /*
  245.  * standard keyboard mappings for menu()
  246.  *
  247.  *    illegal command
  248.  *    redraw            ^L, ^R
  249.  *    continue        space
  250.  *    continue no mark    return, newline
  251.  *    repeat message        ^P
  252.  *    help            ?
  253.  *    shell escape        !
  254.  *    version            V
  255.  *    alternative commands    :
  256.  *    quit            Q
  257.  *
  258.  *    save            S, O
  259.  *    save, no header        W
  260.  *    reply            R
  261.  *    follow up        F
  262.  *    mail (forward)        M
  263.  *    cancel            C
  264.  *    unsubscribe        U
  265.  *    group overview        Y
  266.  *    kill handling        K
  267.  *    junk articles        J
  268.  *
  269.  *    read, then next        X
  270.  *    read, then same        Z
  271.  *    no update, next        N
  272.  *    prev group        P
  273.  *    goto group        G
  274.  *    advance group        A
  275.  *    back group        B
  276.  *
  277.  *    article identifier    a-z 0-9
  278.  *    inverse            @
  279.  *    select current, next    .
  280.  *    next            , (down arrow)
  281.  *    prev            / (up arrow)
  282.  *    select subject        *
  283.  *    range            -
  284.  *    auto select         +
  285.  *
  286.  *    next page        >
  287.  *    prev page        <
  288.  *    first page        ^
  289.  *    last page        $
  290.  *
  291.  *    pre-view article    %
  292.  *
  293.  *    layout            L
  294.  */
  295.  
  296.  
  297. export int menu_key_map[KEY_MAP_SIZE] = {
  298.  
  299. /* NUL ^@ */    K_UNBOUND,
  300. /* SOH ^A */    K_UNBOUND,
  301. /* STX ^B */    K_UNBOUND,
  302. /* ETX ^C */    K_UNBOUND,
  303. /* EOT ^D */    K_UNBOUND,
  304. /* ENQ ^E */    K_UNBOUND,
  305. /* ACK ^F */    K_UNBOUND,
  306. /* BEL ^G */        K_INVALID,
  307. /* BS  ^H */        K_PREV_LINE,
  308. /* TAB ^I */    K_UNBOUND,
  309. /* NL  ^J */        K_CONTINUE_NO_MARK,
  310. /* VT  ^K */    K_UNBOUND,
  311. /* FF  ^L */        K_REDRAW,
  312. /* CR  ^M */        K_CONTINUE_NO_MARK,
  313. /* SO  ^N */    K_UNBOUND,
  314. /* SI  ^O */    K_UNBOUND,
  315. /* DLE ^P */        K_LAST_MESSAGE,
  316. /* DC1 ^Q */    K_UNBOUND,
  317. /* DC2 ^R */        K_REDRAW,
  318. /* DC3 ^S */    K_UNBOUND,
  319. /* DC4 ^T */    K_UNBOUND,
  320. /* NAK ^U */    K_UNBOUND,
  321. /* SYN ^V */        K_NEXT_PAGE,
  322. /* ETB ^W */    K_UNBOUND,
  323. /* CAN ^X */    K_UNBOUND,
  324. /* EM  ^Y */    K_UNBOUND,
  325. /* SUB ^Z */    K_UNBOUND,
  326. /* ESC ^[ */    K_UNBOUND,
  327. /* FS  ^\ */    K_UNBOUND,
  328. /* GS  ^] */    K_UNBOUND,
  329. /* RS  ^^ */    K_UNBOUND,
  330. /* US  ^_ */    K_UNBOUND,
  331. /* SP  */        K_CONTINUE,
  332. /* !   */        K_SHELL,
  333. /* "   */        K_LAYOUT,
  334. /* #   */    K_UNBOUND,
  335. /* $   */        K_LAST_PAGE,
  336. /* %   */        K_PREVIEW,
  337. /* &   */    K_UNBOUND,
  338. /* '   */    K_UNBOUND,
  339. /* (   */        K_OPEN_SUBJECT,
  340. /* )   */        K_CLOSE_SUBJECT,
  341. /* *   */        K_SELECT_SUBJECT,
  342. /* +   */        K_AUTO_SELECT,
  343. /* ,   */        K_NEXT_LINE,
  344. /* -   */        K_SELECT_RANGE,
  345. /* .   */        K_SELECT,
  346. /* /   */        K_PREV_LINE,
  347. /* 0   */    K_ARTICLE_ID + 26,
  348. /* 1   */    K_ARTICLE_ID + 27,
  349. /* 2   */    K_ARTICLE_ID + 28,
  350. /* 3   */    K_ARTICLE_ID + 29,
  351. /* 4   */    K_ARTICLE_ID + 30,
  352. /* 5   */    K_ARTICLE_ID + 31,
  353. /* 6   */    K_ARTICLE_ID + 32,
  354. /* 7   */    K_ARTICLE_ID + 33,
  355. /* 8   */    K_ARTICLE_ID + 34,
  356. /* 9   */    K_ARTICLE_ID + 35,
  357. /* :   */        K_EXTENDED_CMD,
  358. /* ;   */    K_UNBOUND,
  359. /* <   */        K_PREV_PAGE,
  360. /* =   */        K_GOTO_MATCH,
  361. /* >   */        K_NEXT_PAGE,
  362. /* ?   */        K_HELP,
  363. /* @   */        K_SELECT_INVERT,
  364. /* A   */        K_ADVANCE_GROUP,
  365. /* B   */        K_BACK_GROUP,
  366. /* C   */        K_CANCEL,
  367. /* D   */    K_UNBOUND,
  368. /* E   */    K_UNBOUND,
  369. /* F   */        K_FOLLOW_UP,
  370. /* G   */        K_GOTO_GROUP,
  371. /* H   */    K_UNBOUND,
  372. /* I   */    K_UNBOUND,
  373. /* J   */        K_JUNK_ARTICLES,
  374. /* K   */        K_KILL_HANDLING,
  375. /* L   */        K_LEAVE_NEXT,
  376. /* M   */        K_MAIL_OR_FORWARD,
  377. /* N   */        K_NEXT_GROUP_NO_UPDATE,
  378. /* O   */        K_SAVE_SHORT_HEADER,
  379. /* P   */        K_PREVIOUS /* group */,
  380. /* Q   */        K_QUIT,
  381. /* R   */        K_REPLY,
  382. /* S   */        K_SAVE_FULL_HEADER,
  383. /* T   */    K_UNBOUND,
  384. /* U   */        K_UNSUBSCRIBE,
  385. /* V   */        K_VERSION,
  386. /* W   */        K_SAVE_NO_HEADER,
  387. /* X   */        K_READ_GROUP_UPDATE,
  388. /* Y   */        K_GROUP_OVERVIEW,
  389. /* Z   */        K_READ_GROUP_THEN_SAME,
  390. /* [   */    K_UNBOUND,
  391. /* \   */    K_UNBOUND,
  392. /* ]   */    K_UNBOUND,
  393. /* ^   */        K_FIRST_PAGE,
  394. /* _   */    K_UNBOUND,
  395. /* `   */    K_UNBOUND,
  396. /* a   */    K_ARTICLE_ID +  0,
  397. /* b   */    K_ARTICLE_ID +  1,
  398. /* c   */    K_ARTICLE_ID +  2,
  399. /* d   */    K_ARTICLE_ID +  3,
  400. /* e   */    K_ARTICLE_ID +  4,
  401. /* f   */    K_ARTICLE_ID +  5,
  402. /* g   */    K_ARTICLE_ID +  6,
  403. /* h   */    K_ARTICLE_ID +  7,
  404. /* i   */    K_ARTICLE_ID +  8,
  405. /* j   */    K_ARTICLE_ID +  9,
  406. /* k   */    K_ARTICLE_ID + 10,
  407. /* l   */    K_ARTICLE_ID + 11,
  408. /* m   */    K_ARTICLE_ID + 12,
  409. /* n   */    K_ARTICLE_ID + 13,
  410. /* o   */    K_ARTICLE_ID + 14,
  411. /* p   */    K_ARTICLE_ID + 15,
  412. /* q   */    K_ARTICLE_ID + 16,
  413. /* r   */    K_ARTICLE_ID + 17,
  414. /* s   */    K_ARTICLE_ID + 18,
  415. /* t   */    K_ARTICLE_ID + 19,
  416. /* u   */    K_ARTICLE_ID + 20,
  417. /* v   */    K_ARTICLE_ID + 21,
  418. /* w   */    K_ARTICLE_ID + 22,
  419. /* x   */    K_ARTICLE_ID + 23,
  420. /* y   */    K_ARTICLE_ID + 24,
  421. /* z   */    K_ARTICLE_ID + 25,
  422. /* {   */    K_UNBOUND,
  423. /* |   */    K_UNBOUND,
  424. /* }   */    K_UNBOUND,
  425. /* ~   */        K_UNSELECT_ALL,
  426. /* DEL */        K_PREV_LINE,
  427. /* 200 */    K_UNBOUND,
  428. /* up  */        K_PREV_LINE,
  429. /* down */        K_NEXT_LINE,
  430. /* left */    K_UNBOUND,
  431. /* right */    K_UNBOUND,
  432. /* #0  */    K_UNBOUND,
  433. /* #1  */    K_UNBOUND,
  434. /* #2  */    K_UNBOUND,
  435. /* #3  */    K_UNBOUND,
  436. /* #4  */    K_UNBOUND,
  437. /* #5  */    K_UNBOUND,
  438. /* #6  */    K_UNBOUND,
  439. /* #7  */    K_UNBOUND,
  440. /* #8  */    K_UNBOUND,
  441. /* #9  */    K_UNBOUND,
  442. /* mouse d1 */   K_M_SELECT,
  443. /* mouse d2 */   K_M_PREVIEW,
  444. /* mouse d3 */   K_NEXT_GROUP_NO_UPDATE,
  445. /* mouse u1 */   K_M_SELECT_RANGE,
  446. /* mouse u2 */   K_INVALID,
  447. /* mouse u3 */   K_INVALID
  448. };
  449.  
  450. export int orig_menu_map[KEY_MAP_SIZE];    /* initially empty */
  451.  
  452.  
  453. static struct command_name_map {
  454.     char *    cmd_name;
  455.     int       cmd_code;
  456.     int          cmd_restriction;
  457. } command_name_map[] = {
  458.  
  459.     "advance-article",        K_FORW_ARTICLE,        K_ONLY_MORE,
  460.     "advance-group",        K_ADVANCE_GROUP,    0,
  461.     "article",            K_ARTICLE_ID,        K_ONLY_MENU,
  462.     "as",            K_EQUAL_KEY,        0,
  463.  
  464.     "back-article",        K_BACK_ARTICLE,        K_ONLY_MORE,
  465.     "back-group",        K_BACK_GROUP,        0,
  466.  
  467.     "cancel",            K_CANCEL,        0,
  468.     "close-subject",        K_CLOSE_SUBJECT,    K_ONLY_MENU,
  469.     "command",            K_EXTENDED_CMD,        0,
  470.     "compress",            K_COMPRESS,        K_ONLY_MORE,
  471.     "continue",            K_CONTINUE,        0,
  472.     "continue-no-mark",        K_CONTINUE_NO_MARK,    K_ONLY_MENU,
  473.  
  474.     "decode",            K_UUDECODE,        0,
  475.  
  476.     "find",            K_GOTO_MATCH,        0,
  477.     "find-next",        K_NEXT_MATCH,        K_ONLY_MORE,
  478.     "follow",            K_FOLLOW_UP,        0,
  479.     "full-digest",        K_FULL_DIGEST,        K_ONLY_MORE,
  480.  
  481.     "goto-group",        K_GOTO_GROUP,        0,
  482.     "goto-menu",        K_BACK_TO_MENU,        K_ONLY_MORE,
  483.  
  484.     "help",            K_HELP,            0,
  485.  
  486.     "junk-articles",        K_JUNK_ARTICLES,    K_ONLY_MENU,
  487.  
  488.     "kill-select",        K_KILL_HANDLING,    0,
  489.  
  490.     "layout",            K_LAYOUT,        K_ONLY_MENU,
  491.     "leave-article",        K_LEAVE_ARTICLE,    K_ONLY_MORE,
  492.     "leave-next",        K_LEAVE_NEXT,        K_ONLY_MORE,
  493.     "line+1",            K_NEXT_LINE,        0,
  494.     "line-1",            K_PREV_LINE,        K_ONLY_MENU,
  495.     "line=@",            K_GOTO_LINE,        K_ONLY_MORE,
  496.  
  497.     "macro",            K_MACRO,        0,
  498.     "mail",            K_MAIL_OR_FORWARD,    0,
  499.     "message",            K_LAST_MESSAGE,        0,
  500.     "mouse-continue",        K_M_CONTINUE,        K_ONLY_MORE,
  501.     "mouse-preview",        K_M_PREVIEW,        K_ONLY_MENU,
  502.     "mouse-select",        K_M_SELECT,        K_ONLY_MENU,
  503.     "mouse-select-range",    K_M_SELECT_RANGE,    K_ONLY_MENU,
  504.     "mouse-select-subject",    K_M_SELECT_SUBJECT,    K_ONLY_MENU,
  505.     "mouse-toggle",        K_M_TOGGLE,        0,
  506.  
  507.     "next-article",        K_NEXT_ARTICLE,        K_ONLY_MORE,
  508.     "next-group",        K_NEXT_GROUP_NO_UPDATE,    0,
  509.     "next-subject",        K_NEXT_SUBJECT,        K_ONLY_MORE,
  510.     "nil",            K_UNBOUND,        0,
  511.  
  512.     "open-subject",        K_OPEN_SUBJECT,        K_ONLY_MENU,
  513.     "overview",            K_GROUP_OVERVIEW,    0,
  514.  
  515.     "page+1",            K_NEXT_PAGE,        0,
  516.     "page+1/2",            K_NEXT_HALF_PAGE,    K_ONLY_MORE,
  517.     "page-1",            K_PREV_PAGE,        0,
  518.     "page-1/2",            K_PREV_HALF_PAGE,    K_ONLY_MORE,
  519.     "page=$",            K_LAST_PAGE,        0,
  520.     "page=0",            K_HEADER_PAGE,        0,
  521.     "page=1",            K_FIRST_PAGE,        0,
  522.     "page=@",            K_GOTO_PAGE,        K_ONLY_MORE,
  523.  
  524.     "patch",            K_PATCH,        0,
  525.     "post",            K_POST,            0,
  526.     "prefix",            K_PREFIX_KEY,        0,
  527.     "preview",            K_PREVIEW,        0,
  528.     "previous",            K_PREVIOUS,        0,
  529.     "print",            K_PRINT,        0,
  530.  
  531.     "quit",            K_QUIT,            0,
  532.  
  533.     "read-return",        K_READ_GROUP_THEN_SAME,    K_ONLY_MENU,
  534.     "read-skip",        K_READ_GROUP_UPDATE,    0,
  535.     "redraw",            K_REDRAW,        0,
  536.     "reply",            K_REPLY,        0,
  537.     "rot13",            K_ROT13,        K_ONLY_MORE,
  538.  
  539.     "save-body",        K_SAVE_NO_HEADER,    0,
  540.     "save-full",        K_SAVE_FULL_HEADER,    0,
  541.     "save-short",        K_SAVE_SHORT_HEADER,    0,
  542.     "select",            K_SELECT,        K_ONLY_MENU,
  543.     "select-auto",        K_AUTO_SELECT,        K_ONLY_MENU,
  544.     "select-invert",        K_SELECT_INVERT,    K_ONLY_MENU,
  545.     "select-range",        K_SELECT_RANGE,        K_ONLY_MENU,
  546.     "select-subject",        K_SELECT_SUBJECT,    0,
  547.     "shell",            K_SHELL,        0,
  548.     "skip-lines",        K_SKIP_LINES,        0,
  549.  
  550.     "unselect-all",        K_UNSELECT_ALL,        K_ONLY_MENU,
  551.     "unshar",            K_UNSHAR,        0,
  552.     "unsub",            K_UNSUBSCRIBE,        0,
  553.  
  554.     "version",            K_VERSION,        0,
  555.  
  556.     (char *)NULL,        0,            0
  557. };
  558.  
  559. static int name_map_size;
  560. #define max_cmd_name_length 16    /* recalculate if table is changed */
  561.  
  562. export key_type global_key_map[KEY_MAP_SIZE];
  563.  
  564.  
  565. void
  566. init_key_map()
  567. {
  568.     register int c;
  569.     register struct command_name_map *cnmp;
  570.  
  571.     for (c = 0; c < KEY_MAP_SIZE; c++) global_key_map[c] = c;
  572.     for (c = NORMAL_KEYS+ARROW_KEYS+MULTI_KEYS; c < KEY_MAP_SIZE; c++) {
  573.     menu_key_map[c] = K_UNBOUND;
  574.     more_key_map[c] = K_UNBOUND;
  575.     }
  576.  
  577.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++);
  578.     name_map_size = cnmp - command_name_map;
  579. }
  580.  
  581.  
  582. int
  583. lookup_command(command, restriction)
  584. char *command;
  585. int restriction;
  586. {
  587.     register struct command_name_map *cnmp;
  588.     register i, j, k, t;
  589.  
  590.     i = 0; j = name_map_size - 1;
  591.  
  592.     while (i <= j) {
  593.     k = (i + j) / 2;
  594.     cnmp = &command_name_map[k];
  595.  
  596.     if ( (t=strcmp(command, cnmp->cmd_name)) > 0)
  597.         i = k+1;
  598.     else
  599.     if (t < 0)
  600.         j = k-1;
  601.     else {
  602.         switch (restriction) {
  603.          case K_ONLY_MENU:
  604.          case K_ONLY_MORE:
  605.         if (cnmp->cmd_restriction == restriction) break;
  606.         /*FALLTHRU*/
  607.          case 0:
  608.         if (cnmp->cmd_restriction == 0) break;
  609.         return K_INVALID-1;
  610.          default:
  611.         break;
  612.         }
  613.         return cnmp->cmd_code;
  614.     }
  615.     }
  616.  
  617.     return K_INVALID;
  618. }
  619.  
  620.  
  621. int
  622. cmd_completion(path, index)
  623. char *path;
  624. int index;
  625. {
  626.     static char *head, *tail = NULL;
  627.     static int len;
  628.     static struct command_name_map *cmd, *help_cmd;
  629.  
  630.     if (index < 0) return 0;
  631.  
  632.     if (path) {
  633.     head = path;
  634.     tail = path + index;
  635.     while (*head && isspace(*head)) head++;
  636.     help_cmd = cmd = command_name_map;
  637.     len = tail - head;
  638.  
  639.     return 1;
  640.     }
  641.  
  642.     if (index) {
  643.     list_completion((char *)NULL);
  644.  
  645.     if (help_cmd->cmd_name == NULL)
  646.         help_cmd = command_name_map;
  647.  
  648.     for (;help_cmd->cmd_name; help_cmd++) {
  649.         index = strncmp(help_cmd->cmd_name, head, len);
  650.         if (index < 0) continue;
  651.         if (index > 0) {
  652.         help_cmd = command_name_map;
  653.         break;
  654.         }
  655.         if (list_completion(help_cmd->cmd_name) == 0) break;
  656.     }
  657.     fl;
  658.     return 1;
  659.     }
  660.  
  661.     for (; cmd->cmd_name; cmd++) {
  662.     if (len == 0)
  663.         index = 0;
  664.     else
  665.         index = strncmp(cmd->cmd_name, head, len);
  666.     if (index < 0) continue;
  667.     if (index > 0) break;
  668.     if (cmd->cmd_code == K_MACRO ||
  669.         cmd->cmd_code == K_ARTICLE_ID ||
  670.         cmd->cmd_code == K_PREFIX_KEY ||
  671.         cmd->cmd_code == K_EQUAL_KEY)
  672.         sprintf(tail, "%s ", cmd->cmd_name + len);
  673.     else
  674.         strcpy(tail, cmd->cmd_name + len);
  675.     cmd++;
  676.     return 1;
  677.     }
  678.     return 0;
  679. }
  680.  
  681.  
  682. char *command_name(cmd)
  683. int cmd;
  684. {
  685.     register struct command_name_map *cnmp;
  686.  
  687.     cmd &= ~GETC_COMMAND;
  688.  
  689.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++)
  690.     if (cnmp->cmd_code == cmd) return cnmp->cmd_name;
  691.  
  692.     return "unknown";
  693. }
  694.  
  695.  
  696. /*
  697.  * convert key name into ascii code
  698.  *
  699.  *    key names are:
  700.  *        c    character c
  701.  *        ^C    control-C
  702.  *        0xNN    hex value (0..0x7f)
  703.  *        0NNN    octal value (0..0177)
  704.  *        NNN    decimal value (0..127)
  705.  *        up, down, left, rigth    arrow keys
  706.  *        #0..#9            function keys (initially undefined)
  707.  */
  708.  
  709. key_type parse_key(str)
  710. char *str;
  711. {
  712.     int x;
  713.  
  714.     if (str[1] == NUL)
  715.     return (data_bits < 8) ? (str[0] & 0177) : str[0];
  716.  
  717.     if (str[0] == '^')
  718.     if (str[1] == '?')
  719.         return 0177;
  720.     else
  721.         return CONTROL_(str[1]);
  722.  
  723.     if (isdigit(str[0])) {
  724.     if (str[0] == '0')
  725.         if (str[1] == 'x')
  726.         sscanf(str+2, "%x", &x);
  727.         else
  728.         sscanf(str+1, "%o", &x);
  729.     else
  730.         sscanf(str, "%d", &x);
  731.  
  732.     return x;
  733.     }
  734.  
  735.     if (str[0] == '#' && isdigit(str[1]))
  736.     return K_function(str[1] - '0');
  737.  
  738.     if (str[0] == '#') str++;
  739.     
  740.     if (strcmp(str, "up") == 0)
  741.     return K_up_arrow;
  742.  
  743.     if (strcmp(str, "down") == 0)
  744.     return K_down_arrow;
  745.  
  746.     if (strcmp(str, "left") == 0)
  747.     return K_left_arrow;
  748.  
  749.     if (strcmp(str, "right") == 0)
  750.     return K_right_arrow;
  751.  
  752.    if (strcmp(str, "mouse_d1") == 0)   /* thp */
  753.     return K_m_d1;
  754.    if (strcmp(str, "mouse_d2") == 0)   /* thp */
  755.     return K_m_d2;
  756.    if (strcmp(str, "mouse_d3") == 0)   /* thp */
  757.     return K_m_d3;
  758.    if (strcmp(str, "mouse_u1") == 0)   /* thp */
  759.     return K_m_u1;
  760.   if (strcmp(str, "mouse_u2") == 0)   /* thp */
  761.     return K_m_u2;
  762.   if (strcmp(str, "mouse_u3") == 0)   /* thp */
  763.     return K_m_u3;
  764.  
  765.     init_message("unknown key: %s", str);
  766.  
  767.     return 0200;
  768. }
  769.  
  770. char *key_name(c)
  771. key_type c;
  772. {
  773.     static char buf[10];
  774.  
  775.     if (c >= NORMAL_KEYS && c <= (key_type)(KEY_MAP_SIZE-NATIONAL_KEYS)) {
  776.     switch (c) {
  777.      case K_up_arrow:
  778.         return "up";
  779.      case K_down_arrow:
  780.         return "down";
  781.      case K_left_arrow:
  782.         return "left";
  783.      case K_right_arrow:
  784.         return "right";
  785.      case K_m_d1:
  786.         return "mouse_d1";
  787.      case K_m_d2:
  788.         return "mouse_d2";
  789.      case K_m_d3:
  790.         return "mouse_d3";
  791.      case K_m_u1:
  792.         return "mouse_u1";
  793.      case K_m_u2:
  794.         return "mouse_u2";
  795.      case K_m_u3:
  796.         return "mouse_u3";
  797.      default:
  798.         buf[0] = '#';
  799.         buf[1] = (c - K_function(0))
  800.         + (c >= (key_type)K_function(MULTI_KEYS) ? 'A'-K_function(MULTI_KEYS) : '0');
  801.         buf[2] = NUL;
  802.         goto out;
  803.     }
  804.     }
  805.  
  806.     if (c == SP)
  807.     return "space";
  808.  
  809.     if (c < SP) {
  810.     buf[0] = '^';
  811.     buf[1] = c + '@';
  812.     buf[2] = NUL;
  813.     goto out;
  814.     }
  815.  
  816.     if (c == 0177) {
  817.     strcpy(buf, "^?");
  818.     goto out;
  819.     }
  820.  
  821.     if (data_bits < 8 && c >= NORMAL_KEYS) {
  822.     sprintf(buf, "0x%02x", c);
  823.     goto out;
  824.     }
  825.  
  826.     buf[0] = c;
  827.     buf[1] = NUL;
  828.  
  829.  out:
  830.     return buf;
  831. }
  832.  
  833.  
  834. void
  835. dump_global_map()
  836. {
  837.     register key_type c;
  838.  
  839.     clrdisp();
  840.     so_printf("\1REMAPPED KEYS\1\n\n");
  841.     pg_init(2, 4);
  842.  
  843.     for (c = 0; c < KEY_MAP_SIZE; c++)
  844.     if (c != global_key_map[c]) {
  845.         if (pg_next() < 0) break;
  846.         tprintf("%s", key_name(c));
  847.         pg_indent(6);
  848.         tprintf("-> %s", key_name(global_key_map[c]));
  849.     }
  850.  
  851.     pg_end();
  852. }
  853.  
  854. int
  855. dump_key_map(where)
  856. char *where;
  857. {
  858.     register struct command_name_map *cnmp;
  859.     register key_type c;
  860.     register int code, first_prt;
  861.     int *map, restriction;
  862.     
  863.     if ((code = lookup_keymap(where)) < 0) return -1;
  864.     map = keymaps[code].km_map;
  865.     restriction = keymaps[code].km_flag & (K_ONLY_MENU | K_ONLY_MORE);
  866.  
  867.     clrdisp();
  868.     so_printf("\1KEY BINDINGS (%s)\1\n\n", where);
  869.  
  870.     if (restriction == K_ONLY_MENU) {
  871.     tprintf("\rarticle:  ");
  872.     for (c = 0; c < KEY_MAP_SIZE; c++)
  873.         if (map[c] & K_ARTICLE_ID) tprintf("%s", key_name(c));
  874.     }
  875.  
  876.     pg_init(4, 2);
  877.  
  878.     for (cnmp = command_name_map; cnmp->cmd_name; cnmp++) {
  879.     if (cnmp->cmd_restriction && cnmp->cmd_restriction != restriction)
  880.         continue;
  881.     if (cnmp->cmd_code == K_UNBOUND) continue;
  882.     if (cnmp->cmd_code == K_MACRO) continue;
  883.  
  884.     code = cnmp->cmd_code;
  885.     first_prt = 1;
  886.  
  887.     for (c = 0; c < KEY_MAP_SIZE; c++)
  888.         if (map[c] == code) {
  889.         if (first_prt) {
  890.             if (pg_next() < 0) goto out;
  891.             tprintf("%s", cnmp->cmd_name);
  892.             pg_indent(max_cmd_name_length);
  893.             first_prt = 0;
  894.         }
  895.         tprintf(" %s", key_name(c));
  896.         }
  897.     }
  898.  
  899.     for (c = 0; c < KEY_MAP_SIZE; c++)
  900.     if (map[c] & K_MACRO) {
  901.         if (pg_next() < 0) goto out;
  902.         tprintf("macro %d: %s", (map[c] & ~K_MACRO), key_name(c));
  903.         if (map == menu_key_map && orig_menu_map[c] != K_UNBOUND) 
  904.         tprintf(" (%s)", command_name(orig_menu_map[c]));
  905.     }
  906.     else if (map[c] & K_PREFIX_KEY) {
  907.         if (pg_next() < 0) goto out;
  908.         tprintf("prefix %s: %s",
  909.            keymaps[(map[c] & ~K_PREFIX_KEY)].km_name, key_name(c));
  910.     }
  911.  
  912.  out:
  913.     pg_end();
  914.     return 0;
  915. }
  916.  
  917. #define MAX_KEYMAPS    17
  918.  
  919. struct key_map_def keymaps[MAX_KEYMAPS+1] = {
  920.     "#",    NULL,        K_MULTI_KEY_MAP,
  921.     "key",    NULL,        K_GLOBAL_KEY_MAP,
  922.     "menu",    menu_key_map,    K_BIND_ORIG | K_ONLY_MENU,
  923.     "show",    more_key_map,    K_ONLY_MORE,
  924.     "both",    menu_key_map,    K_BOTH_MAPS | K_BIND_ORIG,
  925.     "more",    more_key_map,    K_ONLY_MORE,
  926.     "read",    more_key_map,    K_ONLY_MORE,
  927.     NULL,
  928. };
  929.  
  930. int
  931. lookup_keymap(name)
  932. char *name;
  933. {
  934.     register struct key_map_def *m;
  935.     
  936.     if (name[0] == '#') return 0;
  937.     
  938.     for (m = keymaps; m->km_name; m++) {
  939.     if (strcmp(name, m->km_name) == 0) return m - keymaps;
  940.     }
  941.     return keymaps - m;
  942. }
  943.  
  944. int
  945. make_keymap(name)
  946. char *name;
  947. {
  948.     register struct key_map_def *m;
  949.     register int *kp;
  950.     int ix;
  951.     
  952.     ix = lookup_keymap(name);
  953.     if (ix >= 0) return -1;
  954.     ix = -ix;
  955.     if (ix == MAX_KEYMAPS) return -2;
  956.     
  957.     m = &keymaps[ix];
  958.     m->km_name = copy_str(name);
  959.     m->km_map = newobj(int, KEY_MAP_SIZE);
  960.     m->km_flag = K_ONLY_MORE | K_ONLY_MENU;
  961.     for (kp = m->km_map; kp < &(m->km_map)[KEY_MAP_SIZE]; ) *kp++ = K_UNBOUND;
  962.  
  963.     return ix;
  964. }
  965.  
  966. int
  967. keymap_completion(buf, ix)
  968. char *buf;
  969. int ix;
  970. {
  971.     static char *head, *tail = NULL;
  972.     static int len;
  973.     static struct key_map_def *map, *help_map;
  974.  
  975.     if (ix < 0) return 0;
  976.  
  977.     if (buf) {
  978.     head = buf;
  979.     tail = buf + ix;
  980.     while (*head && isspace(*head)) head++;
  981.     help_map = map = keymaps;
  982.     len = tail - head;
  983.  
  984.     return 1;
  985.     }
  986.  
  987.     if (ix) {
  988.     list_completion((char *)NULL);
  989.  
  990.     if (help_map->km_name == NULL)
  991.         help_map = keymaps;
  992.  
  993.     for (;help_map->km_name; help_map++) {
  994.         if (strncmp(help_map->km_name, head, len)) continue;
  995.         if (list_completion(help_map->km_name) == 0) break;
  996.     }
  997.     fl;
  998.     return 1;
  999.     }
  1000.  
  1001.     for (; map->km_name; map++) {
  1002.     if (len && strncmp(map->km_name, head, len)) continue;
  1003.     strcpy(tail, map->km_name + len);
  1004.     if (map != keymaps) strcat(tail, " ");
  1005.     map++;
  1006.     return 1;
  1007.     }
  1008.     return 0;
  1009. }
  1010.