[BACK]Return to ops.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/ops.c, Revision 1.1

1.1     ! downsj      1: /* $OpenBSD$   */
        !             2: /* vi:set ts=4 sw=4:
        !             3:  *
        !             4:  * VIM - Vi IMproved       by Bram Moolenaar
        !             5:  *
        !             6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
        !             7:  * Do ":help credits" in Vim to see a list of people who contributed.
        !             8:  */
        !             9:
        !            10: /*
        !            11:  * ops.c: implementation of various operators: do_shift, do_delete, do_tilde,
        !            12:  *       do_change, do_yank, do_put, do_join
        !            13:  */
        !            14:
        !            15: #include "vim.h"
        !            16: #include "globals.h"
        !            17: #include "proto.h"
        !            18: #include "option.h"
        !            19: #include "ops.h"
        !            20:
        !            21: /*
        !            22:  * Number of registers.
        !            23:  *      0 = unnamed register, for normal yanks and puts
        !            24:  *   1..9 = number registers, for deletes
        !            25:  * 10..35 = named registers
        !            26:  *     36 = delete register (-)
        !            27:  *     37 = GUI selection register (*). Only if USE_GUI defined
        !            28:  */
        !            29: #ifdef USE_GUI
        !            30: # define NUM_REGISTERS         38
        !            31: #else
        !            32: # define NUM_REGISTERS         37
        !            33: #endif
        !            34:
        !            35: /*
        !            36:  * Symbolic names for some registers.
        !            37:  */
        !            38: #define DELETION_REGISTER      36
        !            39: #ifdef USE_GUI
        !            40: # define GUI_SELECTION_REGISTER    37
        !            41: #endif
        !            42:
        !            43: /*
        !            44:  * Each yank buffer is an array of pointers to lines.
        !            45:  */
        !            46: static struct yankbuf
        !            47: {
        !            48:    char_u      **y_array;      /* pointer to array of line pointers */
        !            49:    linenr_t    y_size;         /* number of lines in y_array */
        !            50:    char_u      y_type;         /* MLINE, MCHAR or MBLOCK */
        !            51: } y_buf[NUM_REGISTERS];
        !            52:
        !            53: static struct  yankbuf *y_current;         /* ptr to current yank buffer */
        !            54: static int     yankappend;                 /* TRUE when appending */
        !            55: static struct  yankbuf *y_previous = NULL; /* ptr to last written yank buffr */
        !            56:
        !            57: /*
        !            58:  * structure used by block_prep, do_delete and do_yank for blockwise operators
        !            59:  */
        !            60: struct block_def
        !            61: {
        !            62:    int         startspaces;
        !            63:    int         endspaces;
        !            64:    int         textlen;
        !            65:    char_u      *textstart;
        !            66:    colnr_t     textcol;
        !            67: };
        !            68:
        !            69: static void        get_yank_buffer __ARGS((int));
        !            70: static int     stuff_yank __ARGS((int, char_u *));
        !            71: static void        free_yank __ARGS((long));
        !            72: static void        free_yank_all __ARGS((void));
        !            73: static void        block_prep __ARGS((struct block_def *, linenr_t, int));
        !            74: static int     same_leader __ARGS((int, char_u *, int, char_u *));
        !            75: static int     fmt_end_block __ARGS((linenr_t, int *, char_u **));
        !            76:
        !            77: /*
        !            78:  * do_shift - handle a shift operation
        !            79:  */
        !            80:    void
        !            81: do_shift(op, curs_top, amount)
        !            82:    int             op;
        !            83:    int             curs_top;
        !            84:    int             amount;
        !            85: {
        !            86:    register long   i;
        !            87:    int             first_char;
        !            88:
        !            89:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
        !            90:                   (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
        !            91:        return;
        !            92:    for (i = op_line_count; --i >= 0; )
        !            93:    {
        !            94:        first_char = *ml_get_curline();
        !            95:        if (first_char == NUL)                          /* empty line */
        !            96:            curwin->w_cursor.col = 0;
        !            97:        /*
        !            98:         * Don't move the line right if it starts with # and p_si is set.
        !            99:         */
        !           100:        else
        !           101: #if defined(SMARTINDENT) || defined(CINDENT)
        !           102:            if (first_char != '#' || (
        !           103: # ifdef SMARTINDENT
        !           104:                         !curbuf->b_p_si
        !           105: # endif
        !           106: # if defined(SMARTINDENT) && defined(CINDENT)
        !           107:                            &&
        !           108: # endif
        !           109: # ifdef CINDENT
        !           110:                         (!curbuf->b_p_cin || !in_cinkeys('#', ' ', TRUE))
        !           111: # endif
        !           112:                                        ))
        !           113: #endif
        !           114:        {
        !           115:            /* if (op_block_mode)
        !           116:                    shift the block, not the whole line
        !           117:            else */
        !           118:                shift_line(op == LSHIFT, p_sr, amount);
        !           119:        }
        !           120:        ++curwin->w_cursor.lnum;
        !           121:    }
        !           122:
        !           123:    if (curs_top)           /* put cursor on first line, for ">>" */
        !           124:    {
        !           125:        curwin->w_cursor.lnum -= op_line_count;
        !           126:        beginline(MAYBE);   /* shift_line() may have changed cursor.col */
        !           127:    }
        !           128:    else
        !           129:        --curwin->w_cursor.lnum;        /* put cursor on last line, for ":>" */
        !           130:    updateScreen(CURSUPD);
        !           131:
        !           132:    if (op_line_count > p_report)
        !           133:       smsg((char_u *)"%ld line%s %ced %d time%s", op_line_count,
        !           134:                           plural(op_line_count), (op == RSHIFT) ? '>' : '<',
        !           135:                           amount, plural((long)amount));
        !           136: }
        !           137:
        !           138: /*
        !           139:  * shift the current line one shiftwidth left (if left != 0) or right
        !           140:  * leaves cursor on first blank in the line
        !           141:  */
        !           142:    void
        !           143: shift_line(left, round, amount)
        !           144:    int left;
        !           145:    int round;
        !           146:    int amount;
        !           147: {
        !           148:    register int count;
        !           149:    register int i, j;
        !           150:    int p_sw = (int)curbuf->b_p_sw;
        !           151:
        !           152:    count = get_indent();           /* get current indent */
        !           153:
        !           154:    if (round)                      /* round off indent */
        !           155:    {
        !           156:        i = count / p_sw;           /* number of p_sw rounded down */
        !           157:        j = count % p_sw;           /* extra spaces */
        !           158:        if (j && left)              /* first remove extra spaces */
        !           159:            --amount;
        !           160:        if (left)
        !           161:        {
        !           162:            i -= amount;
        !           163:            if (i < 0)
        !           164:                i = 0;
        !           165:        }
        !           166:        else
        !           167:            i += amount;
        !           168:        count = i * p_sw;
        !           169:    }
        !           170:    else                /* original vi indent */
        !           171:    {
        !           172:        if (left)
        !           173:        {
        !           174:            count -= p_sw * amount;
        !           175:            if (count < 0)
        !           176:                count = 0;
        !           177:        }
        !           178:        else
        !           179:            count += p_sw * amount;
        !           180:    }
        !           181:    set_indent(count, TRUE);        /* set new indent */
        !           182: }
        !           183:
        !           184: #if defined(LISPINDENT) || defined(CINDENT)
        !           185: /*
        !           186:  * do_reindent - handle reindenting a block of lines for C or lisp.
        !           187:  *
        !           188:  * mechanism copied from do_shift, above
        !           189:  */
        !           190:    void
        !           191: do_reindent(how)
        !           192:    int (*how) __ARGS((void));
        !           193: {
        !           194:    register long   i;
        !           195:    char_u          *l;
        !           196:    int             count;
        !           197:
        !           198:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
        !           199:                    (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
        !           200:        return;
        !           201:
        !           202:    for (i = op_line_count; --i >= 0 && !got_int; )
        !           203:    {
        !           204:        /* it's a slow thing to do, so give feedback so there's no worry that
        !           205:         * the computer's just hung. */
        !           206:
        !           207:        if ((i % 50 == 0 || i == op_line_count - 1) && op_line_count > p_report)
        !           208:            smsg((char_u *)"%ld line%s to indent... ", i, plural(i));
        !           209:
        !           210:        /*
        !           211:         * Be vi-compatible: For lisp indenting the first line is not
        !           212:         * indented, unless there is only one line.
        !           213:         */
        !           214: #ifdef LISPINDENT
        !           215:        if (i != op_line_count - 1 || op_line_count == 1 ||
        !           216:                                                       how != get_lisp_indent)
        !           217: #endif
        !           218:        {
        !           219:            l = skipwhite(ml_get_curline());
        !           220:            if (*l == NUL)                  /* empty or blank line */
        !           221:                count = 0;
        !           222:            else
        !           223:                count = how();              /* get the indent for this line */
        !           224:
        !           225:            set_indent(count, TRUE);
        !           226:        }
        !           227:        ++curwin->w_cursor.lnum;
        !           228:    }
        !           229:
        !           230:    /* put cursor on first non-blank of indented line */
        !           231:    curwin->w_cursor.lnum -= op_line_count;
        !           232:    beginline(MAYBE);
        !           233:
        !           234:    updateScreen(CURSUPD);
        !           235:
        !           236:    if (op_line_count > p_report)
        !           237:    {
        !           238:        i = op_line_count - (i + 1);
        !           239:        smsg((char_u *)"%ld line%s indented ", i, plural(i));
        !           240:    }
        !           241: }
        !           242: #endif /* defined(LISPINDENT) || defined(CINDENT) */
        !           243:
        !           244: /*
        !           245:  * check if character is name of yank buffer
        !           246:  * Note: There is no check for 0 (default register), caller should do this
        !           247:  */
        !           248:    int
        !           249: is_yank_buffer(c, writing)
        !           250:    int     c;
        !           251:    int     writing;        /* if TRUE check for writable buffers */
        !           252: {
        !           253:    if (c > '~')
        !           254:        return FALSE;
        !           255:    if (isalnum(c) || (!writing && vim_strchr((char_u *)".%:", c) != NULL) ||
        !           256:                                                          c == '"' || c == '-'
        !           257: #ifdef USE_GUI
        !           258:                                                   || (gui.in_use && c == '*')
        !           259: #endif
        !           260:                                                        )
        !           261:        return TRUE;
        !           262:    return FALSE;
        !           263: }
        !           264:
        !           265: /*
        !           266:  * Set y_current and yankappend, according to the value of yankbuffer.
        !           267:  *
        !           268:  * If yankbuffer is 0 and writing, use buffer 0
        !           269:  * If yankbuffer is 0 and reading, use previous buffer
        !           270:  */
        !           271:    static void
        !           272: get_yank_buffer(writing)
        !           273:    int     writing;
        !           274: {
        !           275:    register int i;
        !           276:
        !           277:    yankappend = FALSE;
        !           278:    if (((yankbuffer == 0 && !writing) || yankbuffer == '"') &&
        !           279:                                                           y_previous != NULL)
        !           280:    {
        !           281:        y_current = y_previous;
        !           282:        return;
        !           283:    }
        !           284:    i = yankbuffer;
        !           285:    if (isdigit(i))
        !           286:        i -= '0';
        !           287:    else if (islower(i))
        !           288:        i -= 'a' - 10;
        !           289:    else if (isupper(i))
        !           290:    {
        !           291:        i -= 'A' - 10;
        !           292:        yankappend = TRUE;
        !           293:    }
        !           294:    else if (yankbuffer == '-')
        !           295:        i = DELETION_REGISTER;
        !           296: #ifdef USE_GUI
        !           297:    else if (gui.in_use && yankbuffer == '*')
        !           298:        i = GUI_SELECTION_REGISTER;
        !           299: #endif
        !           300:    else                /* not 0-9, a-z, A-Z or '-': use buffer 0 */
        !           301:        i = 0;
        !           302:    y_current = &(y_buf[i]);
        !           303:    if (writing)        /* remember the buffer we write into for do_put() */
        !           304:        y_previous = y_current;
        !           305: }
        !           306:
        !           307: /*
        !           308:  * return TRUE if the current yank buffer has type MLINE
        !           309:  */
        !           310:    int
        !           311: yank_buffer_mline()
        !           312: {
        !           313:    if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, FALSE))
        !           314:        return FALSE;
        !           315:    get_yank_buffer(FALSE);
        !           316:    return (y_current->y_type == MLINE);
        !           317: }
        !           318:
        !           319: /*
        !           320:  * start or stop recording into a yank buffer
        !           321:  *
        !           322:  * return FAIL for failure, OK otherwise
        !           323:  */
        !           324:    int
        !           325: do_record(c)
        !           326:    int c;
        !           327: {
        !           328:    char_u      *p;
        !           329:    static int  bufname;
        !           330:    int         retval;
        !           331:
        !           332:    if (Recording == FALSE)         /* start recording */
        !           333:    {
        !           334:                        /* registers 0-9, a-z and " are allowed */
        !           335:        if (c > '~' || (!isalnum(c) && c != '"'))
        !           336:            retval = FAIL;
        !           337:        else
        !           338:        {
        !           339:            Recording = TRUE;
        !           340:            showmode();
        !           341:            bufname = c;
        !           342:            retval = OK;
        !           343:        }
        !           344:    }
        !           345:    else                            /* stop recording */
        !           346:    {
        !           347:        Recording = FALSE;
        !           348:        MSG("");
        !           349:        p = get_recorded();
        !           350:        if (p == NULL)
        !           351:            retval = FAIL;
        !           352:        else
        !           353:            retval = (stuff_yank(bufname, p));
        !           354:    }
        !           355:    return retval;
        !           356: }
        !           357:
        !           358: /*
        !           359:  * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
        !           360:  * 'p' is assumed to be alloced.
        !           361:  *
        !           362:  * return FAIL for failure, OK otherwise
        !           363:  */
        !           364:    static int
        !           365: stuff_yank(bufname, p)
        !           366:    int bufname;
        !           367:    char_u *p;
        !           368: {
        !           369:    char_u *lp;
        !           370:    char_u **pp;
        !           371:
        !           372:    yankbuffer = bufname;
        !           373:                                            /* check for read-only buffer */
        !           374:    if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
        !           375:        return FAIL;
        !           376:    get_yank_buffer(TRUE);
        !           377:    if (yankappend && y_current->y_array != NULL)
        !           378:    {
        !           379:        pp = &(y_current->y_array[y_current->y_size - 1]);
        !           380:        lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
        !           381:        if (lp == NULL)
        !           382:        {
        !           383:            vim_free(p);
        !           384:            return FAIL;
        !           385:        }
        !           386:        STRCPY(lp, *pp);
        !           387:        STRCAT(lp, p);
        !           388:        vim_free(p);
        !           389:        vim_free(*pp);
        !           390:        *pp = lp;
        !           391:    }
        !           392:    else
        !           393:    {
        !           394:        free_yank_all();
        !           395:        if ((y_current->y_array =
        !           396:                        (char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
        !           397:        {
        !           398:            vim_free(p);
        !           399:            return FAIL;
        !           400:        }
        !           401:        y_current->y_array[0] = p;
        !           402:        y_current->y_size = 1;
        !           403:        y_current->y_type = MCHAR;  /* used to be MLINE, why? */
        !           404:    }
        !           405:    return OK;
        !           406: }
        !           407:
        !           408: /*
        !           409:  * execute a yank buffer (register): copy it into the stuff buffer
        !           410:  *
        !           411:  * return FAIL for failure, OK otherwise
        !           412:  */
        !           413:    int
        !           414: do_execbuf(c, colon, addcr)
        !           415:    int c;
        !           416:    int colon;              /* insert ':' before each line */
        !           417:    int addcr;              /* always add '\n' to end of line */
        !           418: {
        !           419:    static int  lastc = NUL;
        !           420:    long        i;
        !           421:    char_u      *p;
        !           422:    int         truncated;
        !           423:    int         retval;
        !           424:
        !           425:
        !           426:    if (c == '@')                   /* repeat previous one */
        !           427:        c = lastc;
        !           428:    if (c == '%' || !is_yank_buffer(c, FALSE))  /* check for valid buffer */
        !           429:        return FAIL;
        !           430:    lastc = c;
        !           431:
        !           432:    if (c == ':')                   /* use last command line */
        !           433:    {
        !           434:        if (last_cmdline == NULL)
        !           435:        {
        !           436:            EMSG(e_nolastcmd);
        !           437:            return FAIL;
        !           438:        }
        !           439:        vim_free(new_last_cmdline); /* don't keep the cmdline containing @: */
        !           440:        new_last_cmdline = NULL;
        !           441:        if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
        !           442:            return FAIL;
        !           443:        if (ins_typebuf(last_cmdline, FALSE, 0, TRUE) == FAIL)
        !           444:            return FAIL;
        !           445:        if (ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
        !           446:            return FAIL;
        !           447:    }
        !           448:    else if (c == '.')              /* use last inserted text */
        !           449:    {
        !           450:        p = get_last_insert();
        !           451:        if (p == NULL)
        !           452:        {
        !           453:            EMSG(e_noinstext);
        !           454:            return FAIL;
        !           455:        }
        !           456:        i = STRLEN(p);
        !           457:        if (i > 0 && p[i - 1] == ESC)   /* remove trailing ESC */
        !           458:        {
        !           459:            p[i - 1] = NUL;
        !           460:            truncated = TRUE;
        !           461:        }
        !           462:        else
        !           463:            truncated = FALSE;
        !           464:        retval = ins_typebuf(p, FALSE, 0, TRUE);
        !           465:        if (truncated)
        !           466:            p[i - 1] = ESC;
        !           467:        return retval;
        !           468:    }
        !           469:    else
        !           470:    {
        !           471:        yankbuffer = c;
        !           472:        get_yank_buffer(FALSE);
        !           473:        if (y_current->y_array == NULL)
        !           474:            return FAIL;
        !           475:
        !           476:        /*
        !           477:         * Insert lines into typeahead buffer, from last one to first one.
        !           478:         */
        !           479:        for (i = y_current->y_size; --i >= 0; )
        !           480:        {
        !           481:        /* insert newline between lines and after last line if type is MLINE */
        !           482:            if (y_current->y_type == MLINE || i < y_current->y_size - 1
        !           483:                                                                     || addcr)
        !           484:            {
        !           485:                if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
        !           486:                    return FAIL;
        !           487:            }
        !           488:            if (ins_typebuf(y_current->y_array[i], FALSE, 0, TRUE) == FAIL)
        !           489:                return FAIL;
        !           490:            if (colon && ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
        !           491:                return FAIL;
        !           492:        }
        !           493:        Exec_reg = TRUE;        /* disable the 'q' command */
        !           494:    }
        !           495:    return OK;
        !           496: }
        !           497:
        !           498: /*
        !           499:  * Insert a yank buffer: copy it into the Read buffer.
        !           500:  * Used by CTRL-R command and middle mouse button in insert mode.
        !           501:  *
        !           502:  * return FAIL for failure, OK otherwise
        !           503:  */
        !           504:    int
        !           505: insertbuf(c)
        !           506:    int c;
        !           507: {
        !           508:    long    i;
        !           509:    int     retval = OK;
        !           510:
        !           511:    /*
        !           512:     * It is possible to get into an endless loop by having CTRL-R a in
        !           513:     * register a and then, in insert mode, doing CTRL-R a.
        !           514:     * If you hit CTRL-C, the loop will be broken here.
        !           515:     */
        !           516:    mch_breakcheck();
        !           517:    if (got_int)
        !           518:        return FAIL;
        !           519:
        !           520:    /* check for valid buffer */
        !           521:    if (c != NUL && !is_yank_buffer(c, FALSE))
        !           522:        return FAIL;
        !           523:
        !           524: #ifdef USE_GUI
        !           525:    if (c == '*')
        !           526:        gui_get_selection();            /* may fill * register */
        !           527: #endif
        !           528:
        !           529:    if (c == '.')                       /* insert last inserted text */
        !           530:        retval = stuff_inserted(NUL, 1L, TRUE);
        !           531:    else if (c == '%')                  /* insert file name */
        !           532:    {
        !           533:        if (check_fname() == FAIL)
        !           534:            return FAIL;
        !           535:        stuffReadbuff(curbuf->b_xfilename);
        !           536:    }
        !           537:    else if (c == ':')                  /* insert last command line */
        !           538:    {
        !           539:        if (last_cmdline == NULL)
        !           540:        {
        !           541:            EMSG(e_nolastcmd);
        !           542:            return FAIL;
        !           543:        }
        !           544:        stuffReadbuff(last_cmdline);
        !           545:    }
        !           546:    else                                /* name or number register */
        !           547:    {
        !           548:        yankbuffer = c;
        !           549:        get_yank_buffer(FALSE);
        !           550:        if (y_current->y_array == NULL)
        !           551:            retval = FAIL;
        !           552:        else
        !           553:        {
        !           554:
        !           555:            for (i = 0; i < y_current->y_size; ++i)
        !           556:            {
        !           557:                stuffReadbuff(y_current->y_array[i]);
        !           558:                /* insert newline between lines and after last line if type is
        !           559:                 * MLINE */
        !           560:                if (y_current->y_type == MLINE || i < y_current->y_size - 1)
        !           561:                    stuffReadbuff((char_u *)"\n");
        !           562:            }
        !           563:        }
        !           564:    }
        !           565:
        !           566:    return retval;
        !           567: }
        !           568:
        !           569: /*
        !           570:  * paste a yank buffer into the command line.
        !           571:  * used by CTRL-R command in command-line mode
        !           572:  * insertbuf() can't be used here, because special characters from the
        !           573:  * register contents will be interpreted as commands.
        !           574:  *
        !           575:  * return FAIL for failure, OK otherwise
        !           576:  */
        !           577:    int
        !           578: cmdline_paste(c)
        !           579:    int c;
        !           580: {
        !           581:    long i;
        !           582:
        !           583:    if (!is_yank_buffer(c, FALSE))      /* check for valid buffer */
        !           584:        return FAIL;
        !           585:
        !           586: #ifdef USE_GUI
        !           587:    if (c == '*')
        !           588:        gui_get_selection();
        !           589: #endif
        !           590:
        !           591:    if (c == '.')                       /* insert last inserted text */
        !           592:        return FAIL;                    /* Unimplemented */
        !           593:
        !           594:    if (c == '%')                       /* insert file name */
        !           595:    {
        !           596:        if (check_fname() == FAIL)
        !           597:            return FAIL;
        !           598:        return put_on_cmdline(curbuf->b_xfilename, -1, TRUE);
        !           599:    }
        !           600:
        !           601:    if (c == ':')                       /* insert last command line */
        !           602:    {
        !           603:        if (last_cmdline == NULL)
        !           604:            return FAIL;
        !           605:        return put_on_cmdline(last_cmdline, -1, TRUE);
        !           606:    }
        !           607:
        !           608:    yankbuffer = c;
        !           609:    get_yank_buffer(FALSE);
        !           610:    if (y_current->y_array == NULL)
        !           611:        return FAIL;
        !           612:
        !           613:    for (i = 0; i < y_current->y_size; ++i)
        !           614:    {
        !           615:        put_on_cmdline(y_current->y_array[i], -1, FALSE);
        !           616:
        !           617:        /* insert ^M between lines and after last line if type is MLINE */
        !           618:        if (y_current->y_type == MLINE || i < y_current->y_size - 1)
        !           619:            put_on_cmdline((char_u *)"\r", 1, FALSE);
        !           620:    }
        !           621:    return OK;
        !           622: }
        !           623:
        !           624: /*
        !           625:  * do_delete - handle a delete operation
        !           626:  */
        !           627:    void
        !           628: do_delete()
        !           629: {
        !           630:    register int        n;
        !           631:    linenr_t            lnum;
        !           632:    char_u              *ptr;
        !           633:    char_u              *newp, *oldp;
        !           634:    linenr_t            old_lcount = curbuf->b_ml.ml_line_count;
        !           635:    int                 did_yank = FALSE;
        !           636:    struct block_def    bd;
        !           637:
        !           638:    if (curbuf->b_ml.ml_flags & ML_EMPTY)           /* nothing to do */
        !           639:        return;
        !           640:
        !           641: /*
        !           642:  * Imitate the strange Vi behaviour: If the delete spans more than one line
        !           643:  * and op_motion_type == MCHAR and the result is a blank line, make the delete
        !           644:  * linewise. Don't do this for the change command.
        !           645:  */
        !           646:    if (op_motion_type == MCHAR && op_line_count > 1 && op_type == DELETE)
        !           647:    {
        !           648:        ptr = ml_get(curbuf->b_op_end.lnum) + curbuf->b_op_end.col +
        !           649:                                                                 op_inclusive;
        !           650:        ptr = skipwhite(ptr);
        !           651:        if (*ptr == NUL && inindent(0))
        !           652:            op_motion_type = MLINE;
        !           653:    }
        !           654:
        !           655: /*
        !           656:  * Check for trying to delete (e.g. "D") in an empty line.
        !           657:  * Note: For change command it is ok.
        !           658:  */
        !           659:    if (op_motion_type == MCHAR && op_line_count == 1 &&
        !           660:                op_type == DELETE && *ml_get(curbuf->b_op_start.lnum) == NUL)
        !           661:    {
        !           662:        beep_flush();
        !           663:        return;
        !           664:    }
        !           665:
        !           666: /*
        !           667:  * Do a yank of whatever we're about to delete.
        !           668:  * If a yank buffer was specified, put the deleted text into that buffer
        !           669:  */
        !           670:    if (yankbuffer != 0)
        !           671:    {
        !           672:                                        /* check for read-only buffer */
        !           673:        if (!is_yank_buffer(yankbuffer, TRUE))
        !           674:        {
        !           675:            beep_flush();
        !           676:            return;
        !           677:        }
        !           678:        get_yank_buffer(TRUE);          /* yank into specified buffer */
        !           679:        if (do_yank(TRUE, FALSE) == OK) /* yank without message */
        !           680:            did_yank = TRUE;
        !           681:    }
        !           682:
        !           683: /*
        !           684:  * Put deleted text into register 1 and shift number buffers if
        !           685:  * the delete contains a line break, or when a yankbuffer has been specified!
        !           686:  */
        !           687:    if (yankbuffer != 0 || op_motion_type == MLINE || op_line_count > 1)
        !           688:    {
        !           689:        y_current = &y_buf[9];
        !           690:        free_yank_all();                /* free buffer nine */
        !           691:        for (n = 9; n > 1; --n)
        !           692:            y_buf[n] = y_buf[n - 1];
        !           693:        y_previous = y_current = &y_buf[1];
        !           694:        y_buf[1].y_array = NULL;        /* set buffer one to empty */
        !           695:        yankbuffer = 0;
        !           696:    }
        !           697:    else if (yankbuffer == 0)           /* yank into unnamed buffer */
        !           698:    {
        !           699:        yankbuffer = '-';               /* use special delete buffer */
        !           700:        get_yank_buffer(TRUE);
        !           701:        yankbuffer = 0;
        !           702:    }
        !           703:
        !           704:    if (yankbuffer == 0 && do_yank(TRUE, FALSE) == OK)
        !           705:        did_yank = TRUE;
        !           706:
        !           707: /*
        !           708:  * If there's too much stuff to fit in the yank buffer, then get a
        !           709:  * confirmation before doing the delete. This is crude, but simple. And it
        !           710:  * avoids doing a delete of something we can't put back if we want.
        !           711:  */
        !           712:    if (!did_yank)
        !           713:    {
        !           714:        if (ask_yesno((char_u *)"cannot yank; delete anyway", TRUE) != 'y')
        !           715:        {
        !           716:            emsg(e_abort);
        !           717:            return;
        !           718:        }
        !           719:    }
        !           720:
        !           721: /*
        !           722:  * block mode delete
        !           723:  */
        !           724:    if (op_block_mode)
        !           725:    {
        !           726:        if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
        !           727:                               (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
        !           728:            return;
        !           729:
        !           730:        for (lnum = curwin->w_cursor.lnum;
        !           731:                               curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
        !           732:                                                      ++curwin->w_cursor.lnum)
        !           733:        {
        !           734:            block_prep(&bd, curwin->w_cursor.lnum, TRUE);
        !           735:            if (bd.textlen == 0)        /* nothing to delete */
        !           736:                continue;
        !           737:
        !           738:        /*
        !           739:         * If we delete a TAB, it may be replaced by several characters.
        !           740:         * Thus the number of characters may increase!
        !           741:         */
        !           742:            n = bd.textlen - bd.startspaces - bd.endspaces;     /* number of chars deleted */
        !           743:            oldp = ml_get_curline();
        !           744:            newp = alloc_check((unsigned)STRLEN(oldp) + 1 - n);
        !           745:            if (newp == NULL)
        !           746:                continue;
        !           747:        /* copy up to deleted part */
        !           748:            vim_memmove(newp, oldp, (size_t)bd.textcol);
        !           749:        /* insert spaces */
        !           750:            copy_spaces(newp + bd.textcol, (size_t)(bd.startspaces + bd.endspaces));
        !           751:        /* copy the part after the deleted part */
        !           752:            oldp += bd.textcol + bd.textlen;
        !           753:            vim_memmove(newp + bd.textcol + bd.startspaces + bd.endspaces,
        !           754:                                                      oldp, STRLEN(oldp) + 1);
        !           755:        /* replace the line */
        !           756:            ml_replace(curwin->w_cursor.lnum, newp, FALSE);
        !           757:        }
        !           758:        curwin->w_cursor.lnum = lnum;
        !           759:        CHANGED;
        !           760:        updateScreen(VALID_TO_CURSCHAR);
        !           761:        op_line_count = 0;      /* no lines deleted */
        !           762:    }
        !           763:    else if (op_motion_type == MLINE)
        !           764:    {
        !           765:        if (op_type == CHANGE)
        !           766:        {
        !           767:                /* Delete the lines except the first one.
        !           768:                 * Temporarily move the cursor to the next line.
        !           769:                 * Save the current line number, if the last line is deleted
        !           770:                 * it may be changed.
        !           771:                 */
        !           772:            if (op_line_count > 1)
        !           773:            {
        !           774:                lnum = curwin->w_cursor.lnum;
        !           775:                ++curwin->w_cursor.lnum;
        !           776:                dellines((long)(op_line_count - 1), TRUE, TRUE);
        !           777:                curwin->w_cursor.lnum = lnum;
        !           778:            }
        !           779:            if (u_save_cursor() == FAIL)
        !           780:                return;
        !           781:            if (curbuf->b_p_ai)             /* don't delete indent */
        !           782:            {
        !           783:                beginline(TRUE);            /* put cursor on first non-white */
        !           784:                did_ai = TRUE;              /* delete the indent when ESC hit */
        !           785:            }
        !           786:            truncate_line(FALSE);
        !           787:            if (curwin->w_cursor.col > 0)
        !           788:                --curwin->w_cursor.col;     /* put cursor on last char in line */
        !           789:        }
        !           790:        else
        !           791:        {
        !           792:            dellines(op_line_count, TRUE, TRUE);
        !           793:        }
        !           794:        u_clearline();  /* "U" command should not be possible after "dd" */
        !           795:        beginline(TRUE);
        !           796:    }
        !           797:    else if (op_line_count == 1)        /* delete characters within one line */
        !           798:    {
        !           799:        if (u_save_cursor() == FAIL)
        !           800:            return;
        !           801:            /* if 'cpoptions' contains '$', display '$' at end of change */
        !           802:        if (vim_strchr(p_cpo, CPO_DOLLAR) != NULL && op_type == CHANGE &&
        !           803:             curbuf->b_op_end.lnum == curwin->w_cursor.lnum && !op_is_VIsual)
        !           804:            display_dollar(curbuf->b_op_end.col - !op_inclusive);
        !           805:        n = curbuf->b_op_end.col - curbuf->b_op_start.col + 1 - !op_inclusive;
        !           806:        while (n-- > 0)
        !           807:            if (delchar(TRUE) == FAIL)
        !           808:                break;
        !           809:    }
        !           810:    else                                /* delete characters between lines */
        !           811:    {
        !           812:        if (u_save_cursor() == FAIL)            /* save first line for undo */
        !           813:            return;
        !           814:        truncate_line(TRUE);            /* delete from cursor to end of line */
        !           815:
        !           816:        curbuf->b_op_start = curwin->w_cursor;  /* remember curwin->w_cursor */
        !           817:        ++curwin->w_cursor.lnum;
        !           818:                                                /* includes save for undo */
        !           819:        dellines((long)(op_line_count - 2), TRUE, TRUE);
        !           820:
        !           821:        if (u_save_cursor() == FAIL)            /* save last line for undo */
        !           822:            return;
        !           823:        n = curbuf->b_op_end.col - !op_inclusive;
        !           824:        curwin->w_cursor.col = 0;
        !           825:        while (n-- >= 0)            /* delete from start of line until op_end */
        !           826:            if (delchar(TRUE) == FAIL)
        !           827:                break;
        !           828:        curwin->w_cursor = curbuf->b_op_start;  /* restore curwin->w_cursor */
        !           829:        (void)do_join(FALSE, curs_rows() == OK);
        !           830:    }
        !           831:
        !           832:    if ((op_motion_type == MCHAR && op_line_count == 1) || op_type == CHANGE)
        !           833:    {
        !           834:        if (dollar_vcol)
        !           835:            must_redraw = 0;        /* don't want a redraw now */
        !           836:        cursupdate();
        !           837:        if (!dollar_vcol)
        !           838:            updateline();
        !           839:    }
        !           840:    else if (!global_busy)          /* no need to update screen for :global */
        !           841:        updateScreen(CURSUPD);
        !           842:
        !           843:    msgmore(curbuf->b_ml.ml_line_count - old_lcount);
        !           844:
        !           845:        /* correct op_end for deleted text (for "']" command) */
        !           846:    if (op_block_mode)
        !           847:        curbuf->b_op_end.col = curbuf->b_op_start.col;
        !           848:    else
        !           849:        curbuf->b_op_end = curbuf->b_op_start;
        !           850: }
        !           851:
        !           852: /*
        !           853:  * do_tilde - handle the (non-standard vi) tilde operator
        !           854:  */
        !           855:    void
        !           856: do_tilde()
        !           857: {
        !           858:    FPOS                pos;
        !           859:    struct block_def    bd;
        !           860:
        !           861:    if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
        !           862:                               (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
        !           863:        return;
        !           864:
        !           865:    pos = curbuf->b_op_start;
        !           866:    if (op_block_mode)                  /* Visual block mode */
        !           867:    {
        !           868:        for (; pos.lnum <= curbuf->b_op_end.lnum; ++pos.lnum)
        !           869:        {
        !           870:            block_prep(&bd, pos.lnum, FALSE);
        !           871:            pos.col = bd.textcol;
        !           872:            while (--bd.textlen >= 0)
        !           873:            {
        !           874:                swapchar(&pos);
        !           875:                if (inc(&pos) == -1)    /* at end of file */
        !           876:                    break;
        !           877:            }
        !           878:        }
        !           879:    }
        !           880:    else            /* not block mode */
        !           881:    {
        !           882:        if (op_motion_type == MLINE)
        !           883:        {
        !           884:                pos.col = 0;
        !           885:                curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
        !           886:                if (curbuf->b_op_end.col)
        !           887:                        --curbuf->b_op_end.col;
        !           888:        }
        !           889:        else if (!op_inclusive)
        !           890:            dec(&(curbuf->b_op_end));
        !           891:
        !           892:        while (ltoreq(pos, curbuf->b_op_end))
        !           893:        {
        !           894:            swapchar(&pos);
        !           895:            if (inc(&pos) == -1)    /* at end of file */
        !           896:                break;
        !           897:        }
        !           898:    }
        !           899:
        !           900:    if (op_motion_type == MCHAR && op_line_count == 1 && !op_block_mode)
        !           901:    {
        !           902:        cursupdate();
        !           903:        updateline();
        !           904:    }
        !           905:    else
        !           906:        updateScreen(CURSUPD);
        !           907:
        !           908:    if (op_line_count > p_report)
        !           909:            smsg((char_u *)"%ld line%s ~ed",
        !           910:                                        op_line_count, plural(op_line_count));
        !           911: }
        !           912:
        !           913: /*
        !           914:  * If op_type == UPPER: make uppercase,
        !           915:  * if op_type == LOWER: make lowercase,
        !           916:  * else swap case of character at 'pos'
        !           917:  */
        !           918:    void
        !           919: swapchar(pos)
        !           920:    FPOS    *pos;
        !           921: {
        !           922:    int     c;
        !           923:
        !           924:    c = gchar(pos);
        !           925:    if (islower(c) && op_type != LOWER)
        !           926:    {
        !           927:        pchar(*pos, toupper(c));
        !           928:        CHANGED;
        !           929:    }
        !           930:    else if (isupper(c) && op_type != UPPER)
        !           931:    {
        !           932:        pchar(*pos, tolower(c));
        !           933:        CHANGED;
        !           934:    }
        !           935: }
        !           936:
        !           937: /*
        !           938:  * do_change - handle a change operation
        !           939:  *
        !           940:  * return TRUE if edit() returns because of a CTRL-O command
        !           941:  */
        !           942:    int
        !           943: do_change()
        !           944: {
        !           945:    register colnr_t           l;
        !           946:
        !           947:    l = curbuf->b_op_start.col;
        !           948:    if (op_motion_type == MLINE)
        !           949:    {
        !           950:        l = 0;
        !           951:        can_si = TRUE;      /* It's like opening a new line, do si */
        !           952:    }
        !           953:
        !           954:    if (!op_empty)
        !           955:        do_delete();            /* delete the text and take care of undo */
        !           956:
        !           957:    if ((l > curwin->w_cursor.col) && !lineempty(curwin->w_cursor.lnum))
        !           958:        inc_cursor();
        !           959:
        !           960: #ifdef LISPINDENT
        !           961:    if (op_motion_type == MLINE)
        !           962:    {
        !           963:        if (curbuf->b_p_lisp && curbuf->b_p_ai)
        !           964:            fixthisline(get_lisp_indent);
        !           965: # ifdef CINDENT
        !           966:        else if (curbuf->b_p_cin)
        !           967:            fixthisline(get_c_indent);
        !           968: # endif
        !           969:    }
        !           970: #endif
        !           971:
        !           972:    op_type = NOP;          /* don't want op_type == CHANGED in Insert mode */
        !           973:    return edit(NUL, FALSE, (linenr_t)1);
        !           974: }
        !           975:
        !           976: /*
        !           977:  * set all the yank buffers to empty (called from main())
        !           978:  */
        !           979:    void
        !           980: init_yank()
        !           981: {
        !           982:    register int i;
        !           983:
        !           984:    for (i = 0; i < NUM_REGISTERS; ++i)
        !           985:        y_buf[i].y_array = NULL;
        !           986: }
        !           987:
        !           988: /*
        !           989:  * Free "n" lines from the current yank buffer.
        !           990:  * Called for normal freeing and in case of error.
        !           991:  */
        !           992:    static void
        !           993: free_yank(n)
        !           994:    long n;
        !           995: {
        !           996:    if (y_current->y_array != NULL)
        !           997:    {
        !           998:        register long i;
        !           999:
        !          1000:        for (i = n; --i >= 0; )
        !          1001:        {
        !          1002:            if ((i & 1023) == 1023)                 /* this may take a while */
        !          1003:            {
        !          1004:                /*
        !          1005:                 * This message should never cause a hit-return message.
        !          1006:                 * Overwrite this message with any next message.
        !          1007:                 */
        !          1008:                ++no_wait_return;
        !          1009:                smsg((char_u *)"freeing %ld lines", i + 1);
        !          1010:                --no_wait_return;
        !          1011:                msg_didout = FALSE;
        !          1012:                msg_col = 0;
        !          1013:            }
        !          1014:            vim_free(y_current->y_array[i]);
        !          1015:        }
        !          1016:        vim_free(y_current->y_array);
        !          1017:        y_current->y_array = NULL;
        !          1018:        if (n >= 1000)
        !          1019:            MSG("");
        !          1020:    }
        !          1021: }
        !          1022:
        !          1023:    static void
        !          1024: free_yank_all()
        !          1025: {
        !          1026:        free_yank(y_current->y_size);
        !          1027: }
        !          1028:
        !          1029: /*
        !          1030:  * Yank the text between curwin->w_cursor and startpos into a yank buffer.
        !          1031:  * If we are to append ("uppercase), we first yank into a new yank buffer and
        !          1032:  * then concatenate the old and the new one (so we keep the old one in case
        !          1033:  * of out-of-memory).
        !          1034:  *
        !          1035:  * return FAIL for failure, OK otherwise
        !          1036:  */
        !          1037:    int
        !          1038: do_yank(deleting, mess)
        !          1039:    int deleting;
        !          1040:    int mess;
        !          1041: {
        !          1042:    long                i;              /* index in y_array[] */
        !          1043:    struct yankbuf      *curr;          /* copy of y_current */
        !          1044:    struct yankbuf      newbuf;         /* new yank buffer when appending */
        !          1045:    char_u              **new_ptr;
        !          1046:    register linenr_t   lnum;           /* current line number */
        !          1047:    long                j;
        !          1048:    int                 yanktype = op_motion_type;
        !          1049:    long                yanklines = op_line_count;
        !          1050:    linenr_t            yankendlnum = curbuf->b_op_end.lnum;
        !          1051:
        !          1052:    char_u              *pnew;
        !          1053:    struct block_def    bd;
        !          1054:
        !          1055:                                    /* check for read-only buffer */
        !          1056:    if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
        !          1057:    {
        !          1058:        beep_flush();
        !          1059:        return FAIL;
        !          1060:    }
        !          1061:    if (!deleting)                  /* do_delete() already set y_current */
        !          1062:        get_yank_buffer(TRUE);
        !          1063:
        !          1064:    curr = y_current;
        !          1065:                                    /* append to existing contents */
        !          1066:    if (yankappend && y_current->y_array != NULL)
        !          1067:        y_current = &newbuf;
        !          1068:    else
        !          1069:        free_yank_all();        /* free previously yanked lines */
        !          1070:
        !          1071: /*
        !          1072:  * If the cursor was in column 1 before and after the movement, and the
        !          1073:  * operator is not inclusive, the yank is always linewise.
        !          1074:  */
        !          1075:    if (op_motion_type == MCHAR && curbuf->b_op_start.col == 0 &&
        !          1076:                  !op_inclusive && curbuf->b_op_end.col == 0 && yanklines > 1)
        !          1077:    {
        !          1078:        yanktype = MLINE;
        !          1079:        --yankendlnum;
        !          1080:        --yanklines;
        !          1081:    }
        !          1082:
        !          1083:    y_current->y_size = yanklines;
        !          1084:    y_current->y_type = yanktype;   /* set the yank buffer type */
        !          1085:    y_current->y_array = (char_u **)lalloc((long_u)(sizeof(char_u *) *
        !          1086:                                                            yanklines), TRUE);
        !          1087:
        !          1088:    if (y_current->y_array == NULL)
        !          1089:    {
        !          1090:        y_current = curr;
        !          1091:        return FAIL;
        !          1092:    }
        !          1093:
        !          1094:    i = 0;
        !          1095:    lnum = curbuf->b_op_start.lnum;
        !          1096:
        !          1097: /*
        !          1098:  * Visual block mode
        !          1099:  */
        !          1100:    if (op_block_mode)
        !          1101:    {
        !          1102:        y_current->y_type = MBLOCK; /* set the yank buffer type */
        !          1103:        for ( ; lnum <= yankendlnum; ++lnum)
        !          1104:        {
        !          1105:            block_prep(&bd, lnum, FALSE);
        !          1106:
        !          1107:            if ((pnew = alloc(bd.startspaces + bd.endspaces +
        !          1108:                                          bd.textlen + 1)) == NULL)
        !          1109:                goto fail;
        !          1110:            y_current->y_array[i++] = pnew;
        !          1111:
        !          1112:            copy_spaces(pnew, (size_t)bd.startspaces);
        !          1113:            pnew += bd.startspaces;
        !          1114:
        !          1115:            vim_memmove(pnew, bd.textstart, (size_t)bd.textlen);
        !          1116:            pnew += bd.textlen;
        !          1117:
        !          1118:            copy_spaces(pnew, (size_t)bd.endspaces);
        !          1119:            pnew += bd.endspaces;
        !          1120:
        !          1121:            *pnew = NUL;
        !          1122:        }
        !          1123:    }
        !          1124:    else
        !          1125:    {
        !          1126: /*
        !          1127:  * there are three parts for non-block mode:
        !          1128:  * 1. if yanktype != MLINE yank last part of the top line
        !          1129:  * 2. yank the lines between op_start and op_end, inclusive when
        !          1130:  *    yanktype == MLINE
        !          1131:  * 3. if yanktype != MLINE yank first part of the bot line
        !          1132:  */
        !          1133:        if (yanktype != MLINE)
        !          1134:        {
        !          1135:            if (yanklines == 1)     /* op_start and op_end on same line */
        !          1136:            {
        !          1137:                j = curbuf->b_op_end.col - curbuf->b_op_start.col +
        !          1138:                                                            1 - !op_inclusive;
        !          1139:                if ((y_current->y_array[0] = strnsave(ml_get(lnum) +
        !          1140:                                     curbuf->b_op_start.col, (int)j)) == NULL)
        !          1141:                {
        !          1142: fail:
        !          1143:                    free_yank(i);   /* free the allocated lines */
        !          1144:                    y_current = curr;
        !          1145:                    return FAIL;
        !          1146:                }
        !          1147:                goto success;
        !          1148:            }
        !          1149:            if ((y_current->y_array[0] = strsave(ml_get(lnum++) +
        !          1150:                                             curbuf->b_op_start.col)) == NULL)
        !          1151:                goto fail;
        !          1152:            ++i;
        !          1153:        }
        !          1154:
        !          1155:        while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
        !          1156:        {
        !          1157:            if ((y_current->y_array[i] = strsave(ml_get(lnum++))) == NULL)
        !          1158:                goto fail;
        !          1159:            ++i;
        !          1160:        }
        !          1161:        if (yanktype != MLINE)
        !          1162:        {
        !          1163:            if ((y_current->y_array[i] = strnsave(ml_get(yankendlnum),
        !          1164:                           curbuf->b_op_end.col + 1 - !op_inclusive)) == NULL)
        !          1165:                goto fail;
        !          1166:        }
        !          1167:    }
        !          1168:
        !          1169: success:
        !          1170:    if (curr != y_current)      /* append the new block to the old block */
        !          1171:    {
        !          1172:        new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
        !          1173:                                   (curr->y_size + y_current->y_size)), TRUE);
        !          1174:        if (new_ptr == NULL)
        !          1175:            goto fail;
        !          1176:        for (j = 0; j < curr->y_size; ++j)
        !          1177:            new_ptr[j] = curr->y_array[j];
        !          1178:        vim_free(curr->y_array);
        !          1179:        curr->y_array = new_ptr;
        !          1180:
        !          1181:        if (yanktype == MLINE)  /* MLINE overrides MCHAR and MBLOCK */
        !          1182:            curr->y_type = MLINE;
        !          1183:
        !          1184:        /* concatenate the last line of the old block with the first line of
        !          1185:         * the new block */
        !          1186:        if (curr->y_type == MCHAR)
        !          1187:        {
        !          1188:            pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
        !          1189:                              + STRLEN(y_current->y_array[0]) + 1), TRUE);
        !          1190:            if (pnew == NULL)
        !          1191:            {
        !          1192:                    i = y_current->y_size - 1;
        !          1193:                    goto fail;
        !          1194:            }
        !          1195:            STRCPY(pnew, curr->y_array[--j]);
        !          1196:            STRCAT(pnew, y_current->y_array[0]);
        !          1197:            vim_free(curr->y_array[j]);
        !          1198:            vim_free(y_current->y_array[0]);
        !          1199:            curr->y_array[j++] = pnew;
        !          1200:            i = 1;
        !          1201:        }
        !          1202:        else
        !          1203:            i = 0;
        !          1204:        while (i < y_current->y_size)
        !          1205:            curr->y_array[j++] = y_current->y_array[i++];
        !          1206:        curr->y_size = j;
        !          1207:        vim_free(y_current->y_array);
        !          1208:        y_current = curr;
        !          1209:    }
        !          1210:    if (mess)                   /* Display message about yank? */
        !          1211:    {
        !          1212:        if (yanktype == MCHAR && !op_block_mode)
        !          1213:            --yanklines;
        !          1214:        if (yanklines > p_report)
        !          1215:        {
        !          1216:            cursupdate();       /* redisplay now, so message is not deleted */
        !          1217:            smsg((char_u *)"%ld line%s yanked", yanklines, plural(yanklines));
        !          1218:        }
        !          1219:    }
        !          1220:
        !          1221:    return OK;
        !          1222: }
        !          1223:
        !          1224: /*
        !          1225:  * put contents of register into the text
        !          1226:  * For ":put" command count == -1.
        !          1227:  */
        !          1228:    void
        !          1229: do_put(dir, count, fix_indent)
        !          1230:    int     dir;                /* BACKWARD for 'P', FORWARD for 'p' */
        !          1231:    long    count;
        !          1232:    int     fix_indent;         /* make indent look nice */
        !          1233: {
        !          1234:    char_u      *ptr;
        !          1235:    char_u      *newp, *oldp;
        !          1236:    int         yanklen;
        !          1237:    int         oldlen;
        !          1238:    int         totlen = 0;                 /* init for gcc */
        !          1239:    linenr_t    lnum;
        !          1240:    colnr_t     col;
        !          1241:    long        i;                          /* index in y_array[] */
        !          1242:    int         y_type;
        !          1243:    long        y_size;
        !          1244:    char_u      **y_array;
        !          1245:    long        nr_lines = 0;
        !          1246:    colnr_t     vcol;
        !          1247:    int         delcount;
        !          1248:    int         incr = 0;
        !          1249:    long        j;
        !          1250:    FPOS        new_cursor;
        !          1251:    int         indent;
        !          1252:    int         orig_indent = 0;            /* init for gcc */
        !          1253:    int         indent_diff = 0;            /* init for gcc */
        !          1254:    int         first_indent = TRUE;
        !          1255:    FPOS        old_pos;
        !          1256:    struct block_def bd;
        !          1257:    char_u      *insert_string = NULL;
        !          1258:
        !          1259: #ifdef USE_GUI
        !          1260:    if (yankbuffer == '*')
        !          1261:        gui_get_selection();
        !          1262: #endif
        !          1263:
        !          1264:    if (fix_indent)
        !          1265:        orig_indent = get_indent();
        !          1266:
        !          1267:    curbuf->b_op_start = curwin->w_cursor;      /* default for "'[" command */
        !          1268:    if (dir == FORWARD)
        !          1269:        curbuf->b_op_start.col++;
        !          1270:    curbuf->b_op_end = curwin->w_cursor;        /* default for "']" command */
        !          1271:
        !          1272:    /*
        !          1273:     * Using inserted text works differently, because the buffer includes
        !          1274:     * special characters (newlines, etc.).
        !          1275:     */
        !          1276:    if (yankbuffer == '.')
        !          1277:    {
        !          1278:        (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
        !          1279:                                    (count == -1 ? 'O' : 'i')), count, FALSE);
        !          1280:        return;
        !          1281:    }
        !          1282:
        !          1283:    /*
        !          1284:     * For '%' (file name) and ':' (last command line) we have to create a
        !          1285:     * fake yank buffer.
        !          1286:     */
        !          1287:    if (yankbuffer == '%')              /* use file name */
        !          1288:    {
        !          1289:        if (check_fname() == FAIL)
        !          1290:            return;
        !          1291:        insert_string = curbuf->b_xfilename;
        !          1292:    }
        !          1293:    else if (yankbuffer == ':')         /* use last command line */
        !          1294:    {
        !          1295:        if (last_cmdline == NULL)
        !          1296:        {
        !          1297:            EMSG(e_nolastcmd);
        !          1298:            return;
        !          1299:        }
        !          1300:        insert_string = last_cmdline;
        !          1301:    }
        !          1302:
        !          1303:    if (insert_string != NULL)
        !          1304:    {
        !          1305:        y_type = MCHAR;                 /* use fake one-line yank buffer */
        !          1306:        y_size = 1;
        !          1307:        y_array = &insert_string;
        !          1308:    }
        !          1309:    else
        !          1310:    {
        !          1311:        get_yank_buffer(FALSE);
        !          1312:
        !          1313:        y_type = y_current->y_type;
        !          1314:        y_size = y_current->y_size;
        !          1315:        y_array = y_current->y_array;
        !          1316:    }
        !          1317:
        !          1318:    if (count == -1)        /* :put command */
        !          1319:    {
        !          1320:        y_type = MLINE;
        !          1321:        count = 1;
        !          1322:    }
        !          1323:
        !          1324:    if (y_size == 0 || y_array == NULL)
        !          1325:    {
        !          1326:        EMSG2("Nothing in register %s", transchar(yankbuffer));
        !          1327:        return;
        !          1328:    }
        !          1329:
        !          1330:    if (y_type == MBLOCK)
        !          1331:    {
        !          1332:        lnum = curwin->w_cursor.lnum + y_size + 1;
        !          1333:        if (lnum > curbuf->b_ml.ml_line_count)
        !          1334:            lnum = curbuf->b_ml.ml_line_count + 1;
        !          1335:        if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
        !          1336:            return;
        !          1337:    }
        !          1338:    else if (u_save_cursor() == FAIL)
        !          1339:        return;
        !          1340:
        !          1341:    yanklen = STRLEN(y_array[0]);
        !          1342:    CHANGED;
        !          1343:
        !          1344:    lnum = curwin->w_cursor.lnum;
        !          1345:    col = curwin->w_cursor.col;
        !          1346:
        !          1347: /*
        !          1348:  * block mode
        !          1349:  */
        !          1350:    if (y_type == MBLOCK)
        !          1351:    {
        !          1352:        if (dir == FORWARD && gchar_cursor() != NUL)
        !          1353:        {
        !          1354:            getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
        !          1355:            ++col;
        !          1356:            ++curwin->w_cursor.col;
        !          1357:        }
        !          1358:        else
        !          1359:            getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
        !          1360:        for (i = 0; i < y_size; ++i)
        !          1361:        {
        !          1362:            bd.startspaces = 0;
        !          1363:            bd.endspaces = 0;
        !          1364:            bd.textcol = 0;
        !          1365:            vcol = 0;
        !          1366:            delcount = 0;
        !          1367:
        !          1368:        /* add a new line */
        !          1369:            if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
        !          1370:            {
        !          1371:                ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
        !          1372:                                                           (colnr_t)1, FALSE);
        !          1373:                ++nr_lines;
        !          1374:            }
        !          1375:            oldp = ml_get_curline();
        !          1376:            oldlen = STRLEN(oldp);
        !          1377:            for (ptr = oldp; vcol < col && *ptr; ++ptr)
        !          1378:            {
        !          1379:                /* Count a tab for what it's worth (if list mode not on) */
        !          1380:                incr = lbr_chartabsize(ptr, (colnr_t)vcol);
        !          1381:                vcol += incr;
        !          1382:                ++bd.textcol;
        !          1383:            }
        !          1384:            if (vcol < col) /* line too short, padd with spaces */
        !          1385:            {
        !          1386:                bd.startspaces = col - vcol;
        !          1387:            }
        !          1388:            else if (vcol > col)
        !          1389:            {
        !          1390:                bd.endspaces = vcol - col;
        !          1391:                bd.startspaces = incr - bd.endspaces;
        !          1392:                --bd.textcol;
        !          1393:                delcount = 1;
        !          1394:            }
        !          1395:            yanklen = STRLEN(y_array[i]);
        !          1396:            totlen = count * yanklen + bd.startspaces + bd.endspaces;
        !          1397:            newp = alloc_check((unsigned)totlen + oldlen + 1);
        !          1398:            if (newp == NULL)
        !          1399:                break;
        !          1400:        /* copy part up to cursor to new line */
        !          1401:            ptr = newp;
        !          1402:            vim_memmove(ptr, oldp, (size_t)bd.textcol);
        !          1403:            ptr += bd.textcol;
        !          1404:        /* may insert some spaces before the new text */
        !          1405:            copy_spaces(ptr, (size_t)bd.startspaces);
        !          1406:            ptr += bd.startspaces;
        !          1407:        /* insert the new text */
        !          1408:            for (j = 0; j < count; ++j)
        !          1409:            {
        !          1410:                vim_memmove(ptr, y_array[i], (size_t)yanklen);
        !          1411:                ptr += yanklen;
        !          1412:            }
        !          1413:        /* may insert some spaces after the new text */
        !          1414:            copy_spaces(ptr, (size_t)bd.endspaces);
        !          1415:            ptr += bd.endspaces;
        !          1416:        /* move the text after the cursor to the end of the line. */
        !          1417:            vim_memmove(ptr, oldp + bd.textcol + delcount,
        !          1418:                                (size_t)(oldlen - bd.textcol - delcount + 1));
        !          1419:            ml_replace(curwin->w_cursor.lnum, newp, FALSE);
        !          1420:
        !          1421:            ++curwin->w_cursor.lnum;
        !          1422:            if (i == 0)
        !          1423:                curwin->w_cursor.col += bd.startspaces;
        !          1424:        }
        !          1425:                                                /* for "']" command */
        !          1426:        curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
        !          1427:        curbuf->b_op_end.col = bd.textcol + totlen - 1;
        !          1428:        curwin->w_cursor.lnum = lnum;
        !          1429:        cursupdate();
        !          1430:        updateScreen(VALID_TO_CURSCHAR);
        !          1431:    }
        !          1432:    else        /* not block mode */
        !          1433:    {
        !          1434:        if (y_type == MCHAR)
        !          1435:        {
        !          1436:    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next char */
        !          1437:            if (dir == FORWARD && gchar_cursor() != NUL)
        !          1438:            {
        !          1439:                ++col;
        !          1440:                if (yanklen)
        !          1441:                {
        !          1442:                    ++curwin->w_cursor.col;
        !          1443:                    ++curbuf->b_op_end.col;
        !          1444:                }
        !          1445:            }
        !          1446:            new_cursor = curwin->w_cursor;
        !          1447:        }
        !          1448:        else if (dir == BACKWARD)
        !          1449:    /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
        !          1450:            --lnum;
        !          1451:
        !          1452: /*
        !          1453:  * simple case: insert into current line
        !          1454:  */
        !          1455:        if (y_type == MCHAR && y_size == 1)
        !          1456:        {
        !          1457:            totlen = count * yanklen;
        !          1458:            if (totlen)
        !          1459:            {
        !          1460:                oldp = ml_get(lnum);
        !          1461:                newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
        !          1462:                if (newp == NULL)
        !          1463:                    return;             /* alloc() will give error message */
        !          1464:                vim_memmove(newp, oldp, (size_t)col);
        !          1465:                ptr = newp + col;
        !          1466:                for (i = 0; i < count; ++i)
        !          1467:                {
        !          1468:                    vim_memmove(ptr, y_array[0], (size_t)yanklen);
        !          1469:                    ptr += yanklen;
        !          1470:                }
        !          1471:                vim_memmove(ptr, oldp + col, STRLEN(oldp + col) + 1);
        !          1472:                ml_replace(lnum, newp, FALSE);
        !          1473:                                          /* put cursor on last putted char */
        !          1474:                curwin->w_cursor.col += (colnr_t)(totlen - 1);
        !          1475:            }
        !          1476:            curbuf->b_op_end = curwin->w_cursor;
        !          1477:            updateline();
        !          1478:        }
        !          1479:        else
        !          1480:        {
        !          1481:            while (--count >= 0)
        !          1482:            {
        !          1483:                i = 0;
        !          1484:                if (y_type == MCHAR)
        !          1485:                {
        !          1486:                    /*
        !          1487:                     * Split the current line in two at the insert position.
        !          1488:                     * First insert y_array[size - 1] in front of second line.
        !          1489:                     * Then append y_array[0] to first line.
        !          1490:                     */
        !          1491:                    ptr = ml_get(lnum) + col;
        !          1492:                    totlen = STRLEN(y_array[y_size - 1]);
        !          1493:                    newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
        !          1494:                    if (newp == NULL)
        !          1495:                        goto error;
        !          1496:                    STRCPY(newp, y_array[y_size - 1]);
        !          1497:                    STRCAT(newp, ptr);
        !          1498:                        /* insert second line */
        !          1499:                    ml_append(lnum, newp, (colnr_t)0, FALSE);
        !          1500:                    vim_free(newp);
        !          1501:
        !          1502:                    oldp = ml_get(lnum);
        !          1503:                    newp = alloc_check((unsigned)(col + yanklen + 1));
        !          1504:                    if (newp == NULL)
        !          1505:                        goto error;
        !          1506:                                            /* copy first part of line */
        !          1507:                    vim_memmove(newp, oldp, (size_t)col);
        !          1508:                                            /* append to first line */
        !          1509:                    vim_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
        !          1510:                    ml_replace(lnum, newp, FALSE);
        !          1511:
        !          1512:                    curwin->w_cursor.lnum = lnum;
        !          1513:                    i = 1;
        !          1514:                }
        !          1515:
        !          1516:                while (i < y_size)
        !          1517:                {
        !          1518:                    if ((y_type != MCHAR || i < y_size - 1) &&
        !          1519:                        ml_append(lnum, y_array[i], (colnr_t)0, FALSE) == FAIL)
        !          1520:                            goto error;
        !          1521:                    lnum++;
        !          1522:                    i++;
        !          1523:                    if (fix_indent)
        !          1524:                    {
        !          1525:                        old_pos = curwin->w_cursor;
        !          1526:                        curwin->w_cursor.lnum = lnum;
        !          1527:                        ptr = ml_get(lnum);
        !          1528: #if defined(SMARTINDENT) || defined(CINDENT)
        !          1529:                        if (*ptr == '#'
        !          1530: # ifdef SMARTINDENT
        !          1531:                           && curbuf->b_p_si
        !          1532: # endif
        !          1533: # ifdef CINDENT
        !          1534:                           && curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
        !          1535: # endif
        !          1536:                                            )
        !          1537:
        !          1538:                            indent = 0;     /* Leave # lines at start */
        !          1539:                        else
        !          1540: #endif
        !          1541:                             if (*ptr == NUL)
        !          1542:                            indent = 0;     /* Ignore empty lines */
        !          1543:                        else if (first_indent)
        !          1544:                        {
        !          1545:                            indent_diff = orig_indent - get_indent();
        !          1546:                            indent = orig_indent;
        !          1547:                            first_indent = FALSE;
        !          1548:                        }
        !          1549:                        else if ((indent = get_indent() + indent_diff) < 0)
        !          1550:                            indent = 0;
        !          1551:                        set_indent(indent, TRUE);
        !          1552:                        curwin->w_cursor = old_pos;
        !          1553:                    }
        !          1554:                    ++nr_lines;
        !          1555:                }
        !          1556:            }
        !          1557:
        !          1558:            /* put '] at last inserted character */
        !          1559:            curbuf->b_op_end.lnum = lnum;
        !          1560:            col = STRLEN(y_array[y_size - 1]);
        !          1561:            if (col > 1)
        !          1562:                curbuf->b_op_end.col = col - 1;
        !          1563:            else
        !          1564:                curbuf->b_op_end.col = 0;
        !          1565:
        !          1566:            if (y_type == MLINE)
        !          1567:            {
        !          1568:                curwin->w_cursor.col = 0;
        !          1569:                if (dir == FORWARD)
        !          1570:                {
        !          1571:                    updateScreen(NOT_VALID);    /* recomp. curwin->w_botline */
        !          1572:                    ++curwin->w_cursor.lnum;
        !          1573:                }
        !          1574:                    /* put cursor on first non-blank in last inserted line */
        !          1575:                beginline(TRUE);
        !          1576:            }
        !          1577:            else        /* put cursor on first inserted character */
        !          1578:            {
        !          1579:                curwin->w_cursor = new_cursor;
        !          1580:            }
        !          1581:
        !          1582: error:
        !          1583:            if (y_type == MLINE)        /* for '[ */
        !          1584:            {
        !          1585:                curbuf->b_op_start.col = 0;
        !          1586:                if (dir == FORWARD)
        !          1587:                    curbuf->b_op_start.lnum++;
        !          1588:            }
        !          1589:            mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
        !          1590:                                                       MAXLNUM, nr_lines, 0L);
        !          1591:            updateScreen(CURSUPD);
        !          1592:        }
        !          1593:    }
        !          1594:
        !          1595:    msgmore(nr_lines);
        !          1596:    curwin->w_set_curswant = TRUE;
        !          1597: }
        !          1598:
        !          1599: /* Return the character name of the register with the given number */
        !          1600:    int
        !          1601: get_register_name(num)
        !          1602:    int num;
        !          1603: {
        !          1604:    if (num == -1)
        !          1605:        return '"';
        !          1606:    else if (num < 10)
        !          1607:        return num + '0';
        !          1608:    else if (num == DELETION_REGISTER)
        !          1609:        return '-';
        !          1610: #ifdef USE_GUI
        !          1611:    else if (num == GUI_SELECTION_REGISTER)
        !          1612:        return '*';
        !          1613: #endif
        !          1614:    else
        !          1615:        return num + 'a' - 10;
        !          1616: }
        !          1617:
        !          1618: /*
        !          1619:  * display the contents of the yank buffers
        !          1620:  */
        !          1621:    void
        !          1622: do_dis(arg)
        !          1623:    char_u *arg;
        !          1624: {
        !          1625:    register int            i, n;
        !          1626:    register long           j;
        !          1627:    register char_u         *p;
        !          1628:    register struct yankbuf *yb;
        !          1629:    char_u name;
        !          1630:
        !          1631:    if (arg != NULL && *arg == NUL)
        !          1632:        arg = NULL;
        !          1633:
        !          1634:    set_highlight('t');     /* Highlight title */
        !          1635:    start_highlight();
        !          1636:    MSG_OUTSTR("\n--- Registers ---");
        !          1637:    stop_highlight();
        !          1638:    for (i = -1; i < NUM_REGISTERS; ++i)
        !          1639:    {
        !          1640:        if (i == -1)
        !          1641:        {
        !          1642:            if (y_previous != NULL)
        !          1643:                yb = y_previous;
        !          1644:            else
        !          1645:                yb = &(y_buf[0]);
        !          1646:        }
        !          1647:        else
        !          1648:            yb = &(y_buf[i]);
        !          1649:        name = get_register_name(i);
        !          1650:        if (yb->y_array != NULL && (arg == NULL ||
        !          1651:                                               vim_strchr(arg, name) != NULL))
        !          1652:        {
        !          1653:            msg_outchar('\n');
        !          1654:            msg_outchar('"');
        !          1655:            msg_outchar(name);
        !          1656:            MSG_OUTSTR("   ");
        !          1657:
        !          1658:            n = (int)Columns - 6;
        !          1659:            for (j = 0; j < yb->y_size && n > 1; ++j)
        !          1660:            {
        !          1661:                if (j)
        !          1662:                {
        !          1663:                    MSG_OUTSTR("^J");
        !          1664:                    n -= 2;
        !          1665:                }
        !          1666:                for (p = yb->y_array[j]; *p && (n -= charsize(*p)) >= 0; ++p)
        !          1667:                    msg_outtrans_len(p, 1);
        !          1668:            }
        !          1669:            flushbuf();             /* show one line at a time */
        !          1670:        }
        !          1671:    }
        !          1672:
        !          1673:    /*
        !          1674:     * display last inserted text
        !          1675:     */
        !          1676:    if ((p = get_last_insert()) != NULL &&
        !          1677:        (arg == NULL || vim_strchr(arg, '.') != NULL))
        !          1678:    {
        !          1679:        MSG_OUTSTR("\n\".   ");
        !          1680:        dis_msg(p, TRUE);
        !          1681:    }
        !          1682:
        !          1683:    /*
        !          1684:     * display last command line
        !          1685:     */
        !          1686:    if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL))
        !          1687:    {
        !          1688:        MSG_OUTSTR("\n\":   ");
        !          1689:        dis_msg(last_cmdline, FALSE);
        !          1690:    }
        !          1691:
        !          1692:    /*
        !          1693:     * display current file name
        !          1694:     */
        !          1695:    if (curbuf->b_xfilename != NULL &&
        !          1696:                                (arg == NULL || vim_strchr(arg, '%') != NULL))
        !          1697:    {
        !          1698:        MSG_OUTSTR("\n\"%   ");
        !          1699:        dis_msg(curbuf->b_xfilename, FALSE);
        !          1700:    }
        !          1701: }
        !          1702:
        !          1703: /*
        !          1704:  * display a string for do_dis()
        !          1705:  * truncate at end of screen line
        !          1706:  */
        !          1707:    void
        !          1708: dis_msg(p, skip_esc)
        !          1709:    char_u      *p;
        !          1710:    int         skip_esc;           /* if TRUE, ignore trailing ESC */
        !          1711: {
        !          1712:    int     n;
        !          1713:
        !          1714:    n = (int)Columns - 6;
        !          1715:    while (*p && !(*p == ESC && skip_esc && *(p + 1) == NUL) &&
        !          1716:                        (n -= charsize(*p)) >= 0)
        !          1717:        msg_outtrans_len(p++, 1);
        !          1718: }
        !          1719:
        !          1720: /*
        !          1721:  * join 'count' lines (minimal 2), including u_save()
        !          1722:  */
        !          1723:    void
        !          1724: do_do_join(count, insert_space, redraw)
        !          1725:    long    count;
        !          1726:    int     insert_space;
        !          1727:    int     redraw;                 /* can redraw, curwin->w_col valid */
        !          1728: {
        !          1729:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
        !          1730:                    (linenr_t)(curwin->w_cursor.lnum + count)) == FAIL)
        !          1731:        return;
        !          1732:
        !          1733:    if (count > 10)
        !          1734:        redraw = FALSE;             /* don't redraw each small change */
        !          1735:    while (--count > 0)
        !          1736:    {
        !          1737:        line_breakcheck();
        !          1738:        if (got_int || do_join(insert_space, redraw) == FAIL)
        !          1739:        {
        !          1740:            beep_flush();
        !          1741:            break;
        !          1742:        }
        !          1743:    }
        !          1744:    if (redraw)
        !          1745:        redraw_later(VALID_TO_CURSCHAR);
        !          1746:    else
        !          1747:        redraw_later(NOT_VALID);
        !          1748:
        !          1749:    /*
        !          1750:     * Need to update the screen if the line where the cursor is became too
        !          1751:     * long to fit on the screen.
        !          1752:     */
        !          1753:    cursupdate();
        !          1754: }
        !          1755:
        !          1756: /*
        !          1757:  * Join two lines at the cursor position.
        !          1758:  *
        !          1759:  * return FAIL for failure, OK ohterwise
        !          1760:  */
        !          1761:    int
        !          1762: do_join(insert_space, redraw)
        !          1763:    int         insert_space;
        !          1764:    int         redraw;     /* should only be TRUE when curwin->w_row valid */
        !          1765: {
        !          1766:    char_u      *curr;
        !          1767:    char_u      *next;
        !          1768:    char_u      *newp;
        !          1769:    int         endcurr1, endcurr2;
        !          1770:    int         currsize;       /* size of the current line */
        !          1771:    int         nextsize;       /* size of the next line */
        !          1772:    int         spaces;         /* number of spaces to insert */
        !          1773:    int         rows_to_del = 0;/* number of rows on screen to delete */
        !          1774:    linenr_t    t;
        !          1775:
        !          1776:    if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
        !          1777:        return FAIL;            /* can't join on last line */
        !          1778:
        !          1779:    if (redraw)
        !          1780:        rows_to_del = plines_m(curwin->w_cursor.lnum,
        !          1781:                                                   curwin->w_cursor.lnum + 1);
        !          1782:
        !          1783:    curr = ml_get_curline();
        !          1784:    currsize = STRLEN(curr);
        !          1785:    endcurr1 = endcurr2 = NUL;
        !          1786:    if (currsize > 0)
        !          1787:    {
        !          1788:        endcurr1 = *(curr + currsize - 1);
        !          1789:        if (currsize > 1)
        !          1790:            endcurr2 = *(curr + currsize - 2);
        !          1791:    }
        !          1792:
        !          1793:    next = ml_get((linenr_t)(curwin->w_cursor.lnum + 1));
        !          1794:    spaces = 0;
        !          1795:    if (insert_space)
        !          1796:    {
        !          1797:        next = skipwhite(next);
        !          1798:        spaces = 1;
        !          1799:        if (*next == ')' || currsize == 0)
        !          1800:            spaces = 0;
        !          1801:        else
        !          1802:        {
        !          1803:            if (endcurr1 == ' ' || endcurr1 == TAB)
        !          1804:            {
        !          1805:                spaces = 0;
        !          1806:                if (currsize > 1)
        !          1807:                    endcurr1 = endcurr2;
        !          1808:            }
        !          1809:            if (p_js && vim_strchr((char_u *)".!?", endcurr1) != NULL)
        !          1810:                spaces = 2;
        !          1811:        }
        !          1812:    }
        !          1813:    nextsize = STRLEN(next);
        !          1814:
        !          1815:    newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
        !          1816:    if (newp == NULL)
        !          1817:        return FAIL;
        !          1818:
        !          1819:    /*
        !          1820:     * Insert the next line first, because we already have that pointer.
        !          1821:     * Curr has to be obtained again, because getting next will have
        !          1822:     * invalidated it.
        !          1823:     */
        !          1824:    vim_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
        !          1825:
        !          1826:    curr = ml_get_curline();
        !          1827:    vim_memmove(newp, curr, (size_t)currsize);
        !          1828:
        !          1829:    copy_spaces(newp + currsize, (size_t)spaces);
        !          1830:
        !          1831:    ml_replace(curwin->w_cursor.lnum, newp, FALSE);
        !          1832:
        !          1833:    /*
        !          1834:     * Delete the following line. To do this we move the cursor there
        !          1835:     * briefly, and then move it back. After dellines() the cursor may
        !          1836:     * have moved up (last line deleted), so the current lnum is kept in t.
        !          1837:     */
        !          1838:    t = curwin->w_cursor.lnum;
        !          1839:    ++curwin->w_cursor.lnum;
        !          1840:    dellines(1L, FALSE, FALSE);
        !          1841:    curwin->w_cursor.lnum = t;
        !          1842:
        !          1843:    /*
        !          1844:     * the number of rows on the screen is reduced by the difference
        !          1845:     * in number of rows of the two old lines and the one new line
        !          1846:     */
        !          1847:    if (redraw)
        !          1848:    {
        !          1849:        rows_to_del -= plines(curwin->w_cursor.lnum);
        !          1850:        if (rows_to_del > 0)
        !          1851:            win_del_lines(curwin, curwin->w_cline_row + curwin->w_cline_height,
        !          1852:                                                     rows_to_del, TRUE, TRUE);
        !          1853:    }
        !          1854:
        !          1855:    /*
        !          1856:     * go to first character of the joined line
        !          1857:     */
        !          1858:    if (currsize == 0)
        !          1859:        curwin->w_cursor.col = 0;
        !          1860:    else
        !          1861:    {
        !          1862:        curwin->w_cursor.col = currsize - 1;
        !          1863:        (void)oneright();
        !          1864:    }
        !          1865:    CHANGED;
        !          1866:
        !          1867:    return OK;
        !          1868: }
        !          1869:
        !          1870: /*
        !          1871:  * Return TRUE if the two comment leaders given are the same.  The cursor is
        !          1872:  * in the first line.  White-space is ignored.  Note that the whole of
        !          1873:  * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
        !          1874:  */
        !          1875:    static int
        !          1876: same_leader(leader1_len, leader1_flags, leader2_len, leader2_flags)
        !          1877:    int     leader1_len;
        !          1878:    char_u  *leader1_flags;
        !          1879:    int     leader2_len;
        !          1880:    char_u  *leader2_flags;
        !          1881: {
        !          1882:    int     idx1 = 0, idx2 = 0;
        !          1883:    char_u  *p;
        !          1884:    char_u  *line1;
        !          1885:    char_u  *line2;
        !          1886:
        !          1887:    if (leader1_len == 0)
        !          1888:        return (leader2_len == 0);
        !          1889:
        !          1890:    /*
        !          1891:     * If first leader has 'f' flag, the lines can be joined only if the
        !          1892:     * second line does not have a leader.
        !          1893:     * If first leader has 'e' flag, the lines can never be joined.
        !          1894:     * If fist leader has 's' flag, the lines can only be joined if there is
        !          1895:     * some text after it and the second line has the 'm' flag.
        !          1896:     */
        !          1897:    if (leader1_flags != NULL)
        !          1898:    {
        !          1899:        for (p = leader1_flags; *p && *p != ':'; ++p)
        !          1900:        {
        !          1901:            if (*p == COM_FIRST)
        !          1902:                return (leader2_len == 0);
        !          1903:            if (*p == COM_END)
        !          1904:                return FALSE;
        !          1905:            if (*p == COM_START)
        !          1906:            {
        !          1907:                if (*(ml_get_curline() + leader1_len) == NUL)
        !          1908:                    return FALSE;
        !          1909:                if (leader2_flags == NULL || leader2_len == 0)
        !          1910:                    return FALSE;
        !          1911:                for (p = leader2_flags; *p && *p != ':'; ++p)
        !          1912:                    if (*p == COM_MIDDLE)
        !          1913:                        return TRUE;
        !          1914:                return FALSE;
        !          1915:            }
        !          1916:        }
        !          1917:    }
        !          1918:
        !          1919:    /*
        !          1920:     * Get current line and next line, compare the leaders.
        !          1921:     * The first line has to be saved, only one line can be locked at a time.
        !          1922:     */
        !          1923:    line1 = strsave(ml_get_curline());
        !          1924:    if (line1 != NULL)
        !          1925:    {
        !          1926:        for (idx1 = 0; vim_iswhite(line1[idx1]); ++idx1)
        !          1927:            ;
        !          1928:        line2 = ml_get(curwin->w_cursor.lnum + 1);
        !          1929:        for (idx2 = 0; idx2 < leader2_len; ++idx2)
        !          1930:        {
        !          1931:            if (!vim_iswhite(line2[idx2]))
        !          1932:            {
        !          1933:                if (line1[idx1++] != line2[idx2])
        !          1934:                    break;
        !          1935:            }
        !          1936:            else
        !          1937:                while (vim_iswhite(line1[idx1]))
        !          1938:                    ++idx1;
        !          1939:        }
        !          1940:        vim_free(line1);
        !          1941:    }
        !          1942:    return (idx2 == leader2_len && idx1 == leader1_len);
        !          1943: }
        !          1944:
        !          1945: /*
        !          1946:  * implementation of the format operator 'Q'
        !          1947:  */
        !          1948:    void
        !          1949: do_format()
        !          1950: {
        !          1951:    long        old_line_count = curbuf->b_ml.ml_line_count;
        !          1952:    int         prev_is_blank = FALSE;
        !          1953:    int         is_end_block = TRUE;
        !          1954:    int         next_is_end_block;
        !          1955:    int         leader_len = 0;     /* init for gcc */
        !          1956:    int         next_leader_len;
        !          1957:    char_u      *leader_flags = NULL;
        !          1958:    char_u      *next_leader_flags;
        !          1959:    int         advance = TRUE;
        !          1960:    int         second_indent = -1;
        !          1961:    int         do_second_indent;
        !          1962:    int         first_par_line = TRUE;
        !          1963:
        !          1964:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
        !          1965:                   (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
        !          1966:        return;
        !          1967:
        !          1968:    /* check for 'q' and '2' in 'formatoptions' */
        !          1969:    fo_do_comments = has_format_option(FO_Q_COMS);
        !          1970:    do_second_indent = has_format_option(FO_Q_SECOND);
        !          1971:
        !          1972:    /*
        !          1973:     * get info about the previous and current line.
        !          1974:     */
        !          1975:    if (curwin->w_cursor.lnum > 1)
        !          1976:        is_end_block = fmt_end_block(curwin->w_cursor.lnum - 1,
        !          1977:                                        &next_leader_len, &next_leader_flags);
        !          1978:    next_is_end_block = fmt_end_block(curwin->w_cursor.lnum,
        !          1979:                                        &next_leader_len, &next_leader_flags);
        !          1980:
        !          1981:    curwin->w_cursor.lnum--;
        !          1982:    while (--op_line_count >= 0)
        !          1983:    {
        !          1984:        /*
        !          1985:         * Advance to next block.
        !          1986:         */
        !          1987:        if (advance)
        !          1988:        {
        !          1989:            curwin->w_cursor.lnum++;
        !          1990:            prev_is_blank = is_end_block;
        !          1991:            is_end_block = next_is_end_block;
        !          1992:            leader_len = next_leader_len;
        !          1993:            leader_flags = next_leader_flags;
        !          1994:        }
        !          1995:
        !          1996:        /*
        !          1997:         * The last line to be formatted.
        !          1998:         */
        !          1999:        if (op_line_count == 0)
        !          2000:        {
        !          2001:            next_is_end_block = TRUE;
        !          2002:            next_leader_len = 0;
        !          2003:            next_leader_flags = NULL;
        !          2004:        }
        !          2005:        else
        !          2006:            next_is_end_block = fmt_end_block(curwin->w_cursor.lnum + 1,
        !          2007:                                        &next_leader_len, &next_leader_flags);
        !          2008:        advance = TRUE;
        !          2009:
        !          2010:        /*
        !          2011:         * For the first line of a paragraph, check indent of second line.
        !          2012:         * Don't do this for comments and empty lines.
        !          2013:         */
        !          2014:        if (first_par_line && do_second_indent &&
        !          2015:                prev_is_blank && !is_end_block &&
        !          2016:                curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count &&
        !          2017:                leader_len == 0 && next_leader_len == 0 &&
        !          2018:                !lineempty(curwin->w_cursor.lnum + 1))
        !          2019:            second_indent = get_indent_lnum(curwin->w_cursor.lnum + 1);
        !          2020:
        !          2021:        /*
        !          2022:         * Skip end-of-block (blank) lines
        !          2023:         */
        !          2024:        if (is_end_block)
        !          2025:        {
        !          2026:        }
        !          2027:        /*
        !          2028:         * If we have got to the end of a paragraph, format it.
        !          2029:         */
        !          2030:        else if (next_is_end_block || !same_leader(leader_len, leader_flags,
        !          2031:                                          next_leader_len, next_leader_flags))
        !          2032:        {
        !          2033:            /* replace indent in first line with minimal number of tabs and
        !          2034:             * spaces, according to current options */
        !          2035:            set_indent(get_indent(), TRUE);
        !          2036:
        !          2037:            /* put cursor on last non-space */
        !          2038:            coladvance(MAXCOL);
        !          2039:            while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
        !          2040:                dec_cursor();
        !          2041:            curs_columns(FALSE);            /* update curwin->w_virtcol */
        !          2042:
        !          2043:            /* do the formatting */
        !          2044:            State = INSERT;     /* for Opencmd() */
        !          2045:            insertchar(NUL, TRUE, second_indent);
        !          2046:            State = NORMAL;
        !          2047:            first_par_line = TRUE;
        !          2048:            second_indent = -1;
        !          2049:        }
        !          2050:        else
        !          2051:        {
        !          2052:            /*
        !          2053:             * Still in same paragraph, so join the lines together.
        !          2054:             * But first delete the comment leader from the second line.
        !          2055:             */
        !          2056:            advance = FALSE;
        !          2057:            curwin->w_cursor.lnum++;
        !          2058:            curwin->w_cursor.col = 0;
        !          2059:            while (next_leader_len--)
        !          2060:                delchar(FALSE);
        !          2061:            curwin->w_cursor.lnum--;
        !          2062:            if (do_join(TRUE, FALSE) == FAIL)
        !          2063:            {
        !          2064:                beep_flush();
        !          2065:                break;
        !          2066:            }
        !          2067:            first_par_line = FALSE;
        !          2068:        }
        !          2069:    }
        !          2070:    fo_do_comments = FALSE;
        !          2071:    /*
        !          2072:     * Leave the cursor at the first non-blank of the last formatted line.
        !          2073:     * If the cursor was move one line back (e.g. with "Q}") go to the next
        !          2074:     * line, so "." will do the next lines.
        !          2075:     */
        !          2076:    if (op_end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
        !          2077:        ++curwin->w_cursor.lnum;
        !          2078:    beginline(TRUE);
        !          2079:    updateScreen(NOT_VALID);
        !          2080:    msgmore(curbuf->b_ml.ml_line_count - old_line_count);
        !          2081: }
        !          2082:
        !          2083: /*
        !          2084:  * Blank lines, and lines containing only the comment leader, are left
        !          2085:  * untouched by the formatting.  The function returns TRUE in this
        !          2086:  * case.  It also returns TRUE when a line starts with the end of a comment
        !          2087:  * ('e' in comment flags), so that this line is skipped, and not joined to the
        !          2088:  * previous line.  A new paragraph starts after a blank line, or when the
        !          2089:  * comment leader changes -- webb.
        !          2090:  */
        !          2091:    static int
        !          2092: fmt_end_block(lnum, leader_len, leader_flags)
        !          2093:    linenr_t    lnum;
        !          2094:    int         *leader_len;
        !          2095:    char_u      **leader_flags;
        !          2096: {
        !          2097:    char_u      *flags = NULL;      /* init for GCC */
        !          2098:    char_u      *ptr;
        !          2099:
        !          2100:    ptr = ml_get(lnum);
        !          2101:    *leader_len = get_leader_len(ptr, leader_flags);
        !          2102:
        !          2103:    if (*leader_len > 0)
        !          2104:    {
        !          2105:        /*
        !          2106:         * Search for 'e' flag in comment leader flags.
        !          2107:         */
        !          2108:        flags = *leader_flags;
        !          2109:        while (*flags && *flags != ':' && *flags != COM_END)
        !          2110:            ++flags;
        !          2111:    }
        !          2112:
        !          2113:    return (ptr[*leader_len] == NUL ||
        !          2114:            (*leader_len > 0 && *flags == COM_END) ||
        !          2115:             startPS(lnum, NUL, FALSE));
        !          2116: }
        !          2117:
        !          2118: /*
        !          2119:  * prepare a few things for block mode yank/delete/tilde
        !          2120:  *
        !          2121:  * for delete:
        !          2122:  * - textlen includes the first/last char to be (partly) deleted
        !          2123:  * - start/endspaces is the number of columns that are taken by the
        !          2124:  *  first/last deleted char minus the number of columns that have to be deleted.
        !          2125:  * for yank and tilde:
        !          2126:  * - textlen includes the first/last char to be wholly yanked
        !          2127:  * - start/endspaces is the number of columns of the first/last yanked char
        !          2128:  *   that are to be yanked.
        !          2129:  */
        !          2130:    static void
        !          2131: block_prep(bd, lnum, is_del)
        !          2132:    struct block_def    *bd;
        !          2133:    linenr_t            lnum;
        !          2134:    int                 is_del;
        !          2135: {
        !          2136:    colnr_t     vcol;
        !          2137:    int         incr = 0;
        !          2138:    char_u      *pend;
        !          2139:    char_u      *pstart;
        !          2140:
        !          2141:    bd->startspaces = 0;
        !          2142:    bd->endspaces = 0;
        !          2143:    bd->textlen = 0;
        !          2144:    bd->textcol = 0;
        !          2145:    vcol = 0;
        !          2146:    pstart = ml_get(lnum);
        !          2147:    while (vcol < op_start_vcol && *pstart)
        !          2148:    {
        !          2149:        /* Count a tab for what it's worth (if list mode not on) */
        !          2150:        incr = lbr_chartabsize(pstart, (colnr_t)vcol);
        !          2151:        vcol += incr;
        !          2152:        ++pstart;
        !          2153:        ++bd->textcol;
        !          2154:    }
        !          2155:    if (vcol < op_start_vcol)   /* line too short */
        !          2156:    {
        !          2157:        if (!is_del)
        !          2158:            bd->endspaces = op_end_vcol - op_start_vcol + 1;
        !          2159:    }
        !          2160:    else /* vcol >= op_start_vcol */
        !          2161:    {
        !          2162:        bd->startspaces = vcol - op_start_vcol;
        !          2163:        if (is_del && vcol > op_start_vcol)
        !          2164:            bd->startspaces = incr - bd->startspaces;
        !          2165:        pend = pstart;
        !          2166:        if (vcol > op_end_vcol)     /* it's all in one character */
        !          2167:        {
        !          2168:            bd->startspaces = op_end_vcol - op_start_vcol + 1;
        !          2169:            if (is_del)
        !          2170:                bd->startspaces = incr - bd->startspaces;
        !          2171:        }
        !          2172:        else
        !          2173:        {
        !          2174:            while (vcol <= op_end_vcol && *pend)
        !          2175:            {
        !          2176:                /* Count a tab for what it's worth (if list mode not on) */
        !          2177:                incr = lbr_chartabsize(pend, (colnr_t)vcol);
        !          2178:                vcol += incr;
        !          2179:                ++pend;
        !          2180:            }
        !          2181:            if (vcol < op_end_vcol && !is_del)  /* line too short */
        !          2182:            {
        !          2183:                bd->endspaces = op_end_vcol - vcol;
        !          2184:            }
        !          2185:            else if (vcol > op_end_vcol)
        !          2186:            {
        !          2187:                bd->endspaces = vcol - op_end_vcol - 1;
        !          2188:                if (!is_del && pend != pstart && bd->endspaces)
        !          2189:                    --pend;
        !          2190:            }
        !          2191:        }
        !          2192:        if (is_del && bd->startspaces)
        !          2193:        {
        !          2194:            --pstart;
        !          2195:            --bd->textcol;
        !          2196:        }
        !          2197:        bd->textlen = (int)(pend - pstart);
        !          2198:    }
        !          2199:    bd->textstart = pstart;
        !          2200: }
        !          2201:
        !          2202: #define NUMBUFLEN 30
        !          2203:
        !          2204: /*
        !          2205:  * add or subtract 'Prenum1' from a number in a line
        !          2206:  * 'command' is CTRL-A for add, CTRL-X for subtract
        !          2207:  *
        !          2208:  * return FAIL for failure, OK otherwise
        !          2209:  */
        !          2210:    int
        !          2211: do_addsub(command, Prenum1)
        !          2212:    int         command;
        !          2213:    linenr_t    Prenum1;
        !          2214: {
        !          2215:    register int    col;
        !          2216:    char_u          buf[NUMBUFLEN];
        !          2217:    int             hex;            /* 'X': hexadecimal; '0': octal */
        !          2218:    static int      hexupper = FALSE;   /* 0xABC */
        !          2219:    long            n;
        !          2220:    char_u          *ptr;
        !          2221:    int             i;
        !          2222:    int             c;
        !          2223:    int             zeros = 0;      /* number of leading zeros */
        !          2224:    int             digits = 0;     /* number of digits in the number */
        !          2225:
        !          2226:    ptr = ml_get_curline();
        !          2227:    col = curwin->w_cursor.col;
        !          2228:
        !          2229:        /* first check if we are on a hexadecimal number */
        !          2230:    while (col > 0 && isxdigit(ptr[col]))
        !          2231:        --col;
        !          2232:    if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
        !          2233:                        ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
        !          2234:        --col;      /* found hexadecimal number */
        !          2235:    else
        !          2236:    {
        !          2237:        /* first search forward and then backward for start of number */
        !          2238:        col = curwin->w_cursor.col;
        !          2239:
        !          2240:        while (ptr[col] != NUL && !isdigit(ptr[col]))
        !          2241:            ++col;
        !          2242:
        !          2243:        while (col > 0 && isdigit(ptr[col - 1]))
        !          2244:            --col;
        !          2245:    }
        !          2246:
        !          2247:    if (isdigit(ptr[col]) && u_save_cursor() == OK)
        !          2248:    {
        !          2249:        ptr = ml_get_curline();                 /* get it again, because
        !          2250:                                                   u_save may have changed it */
        !          2251:        curwin->w_set_curswant = TRUE;
        !          2252:
        !          2253:        hex = 0;                                /* default is decimal */
        !          2254:        if (ptr[col] == '0')                    /* could be hex or octal */
        !          2255:        {
        !          2256:            hex = TO_UPPER(ptr[col + 1]);       /* assume hexadecimal */
        !          2257:            if (hex != 'X' || !isxdigit(ptr[col + 2]))
        !          2258:            {
        !          2259:                if (isdigit(hex))
        !          2260:                    hex = '0';                  /* octal */
        !          2261:                else
        !          2262:                    hex = 0;                    /* 0 by itself is decimal */
        !          2263:            }
        !          2264:        }
        !          2265:
        !          2266:        if (!hex && col > 0 && ptr[col - 1] == '-')
        !          2267:            --col;
        !          2268:
        !          2269:        ptr += col;
        !          2270:        /*
        !          2271:         * we copy the number into a buffer because some versions of sscanf
        !          2272:         * cannot handle characters with the upper bit set, making some special
        !          2273:         * characters handled like digits.
        !          2274:         */
        !          2275:        for (i = 0; *ptr && !(*ptr & 0x80) && i < NUMBUFLEN - 1; ++i)
        !          2276:            buf[i] = *ptr++;
        !          2277:        buf[i] = NUL;
        !          2278:
        !          2279:        if (hex == '0')
        !          2280:            sscanf((char *)buf, "%lo", &n);
        !          2281:        else if (hex)
        !          2282:            sscanf((char *)buf + 2, "%lx", &n); /* "%X" doesn't work! */
        !          2283:        else
        !          2284:            n = atol((char *)buf);
        !          2285:
        !          2286:        if (command == Ctrl('A'))
        !          2287:            n += Prenum1;
        !          2288:        else
        !          2289:            n -= Prenum1;
        !          2290:
        !          2291:        if (hex == 'X')                 /* skip the '0x' */
        !          2292:            col += 2;
        !          2293:        else if (hex == '0')
        !          2294:            col++;                      /* skip the '0' */
        !          2295:        curwin->w_cursor.col = col;
        !          2296:
        !          2297:        c = gchar_cursor();
        !          2298:        do                              /* delete the old number */
        !          2299:        {
        !          2300:            if (digits == 0 && c == '0')
        !          2301:                ++zeros;                /* count the number of leading zeros */
        !          2302:            else
        !          2303:                ++digits;               /* count the number of digits */
        !          2304:            if (isalpha(c))
        !          2305:            {
        !          2306:                if (isupper(c))
        !          2307:                    hexupper = TRUE;
        !          2308:                else
        !          2309:                    hexupper = FALSE;
        !          2310:            }
        !          2311:            (void)delchar(FALSE);
        !          2312:            c = gchar_cursor();
        !          2313:        }
        !          2314:        while (hex ? (hex == '0' ? c >= '0' && c <= '7' :
        !          2315:                                        isxdigit(c)) : isdigit(c));
        !          2316:
        !          2317:        if (hex == 0)
        !          2318:            sprintf((char *)buf, "%ld", n);
        !          2319:        else
        !          2320:        {
        !          2321:            if (hex == '0')
        !          2322:                sprintf((char *)buf, "%lo", n);
        !          2323:            else if (hex && hexupper)
        !          2324:                sprintf((char *)buf, "%lX", n);
        !          2325:            else if (hex)
        !          2326:                sprintf((char *)buf, "%lx", n);
        !          2327:            /* adjust number of zeros to the new number of digits, so the
        !          2328:             * total length of the number remains the same */
        !          2329:            if (zeros)
        !          2330:            {
        !          2331:                zeros += digits - STRLEN(buf);
        !          2332:                if (zeros > 0)
        !          2333:                {
        !          2334:                    vim_memmove(buf + zeros, buf, STRLEN(buf) + 1);
        !          2335:                    for (col = 0; zeros > 0; --zeros)
        !          2336:                        buf[col++] = '0';
        !          2337:                }
        !          2338:            }
        !          2339:        }
        !          2340:        ins_str(buf);                   /* insert the new number */
        !          2341:        --curwin->w_cursor.col;
        !          2342:        updateline();
        !          2343:        return OK;
        !          2344:    }
        !          2345:    else
        !          2346:    {
        !          2347:        beep_flush();
        !          2348:        return FAIL;
        !          2349:    }
        !          2350: }
        !          2351:
        !          2352: #ifdef VIMINFO
        !          2353:    int
        !          2354: read_viminfo_register(line, fp, force)
        !          2355:    char_u  *line;
        !          2356:    FILE    *fp;
        !          2357:    int     force;
        !          2358: {
        !          2359:    int     eof;
        !          2360:    int     do_it = TRUE;
        !          2361:    int     size;
        !          2362:    int     limit;
        !          2363:    int     i;
        !          2364:    int     set_prev = FALSE;
        !          2365:    char_u  *str;
        !          2366:    char_u  **array = NULL;
        !          2367:
        !          2368:    /* We only get here (hopefully) if line[0] == '"' */
        !          2369:    str = line + 1;
        !          2370:    if (*str == '"')
        !          2371:    {
        !          2372:        set_prev = TRUE;
        !          2373:        str++;
        !          2374:    }
        !          2375:    if (!isalnum(*str) && *str != '-')
        !          2376:    {
        !          2377:        EMSG2("viminfo: Illegal register name in line %s", line);
        !          2378:        do_it = FALSE;
        !          2379:    }
        !          2380:    yankbuffer = *str++;
        !          2381:    get_yank_buffer(FALSE);
        !          2382:    yankbuffer = 0;
        !          2383:    if (!force && y_current->y_array != NULL)
        !          2384:        do_it = FALSE;
        !          2385:    size = 0;
        !          2386:    limit = 100;        /* Optimized for registers containing <= 100 lines */
        !          2387:    if (do_it)
        !          2388:    {
        !          2389:        if (set_prev)
        !          2390:            y_previous = y_current;
        !          2391:        vim_free(y_current->y_array);
        !          2392:        array = y_current->y_array =
        !          2393:                       (char_u **)alloc((unsigned)(limit * sizeof(char_u *)));
        !          2394:        str = skipwhite(str);
        !          2395:        if (STRNCMP(str, "CHAR", 4) == 0)
        !          2396:            y_current->y_type = MCHAR;
        !          2397:        else if (STRNCMP(str, "BLOCK", 5) == 0)
        !          2398:            y_current->y_type = MBLOCK;
        !          2399:        else
        !          2400:            y_current->y_type = MLINE;
        !          2401:    }
        !          2402:    while (!(eof = vim_fgets(line, LSIZE, fp)) && line[0] == TAB)
        !          2403:    {
        !          2404:        if (do_it)
        !          2405:        {
        !          2406:            if (size >= limit)
        !          2407:            {
        !          2408:                y_current->y_array = (char_u **)
        !          2409:                              alloc((unsigned)(limit * 2 * sizeof(char_u *)));
        !          2410:                for (i = 0; i < limit; i++)
        !          2411:                    y_current->y_array[i] = array[i];
        !          2412:                vim_free(array);
        !          2413:                limit *= 2;
        !          2414:                array = y_current->y_array;
        !          2415:            }
        !          2416:            viminfo_readstring(line);
        !          2417:            str = strsave(line + 1);
        !          2418:            if (str != NULL)
        !          2419:                array[size++] = str;
        !          2420:            else
        !          2421:                do_it = FALSE;
        !          2422:        }
        !          2423:    }
        !          2424:    if (do_it)
        !          2425:    {
        !          2426:        if (size == 0)
        !          2427:        {
        !          2428:            vim_free(array);
        !          2429:            y_current->y_array = NULL;
        !          2430:        }
        !          2431:        else if (size < limit)
        !          2432:        {
        !          2433:            y_current->y_array =
        !          2434:                        (char_u **)alloc((unsigned)(size * sizeof(char_u *)));
        !          2435:            for (i = 0; i < size; i++)
        !          2436:                y_current->y_array[i] = array[i];
        !          2437:            vim_free(array);
        !          2438:        }
        !          2439:        y_current->y_size = size;
        !          2440:    }
        !          2441:    return eof;
        !          2442: }
        !          2443:
        !          2444:    void
        !          2445: write_viminfo_registers(fp)
        !          2446:    FILE    *fp;
        !          2447: {
        !          2448:    int     i, j;
        !          2449:    char_u  *type;
        !          2450:    char_u  c;
        !          2451:    int     num_lines;
        !          2452:    int     max_num_lines;
        !          2453:
        !          2454:    fprintf(fp, "\n# Registers:\n");
        !          2455:
        !          2456:    max_num_lines = get_viminfo_parameter('"');
        !          2457:    if (max_num_lines == 0)
        !          2458:        return;
        !          2459:    for (i = 0; i < NUM_REGISTERS; i++)
        !          2460:    {
        !          2461:        if (y_buf[i].y_array == NULL)
        !          2462:            continue;
        !          2463: #ifdef USE_GUI
        !          2464:        /* Skip '*' register, we don't want it back next time */
        !          2465:        if (i == GUI_SELECTION_REGISTER)
        !          2466:            continue;
        !          2467: #endif
        !          2468:        switch (y_buf[i].y_type)
        !          2469:        {
        !          2470:            case MLINE:
        !          2471:                type = (char_u *)"LINE";
        !          2472:                break;
        !          2473:            case MCHAR:
        !          2474:                type = (char_u *)"CHAR";
        !          2475:                break;
        !          2476:            case MBLOCK:
        !          2477:                type = (char_u *)"BLOCK";
        !          2478:                break;
        !          2479:            default:
        !          2480:                sprintf((char *)IObuff, "Unknown register type %d",
        !          2481:                    y_buf[i].y_type);
        !          2482:                emsg(IObuff);
        !          2483:                type = (char_u *)"LINE";
        !          2484:                break;
        !          2485:        }
        !          2486:        if (y_previous == &y_buf[i])
        !          2487:            fprintf(fp, "\"");
        !          2488:        if (i == DELETION_REGISTER)
        !          2489:            c = '-';
        !          2490:        else if (i < 10)
        !          2491:            c = '0' + i;
        !          2492:        else
        !          2493:            c = 'a' + i - 10;
        !          2494:        fprintf(fp, "\"%c\t%s\n", c, type);
        !          2495:        num_lines = y_buf[i].y_size;
        !          2496:
        !          2497:        /* If max_num_lines < 0, then we save ALL the lines in the register */
        !          2498:        if (max_num_lines > 0 && num_lines > max_num_lines)
        !          2499:            num_lines = max_num_lines;
        !          2500:        for (j = 0; j < num_lines; j++)
        !          2501:        {
        !          2502:            putc('\t', fp);
        !          2503:            viminfo_writestring(fp, y_buf[i].y_array[j]);
        !          2504:        }
        !          2505:    }
        !          2506: }
        !          2507: #endif /* VIMINFO */
        !          2508:
        !          2509: #if defined(USE_GUI) || defined(PROTO)
        !          2510: /*
        !          2511:  * Text selection stuff that uses the GUI selection register '*'.  When using a
        !          2512:  * GUI this may be text from another window, otherwise it is the last text we
        !          2513:  * had highlighted with VIsual mode.  With mouse support, clicking the middle
        !          2514:  * button performs the paste, otherwise you will need to do <"*p>.
        !          2515:  */
        !          2516:
        !          2517:    void
        !          2518: gui_free_selection()
        !          2519: {
        !          2520:    struct yankbuf *y_ptr = y_current;
        !          2521:
        !          2522:    y_current = &y_buf[GUI_SELECTION_REGISTER];     /* '*' register */
        !          2523:    free_yank_all();
        !          2524:    y_current->y_size = 0;
        !          2525:    y_current = y_ptr;
        !          2526: }
        !          2527:
        !          2528: /*
        !          2529:  * Get the selected text and put it in the gui text register '*'.
        !          2530:  */
        !          2531:    void
        !          2532: gui_get_selection()
        !          2533: {
        !          2534:    struct yankbuf *old_y_previous, *old_y_current;
        !          2535:    char_u  old_yankbuffer;
        !          2536:    FPOS    old_cursor, old_visual;
        !          2537:    int     old_op_type;
        !          2538:
        !          2539:    if (gui.selection.owned)
        !          2540:    {
        !          2541:        if (y_buf[GUI_SELECTION_REGISTER].y_array != NULL)
        !          2542:            return;
        !          2543:
        !          2544:        /* Get the text between gui.selection.start & gui.selection.end */
        !          2545:        old_y_previous = y_previous;
        !          2546:        old_y_current = y_current;
        !          2547:        old_yankbuffer = yankbuffer;
        !          2548:        old_cursor = curwin->w_cursor;
        !          2549:        old_visual = VIsual;
        !          2550:        old_op_type = op_type;
        !          2551:        yankbuffer = '*';
        !          2552:        op_type = YANK;
        !          2553:        do_pending_operator('y', NUL, FALSE, NULL, NULL, 0, TRUE, TRUE);
        !          2554:        y_previous = old_y_previous;
        !          2555:        y_current = old_y_current;
        !          2556:        yankbuffer = old_yankbuffer;
        !          2557:        curwin->w_cursor = old_cursor;
        !          2558:        VIsual = old_visual;
        !          2559:        op_type = old_op_type;
        !          2560:    }
        !          2561:    else
        !          2562:    {
        !          2563:        gui_free_selection();
        !          2564:
        !          2565:        /* Try to get selected text from another window */
        !          2566:        gui_request_selection();
        !          2567:    }
        !          2568: }
        !          2569:
        !          2570: /* Convert from the GUI selection string into the '*' register */
        !          2571:    void
        !          2572: gui_yank_selection(type, str, len)
        !          2573:    int     type;
        !          2574:    char_u  *str;
        !          2575:    long_u  len;
        !          2576: {
        !          2577:    struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
        !          2578:    int     lnum;
        !          2579:    int     start;
        !          2580:    int     i;
        !          2581:
        !          2582:    gui_free_selection();
        !          2583:
        !          2584:    /* Count the number of lines within the string */
        !          2585:    y_ptr->y_size = 1;
        !          2586:    for (i = 0; i < len; i++)
        !          2587:        if (str[i] == '\n')
        !          2588:            y_ptr->y_size++;
        !          2589:
        !          2590:    if (type != MCHAR && i > 0 && str[i - 1] == '\n')
        !          2591:        y_ptr->y_size--;
        !          2592:
        !          2593:    y_ptr->y_array = (char_u **)lalloc(y_ptr->y_size * sizeof(char_u *), TRUE);
        !          2594:    if (y_ptr->y_array == NULL)
        !          2595:        return;
        !          2596:    y_ptr->y_type = type;
        !          2597:    lnum = 0;
        !          2598:    start = 0;
        !          2599:    for (i = 0; i < len; i++)
        !          2600:    {
        !          2601:        if (str[i] == NUL)
        !          2602:            str[i] = '\n';
        !          2603:        else if (str[i] == '\n')
        !          2604:        {
        !          2605:            str[i] = NUL;
        !          2606:            if (type == MCHAR || i != len - 1)
        !          2607:            {
        !          2608:                if ((y_ptr->y_array[lnum] = strsave(str + start)) == NULL)
        !          2609:                {
        !          2610:                    y_ptr->y_size = lnum;
        !          2611:                    return;
        !          2612:                }
        !          2613:                lnum++;
        !          2614:                start = i + 1;
        !          2615:            }
        !          2616:        }
        !          2617:    }
        !          2618:    if ((y_ptr->y_array[lnum] = alloc(i - start + 1)) == NULL)
        !          2619:        return;
        !          2620:    if (i - start > 0)
        !          2621:        STRNCPY(y_ptr->y_array[lnum], str + start, i - start);
        !          2622:    y_ptr->y_array[lnum][i - start] = NUL;
        !          2623:    y_ptr->y_size = lnum + 1;
        !          2624: }
        !          2625:
        !          2626: /*
        !          2627:  * Convert the '*' register into a GUI selection string returned in *str with
        !          2628:  * length *len.
        !          2629:  */
        !          2630:    int
        !          2631: gui_convert_selection(str, len)
        !          2632:    char_u  **str;
        !          2633:    long_u  *len;
        !          2634: {
        !          2635:    struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
        !          2636:    char_u  *p;
        !          2637:    int     lnum;
        !          2638:    int     i, j;
        !          2639:
        !          2640:    *str = NULL;
        !          2641:    *len = 0;
        !          2642:    if (y_ptr->y_array == NULL)
        !          2643:        return -1;
        !          2644:
        !          2645:    for (i = 0; i < y_ptr->y_size; i++)
        !          2646:        *len += STRLEN(y_ptr->y_array[i]) + 1;
        !          2647:
        !          2648:    /*
        !          2649:     * Don't want newline character at end of last line if we're in MCHAR mode.
        !          2650:     */
        !          2651:    if (y_ptr->y_type == MCHAR && *len > 1)
        !          2652:        (*len)--;
        !          2653:
        !          2654:    p = *str = lalloc(*len, TRUE);
        !          2655:    if (p == NULL)
        !          2656:        return -1;
        !          2657:    lnum = 0;
        !          2658:    for (i = 0, j = 0; i < *len; i++, j++)
        !          2659:    {
        !          2660:        if (y_ptr->y_array[lnum][j] == '\n')
        !          2661:            p[i] = NUL;
        !          2662:        else if (y_ptr->y_array[lnum][j] == NUL)
        !          2663:        {
        !          2664:            p[i] = '\n';
        !          2665:            lnum++;
        !          2666:            j = -1;
        !          2667:        }
        !          2668:        else
        !          2669:            p[i] = y_ptr->y_array[lnum][j];
        !          2670:    }
        !          2671:    return y_ptr->y_type;
        !          2672: }
        !          2673: #endif /* USE_GUI || PROTO */