home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / map.c < prev    next >
C/C++ Source or Header  |  1998-08-21  |  21KB  |  951 lines

  1. /*
  2.  * map.c    -- map and map! interface routines
  3.  *    Original interface by Otto Lind, 6/3/93
  4.  *    Additional map and map! support by Kevin Buettner, 9/17/94
  5.  *
  6.  * $Header: /usr/build/vile/vile/RCS/map.c,v 1.82 1998/08/22 02:17:49 tom Exp $
  7.  *
  8.  */
  9.  
  10. #include "estruct.h"
  11. #include "edef.h"
  12.  
  13. /*
  14.  * Picture for struct maprec
  15.  * -------------------------
  16.  *
  17.  * Assume the following mappings...
  18.  *
  19.  * map za abc
  20.  * map zb def
  21.  * map q  quit
  22.  *
  23.  * These may be represented by the following picture...
  24.  *
  25.  *   |
  26.  *   v
  27.  * +---+--------+---+---+   +---+--------+---+---+
  28.  * | z |  NULL  | o | o-+-->| q | "quit" | 0 | 0 |
  29.  * +---+--------+-|-+---+   +---+--------+---+---+
  30.  *                |
  31.  *          v
  32.  *              +---+--------+---+---+   +---+--------+---+---+
  33.  *              | a | "abc"  | 0 | o-+-->| b | "def"  | 0 | 0 |
  34.  *              +---+--------+---+---+   +---+--------+---+---+
  35.  *
  36.  * where the pertinent fields are as follows:
  37.  *
  38.  * +----+-----+-------+-------+
  39.  * | ch | srv | dlink | flink |
  40.  * +----+-----+-------+-------+
  41.  *
  42.  * When matching a character sequence, we follow dlink when we've found a
  43.  * matching character.  We change the character to be matched to the next
  44.  * character in the sequence.  If the character doesn't match, we stay at
  45.  * the same level (with the same character) and follow flink.
  46.  *
  47.  */
  48.  
  49. struct maprec {
  50.     int        ch;        /* character to match        */
  51.     UINT        flags;        /* flags word            */
  52.     struct maprec *    dlink;        /* Where to go to match the    */
  53.                     /*   next character in a multi-    */
  54.                     /*   character sequence.    */
  55.     struct maprec *    flink;        /* Where to try next if match    */
  56.                     /*   against current character    */
  57.                     /*   is unsuccessful        */
  58.     int        irv;        /* system defined mapping: The    */
  59.                     /*   (wide) character code to    */
  60.                     /*   replace a matched sequence by */
  61.     char          *    srv;        /* user defined mapping: This    */
  62.                     /*   is the string to replace a    */
  63.                     /*   matched sequence by    */
  64. };
  65.  
  66. #define MAPF_SYSTIMER    0x01
  67. #define MAPF_USERTIMER    0x02
  68. #define MAPF_TIMERS    0x03
  69. #define MAPF_NOREMAP    0x04
  70.  
  71. static int suppress_sysmap;
  72.  
  73. static struct maprec *map_command = NULL;
  74. static struct maprec *map_insert = NULL;
  75. static struct maprec *map_syskey = NULL;
  76. static struct maprec *abbr_map = NULL;
  77.  
  78. static    int    map_common(struct maprec **mpp, const char *bufname, UINT remapflag);
  79. static    int    unmap_common(struct maprec **mpp, const char *bufname);
  80. static    void    addtomap(struct maprec **mpp, const char * ks, int kslen, UINT flags, int irv, char * srv);
  81. static    int    delfrommap(struct maprec **mpp, const char * ks);
  82.  
  83. static    int    abbr_getc (void);
  84. static    int    abbr_c_avail (void);
  85.  
  86. static    int    mapgetc (void);
  87.  
  88. typedef    int (*AvailFunc) (void);
  89. typedef    int (*GetFunc) (void);
  90. typedef    int (*StartFunc) (void);
  91.  
  92. static    int    maplookup(int c, ITBUFF **outp, struct maprec *mp, GetFunc get, AvailFunc avail, StartFunc start, int suffix);
  93.  
  94. #if !OPT_UPBUFF
  95. #define relist_mappings(name)
  96. #endif
  97.  
  98. #define NUMKEYSTR (KBLOCK / 2)
  99.  
  100. #if DOKEYLOG
  101. int do_keylog = 1;
  102. #endif
  103.  
  104. #if OPT_SHOW_MAPS
  105. #define MAPS_PREFIX 12
  106.  
  107. /*ARGSUSED*/
  108. static void
  109. makemaplist(int dummy GCC_UNUSED, void *mapp)
  110. {
  111.     TBUFF *lhsstr = 0;
  112.     struct maprec **lhsstack = 0;
  113.     struct maprec *mp = (struct maprec *) mapp;
  114.     int footnote = 0;
  115.     ALLOC_T depth = 0;
  116.     ALLOC_T maxdepth;
  117.     ALLOC_T i;
  118.  
  119.     lhsstr = tb_init(&lhsstr, 0);
  120.     lhsstack = typeallocn(struct maprec *, maxdepth = NSTRING);
  121.     for_ever {
  122.     if (mp) {
  123.         const char *remapnote;
  124.         char *mapstr;
  125.         char esc_seq[10];    /* FIXME */
  126.         tb_put(&lhsstr, depth, mp->ch);
  127.         if (depth+1 >= maxdepth)
  128.         lhsstack = typereallocn(struct maprec *, lhsstack, maxdepth *= 2);
  129.         lhsstack[depth++] = mp->flink;
  130.  
  131.         mapstr = (char *)0;
  132.         if (mp->srv) {
  133.         mapstr = mp->srv;
  134.         } else if (mp->irv != -1) {
  135.         (void)kcod2escape_seq(mp->irv, esc_seq);
  136.         mapstr = esc_seq;
  137.         }
  138.         if (mapstr) {
  139.             if (mapp && (struct maprec *)mapp == abbr_map) {
  140.                 /* the abbr map is stored inverted */
  141.                 for (i = depth; i != 0; )
  142.                 bputc(tb_values(lhsstr)[--i]);
  143.             } else {
  144.                 if (mp->flags & MAPF_NOREMAP) {
  145.                 remapnote = "(n)";
  146.                 footnote++;
  147.                 } else {
  148.                 remapnote = "   ";
  149.                 }
  150.                 bprintf("%s ", remapnote);
  151.                 for (i = 0; i < depth; i++)
  152.                 bputc(tb_values(lhsstr)[i]);
  153.             }
  154.             bprintf("\t%s\n", mapstr);
  155.         }
  156.         mp = mp->dlink;
  157.     }
  158.     else if (depth != 0)
  159.         mp = lhsstack[--depth];
  160.     else
  161.         break;
  162.     }
  163.     if (footnote) {
  164.     bprintf("[(n) means never remap]\n");
  165.     }
  166.     tb_free(&lhsstr);
  167.     free((char *)lhsstack);
  168. }
  169.  
  170. static int
  171. show_mapped_chars(const char *bname)
  172. {
  173.     struct maprec *mp;
  174.     if (strcmp(bname, MAP_BufName) == 0)
  175.         mp = map_command;
  176.     else if (strcmp(bname, MAPBANG_BufName) == 0)
  177.         mp = map_insert;
  178.     else if (strcmp(bname, ABBR_BufName) == 0)
  179.         mp = abbr_map;
  180.     else if (strcmp(bname, SYSMAP_BufName) == 0)
  181.         mp = map_syskey;
  182.     else
  183.         return FALSE;
  184.     return liststuff(bname, FALSE, makemaplist, 0, (void *)mp);
  185. }
  186.  
  187. #if OPT_UPBUFF
  188. static int
  189. show_Mappings(BUFFER *bp)
  190. {
  191.     b_clr_obsolete(bp);
  192.     return show_mapped_chars(bp->b_bname);
  193. }
  194.  
  195. #undef relist_mappings
  196.  
  197. static void
  198. relist_mappings(const char * bufname)
  199. {
  200.     update_scratch(bufname, show_Mappings);
  201. }
  202. #endif    /* OPT_UPBUFF */
  203.  
  204. #endif    /* OPT_SHOW_MAPS */
  205.  
  206. /*
  207. ** set a map for the character/string combo
  208. */
  209. /* ARGSUSED */
  210. int
  211. map(int f GCC_UNUSED, int n GCC_UNUSED)
  212. {
  213.     return map_common(&map_command, MAP_BufName, 0);
  214. }
  215.  
  216. /* ARGSUSED */
  217. int
  218. map_bang(int f GCC_UNUSED, int n GCC_UNUSED)
  219. {
  220.     return map_common(&map_insert, MAPBANG_BufName, 0);
  221. }
  222.  
  223. /* ARGSUSED */
  224. int
  225. noremap(int f GCC_UNUSED, int n GCC_UNUSED)
  226. {
  227.     return map_common(&map_command, MAP_BufName, MAPF_NOREMAP);
  228. }
  229.  
  230. /* ARGSUSED */
  231. int
  232. noremap_bang(int f GCC_UNUSED, int n GCC_UNUSED)
  233. {
  234.     return map_common(&map_insert, MAPBANG_BufName, MAPF_NOREMAP);
  235. }
  236.  
  237. /* ARGSUSED */
  238. int
  239. abbrev(int f GCC_UNUSED, int n GCC_UNUSED)
  240. {
  241.     return map_common(&abbr_map, ABBR_BufName, MAPF_NOREMAP);
  242. }
  243.  
  244. #if OPT_SHOW_MAPS
  245. /* ARGSUSED */
  246. int
  247. sysmap(int f GCC_UNUSED, int n GCC_UNUSED)
  248. {
  249.     return show_mapped_chars(SYSMAP_BufName);
  250. }
  251. #endif
  252.  
  253. static int
  254. map_common(struct maprec **mpp, const char *bufname, UINT remapflag)
  255. {
  256.     int     status;
  257.     static TBUFF *kbuf;
  258.     static TBUFF *val;
  259.     int len;
  260.  
  261. #if OPT_SHOW_MAPS
  262.     if (end_named_cmd()) {
  263.     return show_mapped_chars(bufname);
  264.     }
  265. #endif
  266.     tb_scopy(&kbuf, "");
  267.     status = kbd_reply("change this string: ", &kbuf, eol_history,
  268.             ' ', KBD_NOMAP|KBD_NOEVAL, no_completion);
  269.     if (status != TRUE)
  270.     return status;
  271.  
  272.     hst_glue(' ');
  273.     tb_scopy(&val, "");
  274.     if (!clexec) {
  275.         status = kbd_reply("to this new string: ", &val, eol_history,
  276.             '\n', KBD_NOMAP, no_completion);
  277.     } else {
  278.         (void)macliteralarg(&val); /* consume to end of line */
  279.         status = tb_length(val) > 1;
  280.     }
  281.     if (status != TRUE)
  282.     return status;
  283.  
  284.     len = tb_length(kbuf) - 1;
  285.     if ((*mpp && *mpp == abbr_map) || (strcmp(bufname, ABBR_BufName) == 0)) {
  286.     /* reverse the lhs */
  287.     int i;
  288.     char t;
  289.     char *s = tb_values(kbuf);
  290.     for (i = 0; i < len/2; i++) {
  291.         t = s[len-i-1];
  292.         s[len-i-1] = s[i];
  293.         s[i] = t;
  294.     }
  295.     }
  296.  
  297.     addtomap(mpp, tb_values(kbuf), len, MAPF_USERTIMER|remapflag, -1, tb_values(val));
  298.     relist_mappings(bufname);
  299.     return TRUE;
  300. }
  301.  
  302. /*
  303. ** remove map entry, restore saved CMDFUNC for key
  304. */
  305. /* ARGSUSED */
  306. int
  307. unmap(int f GCC_UNUSED, int n GCC_UNUSED)
  308. {
  309.     return unmap_common(&map_command, MAP_BufName);
  310. }
  311.  
  312. /* ARGSUSED */
  313. int
  314. unmap_bang(int f GCC_UNUSED, int n GCC_UNUSED)
  315. {
  316.     return unmap_common(&map_insert, MAPBANG_BufName);
  317. }
  318.  
  319. /* ARGSUSED */
  320. int
  321. unmap_system(int f GCC_UNUSED, int n GCC_UNUSED)
  322. {
  323.     return unmap_common(&map_syskey, SYSMAP_BufName);
  324. }
  325.  
  326. /* ARGSUSED */
  327. int
  328. unabbr(int f GCC_UNUSED, int n GCC_UNUSED)
  329. {
  330.     return unmap_common(&abbr_map, ABBR_BufName);
  331. }
  332.  
  333. static int
  334. unmap_common(struct maprec **mpp, const char *bufname)
  335. {
  336.     int     status;
  337.     static TBUFF *kbuf;
  338.  
  339.     /* otherwise it'll be mapped, and not found when looked up */
  340.     if (mpp && mpp == &map_syskey)
  341.     suppress_sysmap = TRUE;
  342.  
  343.     tb_scopy(&kbuf, "");
  344.     status = kbd_reply("unmap string: ", &kbuf, eol_history,
  345.             ' ', KBD_NOMAP, no_completion);
  346.     suppress_sysmap = FALSE;
  347.     if (status != TRUE)
  348.     return status;
  349.  
  350.     if ((*mpp && *mpp == abbr_map) || (strcmp(bufname, ABBR_BufName) == 0)) {
  351.     /* reverse the lhs */
  352.     int i;
  353.     char t;
  354.     int len = tb_length(kbuf) - 1;
  355.     char *s = tb_values(kbuf);
  356.     for (i = 0; i < len/2; i++) {
  357.         t = s[len-i-1];
  358.         s[len-i-1] = s[i];
  359.         s[i] = t;
  360.     }
  361.     }
  362.  
  363.     if (delfrommap(mpp, tb_values(kbuf)) != TRUE) {
  364.     mlforce("[Sequence not mapped]");
  365.     return FALSE;
  366.     }
  367.     relist_mappings(bufname);
  368.     return TRUE;
  369. }
  370.  
  371. /* addtosysmap is used to initialize the system default function key map
  372. */
  373. void
  374. addtosysmap(const char * seq, int seqlen, int code)
  375. {
  376.     addtomap(&map_syskey, seq, seqlen, MAPF_SYSTIMER,
  377.             code, (char *)0);
  378. }
  379.  
  380. static void
  381. addtomap(
  382.     struct maprec **mpp,
  383.     const char * ks,
  384.     int         kslen,
  385.     UINT        flags,
  386.     int        irv,
  387.     char *    srv)
  388. {
  389.     struct maprec *mp = NULL;
  390.  
  391.     if (ks == 0 || kslen == 0)
  392.     return;
  393.  
  394.     while (*mpp && kslen) {
  395.     mp = *mpp;
  396.     mp->flags |= flags;
  397.     if (char2int(*ks) == mp->ch) {
  398.         mpp = &mp->dlink;
  399.         ks++;
  400.         kslen--;
  401.     }
  402.     else
  403.         mpp = &mp->flink;
  404.     }
  405.  
  406.     while (kslen) {
  407.     mp = typealloc(struct maprec);
  408.     if (mp == 0)
  409.         break;
  410.     *mpp = mp;
  411.     mp->dlink = mp->flink = NULL;
  412.     mp->ch = char2int(*ks++);
  413.     mp->srv = NULL;
  414.     mp->flags = flags;
  415.     mp->irv = -1;
  416.     mpp = &mp->dlink;
  417.     kslen--;
  418.     }
  419.  
  420.     if (irv != -1)
  421.     mp->irv = irv;
  422.     if (srv) {
  423.     if (mp->srv)
  424.         free(mp->srv);
  425.     mp->srv = strmalloc(srv);
  426.     }
  427.     mp->flags = flags;
  428. }
  429.  
  430. static int
  431. delfrommap(struct maprec **mpp, const char * ks)
  432. {
  433.     struct maprec **save_m = mpp;
  434.     struct maprec ***mstk = 0;
  435.     const char *save_k = ks;
  436.     int depth = 0;
  437.     int pass;
  438.  
  439.     if (ks == 0 || *ks == 0)
  440.     return FALSE;
  441.  
  442.     for (pass = 0; pass < 2; pass++) {
  443.     mpp   = save_m;
  444.     ks    = save_k;
  445.     depth = 0;
  446.     while (*mpp && *ks) {
  447.         if (pass)
  448.         mstk[depth] = mpp;
  449.         if ((*mpp)->ch == char2int(*ks)) {
  450.         mpp = &(*mpp)->dlink;
  451.         ks++;
  452.         depth++;
  453.         }
  454.         else
  455.         mpp = &(*mpp)->flink;
  456.     }
  457.  
  458.     if (*ks)
  459.         return FALSE;        /* not in map */
  460.     if (!pass)
  461.         mstk = typecallocn(struct maprec **, depth+1);
  462.     }
  463.  
  464.     depth--;
  465.     if ((*mstk[depth])->srv) {
  466.     free((*mstk[depth])->srv);
  467.     (*mstk[depth])->srv = NULL;
  468.     } else if ((*mstk[depth])->irv != -1) {
  469.     (*mstk[depth])->irv = -1;
  470.     } else {
  471.     free((char *)mstk);
  472.     return FALSE;
  473.     }
  474.  
  475.     for (; depth >= 0; depth--) {
  476.     struct maprec *mp = *mstk[depth];
  477.     if (mp->irv == -1 && mp->dlink == NULL && mp->srv == NULL) {
  478.         *mstk[depth] = mp->flink;
  479.         if (depth > 0 && (*mstk[depth-1])->dlink == mp)
  480.         (*mstk[depth-1])->dlink = NULL;
  481.         free((char *)mp);
  482.     }
  483.     else
  484.         break;
  485.     }
  486.     free((char *)mstk);
  487.     return TRUE;
  488. }
  489.  
  490.  
  491. #define INPUT_FROM_TTGET 1
  492. #define INPUT_FROM_MAPGETC 2
  493.  
  494. static ITBUFF *sysmappedchars = NULL;
  495.  
  496. static void
  497. save_keystroke(int c)
  498. {
  499.     KILL *kp;
  500.     KILLREG *kr = &kbs[KEYST_KREG];
  501.  
  502. #if DOKEYLOG
  503.     if (do_keylog) {
  504.         static int keyfd = -1;
  505.         static char *tfilenam;
  506.         if (!tfilenam)
  507.             tfilenam = tempnam("/tmp/vilekeylogs", "vilek");
  508.         if (tfilenam) {
  509.             if (keyfd < 0)
  510.                 keyfd = open(tfilenam, O_CREAT|O_WRONLY, 0600);
  511.             if (keyfd >= 0)
  512.                 write(keyfd, &c, 1);
  513.         }
  514.     }
  515. #endif
  516.     if (kr->kbufh == NULL) {
  517.         kr->kbufh = typealloc(KILL);
  518.         kr->kused = 0;
  519.     }
  520.     if (kr->kbufh == NULL)
  521.         return;
  522.  
  523.     kp = kr->kbufp = kr->kbufh;
  524.     kp->d_next = NULL;
  525.  
  526.     kp->d_chunk[kr->kused++] = (UCHAR)c;
  527.     if (kr->kused >= NUMKEYSTR * 2) { /* time to dump the oldest half */
  528.         (void)memcpy(
  529.             (char *)(kp->d_chunk),
  530.             (char *)(&kp->d_chunk[NUMKEYSTR / 2]),
  531.             NUMKEYSTR / 2);
  532.         kr->kused = NUMKEYSTR / 2;
  533.     }
  534. }
  535.  
  536. /* these two wrappers are provided because at least one pcc-based
  537.     compiler balks at passing TTgetc or TTtypahead as a function pointer */
  538.  
  539. static int
  540. normal_getc(void)
  541. {
  542.     int c = TTgetc();
  543.     TRACE(("normal/getc:%c (%#x)\n", c, c))
  544.     save_keystroke(c);
  545.     return c;
  546. }
  547.  
  548. static int
  549. normal_typeahead(void)
  550. {
  551.     return(TTtypahead());
  552. }
  553.  
  554. static int
  555. normal_start(void)
  556. {
  557.     return TRUE;
  558. }
  559.  
  560. int
  561. sysmapped_c(void)
  562. {
  563.     int c;
  564.  
  565.     /* still some left? */
  566.     if (itb_more(sysmappedchars))
  567.     return itb_last(sysmappedchars);
  568.  
  569.     c = TTgetc();
  570.     TRACE(("mapped/getc:%c (%#x)\n", c, c))
  571.  
  572.     save_keystroke(c);
  573.  
  574.     if (suppress_sysmap)
  575.     return c;
  576.  
  577.     /* will push back on sysmappedchars successful, or not */
  578.     (void)maplookup(c, &sysmappedchars, map_syskey,
  579.         normal_getc, normal_typeahead, normal_start, TRUE);
  580.  
  581.     return itb_last(sysmappedchars);
  582. }
  583.  
  584. int
  585. sysmapped_c_avail(void)
  586. {
  587.     return itb_more(sysmappedchars) || TTtypahead();
  588. }
  589.  
  590.  
  591. static ITBUFF *mapgetc_ungottenchars = NULL;
  592. static int mapgetc_ungotcnt = 0;
  593.  
  594. /* make the assumption that no input will magically appear
  595.  * (un)available to tgetc in between a mapungetc and the next mapgetc.
  596.  * Hence characters can't be ungotten onto the wrong buffer (exception
  597.  * is the last tgot char might be mapungot onto the map buffer.  This
  598.  * is OK (if assumption holds) because the next character will be
  599.  * gotten from this buffer.
  600.  */
  601.  
  602. void
  603. mapungetc(int c)
  604. {
  605.     if (tgetc_avail()) {
  606.     tungetc(c);
  607.     } else {
  608.     (void)itb_append(&mapgetc_ungottenchars, c);
  609.     mapgetc_ungotcnt++;
  610.     }
  611. }
  612.  
  613. static int infloopcount;
  614. static int mapgetc_raw_flag;
  615.  
  616. static int
  617. mapgetc(void)
  618. {
  619.     UINT remapflag;
  620.     if (global_g_val(GMDREMAP))
  621.     remapflag = 0;
  622.     else
  623.     remapflag = NOREMAP;
  624.  
  625.     if (!tgetc_avail() && mapgetc_ungotcnt > 0) {
  626.         if (infloopcount++ > global_g_val(GVAL_MAPLENGTH)) {
  627.         (void)itb_init(&mapgetc_ungottenchars, abortc);
  628.         mapgetc_ungotcnt = 0;
  629.         mlforce("[Infinite loop detected in %s sequence]",
  630.                 (insertmode) ? "map!" : "map");
  631.         catnap(1000,FALSE);  /* FIXX: be sure message gets out */
  632.         return abortc|NOREMAP;
  633.         }
  634.         mapgetc_ungotcnt--;
  635.         return itb_last(mapgetc_ungottenchars) | remapflag;
  636.     }
  637.     infloopcount = 0;
  638.     return tgetc(mapgetc_raw_flag);
  639. }
  640.  
  641. int
  642. mapped_c_avail(void)
  643. {
  644.     return mapgetc_ungotcnt > 0 || tgetc_avail();
  645. }
  646.  
  647. int
  648. mapped_ungotc_avail(void)
  649. {
  650.     return mapgetc_ungotcnt > 0;
  651. }
  652.  
  653. static int
  654. mapped_c_start(void)
  655. {
  656.     return TRUE;
  657. }
  658.  
  659. int
  660. mapped_c(int remap, int raw)
  661. {
  662.     int c;
  663.     int matched;
  664.     struct maprec *mp;
  665.     int speckey = FALSE;
  666.     static ITBUFF *mappedchars = NULL;
  667.  
  668.     /* still some pushback left? */
  669.     mapgetc_raw_flag = raw;
  670.     c = mapgetc();
  671.  
  672.     if ((c & YESREMAP) == 0 && (!remap || (c & NOREMAP)))
  673.     return (c & ~REMAPFLAGS);
  674.  
  675.     c &= ~REMAPFLAGS;
  676.  
  677.     if (reading_msg_line)
  678.     mp = 0;
  679.     else if (insertmode)
  680.     mp = map_insert;
  681.     else
  682.     mp = map_command;
  683.  
  684.     /* if we got a function key from the lower layers, turn it into '#c'
  685.     and see if the user remapped that */
  686.     if (c & SPEC) {
  687.     mapungetc(kcod2key(c));
  688.     c = poundc;
  689.     speckey = TRUE;
  690.     }
  691.  
  692.     do {
  693.     (void)itb_init(&mappedchars, abortc);
  694.  
  695.     matched = maplookup(c, &mappedchars, mp, mapgetc, mapped_c_avail, mapped_c_start, TRUE);
  696.  
  697.  
  698.     while(itb_more(mappedchars))
  699.         mapungetc(itb_next(mappedchars));
  700.  
  701.     /* if the user has not mapped '#c', we return the wide code we got
  702.         in the first place.  unless they wanted it quoted.  then we
  703.         leave it as is */
  704.     if (!raw && speckey && !matched) {
  705.         c = mapgetc() & ~REMAPFLAGS;
  706.         if (c != poundc)
  707.             dbgwrite("BUG: # problem in mapped_c");
  708.         return (mapgetc() & ~REMAPFLAGS) | SPEC;
  709.     }
  710.  
  711.     c = mapgetc();
  712.  
  713.     if (!global_g_val(GMDREMAPFIRST))
  714.         matched = FALSE;
  715.  
  716.     speckey = FALSE;
  717.  
  718.     } while (matched &&
  719.     ((remap && !(c & NOREMAP)) || (c & YESREMAP)) );
  720.  
  721.     return c & ~REMAPFLAGS;
  722.  
  723. }
  724.  
  725. static int abbr_curr_off;
  726. static int abbr_search_lim;
  727.  
  728. static int
  729. abbr_getc(void)
  730. {
  731.     if (abbr_curr_off <= abbr_search_lim)
  732.     return -1; /* won't match anything in the tree */
  733.     return lgetc(DOT.l, --abbr_curr_off) & 0xff;
  734. }
  735.  
  736. static int
  737. abbr_c_avail(void)
  738. {
  739.     return TRUE;
  740. }
  741.  
  742. static int
  743. abbr_c_start(void)
  744. {
  745.     if (abbr_curr_off > abbr_search_lim) {
  746.     /* we need to check the char in front of the match.
  747.        if it's a similar type to the first char of the match,
  748.        i.e. both idents, or both non-idents, we do nothing.
  749.        if whitespace precedes either ident or non-ident, the
  750.        match is good.
  751.      */
  752.     char first, prev;
  753.     first = lgetc(DOT.l,abbr_curr_off);
  754.     prev = lgetc(DOT.l,abbr_curr_off-1);
  755.     if ((isident(first) && isident(prev)) ||
  756.         (!isident(first) && !(isident(prev) || isSpace(prev)))) {
  757.         return FALSE;
  758.     }
  759.     }
  760.     return TRUE;
  761. }
  762.  
  763. void
  764. abbr_check(int *backsp_limit_p)
  765. {
  766.     int matched;
  767.     ITBUFF *abbr_chars = NULL;
  768.     int status = TRUE;
  769.  
  770.     if (llength(DOT.l) < 1)
  771.     return;
  772.     abbr_curr_off = DOT.o;
  773.     abbr_search_lim = *backsp_limit_p;
  774.     (void)itb_init(&abbr_chars, abortc);
  775.     matched = maplookup(abbr_getc(), &abbr_chars, abbr_map,
  776.     abbr_getc, abbr_c_avail, abbr_c_start, FALSE);
  777.  
  778.  
  779.     if (matched) {
  780.         /* there are still some conditions that have to be met by
  781.            the preceding chars, if any */
  782.         if (!abbr_c_start()) {
  783.         itb_free(&abbr_chars);
  784.         return;
  785.         }
  786.         DOT.o -= matched;
  787.         ldelete((B_COUNT)matched, FALSE);
  788.         while(status && itb_more(abbr_chars))
  789.         status = inschar(itb_last(abbr_chars), backsp_limit_p);
  790.     }
  791.     itb_free(&abbr_chars);
  792.     return;
  793. }
  794.  
  795. /* do map tranlations.
  796.     C is first char to begin mapping on
  797.     OUTP is an ITBUFF in which to put the result
  798.     MP is the map in which to look
  799.     GET is a routine to use to get the next character
  800.     AVAIL is the routine that tells if GET can return something now
  801.   returns number of characters matched
  802. */
  803. static int
  804. maplookup(
  805.     int c,
  806.     ITBUFF **outp,
  807.     struct maprec *mp,
  808.     GetFunc get,
  809.     AvailFunc avail,
  810.     StartFunc start,
  811.     int suffix)
  812. {
  813.     struct maprec *rmp = NULL;
  814.     ITBUFF *unmatched = 0;
  815.     int matchedcnt;
  816.     int use_sys_timing;
  817.     int had_start = FALSE;
  818.     register int count = 0;    /* index into 'unmatched[]' */
  819.  
  820.     /*
  821.      * we don't want to delay for a user-specified :map!  starting with
  822.      * poundc since it's likely that the mapping is happening on behalf of
  823.      * a function key.  (it's so the user can ":map! #1 foobar" but still be
  824.      * able to insert a '#' character normally.)  if they've changed poundc
  825.      * so it's not something one normally inserts, then it's okay to delay
  826.      * on it.
  827.      */
  828.     use_sys_timing = (insertmode && c == poundc &&
  829.                 (isPrint(poundc) || isSpace(poundc)));
  830.  
  831.     unmatched = itb_init(&unmatched, 0);
  832.     itb_append(&unmatched, c);
  833.     count++;
  834.  
  835.     matchedcnt = 0;
  836.     while (mp != 0) {
  837.     if (c == mp->ch) {
  838.         if (mp->irv != -1 || mp->srv != NULL) {
  839.         rmp = mp;
  840.         matchedcnt += count;
  841.         unmatched = itb_init(&unmatched, 0);
  842.         count = 0;
  843.  
  844.         /* our code supports matching the longer of two maps one of
  845.          * which is a subset of the other.  vi matches the shorter
  846.          * one.
  847.          */
  848.             if ((*start)()) {
  849.             had_start = TRUE;
  850.             if (!global_g_val(GMDMAPLONGER)) {
  851.             break;
  852.             }
  853.         }
  854.         }
  855.  
  856.         mp = mp->dlink;
  857.  
  858.         if (!mp)
  859.         break;
  860.  
  861.         /* if there's no recorded input, and no user typeahead */
  862.         if (!(*avail)()) {
  863.  
  864.         /* give it a little extra time... */
  865.         int timer = 0;
  866.  
  867.         /* we want to use the longer of the two timers */
  868.  
  869.         /* get the user timer.  it may be zero */
  870.         if (!use_sys_timing && (mp->flags & MAPF_USERTIMER) != 0)
  871.             timer = global_g_val(GVAL_TIMEOUTUSERVAL);
  872.  
  873.         /* if there was no user timer, or this is a system
  874.             sequence, use the system timer if it's bigger */
  875.         if (timer == 0 || (mp->flags & MAPF_SYSTIMER) != 0) {
  876.             if (timer < global_g_val(GVAL_TIMEOUTVAL))
  877.                 timer = global_g_val(GVAL_TIMEOUTVAL);
  878.         }
  879.  
  880.         catnap(timer,TRUE);
  881.  
  882.         if (!(*avail)())
  883.             break;
  884.         }
  885.  
  886.         if ((c = (*get)()) < 0)
  887.         break;
  888.  
  889.         itb_append(&unmatched, c & ~REMAPFLAGS);
  890.         count++;
  891.  
  892.     }
  893.     else
  894.         mp = mp->flink;
  895.     }
  896.  
  897.     if (had_start && (rmp != 0)) {
  898.     /* unget the unmatched suffix */
  899.     while (suffix && (count > 0))
  900.         (void)itb_append(outp, itb_values(unmatched)[--count]);
  901.     /* unget the mapping and elide correct number of recorded chars */
  902.     if (rmp->srv) {
  903.         UINT remapflag;
  904.         char *cp;
  905.         /* cp = rmp->srv + cnt; */
  906.         for (cp = rmp->srv; *cp; cp++)
  907.         ;
  908.         if (rmp->flags & MAPF_NOREMAP)
  909.         remapflag = NOREMAP;
  910.         else
  911.         remapflag = 0;
  912.         while (cp > rmp->srv)
  913.         (void)itb_append(outp, char2int(*--cp)|remapflag);
  914.     }
  915.     else {
  916.         (void)itb_append(outp, rmp->irv);
  917.     }
  918.     }
  919.     else {    /* didn't find a match */
  920.     while (count > 0)
  921.         (void)itb_append(outp, itb_values(unmatched)[--count]);
  922.     matchedcnt = 0;
  923.     }
  924.     itb_free(&unmatched);
  925.     return matchedcnt;
  926. }
  927.  
  928. #if NO_LEAKS
  929. static void
  930. free_maprec(struct maprec **p)
  931. {
  932.     struct    maprec *q;
  933.     if ((q = *p) != 0) {
  934.         free_maprec(&(q->flink));
  935.         free_maprec(&(q->dlink));
  936.         FreeAndNull(q->srv);
  937.         *p = 0;
  938.         free((char *)q);
  939.     }
  940. }
  941.  
  942. void
  943. map_leaks(void)
  944. {
  945.     free_maprec(&map_command);
  946.     free_maprec(&map_insert);
  947.     free_maprec(&map_syskey);
  948.     free_maprec(&abbr_map);
  949. }
  950. #endif    /* NO_LEAKS */
  951.