home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / v / vim_src.zip / BUFFERS.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  16KB  |  803 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMitation
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * buffers.c
  13.  *
  14.  * manipulations with redo buffer and stuff buffer
  15.  */
  16.  
  17. #include "vim.h"
  18. #include "globals.h"
  19. #include "proto.h"
  20. #include "param.h"
  21.  
  22.  
  23. /*
  24.  * structure used to store one block of the stuff/redo/macro buffers
  25.  */
  26. struct bufblock
  27. {
  28.         struct bufblock *b_next;        /* pointer to next bufblock */
  29.         u_char            b_str[1];        /* contents (actually longer) */
  30. };
  31.  
  32. #define MINIMAL_SIZE 20                 /* minimal size for b_str */
  33.  
  34. /*
  35.  * header used for the stuff buffer and the redo buffer
  36.  */
  37. struct buffheader
  38. {
  39.         struct bufblock bh_first;        /* first (dummy) block of list */
  40.         struct bufblock *bh_curr;        /* bufblock for appending */
  41.         int             bh_index;        /* index for reading */
  42.         int             bh_space;        /* space in bh_curr for appending */
  43. };
  44.  
  45. static struct buffheader stuffbuff = {{NULL, NUL}, NULL, 0, 0};
  46. static struct buffheader redobuff = {{NULL, NUL}, NULL, 0, 0};
  47. static struct buffheader recordbuff = {{NULL, NUL}, NULL, 0, 0};
  48.  
  49.     /*
  50.      * when block_redo is TRUE redo buffer will not be changed
  51.      * used by edit() to repeat insertions and 'V' command for redoing
  52.      */
  53. static int        block_redo = FALSE;
  54.  
  55. struct mapblock
  56. {
  57.     struct mapblock *m_next;        /* next mapblock */
  58.     char            *m_keys;        /* mapped from */
  59.     char            *m_str;         /* mapped to */
  60.     int              m_mode;        /* valid mode */
  61. };
  62.  
  63. /* variables used by vgetorpeek() and flush_buffers */
  64. #define MAXMAPLEN 10    /* maximum length of key sequence to be mapped */
  65. static char        typeahead[MAXMAPLEN + 2];
  66. static int        typelen = 0;    /* number of characters in typeahead[] */
  67. static char        *mapstr = NULL;    /* mapped characters */
  68. static int        maplen = 0;        /* number of characters in mapstr */
  69.  
  70. static void        free_buff __ARGS((struct buffheader *));
  71. static void        add_buff __ARGS((struct buffheader *, char *));
  72. static void        add_num_buff __ARGS((struct buffheader *, long));
  73. static u_char    read_stuff __ARGS((int));
  74. static int        start_stuff __ARGS((void));
  75. static int        read_redo __ARGS((int));
  76. static u_char    vgetorpeek __ARGS((int));
  77. static void        showmap __ARGS((struct mapblock *));
  78.  
  79. /*
  80.  * free and clear a buffer
  81.  */
  82.     static void
  83. free_buff(buf)
  84.     struct buffheader *buf;
  85. {
  86.         register struct bufblock *p, *np;
  87.  
  88.         for (p = buf->bh_first.b_next; p != NULL; p = np)
  89.         {
  90.                 np = p->b_next;
  91.                 free((char *)p);
  92.         }
  93.         buf->bh_first.b_next = NULL;
  94. }
  95.  
  96. /*
  97.  * return the contents of a buffer as a single string
  98.  */
  99.     u_char *
  100. get_bufcont(buffer)
  101.     struct buffheader *buffer;
  102. {
  103.         unsigned        count = 0;
  104.         u_char            *p = NULL;
  105.         struct bufblock    *bp;
  106.  
  107. /* compute the total length of the string */
  108.         for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
  109.                 count += strlen((char *)bp->b_str);
  110.  
  111.         if (count != 0 && (p = (u_char *)alloc(count + 1)) != NULL)
  112.         {
  113.                 *p = NUL;
  114.                 for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
  115.                         strcat((char *)p, (char *)bp->b_str);
  116.         }
  117.         return (p);
  118. }
  119.  
  120. /*
  121.  * return the contents of the record buffer as a single string
  122.  *    and clear the record buffer
  123.  */
  124.     u_char *
  125. get_recorded()
  126. {
  127.         u_char *p;
  128.  
  129.         p = get_bufcont(&recordbuff);
  130.         free_buff(&recordbuff);
  131.         return (p);
  132. }
  133.  
  134. /*
  135.  * return the contents of the redo buffer as a single string
  136.  */
  137.     u_char *
  138. get_inserted()
  139. {
  140.         return(get_bufcont(&redobuff));
  141. }
  142.  
  143. /*
  144.  * add string "s" after the current block of buffer "buf"
  145.  */
  146.     static void
  147. add_buff(buf, s)
  148.     register struct buffheader    *buf;
  149.     char                        *s;
  150. {
  151.         struct bufblock *p;
  152.         int             n;
  153.         int             len;
  154.  
  155.         if ((n = strlen(s)) == 0)        /* don't add empty strings */
  156.                 return;
  157.  
  158.         if (buf->bh_first.b_next == NULL)        /* first add to list */
  159.         {
  160.                 buf->bh_space = 0;
  161.                 buf->bh_curr = &(buf->bh_first);
  162.         }
  163.         else if (buf->bh_curr == NULL)    /* buffer has already been read */
  164.         {
  165.                 emsg("Add to read buffer");
  166.                 return;
  167.         }
  168.         else if (buf->bh_index != 0)
  169.                 strcpy((char *)buf->bh_first.b_next->b_str, (char *)buf->bh_first.b_next->b_str + buf->bh_index);
  170.         buf->bh_index = 0;
  171.  
  172.         if (buf->bh_space >= n)
  173.         {
  174.                 strcat((char *)buf->bh_curr->b_str, s);
  175.                 buf->bh_space -= n;
  176.         }
  177.         else
  178.         {
  179.                 if (n < MINIMAL_SIZE)
  180.                         len = MINIMAL_SIZE;
  181.                 else
  182.                         len = n;
  183.                 p = (struct bufblock *)alloc((unsigned)(sizeof(struct bufblock) + len));
  184.                 if (p == NULL)
  185.                         return; /* no space, just forget it */
  186.                 buf->bh_space = len - n;
  187.                 strcpy((char *)p->b_str, s);
  188.  
  189.                 p->b_next = buf->bh_curr->b_next;
  190.                 buf->bh_curr->b_next = p;
  191.                 buf->bh_curr = p;
  192.         }
  193.         return;
  194. }
  195.  
  196.     static void
  197. add_num_buff(buf, n)
  198.     struct buffheader *buf;
  199.     long               n;
  200. {
  201.         char    number[32];
  202.  
  203.         sprintf(number, "%ld", n);
  204.         add_buff(buf, number);
  205. }
  206.  
  207. /*
  208.  * get one character from the stuff buffer
  209.  * If advance == TRUE go to the next char.
  210.  */
  211.     static u_char
  212. read_stuff(advance)
  213.     int            advance;
  214. {
  215.         register u_char c;
  216.         register struct bufblock *curr;
  217.  
  218.  
  219.         if (stuffbuff.bh_first.b_next == NULL)    /* buffer is empty */
  220.             return NUL;
  221.  
  222.         curr = stuffbuff.bh_first.b_next;
  223.         c = curr->b_str[stuffbuff.bh_index];
  224.  
  225.         if (advance)
  226.         {
  227.             if (curr->b_str[++stuffbuff.bh_index] == NUL)
  228.             {
  229.                 stuffbuff.bh_first.b_next = curr->b_next;
  230.                 free((char *)curr);
  231.                 stuffbuff.bh_index = 0;
  232.             }
  233.         }
  234.         return c;
  235. }
  236.  
  237. /*
  238.  * prepare stuff buffer for reading (if it contains something)
  239.  */
  240.     static int
  241. start_stuff()
  242. {
  243.     if (stuffbuff.bh_first.b_next == NULL)
  244.         return FALSE;
  245.     stuffbuff.bh_curr = &(stuffbuff.bh_first);
  246.     stuffbuff.bh_space = 0;
  247.     return TRUE;
  248. }
  249.  
  250. /*
  251.  * check if the stuff buffer is empty
  252.  */
  253.     int
  254. stuff_empty()
  255. {
  256.     if (stuffbuff.bh_first.b_next == NULL)
  257.         return TRUE;
  258.     return FALSE;
  259. }
  260.  
  261. /*
  262.  * remove all typeahead characters (used in case of an error).
  263.  */
  264.     void
  265. flush_buffers()
  266. {
  267.     start_stuff();
  268.     while (read_stuff(TRUE) != NUL)
  269.         ;
  270.     typelen = 0;
  271.     maplen = 0;
  272.     if (mapstr)
  273.         *mapstr = 0;
  274. }
  275.  
  276.     void
  277. ResetBuffers()
  278. {
  279.     if (!block_redo)
  280.         free_buff(&redobuff);
  281. }
  282.  
  283.     void
  284. AppendToRedobuff(s)
  285.     char           *s;
  286. {
  287.     if (!block_redo)
  288.         add_buff(&redobuff, s);
  289. }
  290.  
  291.     void
  292. AppendNumberToRedobuff(n)
  293.     long             n;
  294. {
  295.     if (!block_redo)
  296.         add_num_buff(&redobuff, n);
  297. }
  298.  
  299.     void
  300. stuffReadbuff(s)
  301.     char           *s;
  302. {
  303.     add_buff(&stuffbuff, s);
  304. }
  305.  
  306.     void
  307. stuffnumReadbuff(n)
  308.     long    n;
  309. {
  310.     add_num_buff(&stuffbuff, n);
  311. }
  312.  
  313. /*
  314.  * Read a character from the redo buffer.
  315.  * The redo buffer is left as it is.
  316.  */
  317.     static int
  318. read_redo(init)
  319.     int            init;
  320. {
  321.     static struct bufblock    *bp;
  322.     static u_char            *p;
  323.     int                        c;
  324.  
  325.     if (init)
  326.     {
  327.         if ((bp = redobuff.bh_first.b_next) == NULL)
  328.             return TRUE;
  329.         p = bp->b_str;
  330.         return FALSE;
  331.     }
  332.     if ((c = *p) != NUL)
  333.     {
  334.         if (*++p == NUL && bp->b_next != NULL)
  335.         {
  336.             bp = bp->b_next;
  337.             p = bp->b_str;
  338.         }
  339.     }
  340.     return c;
  341. }
  342.  
  343. /*
  344.  * copy the rest of the redo buffer into the stuff buffer (could be done faster)
  345.  */
  346.     void
  347. copy_redo()
  348. {
  349.     register int c;
  350.  
  351.     while ((c = read_redo(FALSE)) != NUL)
  352.         stuffReadbuff(mkstr(c));
  353. }
  354.  
  355. extern int redo_Quote_busy;        /* this is in normal.c */
  356.  
  357. /*
  358.  * Stuff the redo buffer into the stuffbuff.
  359.  * Insert the redo count into the command.
  360.  */
  361.     int
  362. start_redo(count)
  363.     long count;
  364. {
  365.         register int c;
  366.  
  367.         if (read_redo(TRUE))    /* init the pointers; return if nothing to redo */
  368.                 return FALSE;
  369.  
  370.         c = read_redo(FALSE);
  371.  
  372. /* copy the buffer name, if present */
  373.         if (c == '"')
  374.         {
  375.                 add_buff(&stuffbuff, "\"");
  376.                 c = read_redo(FALSE);
  377.  
  378.         /* if a numbered buffer is used, increment the number */
  379.                 if (c >= '1' && c < '9')
  380.                         ++c;
  381.                 add_buff(&stuffbuff, mkstr(c));
  382.                 c = read_redo(FALSE);
  383.         }
  384.  
  385.         if (c == 'q')    /* redo Quoting */
  386.         {
  387.             Quote = Curpos;
  388.             redo_Quote_busy = TRUE;
  389.             c = read_redo(FALSE);
  390.         }
  391.  
  392. /* try to enter the count (in place of a previous count) */
  393.         if (count)
  394.         {
  395.                 while (isdigit(c))        /* skip "old" count */
  396.                         c = read_redo(FALSE);
  397.                 add_num_buff(&stuffbuff, count);
  398.         }
  399.  
  400. /* copy from the redo buffer into the stuff buffer */
  401.         add_buff(&stuffbuff, mkstr(c));
  402.         copy_redo();
  403.         return TRUE;
  404. }
  405.  
  406. /*
  407.  * Repeat the last insert (R, o, O, a, A, i or I command) by stuffing the redo buffer
  408.  * into the stuffbuff.
  409.  */
  410.     int
  411. start_redo_ins()
  412. {
  413.         register u_char c;
  414.  
  415.         if (read_redo(TRUE))
  416.                 return FALSE;
  417.         start_stuff();
  418.  
  419. /* skip the count and the command character */
  420.         while ((c = read_redo(FALSE)) != NUL)
  421.         {
  422.             c = toupper(c);
  423.             if (strchr("AIRO", c) != NULL)
  424.             {
  425.                 if (c == 'O')
  426.                     stuffReadbuff(NL_STR);
  427.                 break;
  428.             }
  429.         }
  430.  
  431. /* copy the typed text from the redo buffer into the stuff buffer */
  432.         copy_redo();
  433.         block_redo = TRUE;
  434.         return TRUE;
  435. }
  436.  
  437.     void
  438. set_redo_ins()
  439. {
  440.         block_redo = TRUE;
  441. }
  442.  
  443.     void
  444. stop_redo_ins()
  445. {
  446.         block_redo = FALSE;
  447. }
  448.  
  449. struct mapblock maplist = {NULL, NULL, NULL}; /* first dummy entry in maplist */
  450.  
  451. /*
  452.  * insert a string in front of the map-buffer (for '@' command and vgetorpeek)
  453.  */
  454.     int
  455. ins_mapbuf(str)
  456.     char *str;
  457. {
  458.     register char *s;
  459.     register int newlen;
  460.  
  461.     newlen = maplen + strlen(str) + 1;
  462.     if (newlen < 0)                /* string is getting too long */
  463.     {
  464.         emsg(e_toocompl);        /* also calls flush_buffers */
  465.         return -1;
  466.     }
  467.     s = alloc(newlen);
  468.     if (s == NULL)
  469.         return -1;
  470.     strcpy(s, str);
  471.     if (mapstr)
  472.     {
  473.         strcat(s, mapstr);
  474.         free(mapstr);
  475.     }
  476.     mapstr = s;
  477.     maplen = strlen(mapstr);
  478.     return 0;
  479. }
  480.  
  481. extern int arrow_used;        /* this is in edit.c */
  482.  
  483. /*
  484.  * get a character: 1. from the stuffbuffer
  485.  *                    2. from the user
  486.  *
  487.  * KeyTyped is set to TRUE in the case the user typed the key.
  488.  * If advance is TRUE, we really get the character. Otherwise we just look
  489.  * whether there is a character available.
  490.  */
  491.     static u_char
  492. vgetorpeek(advance)
  493.     int        advance;
  494. {
  495.     register int    c;
  496.     int                n = 0;        /* init for GCC */
  497.     char            *str;
  498.     int                len;
  499.     struct mapblock *mp;
  500.     int                mode = State;
  501.  
  502.     if (mode == REPLACE || mode == CMDLINE)
  503.         mode = INSERT;            /* treat replace mode just like insert mode */
  504.     else if (mode == NORMAL_BUSY)
  505.         mode = NORMAL;
  506.  
  507.     start_stuff();
  508.     do
  509.     {
  510.         c = read_stuff(advance);
  511.         if (c != NUL)
  512.             KeyTyped = FALSE;
  513.         else
  514.         {
  515.             /*
  516.              * Loop until we either find a matching mapped key, or we
  517.              * are sure that it is not a mapped key.
  518.              * We do this first for mapstr and then for typeahead.
  519.              * If a mapped key sequence is found we go back to mapstr to
  520.              * try re-mapping.
  521.              */
  522.             if (maplen)        /* first try mapstr */
  523.             {
  524.                 str = mapstr;
  525.                 len = maplen;
  526.             }
  527.             else            /* no mapped chars, try typeahead[] */
  528.             {
  529.                 str = typeahead;
  530.                 len = typelen;
  531.             }
  532.  
  533.             for (;;)        /* loop until we got a character */
  534.             {
  535.                 breakcheck();                /* check for CTRL-C */
  536.                 if (!got_int && len > 0)    /* see if we have a mapped key sequence */
  537.                 {
  538.                     /*
  539.                      * walk through the maplist until we find an
  540.                      * entry that matches.
  541.                      */
  542.                     for (mp = maplist.m_next; mp; mp = mp->m_next)
  543.                     {
  544.                         if (mp->m_mode != mode)
  545.                             continue;
  546.                         n = strlen(mp->m_keys);
  547.                         if (!strncmp(mp->m_keys, str, (size_t)(n > len ? len : n)))
  548.                             break;
  549.                     }
  550.                     if (mp == NULL || (str == mapstr && (n > len ||
  551.                                 p_remap == FALSE))) /* no match found */
  552.                     {
  553.                         c = str[0] & 255;
  554.                         if (str == mapstr)
  555.                             KeyTyped = FALSE;
  556.                         else
  557.                             KeyTyped = TRUE;
  558.                         if (advance)
  559.                         {
  560.                             strncpy(&str[0], &str[1], (size_t)len);
  561.                             if (str == mapstr)
  562.                                 --maplen;
  563.                             else
  564.                                 --typelen;
  565.                         }
  566.                         break;
  567.                     }
  568.                     if (n <= len)    /* complete match */
  569.                     {
  570.                             /* remove the mapped keys */
  571.                         len -= n;
  572.                         strncpy(&str[0], &str[n], (size_t)(len + 1));
  573.                         if (str == mapstr)
  574.                             maplen = len;
  575.                         else
  576.                             typelen = len;
  577.  
  578.                         /*
  579.                          * Put the replacement string in front of mapstr.
  580.                          */
  581.                         if (ins_mapbuf(mp->m_str) < 0)
  582.                         {
  583.                             c = -1;
  584.                             break;
  585.                         }
  586.                         str = mapstr;
  587.                         len = maplen;
  588.                         continue;
  589.                     }
  590.                 }
  591.                 c = inchar(!advance);
  592.                 if (c <= NUL || !advance)    /* no character available or async */
  593.                 {
  594.                     if (!advance)
  595.                         break;
  596.                 }
  597.                 else
  598.                 {
  599.                     typeahead[typelen++] = c;
  600.                     updatescript(c);
  601.                     if (Recording)
  602.                         add_buff(&recordbuff, mkstr(c));
  603.  
  604.                             /* do not sync in insert mode, unless cursor key has
  605.                              * been used */
  606.                     if (mode != INSERT || arrow_used)        
  607.                         u_sync();
  608.                 }
  609.                 len = typelen;
  610.                 str = typeahead;
  611.             }
  612.             if (got_int)        /* interrupted: remove all chars */
  613.             {
  614.                 c = -1;
  615.                 continue;
  616.             }
  617.         }
  618.     } while (c < 0 || (advance && c == NUL));
  619.                         /* if advance is FALSE don't loop on NULs */
  620.  
  621.     return (u_char) c;
  622. }
  623.  
  624.     u_char
  625. vgetc()
  626. {
  627.     return (vgetorpeek(TRUE));
  628. }
  629.  
  630.     u_char
  631. vpeekc()
  632. {
  633.     return (vgetorpeek(FALSE));
  634. }
  635.  
  636. /*
  637.  * unmap[!] {lhs}        : remove key mapping for {lhs}
  638.  * map[!]                : show all key mappings
  639.  * map[!] {lhs}            : show key mapping for {lhs}
  640.  * map[!] {lhs} {rhs}    : set key mapping for {lhs} to {rhs}
  641.  *
  642.  * unmap == 1 for unmap command.
  643.  * arg is pointer to any arguments.
  644.  * mode is INSERT if [!] is present.
  645.  * 
  646.  * Return 0 for success
  647.  *          1 for invalid arguments
  648.  *          2 for no match
  649.  *          3 for ambiguety
  650.  *          4 for out of mem
  651.  */
  652.     int
  653. domap(unmap, arg, mode)
  654.     int        unmap;
  655.     char    *arg;
  656.     int        mode;
  657. {
  658.         struct mapblock *mp, *mprev;
  659.         char *p;
  660.         int n = 0;            /* init for GCC */
  661.         int len = 0;        /* init for GCC */
  662.         char *newstr;
  663.  
  664. /*
  665.  * find end of keys
  666.  */
  667.         p = arg;
  668.         skiptospace(&p);
  669.         if (*p != NUL)
  670.             *p++ = NUL;
  671.         skipspace(&p);
  672.  
  673. /*
  674.  * check arguments and translate function keys
  675.  */
  676.         if (*arg != NUL)
  677.         {
  678.                 if (unmap && *p != NUL)                /* unmap has no arguments */
  679.                     return 1;
  680.                 if (*arg == '#' && isdigit(*(arg + 1)))    /* function key */
  681.                 {
  682.                     if (*++arg == '0')
  683.                         *(u_char *)arg = K_F10;
  684.                     else
  685.                         *arg += K_F1 - '1';
  686.                 }
  687.                 len = strlen(arg);
  688.                 if (len > MAXMAPLEN)            /* maximum lenght of 10 chars */
  689.                     return 2;
  690.         }
  691.  
  692. /*
  693.  * Find an entry in the maplist that matches.
  694.  */
  695.         if (*arg == NUL || (!unmap && *p == NUL))
  696.             settmode(0);                /* set cooked mode so output can be halted */
  697.         for (mp = maplist.m_next, mprev = &maplist; mp; mprev = mp, mp = mp->m_next)
  698.         {
  699.             if (mp->m_mode != mode)
  700.                 continue;
  701.             n = strlen(mp->m_keys);
  702.             if (*arg == NUL)
  703.                 showmap(mp);
  704.             else if (!strncmp(mp->m_keys, arg, (size_t)(n < len ? n : len)))
  705.             {
  706.                 if (!unmap && *p == NUL)
  707.                     showmap(mp);
  708.                 else
  709.                     break;
  710.             }
  711.         }
  712.         if (*arg == NUL || (!unmap && *p == NUL))
  713.         {
  714.                 settmode(1);
  715.                 wait_return(TRUE);
  716.                 return 0;                /* listing finished */
  717.         }
  718.  
  719.         if (mp == NULL)         /* new entry or nothing to remove */
  720.         {
  721.                 if (unmap)
  722.                         return 2;        /* no match */
  723.  
  724.                 /* allocate a new entry for the maplist */
  725.                 mp = (struct mapblock *)alloc((unsigned)sizeof(struct mapblock));
  726.                 if (mp == NULL)
  727.                         return 4;        /* no mem */
  728.                 mp->m_keys = strsave(arg);
  729.                 mp->m_str = strsave(p);
  730.                 if (mp->m_keys == NULL || mp->m_str == NULL)
  731.                 {
  732.                         free(mp->m_keys);
  733.                         free(mp->m_str);
  734.                         free(mp);
  735.                         return 4;        /* no mem */
  736.                 }
  737.  
  738.                 /* add the new entry in front of the maplist */
  739.                 mp->m_next = maplist.m_next;
  740.                 mp->m_mode = mode;
  741.                 maplist.m_next = mp;
  742.                 return 0;                /* added OK */
  743.         }
  744.         if (n != len)
  745.             return 3;                    /* ambigious */
  746.  
  747.         if (unmap)
  748.         {
  749.                 free(mp->m_keys);
  750.                 free(mp->m_str);
  751.                 mprev->m_next = mp->m_next;
  752.                 free(mp);
  753.                 return 0;                /* removed OK */
  754.         }
  755.  
  756. /*
  757.  * replace existing entry
  758.  */
  759.         newstr = strsave(p);
  760.         if (newstr == NULL)
  761.                 return 4;                /* no mem */
  762.         free(mp->m_str);
  763.         mp->m_str = newstr;
  764.  
  765.         return 0;                        /* replaced OK */
  766. }
  767.  
  768.     static void
  769. showmap(mp)
  770.     struct mapblock *mp;
  771. {
  772.     int len;
  773.  
  774.     len = outtrans(mp->m_keys, -1);    /* get length of what we have written */
  775.     while (len < MAXMAPLEN)
  776.     {
  777.         outchar(' ');                /* padd with blanks */
  778.         ++len;
  779.     }
  780.     outtrans(mp->m_str, -1);
  781.     outchar('\n');
  782.     flushbuf();
  783. }
  784.  
  785. /*
  786.  * Write map commands for the current mapping to an .exrc file.
  787.  * Return 1 on error.
  788.  */
  789.     int
  790. makemap(fd)
  791.     FILE *fd;
  792. {
  793.     struct mapblock *mp;
  794.  
  795.     for (mp = maplist.m_next; mp; mp = mp->m_next)
  796.     {
  797.         if (fprintf(fd, "map%c %s %s\n", mp->m_mode == INSERT ? '!' : ' ',
  798.                                     mp->m_keys, mp->m_str) < 0)
  799.             return 1;
  800.     }
  801.     return 0;
  802. }
  803.