home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / vim-2.0.lha / Vim-2.0 / src / ops.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  30.5 KB  |  1,490 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  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.  * ops.c: implementation of various operators: doshift, dodelete, dotilde,
  13.  *          dochange, doyank, doput, dojoin
  14.  */
  15.  
  16. #include "vim.h"
  17. #include "globals.h"
  18. #include "proto.h"
  19. #include "param.h"
  20. #include "ops.h"
  21.  
  22. /*
  23.  * We have one yank buffer for normal yanks and puts, nine yank buffers for
  24.  * deletes and 26 yank buffers for use by name.
  25.  * Each yank buffer is an array of pointers to lines.
  26.  */
  27. static struct yankbuf
  28. {
  29.     char        **y_array;        /* pointer to array of line pointers */
  30.     linenr_t     y_size;         /* number of lines in y_array */
  31.     char        y_type;         /* MLINE, MCHAR or MBLOCK */
  32. } y_buf[36];                    /* 0..9 = number buffers, 10..35 = char buffers */
  33.  
  34. static struct    yankbuf *y_current;        /* ptr to current yank buffer */
  35. static int        yankappend;                /* TRUE when appending */
  36. static struct    yankbuf *y_previous = NULL; /* ptr to last written yank buffer */
  37.  
  38. static void        get_yank_buffer __ARGS((int));
  39. static int        stuff_yank __ARGS((int, char *));
  40. static void        free_yank __ARGS((long));
  41. static void        free_yank_all __ARGS((void));
  42. static void        block_prep __ARGS((linenr_t, int));
  43.  
  44. /* variables use by block_prep, dodelete and doyank */
  45. static int        startspaces;
  46. static int        endspaces;
  47. static int        textlen;
  48. static char        *textstart;
  49. static colnr_t    textcol;
  50.  
  51. /*
  52.  * doshift - handle a shift operation
  53.  */
  54.     void
  55. doshift(op)
  56.     int             op;
  57. {
  58.     register long i;
  59.  
  60.     if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + nlines)))
  61.         return;
  62.  
  63.     Curpos.lnum += nlines;        /* start with last line, leave cursor on first */
  64.     for (i = nlines; --i >= 0; )
  65.         if (lineempty(--Curpos.lnum))
  66.             Curpos.col = 0;
  67.         else
  68.         {
  69.             /* if (Visual_block)
  70.                     shift the block, not the whole line
  71.             else */
  72.                 shift_line(op == LSHIFT, p_sr);
  73.         }
  74.  
  75.     updateScreen(CURSUPD);
  76.  
  77.     if (nlines > p_report)
  78.         smsg("%ld line%s %ced", nlines, plural(nlines),
  79.                                     (op == RSHIFT) ? '>' : '<');
  80. }
  81.  
  82. /*
  83.  * shift the current line one shiftwidth left (if left != 0) or right
  84.  * leaves cursor on first blank in the line
  85.  */
  86.     void
  87. shift_line(left, round)
  88.     int left;
  89.     int    round;
  90. {
  91.     register int count;
  92.     register int i, j;
  93.  
  94.     count = get_indent();            /* get current indent */
  95.  
  96.     if (round)                        /* round off indent */
  97.     {
  98.         i = count / (int)p_sw;        /* compute new indent */
  99.         j = count % (int)p_sw;
  100.         if (j)
  101.         {
  102.             if (!left)
  103.                 ++i;
  104.         }
  105.         else if (left)
  106.         {
  107.             if (i)
  108.                 --i;
  109.         }
  110.         else
  111.             ++i;
  112.         count = i * (int)p_sw;
  113.     }
  114.     else                /* original vi indent */
  115.     {
  116.         if (left)
  117.         {
  118.             count -= (int)p_sw;
  119.             if (count < 0)
  120.                 count = 0;
  121.         }
  122.         else
  123.             count += (int)p_sw;
  124.     }
  125.     set_indent(count, TRUE);        /* set new indent */
  126. }
  127.  
  128. /*
  129.  * Set y_current and yankappend, according to the value of yankbuffer.
  130.  */
  131.     static void
  132. get_yank_buffer(writing)
  133.     int        writing;
  134. {
  135.     register int i;
  136.  
  137.     yankappend = FALSE;
  138.     if (((yankbuffer == 0 && !writing) || yankbuffer == '"') && y_previous != NULL)
  139.     {
  140.         y_current = y_previous;
  141.         return;
  142.     }
  143.     i = yankbuffer;
  144.     if (isdigit(i))
  145.         i -= '0';
  146.     else if (islower(i))
  147.         i -= 'a' - 10;
  148.     else if (isupper(i))
  149.     {
  150.         i -= 'A' - 10;
  151.         yankappend = TRUE;
  152.     }
  153.     else            /* not 0-9, a-z or A-Z: use buffer 0 */
  154.         i = 0;
  155.     y_current = &(y_buf[i]);
  156.     if (writing)        /* remember the buffer we write into for doput() */
  157.         y_previous = y_current;
  158. }
  159.  
  160. /*
  161.  * (stop) recording into a yank buffer
  162.  */
  163.     int
  164. dorecord(c)
  165.     int c;
  166. {
  167.     char *p;
  168.     static int bufname;
  169.  
  170.     if (Recording == FALSE)         /* start recording */
  171.     {
  172.         if (!isalnum(c) && c != '"')    /* registers 0-9, a-z and " are allowed */
  173.             return FALSE;
  174.         Recording = TRUE;
  175.         showmode();
  176.         bufname = c;
  177.         return TRUE;
  178.     }
  179.     else                            /* stop recording */
  180.     {
  181.         Recording = FALSE;
  182.         msg("");
  183.             /* the trailing 'q' command will not have been put in the buffer */
  184.         p = (char *)get_recorded();
  185.         if (p == NULL)
  186.             return FALSE;
  187.         return (stuff_yank(bufname, p));
  188.     }
  189. }
  190.  
  191. /*
  192.  * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
  193.  * 'p' is assumed to be alloced.
  194.  */
  195.     static int
  196. stuff_yank(bufname, p)
  197.     int bufname;
  198.     char *p;
  199. {
  200.     char *lp;
  201.     char **pp;
  202.  
  203.     yankbuffer = bufname;
  204.     if (yankbuffer == '.' || yankbuffer == '%')        /* read-only buffer */
  205.         return FALSE;
  206.     get_yank_buffer(TRUE);
  207.     if (yankappend && y_current->y_array != NULL)
  208.     {
  209.         pp = &(y_current->y_array[y_current->y_size - 1]);
  210.         lp = lalloc((u_long)(strlen(*pp) + strlen(p) + 1), TRUE);
  211.         if (lp == NULL)
  212.         {
  213.             free(p);
  214.             return FALSE;
  215.         }
  216.         strcpy(lp, *pp);
  217.         strcat(lp, p);
  218.         free(p);
  219.         free(*pp);
  220.         *pp = lp;
  221.     }
  222.     else
  223.     {
  224.         free_yank_all();
  225.         if ((y_current->y_array = (char **)alloc((unsigned)sizeof(char *))) == NULL)
  226.         {
  227.             free(p);
  228.             return FALSE;
  229.         }
  230.         y_current->y_array[0] = p;
  231.         y_current->y_size = 1;
  232.         y_current->y_type = MCHAR;    /* used to be MLINE, why? */
  233.     }
  234.     return TRUE;
  235. }
  236.  
  237. /*
  238.  * execute a yank buffer (register): copy it into the stuff buffer
  239.  */
  240.     int
  241. doexecbuf(c)
  242.     int c;
  243. {
  244.     static int lastc = NUL;
  245.     long i;
  246.  
  247.     if (c == '@')            /* repeat previous one */
  248.         c = lastc;
  249.  
  250.     lastc = c;
  251.     if (!isalnum(c) && c != '"')        /* registers 0-9, a-z and " are allowed */
  252.         return FALSE;
  253.  
  254.     yankbuffer = c;
  255.     get_yank_buffer(FALSE);
  256.     if (y_current->y_array == NULL)
  257.         return FALSE;
  258.  
  259.     for (i = y_current->y_size; --i >= 0; )
  260.     {
  261.     /* insert newline between lines and after last line if type is MLINE */
  262.         if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  263.         {
  264.             if (ins_typestr("\n", FALSE) < 0)
  265.                 return FALSE;
  266.         }
  267.         if (ins_typestr(y_current->y_array[i], FALSE) < 0)
  268.             return FALSE;
  269.     }
  270.     Exec_reg = TRUE;        /* disable the 'q' command */
  271.     return TRUE;
  272. }
  273.  
  274. /*
  275.  * insert a yank buffer: copy it into the Read buffer
  276.  */
  277.     int
  278. insertbuf(c)
  279.     int c;
  280. {
  281.     long i;
  282.  
  283.     if (c == '%')                        /* insert file name */
  284.     {
  285.         if (check_fname())
  286.             return FALSE;
  287.         stuffReadbuff(xFilename);
  288.         return TRUE;
  289.     }
  290.  
  291.     if (!isalnum(c) && c != '"')        /* registers 0-9, a-z and " are allowed */
  292.         return FALSE;
  293.  
  294.     yankbuffer = c;
  295.     get_yank_buffer(FALSE);
  296.     if (y_current->y_array == NULL)
  297.         return FALSE;
  298.  
  299.     for (i = 0; i < y_current->y_size; ++i)
  300.     {
  301.         stuffReadbuff(y_current->y_array[i]);
  302.     /* insert newline between lines and after last line if type is MLINE */
  303.         if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  304.             stuffReadbuff("\n");
  305.     }
  306.     return TRUE;
  307. }
  308.  
  309. /*
  310.  * dodelete - handle a delete operation
  311.  */
  312.     void
  313. dodelete()
  314. {
  315.     register int    n;
  316.     linenr_t        lnum;
  317.     char            *ptr;
  318.     linenr_t        old_lcount = line_count;
  319.  
  320.     /*
  321.      * Imitate the strange Vi behaviour: If the delete spans more than one line
  322.      * and mtype == MCHAR and the result is a blank line, make the delete
  323.      * linewise. Don't do this for the change command.
  324.      */
  325.     if (mtype == MCHAR && nlines > 1 && operator == DELETE)
  326.     {
  327.         ptr = nr2ptr(endop.lnum) + endop.col + mincl;
  328.         skipspace(&ptr);
  329.         if (*ptr == NUL && startinmargin())
  330.             mtype = MLINE;
  331.     }
  332.  
  333.         /*
  334.          * Shift number buffers if there is no yankbuffer defined and we do a
  335.          * delete that contains a line break.
  336.          */
  337.     if (yankbuffer == 0 && (mtype == MLINE || nlines > 1))
  338.     {
  339.         y_current = &y_buf[9];
  340.         free_yank_all();                /* free buffer nine */
  341.         for (n = 9; n > 1; --n)
  342.             y_buf[n] = y_buf[n - 1];
  343.         y_previous = y_current = &y_buf[1];
  344.         y_buf[1].y_array = NULL;        /* set buffer one to empty */
  345.     }
  346.     else if (yankbuffer == '.' || yankbuffer == '%')    /* read-only buffer */
  347.     {
  348.         beep();
  349.         return;
  350.     }
  351.     else                                /* yank into specified buffer */
  352.         get_yank_buffer(TRUE);
  353.  
  354.     /*
  355.      * Do a yank of whatever we're about to delete. If there's too much stuff
  356.      * to fit in the yank buffer, then get a confirmation before doing the
  357.      * delete. This is crude, but simple. And it avoids doing a delete of
  358.      * something we can't put back if we want.
  359.      */
  360.     if (!doyank(TRUE))
  361.     {
  362.         if (ask_yesno("cannot yank; delete anyway") != 'y')
  363.         {
  364.             emsg(e_abort);
  365.             return;
  366.         }
  367.     }
  368.  
  369. /*
  370.  * block mode
  371.  */
  372.     if (Visual_block)
  373.     {
  374.         if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  375.             return;
  376.  
  377.         for (lnum = Curpos.lnum; Curpos.lnum <= endop.lnum; ++Curpos.lnum)
  378.         {
  379.             block_prep(Curpos.lnum, TRUE);
  380.             if (textlen == 0)        /* nothing to delete */
  381.                 continue;
  382.  
  383.         /*
  384.          * If we delete a TAB, it may be replaced by several characters.
  385.          * Thus the number of characters may increase!
  386.          */
  387.             n = textlen - startspaces - endspaces;
  388.         /* number of characters increases - make room */
  389.             if (n < 0 && !canincrease(-n))
  390.                 continue;
  391.             ptr = nr2ptr(Curpos.lnum) + textcol;
  392.         /* copy the part after the deleted part */
  393.             memmove(ptr + startspaces + endspaces, ptr + textlen, strlen(ptr + textlen) + 1);
  394.         /* insert spaces */
  395.             copy_spaces(ptr, (size_t)(startspaces + endspaces));
  396.             if (n > 0)
  397.                 canincrease(0);
  398.         }
  399.         Curpos.lnum = lnum;
  400.         CHANGED;
  401.         updateScreen(VALID_TO_CURSCHAR);
  402.         nlines = 0;        /* no lines deleted */
  403.     }
  404.     else if (mtype == MLINE)
  405.     {
  406.         if (operator == CHANGE)
  407.         {
  408.             dellines((long)(nlines - 1), TRUE, TRUE);
  409.             if (!u_saveCurpos())
  410.                 return;
  411.             while (delchar(TRUE));        /* slow but simple */
  412.         }
  413.         else
  414.         {
  415.             dellines(nlines, TRUE, TRUE);
  416.         }
  417.         u_clearline();    /* "U" command should not be possible after "dd" */
  418.     }
  419.     else if (nlines == 1)        /* delete characters within one line */
  420.     {
  421.         if (!u_saveCurpos())
  422.             return;
  423.         n = endop.col - startop.col + 1 - !mincl;
  424.         while (n-- > 0)
  425.             if (!delchar(TRUE))
  426.                 break;
  427.     }
  428.     else                        /* delete characters between lines */
  429.     {
  430.         if (!u_saveCurpos())    /* save first line for undo */
  431.             return;
  432.         n = Curpos.col;
  433.         while (Curpos.col >= n)    /* delete from cursor to end of line */
  434.             if (!delchar(TRUE))
  435.                 break;
  436.  
  437.         startop = Curpos;        /* remember Curpos */
  438.         ++Curpos.lnum;
  439.         dellines((long)(nlines - 2), TRUE, TRUE);    /* includes save for undo */
  440.  
  441.         if (!u_saveCurpos())    /* save last line for undo */
  442.             return;
  443.         n = endop.col - !mincl;
  444.         Curpos.col = 0;
  445.         while (n-- >= 0)        /* delete from start of line until endop */
  446.             if (!delchar(TRUE))
  447.                 break;
  448.         Curpos = startop;        /* restore Curpos */
  449.         dojoin(FALSE, TRUE);
  450.     }
  451.  
  452.     if ((mtype == MCHAR && nlines == 1) || operator == CHANGE)
  453.     {
  454.         cursupdate();
  455.         updateline();
  456.     }
  457.     else
  458.         updateScreen(CURSUPD);
  459.  
  460.     msgmore(line_count - old_lcount);
  461.  
  462.         /* correct endop for deleted text (for "']" command) */
  463.     if (Visual_block)
  464.         endop.col = startop.col;
  465.     else
  466.         endop = startop;
  467. }
  468.  
  469. /*
  470.  * dotilde - handle the (non-standard vi) tilde operator
  471.  */
  472.     void
  473. dotilde()
  474. {
  475.     FPOS pos;
  476.  
  477.     if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  478.         return;
  479.  
  480.     pos = startop;
  481.     if (Visual_block)        /* block mode */
  482.     {
  483.         for (; pos.lnum <= endop.lnum; ++pos.lnum)
  484.         {
  485.             block_prep(pos.lnum, FALSE);
  486.             pos.col = textcol;
  487.             while (--textlen >= 0)
  488.             {
  489.                 swapchar(&pos);
  490.                 if (inc(&pos) == -1)    /* at end of file */
  491.                     break;
  492.             }
  493.         }
  494.     }
  495.     else            /* not block mode */
  496.     {
  497.         if (mtype == MLINE)
  498.         {
  499.                 pos.col = 0;
  500.                 endop.col = strlen(nr2ptr(endop.lnum));
  501.                 if (endop.col)
  502.                         --endop.col;
  503.         }
  504.         else if (!mincl)
  505.             dec(&endop);
  506.  
  507.         while (ltoreq(pos, endop))
  508.         {
  509.             swapchar(&pos);
  510.             if (inc(&pos) == -1)    /* at end of file */
  511.                 break;
  512.         }
  513.     }
  514.  
  515.     if (mtype == MCHAR && nlines == 1 && !Visual_block)
  516.     {
  517.         cursupdate();
  518.         updateline();
  519.     }
  520.     else
  521.         updateScreen(CURSUPD);
  522.  
  523.     if (nlines > p_report)
  524.             smsg("%ld line%s ~ed", nlines, plural(nlines));
  525. }
  526.  
  527. /*
  528.  * If operator == UPPER: make uppercase,
  529.  * if operator == LOWER: make lowercase,
  530.  * else swap case of character at 'pos'
  531.  */
  532.     void
  533. swapchar(pos)
  534.     FPOS    *pos;
  535. {
  536.     int        c;
  537.  
  538.     c = gchar(pos);
  539.     if (islower(c) && operator != LOWER)
  540.     {
  541.         pchar(*pos, toupper(c));
  542.         CHANGED;
  543.     }
  544.     else if (isupper(c) && operator != UPPER)
  545.     {
  546.         pchar(*pos, tolower(c));
  547.         CHANGED;
  548.     }
  549. }
  550.  
  551. /*
  552.  * dochange - handle a change operation
  553.  */
  554.     void
  555. dochange()
  556. {
  557.     register colnr_t            l;
  558.  
  559.     l = startop.col;
  560.  
  561.     if (!no_op)
  562.         dodelete();
  563.  
  564.     if ((l > Curpos.col) && !lineempty(Curpos.lnum))
  565.         incCurpos();
  566.  
  567.     startinsert(NUL, FALSE, (linenr_t)1);
  568. }
  569.  
  570. /*
  571.  * set all the yank buffers to empty (called from main())
  572.  */
  573.     void
  574. init_yank()
  575. {
  576.         register int i;
  577.  
  578.         for (i = 0; i < 36; ++i)
  579.                 y_buf[i].y_array = NULL;
  580. }
  581.  
  582. /*
  583.  * Free "n" lines from the current yank buffer.
  584.  * Called for normal freeing and in case of error.
  585.  */
  586.     static void
  587. free_yank(n)
  588.     long n;
  589. {
  590.     if (y_current->y_array != NULL)
  591.     {
  592.         register long i;
  593.  
  594.         for (i = n; --i >= 0; )
  595.         {
  596.             if (i % 1000 == 999)                    /* this may take a while */
  597.                 smsg("freeing %ld lines", i + 1);
  598.             free(y_current->y_array[i]);
  599.         }
  600.         free((char *)y_current->y_array);
  601.         y_current->y_array = NULL;
  602.         if (n >= 1000)
  603.             msg("");
  604.     }
  605. }
  606.  
  607.     static void
  608. free_yank_all()
  609. {
  610.         free_yank(y_current->y_size);
  611. }
  612.  
  613. /*
  614.  * Yank the text between Curpos and startpos into a yank buffer.
  615.  * If we are to append ("uppercase), we first yank into a new yank buffer and
  616.  * then concatenate the old and the new one (so we keep the old one in case
  617.  * of out-of-memory).
  618.  */
  619.     int
  620. doyank(deleting)
  621.     int deleting;
  622. {
  623.     long                 i;                /* index in y_array[] */
  624.     struct yankbuf        *curr;            /* copy of y_current */
  625.     struct yankbuf        new;             /* new yank buffer when appending */
  626.     char                **new_ptr;
  627.     register linenr_t    lnum;            /* current line number */
  628.     long                 j;
  629.     int                    yanktype = mtype;
  630.     long                yanklines = nlines;
  631.     linenr_t            yankendlnum = endop.lnum;
  632.  
  633.     char                *pnew;
  634.  
  635.     if (yankbuffer == '.' || yankbuffer == '%')            /* read-only buffer */
  636.     {
  637.         beep();
  638.         return FALSE;
  639.     }
  640.     if (!deleting)                    /* dodelete() already set y_current */
  641.         get_yank_buffer(TRUE);
  642.  
  643.     curr = y_current;
  644.     if (yankappend && y_current->y_array != NULL) /* append to existing contents */
  645.         y_current = &new;
  646.     else
  647.         free_yank_all();        /* free previously yanked lines */
  648.  
  649. /*
  650.  * If the cursor was in column 1 before and after the movement, the
  651.  * yank is always linewise.
  652.  */
  653.     if (mtype == MCHAR && startop.col == 0 && endop.col == 0 && nlines > 1)
  654.     {
  655.         yanktype = MLINE;
  656.         if (mincl == FALSE && yankendlnum > startop.lnum)
  657.         {
  658.             --yankendlnum;
  659.             --yanklines;
  660.         }
  661.     }
  662.  
  663.     y_current->y_size = yanklines;
  664.     y_current->y_type = yanktype;    /* set the yank buffer type */
  665.     y_current->y_array = (char **)lalloc((u_long)(sizeof(char *) * yanklines), TRUE);
  666.  
  667.     if (y_current->y_array == NULL)
  668.     {
  669.         y_current = curr;
  670.         return FALSE;
  671.     }
  672.  
  673.     i = 0;
  674.     lnum = startop.lnum;
  675.  
  676.     if (Visual_block)
  677.     {
  678. /*
  679.  * block mode
  680.  */
  681.         y_current->y_type = MBLOCK;    /* set the yank buffer type */
  682.         for ( ; lnum <= yankendlnum; ++lnum)
  683.         {
  684.             block_prep(lnum, FALSE);
  685.             if ((pnew = alloc(startspaces + endspaces + textlen + 1)) == NULL)
  686.                 goto fail;
  687.             y_current->y_array[i++] = pnew;
  688.             copy_spaces(pnew, (size_t)startspaces);
  689.             pnew += startspaces;
  690.             strncpy(pnew, textstart, (size_t)textlen);
  691.             pnew += textlen;
  692.             copy_spaces(pnew, (size_t)endspaces);
  693.             pnew += endspaces;
  694.             *pnew = NUL;
  695.         }
  696.     }
  697.     else
  698.     {
  699. /*
  700.  * there are three parts for non-block mode:
  701.  * 1. if yanktype != MLINE yank last part of the top line
  702.  * 2. yank the lines between startop and endop, inclusive when yanktype == MLINE
  703.  * 3. if yanktype != MLINE yank first part of the bot line
  704.  */
  705.         if (yanktype != MLINE)
  706.         {
  707.             if (yanklines == 1)        /* startop and endop on same line */
  708.             {
  709.                     j = endop.col - startop.col + 1 - !mincl;
  710.                     if ((y_current->y_array[0] = strnsave(nr2ptr(lnum) + startop.col, (int)j)) == NULL)
  711.                     {
  712.     fail:
  713.                             free_yank(i);    /* free the lines that we allocated */
  714.                             y_current = curr;
  715.                             return FALSE;
  716.                     }
  717.                     goto success;
  718.             }
  719.             if ((y_current->y_array[0] = strsave(nr2ptr(lnum++) + startop.col)) == NULL)
  720.                     goto fail;
  721.             ++i;
  722.         }
  723.  
  724.         while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
  725.         {
  726.             if ((y_current->y_array[i] = strsave(nr2ptr(lnum++))) == NULL)
  727.                     goto fail;
  728.             ++i;
  729.         }
  730.         if (yanktype != MLINE)
  731.         {
  732.             if ((y_current->y_array[i] = strnsave(nr2ptr(yankendlnum), endop.col + 1 - !mincl)) == NULL)
  733.                     goto fail;
  734.         }
  735.     }
  736.  
  737. success:
  738.     if (curr != y_current)        /* append the new block to the old block */
  739.     {
  740.         new_ptr = (char **)lalloc((u_long)(sizeof(char *) * (curr->y_size + y_current->y_size)), TRUE);
  741.         if (new_ptr == NULL)
  742.                 goto fail;
  743.         for (j = 0; j < curr->y_size; ++j)
  744.                 new_ptr[j] = curr->y_array[j];
  745.         free(curr->y_array);
  746.         curr->y_array = new_ptr;
  747.  
  748.         if (yanktype == MLINE)     /* MLINE overrides MCHAR and MBLOCK */
  749.                 curr->y_type = MLINE;
  750.         if (curr->y_type == MCHAR)        /* concatenate the last line of the old
  751.                                         block with the first line of the new block */
  752.         {
  753.                 new_ptr = (char **)lalloc((u_long)(strlen(curr->y_array[curr->y_size - 1]) + strlen(y_current->y_array[0]) + 1), TRUE);
  754.                 if (new_ptr == NULL)
  755.                 {
  756.                         i = y_current->y_size - 1;
  757.                         goto fail;
  758.                 }
  759.                 strcpy((char *)new_ptr, curr->y_array[--j]);
  760.                 strcat((char *)new_ptr, y_current->y_array[0]);
  761.                 free(curr->y_array[j]);
  762.                 free(y_current->y_array[0]);
  763.                 curr->y_array[j++] = (char *)new_ptr;
  764.                 i = 1;
  765.         }
  766.         else
  767.                 i = 0;
  768.         while (i < y_current->y_size)
  769.                 curr->y_array[j++] = y_current->y_array[i++];
  770.         curr->y_size = j;
  771.         free(y_current->y_array);
  772.         y_current = curr;
  773.     }
  774.     if (operator == YANK)        /* don't do this when deleting */
  775.     {
  776.         if (yanktype == MCHAR && !Visual_block)
  777.             --yanklines;
  778.         if (yanklines > p_report)
  779.         {
  780.             cursupdate();        /* redisplay now, so message is not deleted */
  781.             smsg("%ld line%s yanked", yanklines, plural(yanklines));
  782.         }
  783.     }
  784.  
  785.     return TRUE;
  786. }
  787.  
  788.     void
  789. doput(dir, count)
  790.     int dir;
  791.     long count;
  792. {
  793.     char        *ptr, *ep;
  794.     int         newlen;
  795.     int            totlen = 0;        /* init for gcc */
  796.     linenr_t    lnum;
  797.     int            col;
  798.     long         i;        /* index in y_array[] */
  799.     int         y_type;
  800.     long         y_size;
  801.     char        **y_array;
  802.     long         nlines = 0;
  803.     int            vcol;
  804.     int            delchar;
  805.     int            incr = 0;
  806.     long        j;
  807.     FPOS        newCurpos;
  808.     int            commandchar;
  809.     char        temp[2];
  810.  
  811.     startop = Curpos;            /* default for "'[" command */
  812.     if (dir == FORWARD)
  813.         startop.col++;
  814.     endop = Curpos;                /* default for "']" command */
  815.     commandchar = (dir == FORWARD ? (count == -1 ? 'o' : 'a') : (count == -1 ? 'O' : 'i'));
  816.     if (yankbuffer == '.')        /* use inserted text */
  817.     {
  818.         stuff_inserted(commandchar, count, FALSE);
  819.         return;
  820.     }
  821.     else if (yankbuffer == '%')    /* use file name */
  822.     {
  823.         if (!check_fname())
  824.         {
  825.             stuffcharReadbuff(commandchar);
  826.             stuffReadbuff(xFilename);
  827.             stuffcharReadbuff(ESC);
  828.         }
  829.         return;
  830.     }
  831.     get_yank_buffer(FALSE);
  832.  
  833.     y_type = y_current->y_type;
  834.     y_size = y_current->y_size;
  835.     y_array = y_current->y_array;
  836.  
  837.     if (count == -1)        /* :put command */
  838.     {
  839.         y_type = MLINE;
  840.         count = 1;
  841.     }
  842.  
  843.     if (y_size == 0 || y_array == NULL)
  844.     {
  845.         temp[0] = yankbuffer;
  846.         temp[1] = NUL;
  847.         emsg2("Nothing in register %s", temp);
  848.         return;
  849.     }
  850.  
  851.     if (y_type == MBLOCK)
  852.     {
  853.         lnum = Curpos.lnum + y_size + 1;
  854.         if (lnum > line_count)
  855.             lnum = line_count + 1;
  856.         if (!u_save(Curpos.lnum - 1, lnum))
  857.             return;
  858.     }
  859.     else if (!u_saveCurpos())
  860.         return;
  861.  
  862.     newlen = strlen(y_array[0]);
  863.     CHANGED;
  864.  
  865.     lnum = Curpos.lnum;
  866.     col = Curpos.col;
  867.  
  868. /*
  869.  * block mode
  870.  */
  871.     if (y_type == MBLOCK)
  872.     {
  873.         if (dir == FORWARD && gcharCurpos() != NUL)
  874.         {
  875.             col = getvcol(&Curpos, 3) + 1;
  876.             ++Curpos.col;
  877.         }
  878.         else
  879.             col = getvcol(&Curpos, 2);
  880.         for (i = 0; i < y_size; ++i)
  881.         {
  882.             startspaces = 0;
  883.             endspaces = 0;
  884.             textcol = 0;
  885.             vcol = 0;
  886.             delchar = 0;
  887.  
  888.         /* add a new line */
  889.             if (Curpos.lnum > line_count)
  890.             {
  891.                 ep = alloc_line(0);
  892.                 if (ep == NULL)
  893.                         goto error;
  894.                 appendline(line_count, ep);
  895.                 ++nlines;
  896.             }
  897.             ptr = nr2ptr(Curpos.lnum);
  898.             while (vcol < col && *ptr)
  899.             {
  900.                 /* Count a tab for what it's worth (if list mode not on) */
  901.                 incr = chartabsize(*ptr, vcol);
  902.                 vcol += incr;
  903.                 ++ptr;
  904.                 ++textcol;
  905.             }
  906.             if (vcol < col)    /* line too short, padd with spaces */
  907.             {
  908.                 startspaces = col - vcol;
  909.             }
  910.             else if (vcol > col)
  911.             {
  912.                 endspaces = vcol - col;
  913.                 startspaces = incr - endspaces;
  914.                 --textcol;
  915.                 delchar = 1;
  916.             }
  917.             newlen = strlen(y_array[i]);
  918.             totlen = count * newlen + startspaces + endspaces;
  919.             if (!canincrease(totlen))
  920.                 break;
  921.             ptr = nr2ptr(Curpos.lnum) + textcol;
  922.  
  923.         /* move the text after the cursor to the end of the line. */
  924.             memmove(ptr + totlen - delchar, ptr, strlen(ptr) + 1);
  925.         /* may insert some spaces before the new text */
  926.             copy_spaces(ptr, (size_t)startspaces);
  927.             ptr += startspaces;
  928.         /* insert the new text */
  929.             for (j = 0; j < count; ++j)
  930.             {
  931.                     strncpy(ptr, y_array[i], (size_t)newlen);
  932.                     ptr += newlen;
  933.             }
  934.         /* may insert some spaces after the new text */
  935.             copy_spaces(ptr, (size_t)endspaces);
  936.  
  937.             ++Curpos.lnum;
  938.             if (i == 0)
  939.                 Curpos.col += startspaces;
  940.         }
  941.         endop.lnum = Curpos.lnum - 1;        /* for "']" command */
  942.         endop.col = textcol + totlen - 1;
  943.         Curpos.lnum = lnum;
  944.         cursupdate();
  945.         updateScreen(VALID_TO_CURSCHAR);
  946.     }
  947.     else        /* not block mode */
  948.     {
  949.         if (y_type == MCHAR)
  950.         {
  951.     /* if type is MCHAR, FORWARD is the same as BACKWARD on the next character */
  952.             if (dir == FORWARD && gcharCurpos() != NUL)
  953.             {
  954.                 ++col;
  955.                 if (newlen)
  956.                 {
  957.                     ++Curpos.col;
  958.                     ++endop.col;
  959.                 }
  960.             }
  961.             newCurpos = Curpos;
  962.         }
  963.         else if (dir == BACKWARD)
  964.     /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
  965.             --lnum;
  966.         else    /* type == MLINE, dir == FORWARD */
  967.         {
  968.             startop.col = 0;
  969.             startop.lnum++;
  970.         }
  971.  
  972. /*
  973.  * simple case: insert into current line
  974.  */
  975.         if (y_type == MCHAR && y_size == 1)
  976.         {
  977.             i = count * newlen;
  978.             if (i)
  979.             {
  980.                 if (!canincrease((int)i))
  981.                     return;                 /* alloc() will give error message */
  982.                 ep = nr2ptr(lnum) + col;
  983.                 memmove(ep + i, ep, strlen(ep) + 1);
  984.                     Curpos.col += (colnr_t)(i - 1);    /* put cursor on last putted char */
  985.                 for (i = 0; i < count; ++i)
  986.                 {
  987.                     strncpy(ep, y_array[0], (size_t)newlen);
  988.                     ep += newlen;
  989.                 }
  990.             }
  991.             endop = Curpos;
  992.             updateline();
  993.         }
  994.         else
  995.         {
  996.             if (y_type == MCHAR)
  997.                 --y_size;
  998.             while (--count >= 0)
  999.             {
  1000.                 i = 0;
  1001.                 if (y_type == MCHAR)
  1002.                 {
  1003.                     /*
  1004.                      * Split the current line in two at the insert position.
  1005.                      * Append y_array[0] to first line.
  1006.                      * Insert y_array[size - 1] in front of second line.
  1007.                      */
  1008.                     ptr = nr2ptr(lnum) + col;
  1009.                     col = strlen(y_array[y_size]);
  1010.                     ep = alloc_line((unsigned)(strlen(ptr) + col));
  1011.                     if (ep == NULL)
  1012.                         goto error;
  1013.                     strcpy(ep, y_array[y_size]);
  1014.                     strcat(ep, ptr);
  1015.                     appendline(lnum, ep);            /* insert in second line */
  1016.                     ++nlines;
  1017.                     *ptr = NUL;
  1018.                     Curpos.lnum = lnum;
  1019.                     if (!canincrease(newlen))        /* lnum == Curpos.lnum! */
  1020.                         goto error;
  1021.                     strcat(nr2ptr(lnum), y_array[0]);/* append to first line */
  1022.                     i = 1;
  1023.                 }
  1024.  
  1025.                 while (i < y_size)
  1026.                 {
  1027.                     ep = save_line(y_array[i++]);
  1028.                     if (ep == NULL)
  1029.                         goto error;
  1030.                     appendline(lnum++, ep);
  1031.                     ++nlines;
  1032.                 }
  1033.                 if (y_type == MCHAR)
  1034.                     ++lnum;     /* lnum is now number of line below inserted lines */
  1035.             }
  1036.  
  1037.             endop.lnum = lnum;        /* for "']" command */
  1038.             if (y_type == MLINE)
  1039.             {
  1040.                 Curpos.col = 0;
  1041.                 endop.col = 0;
  1042.                 if (dir == FORWARD)
  1043.                 {
  1044.                     updateScreen(NOT_VALID);        /* recompute Botline */
  1045.                     ++Curpos.lnum;
  1046.                 }
  1047.                     /* put cursor on first non-blank in last inserted line */
  1048.                 beginline(TRUE);
  1049.             }
  1050.             else        /* put cursor on first inserted character */
  1051.             {
  1052.                 if (col > 1)
  1053.                     endop.col = col - 1;
  1054.                 else
  1055.                     endop.col = 0;
  1056.                 Curpos = newCurpos;
  1057.             }
  1058.  
  1059. error:
  1060.             updateScreen(CURSUPD);
  1061.         }
  1062.     }
  1063.  
  1064.     msgmore(nlines);
  1065.     set_want_col = TRUE;
  1066. }
  1067.  
  1068. /*
  1069.  * display the contents of the yank buffers
  1070.  */
  1071.     void
  1072. dodis()
  1073. {
  1074.     register int i, n;
  1075.     register long j;
  1076.     register char *p;
  1077.     register struct yankbuf *yb;
  1078.  
  1079. #ifdef AMIGA
  1080.     settmode(0);            /* set cooked mode so output can be halted */
  1081. #endif
  1082.     for (i = -1; i < 36; ++i)
  1083.     {
  1084.         if (i == -1)
  1085.         {
  1086.             if (y_previous != NULL)
  1087.                 yb = y_previous;
  1088.             else
  1089.                 yb = &(y_buf[0]);
  1090.         }
  1091.         else
  1092.             yb = &(y_buf[i]);
  1093.         if (yb->y_array != NULL)
  1094.         {
  1095.             if (i == -1)
  1096.                 outstrn("\"\"");
  1097.             else
  1098.             {
  1099.                 outchar('"');
  1100.                 if (i < 10)
  1101.                     outchar(i + '0');
  1102.                 else
  1103.                     outchar(i + 'a' - 10);
  1104.             }
  1105.             outchar(' ');
  1106.  
  1107.             n = (int)Columns - 4;
  1108.             for (j = 0; j < yb->y_size && n > 0; ++j)
  1109.             {
  1110.                 if (j)
  1111.                 {
  1112.                     outstrn("^J");
  1113.                     n -= 2;
  1114.                 }
  1115.                 for (p = yb->y_array[j]; *p && n > 0; ++p)
  1116.                 {
  1117.                     outstrn(transchar(*p));
  1118.                     n -= charsize(*p);
  1119.                 }
  1120.             }
  1121.             outchar('\n');
  1122.             flushbuf();
  1123.         }
  1124.     }
  1125. #ifdef AMIGA
  1126.     settmode(1);
  1127. #endif
  1128.     wait_return(TRUE);
  1129. }
  1130.  
  1131. /*
  1132.  * join 'count' lines (minimal 2), including u_save()
  1133.  */
  1134.     void
  1135. dodojoin(count, insert_space, redraw)
  1136.     long    count;
  1137.     int        insert_space;
  1138.     int        redraw;
  1139. {
  1140.     if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + count)))
  1141.         return;
  1142.  
  1143.     while (--count > 0)
  1144.         if (!dojoin(insert_space, redraw))
  1145.         {
  1146.                 beep();
  1147.                 break;
  1148.         }
  1149.  
  1150.     if (redraw)
  1151.         updateScreen(VALID_TO_CURSCHAR);
  1152. }
  1153.  
  1154.     int
  1155. dojoin(insert_space, redraw)
  1156.     int            insert_space;
  1157.     int            redraw;
  1158. {
  1159.     char        *curr;
  1160.     char        *next;
  1161.     char        *endcurr;
  1162.     int         currsize;        /* size of the current line */
  1163.     int         nextsize;        /* size of the next line */
  1164.     int            spaces;            /* number of spaces to insert */
  1165.     int            rows_to_del;    /* number of rows on screen to delete */
  1166.     linenr_t    t;
  1167.  
  1168.     if (Curpos.lnum == line_count)        /* on last line */
  1169.         return FALSE;
  1170.  
  1171.     rows_to_del = plines_m(Curpos.lnum, Curpos.lnum + 1);
  1172.     curr = nr2ptr(Curpos.lnum);
  1173.     currsize = strlen(curr);
  1174.     next = nr2ptr((linenr_t)(Curpos.lnum + 1));
  1175.     spaces = 0;
  1176.     if (insert_space)
  1177.     {
  1178.         skipspace(&next);
  1179.         spaces = 1;
  1180.         if (*next == ')' || currsize == 0)
  1181.             spaces = 0;
  1182.         else
  1183.         {
  1184.             endcurr = curr + currsize - 1;
  1185.             if (*endcurr == ' ' || *endcurr == TAB)
  1186.             {
  1187.                 spaces = 0;
  1188.                 if (currsize > 1)
  1189.                     --endcurr;
  1190.             }
  1191.             if (p_js && strchr(".!?", *endcurr) != NULL)
  1192.                 spaces = 2;
  1193.         }
  1194.     }
  1195.     nextsize = strlen(next);
  1196.     if (!canincrease(nextsize + spaces))
  1197.         return FALSE;
  1198.  
  1199.     /*
  1200.      * Append the spaces and the next line. Curr has to be obtained again,
  1201.      * because canincrease() will have changed the pointer.
  1202.      */
  1203.     curr = nr2ptr(Curpos.lnum) + currsize;
  1204.     while (spaces--)
  1205.         *curr++ = ' ';
  1206.     strcpy(curr, next);
  1207.  
  1208.     /*
  1209.      * Delete the following line. To do this we move the cursor there
  1210.      * briefly, and then move it back. After dellines() the cursor may
  1211.      * have moved up (last line deleted), so the current lnum is kept in t.
  1212.      */
  1213.     t = Curpos.lnum;
  1214.     ++Curpos.lnum;
  1215.     dellines(1L, FALSE, FALSE);
  1216.     Curpos.lnum = t;
  1217.  
  1218.     /*
  1219.      * the number of rows on the screen is reduced by the difference
  1220.      * in number of rows of the two old lines and the one new line
  1221.      */
  1222.     if (redraw)
  1223.     {
  1224.         rows_to_del -= plines(Curpos.lnum);
  1225.         if (rows_to_del > 0)
  1226.             s_del(Cursrow, rows_to_del, TRUE);
  1227.     }
  1228.  
  1229.      /*
  1230.      * go to first character of the joined line
  1231.      */
  1232.     if (currsize == 0)
  1233.         Curpos.col = 0;
  1234.     else
  1235.     {
  1236.         Curpos.col = currsize - 1;
  1237.         oneright();
  1238.     }
  1239.     CHANGED;
  1240.  
  1241.     return TRUE;
  1242. }
  1243.  
  1244. /*
  1245.  * implementation of the format operator 'Q'
  1246.  */
  1247.     void
  1248. doformat()
  1249. {
  1250.         /* prepare undo and join the lines */
  1251.     dodojoin((long)nlines, TRUE, FALSE);
  1252.  
  1253.         /* put cursor on last non-space */
  1254.     coladvance(MAXCOL);
  1255.     while (Curpos.col && isspace(gcharCurpos()))
  1256.         decCurpos();
  1257.     curs_columns(FALSE);            /* update Cursvcol */
  1258.  
  1259.         /* do the formatting */
  1260.     State = INSERT;        /* for Opencmd() */
  1261.     insertchar(NUL);
  1262.     State = NORMAL;
  1263.     updateScreen(NOT_VALID);
  1264. }
  1265.  
  1266.     void
  1267. startinsert(initstr, startln, count)
  1268.     int            initstr;
  1269.     int         startln;        /* if set, insert at start of line */
  1270.     long         count;
  1271. {
  1272.     Insstart = Curpos;
  1273.     if (startln)
  1274.         Insstart.col = 0;
  1275.  
  1276.     if (initstr != NUL)
  1277.     {
  1278.             ResetRedobuff();
  1279.             AppendNumberToRedobuff(count);
  1280.             AppendCharToRedobuff(initstr);
  1281.     }
  1282.  
  1283.     if (initstr == 'R')
  1284.         State = REPLACE;
  1285.     else
  1286.         State = INSERT;
  1287.  
  1288.     if (p_smd)
  1289.         showmode();
  1290.  
  1291.     change_warning();        /* give a warning if readonly */
  1292.     edit(count);
  1293. }
  1294.  
  1295. /*
  1296.  * prepare a few things for block mode yank/delete/tilde
  1297.  *
  1298.  * for delete:
  1299.  * - textlen includes the first/last char to be (partly) deleted
  1300.  * - start/endspaces is the number of columns that are taken by the
  1301.  *     first/last deleted char minus the number of columns that have to be deleted.
  1302.  * for yank and tilde:
  1303.  * - textlen includes the first/last char to be wholly yanked
  1304.  * - start/endspaces is the number of columns of the first/last yanked char
  1305.  *   that are to be yanked.
  1306.  */
  1307.     static void
  1308. block_prep(lnum, delete)
  1309.     linenr_t    lnum;
  1310.     int            delete;
  1311. {
  1312.     int            vcol;
  1313.     int            incr = 0;
  1314.     char        *pend;
  1315.  
  1316.     startspaces = 0;
  1317.     endspaces = 0;
  1318.     textlen = 0;
  1319.     textcol = 0;
  1320.     vcol = 0;
  1321.     textstart = nr2ptr(lnum);
  1322.     while (vcol < startvcol && *textstart)
  1323.     {
  1324.         /* Count a tab for what it's worth (if list mode not on) */
  1325.         incr = chartabsize(*textstart, vcol);
  1326.         vcol += incr;
  1327.         ++textstart;
  1328.         ++textcol;
  1329.     }
  1330.     if (vcol < startvcol)    /* line too short */
  1331.     {
  1332.         if (!delete)
  1333.             endspaces = endvcol - startvcol + 1;
  1334.     }
  1335.     else /* vcol >= startvcol */
  1336.     {
  1337.         startspaces = vcol - startvcol;
  1338.         if (delete && vcol > startvcol)
  1339.             startspaces = incr - startspaces;
  1340.         pend = textstart;
  1341.         while (vcol <= endvcol && *pend)
  1342.         {
  1343.             /* Count a tab for what it's worth (if list mode not on) */
  1344.             incr = chartabsize(*pend, vcol);
  1345.             vcol += incr;
  1346.             ++pend;
  1347.         }
  1348.         if (vcol < endvcol && !delete)    /* line too short */
  1349.         {
  1350.             endspaces = endvcol - vcol;
  1351.         }
  1352.         else if (vcol > endvcol)
  1353.         {
  1354.             if (delete)
  1355.                 endspaces = vcol - endvcol - 1;
  1356.             else if (pend != textstart)
  1357.             {
  1358.                 endspaces = incr - (vcol - endvcol);
  1359.                 if (endspaces)
  1360.                     --pend;
  1361.             }
  1362.         }
  1363.         if (delete && startspaces)
  1364.         {
  1365.             --textstart;
  1366.             --textcol;
  1367.         }
  1368.         textlen = (int)(pend - textstart);
  1369.     }
  1370. }
  1371.  
  1372.     int
  1373. doaddsub(c, Prenum1)
  1374.     int            c;
  1375.     linenr_t    Prenum1;
  1376. {
  1377.     register int     col;
  1378.     char            buf[30];
  1379.     int                hex;        /* 'x' or 'X': hexadecimal; '0': octal */
  1380.     static int        hexupper = FALSE;    /* 0xABC */
  1381.     long            n;
  1382.     char            *ptr;
  1383.  
  1384.     ptr = nr2ptr(Curpos.lnum);
  1385.     col = Curpos.col;
  1386.  
  1387.         /* first check if we are on a hexadecimal number */
  1388.     while (col > 0 && isxdigit(ptr[col]))
  1389.         --col;
  1390.     if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
  1391.                         ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
  1392.         --col;        /* found hexadecimal number */
  1393.     else
  1394.     {
  1395.         /* first search forward and then backward for start of number */
  1396.         col = Curpos.col;
  1397.  
  1398.         while (ptr[col] != NUL && !isdigit(ptr[col]))
  1399.             ++col;
  1400.  
  1401.         while (col > 0 && isdigit(ptr[col - 1]))
  1402.             --col;
  1403.     }
  1404.  
  1405.     if (isdigit(ptr[col]) && u_saveCurpos())
  1406.     {
  1407.         set_want_col = TRUE;
  1408.  
  1409.         if (ptr[col] != '0')
  1410.             hex = 0;                /* decimal */
  1411.         else
  1412.         {
  1413.             hex = TO_UPPER(ptr[col + 1]);        /* assume hexadecimal */
  1414.             if (hex != 'X' || !isxdigit(ptr[col + 2]))
  1415.             {
  1416.                 if (isdigit(hex))
  1417.                     hex = '0';        /* octal */
  1418.                 else
  1419.                     hex = 0;        /* 0 by itself is decimal */
  1420.             }
  1421.         }
  1422.  
  1423.         if (!hex && col > 0 && ptr[col - 1] == '-')
  1424.             --col;
  1425.  
  1426.         ptr += col;
  1427.         if (hex == '0')
  1428.             sscanf(ptr, "%lo", &n);
  1429.         else if (hex)
  1430.             sscanf(ptr, "%lx", &n);    /* "%X" doesn't work! */
  1431.         else
  1432.             n = atol(ptr);
  1433.  
  1434.         if (c == Ctrl('A'))
  1435.             n += Prenum1;
  1436.         else
  1437.             n -= Prenum1;
  1438.  
  1439.         if (hex == 'X')                    /* skip the '0x' */
  1440.             col += 2;
  1441.         Curpos.col = col;
  1442.         do                                /* delete the old number */
  1443.         {
  1444.             if (isalpha(c))
  1445.             {
  1446.                 if (isupper(c))
  1447.                     hexupper = TRUE;
  1448.                 else
  1449.                     hexupper = FALSE;
  1450.             }
  1451.             delchar(FALSE);
  1452.             c = gcharCurpos();
  1453.         }
  1454.         while (hex ? (hex == '0' ? c >= '0' && c <= '7' : isxdigit(c)) : isdigit(c));
  1455.  
  1456.         if (hex == '0')
  1457.             sprintf(buf, "0%lo", n);
  1458.         else if (hexupper)
  1459.             sprintf(buf, "%lX", n);
  1460.         else if (hex)
  1461.             sprintf(buf, "%lx", n);
  1462.         else
  1463.             sprintf(buf, "%ld", n);
  1464.         insstr(buf);                    /* insert the new number */
  1465.         --Curpos.col;
  1466.         updateline();
  1467.         return TRUE;
  1468.     }
  1469.     else
  1470.     {
  1471.         beep();
  1472.         return FALSE;
  1473.     }
  1474. }
  1475.  
  1476. /*
  1477.  * Return TRUE if startop is on or before the first non-blank character in the line
  1478.  */
  1479.     int
  1480. startinmargin()
  1481. {
  1482.     int        n;
  1483.     char    *ptr;
  1484.  
  1485.     n = 0;
  1486.     for (ptr = nr2ptr(startop.lnum); *ptr && isspace(*ptr); ++ptr)
  1487.         ++n;
  1488.     return (n >= startop.col);
  1489. }
  1490.