[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.2

1.2     ! downsj      1: /* $OpenBSD: ops.c,v 1.1.1.1 1996/09/07 21:40:25 downsj Exp $  */
1.1       downsj      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:    {
1.2     ! downsj   1326:        EMSG2("Nothing in register %s",
        !          1327:                    yankbuffer == 0 ? (char_u *)"\"" : transchar(yankbuffer));
1.1       downsj   1328:        return;
                   1329:    }
                   1330:
                   1331:    if (y_type == MBLOCK)
                   1332:    {
                   1333:        lnum = curwin->w_cursor.lnum + y_size + 1;
                   1334:        if (lnum > curbuf->b_ml.ml_line_count)
                   1335:            lnum = curbuf->b_ml.ml_line_count + 1;
                   1336:        if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
                   1337:            return;
                   1338:    }
                   1339:    else if (u_save_cursor() == FAIL)
                   1340:        return;
                   1341:
                   1342:    yanklen = STRLEN(y_array[0]);
                   1343:    CHANGED;
                   1344:
                   1345:    lnum = curwin->w_cursor.lnum;
                   1346:    col = curwin->w_cursor.col;
                   1347:
                   1348: /*
                   1349:  * block mode
                   1350:  */
                   1351:    if (y_type == MBLOCK)
                   1352:    {
                   1353:        if (dir == FORWARD && gchar_cursor() != NUL)
                   1354:        {
                   1355:            getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
                   1356:            ++col;
                   1357:            ++curwin->w_cursor.col;
                   1358:        }
                   1359:        else
                   1360:            getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
                   1361:        for (i = 0; i < y_size; ++i)
                   1362:        {
                   1363:            bd.startspaces = 0;
                   1364:            bd.endspaces = 0;
                   1365:            bd.textcol = 0;
                   1366:            vcol = 0;
                   1367:            delcount = 0;
                   1368:
                   1369:        /* add a new line */
                   1370:            if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
                   1371:            {
                   1372:                ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
                   1373:                                                           (colnr_t)1, FALSE);
                   1374:                ++nr_lines;
                   1375:            }
                   1376:            oldp = ml_get_curline();
                   1377:            oldlen = STRLEN(oldp);
                   1378:            for (ptr = oldp; vcol < col && *ptr; ++ptr)
                   1379:            {
                   1380:                /* Count a tab for what it's worth (if list mode not on) */
                   1381:                incr = lbr_chartabsize(ptr, (colnr_t)vcol);
                   1382:                vcol += incr;
                   1383:                ++bd.textcol;
                   1384:            }
                   1385:            if (vcol < col) /* line too short, padd with spaces */
                   1386:            {
                   1387:                bd.startspaces = col - vcol;
                   1388:            }
                   1389:            else if (vcol > col)
                   1390:            {
                   1391:                bd.endspaces = vcol - col;
                   1392:                bd.startspaces = incr - bd.endspaces;
                   1393:                --bd.textcol;
                   1394:                delcount = 1;
                   1395:            }
                   1396:            yanklen = STRLEN(y_array[i]);
                   1397:            totlen = count * yanklen + bd.startspaces + bd.endspaces;
                   1398:            newp = alloc_check((unsigned)totlen + oldlen + 1);
                   1399:            if (newp == NULL)
                   1400:                break;
                   1401:        /* copy part up to cursor to new line */
                   1402:            ptr = newp;
                   1403:            vim_memmove(ptr, oldp, (size_t)bd.textcol);
                   1404:            ptr += bd.textcol;
                   1405:        /* may insert some spaces before the new text */
                   1406:            copy_spaces(ptr, (size_t)bd.startspaces);
                   1407:            ptr += bd.startspaces;
                   1408:        /* insert the new text */
                   1409:            for (j = 0; j < count; ++j)
                   1410:            {
                   1411:                vim_memmove(ptr, y_array[i], (size_t)yanklen);
                   1412:                ptr += yanklen;
                   1413:            }
                   1414:        /* may insert some spaces after the new text */
                   1415:            copy_spaces(ptr, (size_t)bd.endspaces);
                   1416:            ptr += bd.endspaces;
                   1417:        /* move the text after the cursor to the end of the line. */
                   1418:            vim_memmove(ptr, oldp + bd.textcol + delcount,
                   1419:                                (size_t)(oldlen - bd.textcol - delcount + 1));
                   1420:            ml_replace(curwin->w_cursor.lnum, newp, FALSE);
                   1421:
                   1422:            ++curwin->w_cursor.lnum;
                   1423:            if (i == 0)
                   1424:                curwin->w_cursor.col += bd.startspaces;
                   1425:        }
                   1426:                                                /* for "']" command */
                   1427:        curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
                   1428:        curbuf->b_op_end.col = bd.textcol + totlen - 1;
                   1429:        curwin->w_cursor.lnum = lnum;
                   1430:        cursupdate();
                   1431:        updateScreen(VALID_TO_CURSCHAR);
                   1432:    }
                   1433:    else        /* not block mode */
                   1434:    {
                   1435:        if (y_type == MCHAR)
                   1436:        {
                   1437:    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next char */
                   1438:            if (dir == FORWARD && gchar_cursor() != NUL)
                   1439:            {
                   1440:                ++col;
                   1441:                if (yanklen)
                   1442:                {
                   1443:                    ++curwin->w_cursor.col;
                   1444:                    ++curbuf->b_op_end.col;
                   1445:                }
                   1446:            }
                   1447:            new_cursor = curwin->w_cursor;
                   1448:        }
                   1449:        else if (dir == BACKWARD)
                   1450:    /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
                   1451:            --lnum;
                   1452:
                   1453: /*
                   1454:  * simple case: insert into current line
                   1455:  */
                   1456:        if (y_type == MCHAR && y_size == 1)
                   1457:        {
                   1458:            totlen = count * yanklen;
                   1459:            if (totlen)
                   1460:            {
                   1461:                oldp = ml_get(lnum);
                   1462:                newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
                   1463:                if (newp == NULL)
                   1464:                    return;             /* alloc() will give error message */
                   1465:                vim_memmove(newp, oldp, (size_t)col);
                   1466:                ptr = newp + col;
                   1467:                for (i = 0; i < count; ++i)
                   1468:                {
                   1469:                    vim_memmove(ptr, y_array[0], (size_t)yanklen);
                   1470:                    ptr += yanklen;
                   1471:                }
                   1472:                vim_memmove(ptr, oldp + col, STRLEN(oldp + col) + 1);
                   1473:                ml_replace(lnum, newp, FALSE);
                   1474:                                          /* put cursor on last putted char */
                   1475:                curwin->w_cursor.col += (colnr_t)(totlen - 1);
                   1476:            }
                   1477:            curbuf->b_op_end = curwin->w_cursor;
                   1478:            updateline();
                   1479:        }
                   1480:        else
                   1481:        {
                   1482:            while (--count >= 0)
                   1483:            {
                   1484:                i = 0;
                   1485:                if (y_type == MCHAR)
                   1486:                {
                   1487:                    /*
                   1488:                     * Split the current line in two at the insert position.
                   1489:                     * First insert y_array[size - 1] in front of second line.
                   1490:                     * Then append y_array[0] to first line.
                   1491:                     */
                   1492:                    ptr = ml_get(lnum) + col;
                   1493:                    totlen = STRLEN(y_array[y_size - 1]);
                   1494:                    newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
                   1495:                    if (newp == NULL)
                   1496:                        goto error;
                   1497:                    STRCPY(newp, y_array[y_size - 1]);
                   1498:                    STRCAT(newp, ptr);
                   1499:                        /* insert second line */
                   1500:                    ml_append(lnum, newp, (colnr_t)0, FALSE);
                   1501:                    vim_free(newp);
                   1502:
                   1503:                    oldp = ml_get(lnum);
                   1504:                    newp = alloc_check((unsigned)(col + yanklen + 1));
                   1505:                    if (newp == NULL)
                   1506:                        goto error;
                   1507:                                            /* copy first part of line */
                   1508:                    vim_memmove(newp, oldp, (size_t)col);
                   1509:                                            /* append to first line */
                   1510:                    vim_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
                   1511:                    ml_replace(lnum, newp, FALSE);
                   1512:
                   1513:                    curwin->w_cursor.lnum = lnum;
                   1514:                    i = 1;
                   1515:                }
                   1516:
                   1517:                while (i < y_size)
                   1518:                {
                   1519:                    if ((y_type != MCHAR || i < y_size - 1) &&
                   1520:                        ml_append(lnum, y_array[i], (colnr_t)0, FALSE) == FAIL)
                   1521:                            goto error;
                   1522:                    lnum++;
                   1523:                    i++;
                   1524:                    if (fix_indent)
                   1525:                    {
                   1526:                        old_pos = curwin->w_cursor;
                   1527:                        curwin->w_cursor.lnum = lnum;
                   1528:                        ptr = ml_get(lnum);
                   1529: #if defined(SMARTINDENT) || defined(CINDENT)
                   1530:                        if (*ptr == '#'
                   1531: # ifdef SMARTINDENT
                   1532:                           && curbuf->b_p_si
                   1533: # endif
                   1534: # ifdef CINDENT
                   1535:                           && curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
                   1536: # endif
                   1537:                                            )
                   1538:
                   1539:                            indent = 0;     /* Leave # lines at start */
                   1540:                        else
                   1541: #endif
                   1542:                             if (*ptr == NUL)
                   1543:                            indent = 0;     /* Ignore empty lines */
                   1544:                        else if (first_indent)
                   1545:                        {
                   1546:                            indent_diff = orig_indent - get_indent();
                   1547:                            indent = orig_indent;
                   1548:                            first_indent = FALSE;
                   1549:                        }
                   1550:                        else if ((indent = get_indent() + indent_diff) < 0)
                   1551:                            indent = 0;
                   1552:                        set_indent(indent, TRUE);
                   1553:                        curwin->w_cursor = old_pos;
                   1554:                    }
                   1555:                    ++nr_lines;
                   1556:                }
                   1557:            }
                   1558:
                   1559:            /* put '] at last inserted character */
                   1560:            curbuf->b_op_end.lnum = lnum;
                   1561:            col = STRLEN(y_array[y_size - 1]);
                   1562:            if (col > 1)
                   1563:                curbuf->b_op_end.col = col - 1;
                   1564:            else
                   1565:                curbuf->b_op_end.col = 0;
                   1566:
                   1567:            if (y_type == MLINE)
                   1568:            {
                   1569:                curwin->w_cursor.col = 0;
                   1570:                if (dir == FORWARD)
                   1571:                {
                   1572:                    updateScreen(NOT_VALID);    /* recomp. curwin->w_botline */
                   1573:                    ++curwin->w_cursor.lnum;
                   1574:                }
                   1575:                    /* put cursor on first non-blank in last inserted line */
                   1576:                beginline(TRUE);
                   1577:            }
                   1578:            else        /* put cursor on first inserted character */
                   1579:            {
                   1580:                curwin->w_cursor = new_cursor;
                   1581:            }
                   1582:
                   1583: error:
                   1584:            if (y_type == MLINE)        /* for '[ */
                   1585:            {
                   1586:                curbuf->b_op_start.col = 0;
                   1587:                if (dir == FORWARD)
                   1588:                    curbuf->b_op_start.lnum++;
                   1589:            }
                   1590:            mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
                   1591:                                                       MAXLNUM, nr_lines, 0L);
                   1592:            updateScreen(CURSUPD);
                   1593:        }
                   1594:    }
                   1595:
                   1596:    msgmore(nr_lines);
                   1597:    curwin->w_set_curswant = TRUE;
                   1598: }
                   1599:
                   1600: /* Return the character name of the register with the given number */
                   1601:    int
                   1602: get_register_name(num)
                   1603:    int num;
                   1604: {
                   1605:    if (num == -1)
                   1606:        return '"';
                   1607:    else if (num < 10)
                   1608:        return num + '0';
                   1609:    else if (num == DELETION_REGISTER)
                   1610:        return '-';
                   1611: #ifdef USE_GUI
                   1612:    else if (num == GUI_SELECTION_REGISTER)
                   1613:        return '*';
                   1614: #endif
                   1615:    else
                   1616:        return num + 'a' - 10;
                   1617: }
                   1618:
                   1619: /*
                   1620:  * display the contents of the yank buffers
                   1621:  */
                   1622:    void
                   1623: do_dis(arg)
                   1624:    char_u *arg;
                   1625: {
                   1626:    register int            i, n;
                   1627:    register long           j;
                   1628:    register char_u         *p;
                   1629:    register struct yankbuf *yb;
                   1630:    char_u name;
                   1631:
                   1632:    if (arg != NULL && *arg == NUL)
                   1633:        arg = NULL;
                   1634:
                   1635:    set_highlight('t');     /* Highlight title */
                   1636:    start_highlight();
                   1637:    MSG_OUTSTR("\n--- Registers ---");
                   1638:    stop_highlight();
                   1639:    for (i = -1; i < NUM_REGISTERS; ++i)
                   1640:    {
                   1641:        if (i == -1)
                   1642:        {
                   1643:            if (y_previous != NULL)
                   1644:                yb = y_previous;
                   1645:            else
                   1646:                yb = &(y_buf[0]);
                   1647:        }
                   1648:        else
                   1649:            yb = &(y_buf[i]);
                   1650:        name = get_register_name(i);
                   1651:        if (yb->y_array != NULL && (arg == NULL ||
                   1652:                                               vim_strchr(arg, name) != NULL))
                   1653:        {
                   1654:            msg_outchar('\n');
                   1655:            msg_outchar('"');
                   1656:            msg_outchar(name);
                   1657:            MSG_OUTSTR("   ");
                   1658:
                   1659:            n = (int)Columns - 6;
                   1660:            for (j = 0; j < yb->y_size && n > 1; ++j)
                   1661:            {
                   1662:                if (j)
                   1663:                {
                   1664:                    MSG_OUTSTR("^J");
                   1665:                    n -= 2;
                   1666:                }
                   1667:                for (p = yb->y_array[j]; *p && (n -= charsize(*p)) >= 0; ++p)
                   1668:                    msg_outtrans_len(p, 1);
                   1669:            }
1.2     ! downsj   1670:            if (n > 1 && yb->y_type == MLINE)
        !          1671:                MSG_OUTSTR("^J");
1.1       downsj   1672:            flushbuf();             /* show one line at a time */
                   1673:        }
                   1674:    }
                   1675:
                   1676:    /*
                   1677:     * display last inserted text
                   1678:     */
                   1679:    if ((p = get_last_insert()) != NULL &&
                   1680:        (arg == NULL || vim_strchr(arg, '.') != NULL))
                   1681:    {
                   1682:        MSG_OUTSTR("\n\".   ");
                   1683:        dis_msg(p, TRUE);
                   1684:    }
                   1685:
                   1686:    /*
                   1687:     * display last command line
                   1688:     */
                   1689:    if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL))
                   1690:    {
                   1691:        MSG_OUTSTR("\n\":   ");
                   1692:        dis_msg(last_cmdline, FALSE);
                   1693:    }
                   1694:
                   1695:    /*
                   1696:     * display current file name
                   1697:     */
                   1698:    if (curbuf->b_xfilename != NULL &&
                   1699:                                (arg == NULL || vim_strchr(arg, '%') != NULL))
                   1700:    {
                   1701:        MSG_OUTSTR("\n\"%   ");
                   1702:        dis_msg(curbuf->b_xfilename, FALSE);
                   1703:    }
                   1704: }
                   1705:
                   1706: /*
                   1707:  * display a string for do_dis()
                   1708:  * truncate at end of screen line
                   1709:  */
                   1710:    void
                   1711: dis_msg(p, skip_esc)
                   1712:    char_u      *p;
                   1713:    int         skip_esc;           /* if TRUE, ignore trailing ESC */
                   1714: {
                   1715:    int     n;
                   1716:
                   1717:    n = (int)Columns - 6;
                   1718:    while (*p && !(*p == ESC && skip_esc && *(p + 1) == NUL) &&
                   1719:                        (n -= charsize(*p)) >= 0)
                   1720:        msg_outtrans_len(p++, 1);
                   1721: }
                   1722:
                   1723: /*
                   1724:  * join 'count' lines (minimal 2), including u_save()
                   1725:  */
                   1726:    void
                   1727: do_do_join(count, insert_space, redraw)
                   1728:    long    count;
                   1729:    int     insert_space;
                   1730:    int     redraw;                 /* can redraw, curwin->w_col valid */
                   1731: {
                   1732:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
                   1733:                    (linenr_t)(curwin->w_cursor.lnum + count)) == FAIL)
                   1734:        return;
                   1735:
                   1736:    if (count > 10)
                   1737:        redraw = FALSE;             /* don't redraw each small change */
                   1738:    while (--count > 0)
                   1739:    {
                   1740:        line_breakcheck();
                   1741:        if (got_int || do_join(insert_space, redraw) == FAIL)
                   1742:        {
                   1743:            beep_flush();
                   1744:            break;
                   1745:        }
                   1746:    }
                   1747:    if (redraw)
                   1748:        redraw_later(VALID_TO_CURSCHAR);
                   1749:    else
                   1750:        redraw_later(NOT_VALID);
                   1751:
                   1752:    /*
                   1753:     * Need to update the screen if the line where the cursor is became too
                   1754:     * long to fit on the screen.
                   1755:     */
                   1756:    cursupdate();
                   1757: }
                   1758:
                   1759: /*
                   1760:  * Join two lines at the cursor position.
                   1761:  *
                   1762:  * return FAIL for failure, OK ohterwise
                   1763:  */
                   1764:    int
                   1765: do_join(insert_space, redraw)
                   1766:    int         insert_space;
                   1767:    int         redraw;     /* should only be TRUE when curwin->w_row valid */
                   1768: {
                   1769:    char_u      *curr;
                   1770:    char_u      *next;
                   1771:    char_u      *newp;
                   1772:    int         endcurr1, endcurr2;
                   1773:    int         currsize;       /* size of the current line */
                   1774:    int         nextsize;       /* size of the next line */
                   1775:    int         spaces;         /* number of spaces to insert */
                   1776:    int         rows_to_del = 0;/* number of rows on screen to delete */
                   1777:    linenr_t    t;
                   1778:
                   1779:    if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
                   1780:        return FAIL;            /* can't join on last line */
                   1781:
                   1782:    if (redraw)
                   1783:        rows_to_del = plines_m(curwin->w_cursor.lnum,
                   1784:                                                   curwin->w_cursor.lnum + 1);
                   1785:
                   1786:    curr = ml_get_curline();
                   1787:    currsize = STRLEN(curr);
                   1788:    endcurr1 = endcurr2 = NUL;
                   1789:    if (currsize > 0)
                   1790:    {
                   1791:        endcurr1 = *(curr + currsize - 1);
                   1792:        if (currsize > 1)
                   1793:            endcurr2 = *(curr + currsize - 2);
                   1794:    }
                   1795:
                   1796:    next = ml_get((linenr_t)(curwin->w_cursor.lnum + 1));
                   1797:    spaces = 0;
                   1798:    if (insert_space)
                   1799:    {
                   1800:        next = skipwhite(next);
                   1801:        spaces = 1;
                   1802:        if (*next == ')' || currsize == 0)
                   1803:            spaces = 0;
                   1804:        else
                   1805:        {
                   1806:            if (endcurr1 == ' ' || endcurr1 == TAB)
                   1807:            {
                   1808:                spaces = 0;
                   1809:                if (currsize > 1)
                   1810:                    endcurr1 = endcurr2;
                   1811:            }
                   1812:            if (p_js && vim_strchr((char_u *)".!?", endcurr1) != NULL)
                   1813:                spaces = 2;
                   1814:        }
                   1815:    }
                   1816:    nextsize = STRLEN(next);
                   1817:
                   1818:    newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
                   1819:    if (newp == NULL)
                   1820:        return FAIL;
                   1821:
                   1822:    /*
                   1823:     * Insert the next line first, because we already have that pointer.
                   1824:     * Curr has to be obtained again, because getting next will have
                   1825:     * invalidated it.
                   1826:     */
                   1827:    vim_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
                   1828:
                   1829:    curr = ml_get_curline();
                   1830:    vim_memmove(newp, curr, (size_t)currsize);
                   1831:
                   1832:    copy_spaces(newp + currsize, (size_t)spaces);
                   1833:
                   1834:    ml_replace(curwin->w_cursor.lnum, newp, FALSE);
                   1835:
                   1836:    /*
                   1837:     * Delete the following line. To do this we move the cursor there
                   1838:     * briefly, and then move it back. After dellines() the cursor may
                   1839:     * have moved up (last line deleted), so the current lnum is kept in t.
                   1840:     */
                   1841:    t = curwin->w_cursor.lnum;
                   1842:    ++curwin->w_cursor.lnum;
                   1843:    dellines(1L, FALSE, FALSE);
                   1844:    curwin->w_cursor.lnum = t;
                   1845:
                   1846:    /*
                   1847:     * the number of rows on the screen is reduced by the difference
                   1848:     * in number of rows of the two old lines and the one new line
                   1849:     */
                   1850:    if (redraw)
                   1851:    {
                   1852:        rows_to_del -= plines(curwin->w_cursor.lnum);
                   1853:        if (rows_to_del > 0)
                   1854:            win_del_lines(curwin, curwin->w_cline_row + curwin->w_cline_height,
                   1855:                                                     rows_to_del, TRUE, TRUE);
                   1856:    }
                   1857:
                   1858:    /*
                   1859:     * go to first character of the joined line
                   1860:     */
                   1861:    if (currsize == 0)
                   1862:        curwin->w_cursor.col = 0;
                   1863:    else
                   1864:    {
                   1865:        curwin->w_cursor.col = currsize - 1;
                   1866:        (void)oneright();
                   1867:    }
                   1868:    CHANGED;
                   1869:
                   1870:    return OK;
                   1871: }
                   1872:
                   1873: /*
                   1874:  * Return TRUE if the two comment leaders given are the same.  The cursor is
                   1875:  * in the first line.  White-space is ignored.  Note that the whole of
                   1876:  * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
                   1877:  */
                   1878:    static int
                   1879: same_leader(leader1_len, leader1_flags, leader2_len, leader2_flags)
                   1880:    int     leader1_len;
                   1881:    char_u  *leader1_flags;
                   1882:    int     leader2_len;
                   1883:    char_u  *leader2_flags;
                   1884: {
                   1885:    int     idx1 = 0, idx2 = 0;
                   1886:    char_u  *p;
                   1887:    char_u  *line1;
                   1888:    char_u  *line2;
                   1889:
                   1890:    if (leader1_len == 0)
                   1891:        return (leader2_len == 0);
                   1892:
                   1893:    /*
                   1894:     * If first leader has 'f' flag, the lines can be joined only if the
                   1895:     * second line does not have a leader.
                   1896:     * If first leader has 'e' flag, the lines can never be joined.
                   1897:     * If fist leader has 's' flag, the lines can only be joined if there is
                   1898:     * some text after it and the second line has the 'm' flag.
                   1899:     */
                   1900:    if (leader1_flags != NULL)
                   1901:    {
                   1902:        for (p = leader1_flags; *p && *p != ':'; ++p)
                   1903:        {
                   1904:            if (*p == COM_FIRST)
                   1905:                return (leader2_len == 0);
                   1906:            if (*p == COM_END)
                   1907:                return FALSE;
                   1908:            if (*p == COM_START)
                   1909:            {
                   1910:                if (*(ml_get_curline() + leader1_len) == NUL)
                   1911:                    return FALSE;
                   1912:                if (leader2_flags == NULL || leader2_len == 0)
                   1913:                    return FALSE;
                   1914:                for (p = leader2_flags; *p && *p != ':'; ++p)
                   1915:                    if (*p == COM_MIDDLE)
                   1916:                        return TRUE;
                   1917:                return FALSE;
                   1918:            }
                   1919:        }
                   1920:    }
                   1921:
                   1922:    /*
                   1923:     * Get current line and next line, compare the leaders.
                   1924:     * The first line has to be saved, only one line can be locked at a time.
                   1925:     */
                   1926:    line1 = strsave(ml_get_curline());
                   1927:    if (line1 != NULL)
                   1928:    {
                   1929:        for (idx1 = 0; vim_iswhite(line1[idx1]); ++idx1)
                   1930:            ;
                   1931:        line2 = ml_get(curwin->w_cursor.lnum + 1);
                   1932:        for (idx2 = 0; idx2 < leader2_len; ++idx2)
                   1933:        {
                   1934:            if (!vim_iswhite(line2[idx2]))
                   1935:            {
                   1936:                if (line1[idx1++] != line2[idx2])
                   1937:                    break;
                   1938:            }
                   1939:            else
                   1940:                while (vim_iswhite(line1[idx1]))
                   1941:                    ++idx1;
                   1942:        }
                   1943:        vim_free(line1);
                   1944:    }
                   1945:    return (idx2 == leader2_len && idx1 == leader1_len);
                   1946: }
                   1947:
                   1948: /*
                   1949:  * implementation of the format operator 'Q'
                   1950:  */
                   1951:    void
                   1952: do_format()
                   1953: {
                   1954:    long        old_line_count = curbuf->b_ml.ml_line_count;
                   1955:    int         prev_is_blank = FALSE;
                   1956:    int         is_end_block = TRUE;
                   1957:    int         next_is_end_block;
                   1958:    int         leader_len = 0;     /* init for gcc */
                   1959:    int         next_leader_len;
                   1960:    char_u      *leader_flags = NULL;
                   1961:    char_u      *next_leader_flags;
                   1962:    int         advance = TRUE;
                   1963:    int         second_indent = -1;
                   1964:    int         do_second_indent;
                   1965:    int         first_par_line = TRUE;
                   1966:
                   1967:    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
                   1968:                   (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
                   1969:        return;
                   1970:
                   1971:    /* check for 'q' and '2' in 'formatoptions' */
                   1972:    fo_do_comments = has_format_option(FO_Q_COMS);
                   1973:    do_second_indent = has_format_option(FO_Q_SECOND);
                   1974:
                   1975:    /*
                   1976:     * get info about the previous and current line.
                   1977:     */
                   1978:    if (curwin->w_cursor.lnum > 1)
                   1979:        is_end_block = fmt_end_block(curwin->w_cursor.lnum - 1,
                   1980:                                        &next_leader_len, &next_leader_flags);
                   1981:    next_is_end_block = fmt_end_block(curwin->w_cursor.lnum,
                   1982:                                        &next_leader_len, &next_leader_flags);
                   1983:
                   1984:    curwin->w_cursor.lnum--;
                   1985:    while (--op_line_count >= 0)
                   1986:    {
                   1987:        /*
                   1988:         * Advance to next block.
                   1989:         */
                   1990:        if (advance)
                   1991:        {
                   1992:            curwin->w_cursor.lnum++;
                   1993:            prev_is_blank = is_end_block;
                   1994:            is_end_block = next_is_end_block;
                   1995:            leader_len = next_leader_len;
                   1996:            leader_flags = next_leader_flags;
                   1997:        }
                   1998:
                   1999:        /*
                   2000:         * The last line to be formatted.
                   2001:         */
                   2002:        if (op_line_count == 0)
                   2003:        {
                   2004:            next_is_end_block = TRUE;
                   2005:            next_leader_len = 0;
                   2006:            next_leader_flags = NULL;
                   2007:        }
                   2008:        else
                   2009:            next_is_end_block = fmt_end_block(curwin->w_cursor.lnum + 1,
                   2010:                                        &next_leader_len, &next_leader_flags);
                   2011:        advance = TRUE;
                   2012:
                   2013:        /*
                   2014:         * For the first line of a paragraph, check indent of second line.
                   2015:         * Don't do this for comments and empty lines.
                   2016:         */
                   2017:        if (first_par_line && do_second_indent &&
                   2018:                prev_is_blank && !is_end_block &&
                   2019:                curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count &&
                   2020:                leader_len == 0 && next_leader_len == 0 &&
                   2021:                !lineempty(curwin->w_cursor.lnum + 1))
                   2022:            second_indent = get_indent_lnum(curwin->w_cursor.lnum + 1);
                   2023:
                   2024:        /*
                   2025:         * Skip end-of-block (blank) lines
                   2026:         */
                   2027:        if (is_end_block)
                   2028:        {
                   2029:        }
                   2030:        /*
                   2031:         * If we have got to the end of a paragraph, format it.
                   2032:         */
                   2033:        else if (next_is_end_block || !same_leader(leader_len, leader_flags,
                   2034:                                          next_leader_len, next_leader_flags))
                   2035:        {
                   2036:            /* replace indent in first line with minimal number of tabs and
                   2037:             * spaces, according to current options */
                   2038:            set_indent(get_indent(), TRUE);
                   2039:
                   2040:            /* put cursor on last non-space */
                   2041:            coladvance(MAXCOL);
                   2042:            while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
                   2043:                dec_cursor();
                   2044:            curs_columns(FALSE);            /* update curwin->w_virtcol */
                   2045:
                   2046:            /* do the formatting */
                   2047:            State = INSERT;     /* for Opencmd() */
                   2048:            insertchar(NUL, TRUE, second_indent);
                   2049:            State = NORMAL;
                   2050:            first_par_line = TRUE;
                   2051:            second_indent = -1;
                   2052:        }
                   2053:        else
                   2054:        {
                   2055:            /*
                   2056:             * Still in same paragraph, so join the lines together.
                   2057:             * But first delete the comment leader from the second line.
                   2058:             */
                   2059:            advance = FALSE;
                   2060:            curwin->w_cursor.lnum++;
                   2061:            curwin->w_cursor.col = 0;
                   2062:            while (next_leader_len--)
                   2063:                delchar(FALSE);
                   2064:            curwin->w_cursor.lnum--;
                   2065:            if (do_join(TRUE, FALSE) == FAIL)
                   2066:            {
                   2067:                beep_flush();
                   2068:                break;
                   2069:            }
                   2070:            first_par_line = FALSE;
                   2071:        }
                   2072:    }
                   2073:    fo_do_comments = FALSE;
                   2074:    /*
                   2075:     * Leave the cursor at the first non-blank of the last formatted line.
                   2076:     * If the cursor was move one line back (e.g. with "Q}") go to the next
                   2077:     * line, so "." will do the next lines.
                   2078:     */
                   2079:    if (op_end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
                   2080:        ++curwin->w_cursor.lnum;
                   2081:    beginline(TRUE);
                   2082:    updateScreen(NOT_VALID);
                   2083:    msgmore(curbuf->b_ml.ml_line_count - old_line_count);
                   2084: }
                   2085:
                   2086: /*
                   2087:  * Blank lines, and lines containing only the comment leader, are left
                   2088:  * untouched by the formatting.  The function returns TRUE in this
                   2089:  * case.  It also returns TRUE when a line starts with the end of a comment
                   2090:  * ('e' in comment flags), so that this line is skipped, and not joined to the
                   2091:  * previous line.  A new paragraph starts after a blank line, or when the
                   2092:  * comment leader changes -- webb.
                   2093:  */
                   2094:    static int
                   2095: fmt_end_block(lnum, leader_len, leader_flags)
                   2096:    linenr_t    lnum;
                   2097:    int         *leader_len;
                   2098:    char_u      **leader_flags;
                   2099: {
                   2100:    char_u      *flags = NULL;      /* init for GCC */
                   2101:    char_u      *ptr;
                   2102:
                   2103:    ptr = ml_get(lnum);
                   2104:    *leader_len = get_leader_len(ptr, leader_flags);
                   2105:
                   2106:    if (*leader_len > 0)
                   2107:    {
                   2108:        /*
                   2109:         * Search for 'e' flag in comment leader flags.
                   2110:         */
                   2111:        flags = *leader_flags;
                   2112:        while (*flags && *flags != ':' && *flags != COM_END)
                   2113:            ++flags;
                   2114:    }
                   2115:
                   2116:    return (ptr[*leader_len] == NUL ||
                   2117:            (*leader_len > 0 && *flags == COM_END) ||
                   2118:             startPS(lnum, NUL, FALSE));
                   2119: }
                   2120:
                   2121: /*
                   2122:  * prepare a few things for block mode yank/delete/tilde
                   2123:  *
                   2124:  * for delete:
                   2125:  * - textlen includes the first/last char to be (partly) deleted
                   2126:  * - start/endspaces is the number of columns that are taken by the
                   2127:  *  first/last deleted char minus the number of columns that have to be deleted.
                   2128:  * for yank and tilde:
                   2129:  * - textlen includes the first/last char to be wholly yanked
                   2130:  * - start/endspaces is the number of columns of the first/last yanked char
                   2131:  *   that are to be yanked.
                   2132:  */
                   2133:    static void
                   2134: block_prep(bd, lnum, is_del)
                   2135:    struct block_def    *bd;
                   2136:    linenr_t            lnum;
                   2137:    int                 is_del;
                   2138: {
                   2139:    colnr_t     vcol;
                   2140:    int         incr = 0;
                   2141:    char_u      *pend;
                   2142:    char_u      *pstart;
                   2143:
                   2144:    bd->startspaces = 0;
                   2145:    bd->endspaces = 0;
                   2146:    bd->textlen = 0;
                   2147:    bd->textcol = 0;
                   2148:    vcol = 0;
                   2149:    pstart = ml_get(lnum);
                   2150:    while (vcol < op_start_vcol && *pstart)
                   2151:    {
                   2152:        /* Count a tab for what it's worth (if list mode not on) */
                   2153:        incr = lbr_chartabsize(pstart, (colnr_t)vcol);
                   2154:        vcol += incr;
                   2155:        ++pstart;
                   2156:        ++bd->textcol;
                   2157:    }
                   2158:    if (vcol < op_start_vcol)   /* line too short */
                   2159:    {
                   2160:        if (!is_del)
                   2161:            bd->endspaces = op_end_vcol - op_start_vcol + 1;
                   2162:    }
                   2163:    else /* vcol >= op_start_vcol */
                   2164:    {
                   2165:        bd->startspaces = vcol - op_start_vcol;
                   2166:        if (is_del && vcol > op_start_vcol)
                   2167:            bd->startspaces = incr - bd->startspaces;
                   2168:        pend = pstart;
                   2169:        if (vcol > op_end_vcol)     /* it's all in one character */
                   2170:        {
                   2171:            bd->startspaces = op_end_vcol - op_start_vcol + 1;
                   2172:            if (is_del)
                   2173:                bd->startspaces = incr - bd->startspaces;
                   2174:        }
                   2175:        else
                   2176:        {
                   2177:            while (vcol <= op_end_vcol && *pend)
                   2178:            {
                   2179:                /* Count a tab for what it's worth (if list mode not on) */
                   2180:                incr = lbr_chartabsize(pend, (colnr_t)vcol);
                   2181:                vcol += incr;
                   2182:                ++pend;
                   2183:            }
                   2184:            if (vcol < op_end_vcol && !is_del)  /* line too short */
                   2185:            {
                   2186:                bd->endspaces = op_end_vcol - vcol;
                   2187:            }
                   2188:            else if (vcol > op_end_vcol)
                   2189:            {
                   2190:                bd->endspaces = vcol - op_end_vcol - 1;
                   2191:                if (!is_del && pend != pstart && bd->endspaces)
                   2192:                    --pend;
                   2193:            }
                   2194:        }
                   2195:        if (is_del && bd->startspaces)
                   2196:        {
                   2197:            --pstart;
                   2198:            --bd->textcol;
                   2199:        }
                   2200:        bd->textlen = (int)(pend - pstart);
                   2201:    }
                   2202:    bd->textstart = pstart;
                   2203: }
                   2204:
                   2205: #define NUMBUFLEN 30
                   2206:
                   2207: /*
                   2208:  * add or subtract 'Prenum1' from a number in a line
                   2209:  * 'command' is CTRL-A for add, CTRL-X for subtract
                   2210:  *
                   2211:  * return FAIL for failure, OK otherwise
                   2212:  */
                   2213:    int
                   2214: do_addsub(command, Prenum1)
                   2215:    int         command;
                   2216:    linenr_t    Prenum1;
                   2217: {
                   2218:    register int    col;
                   2219:    char_u          buf[NUMBUFLEN];
                   2220:    int             hex;            /* 'X': hexadecimal; '0': octal */
                   2221:    static int      hexupper = FALSE;   /* 0xABC */
                   2222:    long            n;
                   2223:    char_u          *ptr;
                   2224:    int             i;
                   2225:    int             c;
                   2226:    int             zeros = 0;      /* number of leading zeros */
                   2227:    int             digits = 0;     /* number of digits in the number */
                   2228:
                   2229:    ptr = ml_get_curline();
                   2230:    col = curwin->w_cursor.col;
                   2231:
                   2232:        /* first check if we are on a hexadecimal number */
                   2233:    while (col > 0 && isxdigit(ptr[col]))
                   2234:        --col;
                   2235:    if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
                   2236:                        ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
                   2237:        --col;      /* found hexadecimal number */
                   2238:    else
                   2239:    {
                   2240:        /* first search forward and then backward for start of number */
                   2241:        col = curwin->w_cursor.col;
                   2242:
                   2243:        while (ptr[col] != NUL && !isdigit(ptr[col]))
                   2244:            ++col;
                   2245:
                   2246:        while (col > 0 && isdigit(ptr[col - 1]))
                   2247:            --col;
                   2248:    }
                   2249:
                   2250:    if (isdigit(ptr[col]) && u_save_cursor() == OK)
                   2251:    {
                   2252:        ptr = ml_get_curline();                 /* get it again, because
                   2253:                                                   u_save may have changed it */
                   2254:        curwin->w_set_curswant = TRUE;
                   2255:
                   2256:        hex = 0;                                /* default is decimal */
                   2257:        if (ptr[col] == '0')                    /* could be hex or octal */
                   2258:        {
                   2259:            hex = TO_UPPER(ptr[col + 1]);       /* assume hexadecimal */
                   2260:            if (hex != 'X' || !isxdigit(ptr[col + 2]))
                   2261:            {
                   2262:                if (isdigit(hex))
                   2263:                    hex = '0';                  /* octal */
                   2264:                else
                   2265:                    hex = 0;                    /* 0 by itself is decimal */
                   2266:            }
                   2267:        }
                   2268:
                   2269:        if (!hex && col > 0 && ptr[col - 1] == '-')
                   2270:            --col;
                   2271:
                   2272:        ptr += col;
                   2273:        /*
                   2274:         * we copy the number into a buffer because some versions of sscanf
                   2275:         * cannot handle characters with the upper bit set, making some special
                   2276:         * characters handled like digits.
                   2277:         */
                   2278:        for (i = 0; *ptr && !(*ptr & 0x80) && i < NUMBUFLEN - 1; ++i)
                   2279:            buf[i] = *ptr++;
                   2280:        buf[i] = NUL;
                   2281:
                   2282:        if (hex == '0')
                   2283:            sscanf((char *)buf, "%lo", &n);
                   2284:        else if (hex)
                   2285:            sscanf((char *)buf + 2, "%lx", &n); /* "%X" doesn't work! */
                   2286:        else
                   2287:            n = atol((char *)buf);
                   2288:
                   2289:        if (command == Ctrl('A'))
                   2290:            n += Prenum1;
                   2291:        else
                   2292:            n -= Prenum1;
                   2293:
                   2294:        if (hex == 'X')                 /* skip the '0x' */
                   2295:            col += 2;
                   2296:        else if (hex == '0')
                   2297:            col++;                      /* skip the '0' */
                   2298:        curwin->w_cursor.col = col;
                   2299:
                   2300:        c = gchar_cursor();
                   2301:        do                              /* delete the old number */
                   2302:        {
                   2303:            if (digits == 0 && c == '0')
                   2304:                ++zeros;                /* count the number of leading zeros */
                   2305:            else
                   2306:                ++digits;               /* count the number of digits */
                   2307:            if (isalpha(c))
                   2308:            {
                   2309:                if (isupper(c))
                   2310:                    hexupper = TRUE;
                   2311:                else
                   2312:                    hexupper = FALSE;
                   2313:            }
                   2314:            (void)delchar(FALSE);
                   2315:            c = gchar_cursor();
                   2316:        }
                   2317:        while (hex ? (hex == '0' ? c >= '0' && c <= '7' :
                   2318:                                        isxdigit(c)) : isdigit(c));
                   2319:
                   2320:        if (hex == 0)
                   2321:            sprintf((char *)buf, "%ld", n);
                   2322:        else
                   2323:        {
                   2324:            if (hex == '0')
                   2325:                sprintf((char *)buf, "%lo", n);
                   2326:            else if (hex && hexupper)
                   2327:                sprintf((char *)buf, "%lX", n);
                   2328:            else if (hex)
                   2329:                sprintf((char *)buf, "%lx", n);
                   2330:            /* adjust number of zeros to the new number of digits, so the
                   2331:             * total length of the number remains the same */
                   2332:            if (zeros)
                   2333:            {
                   2334:                zeros += digits - STRLEN(buf);
                   2335:                if (zeros > 0)
                   2336:                {
                   2337:                    vim_memmove(buf + zeros, buf, STRLEN(buf) + 1);
                   2338:                    for (col = 0; zeros > 0; --zeros)
                   2339:                        buf[col++] = '0';
                   2340:                }
                   2341:            }
                   2342:        }
                   2343:        ins_str(buf);                   /* insert the new number */
                   2344:        --curwin->w_cursor.col;
                   2345:        updateline();
                   2346:        return OK;
                   2347:    }
                   2348:    else
                   2349:    {
                   2350:        beep_flush();
                   2351:        return FAIL;
                   2352:    }
                   2353: }
                   2354:
                   2355: #ifdef VIMINFO
                   2356:    int
                   2357: read_viminfo_register(line, fp, force)
                   2358:    char_u  *line;
                   2359:    FILE    *fp;
                   2360:    int     force;
                   2361: {
                   2362:    int     eof;
                   2363:    int     do_it = TRUE;
                   2364:    int     size;
                   2365:    int     limit;
                   2366:    int     i;
                   2367:    int     set_prev = FALSE;
                   2368:    char_u  *str;
                   2369:    char_u  **array = NULL;
                   2370:
                   2371:    /* We only get here (hopefully) if line[0] == '"' */
                   2372:    str = line + 1;
                   2373:    if (*str == '"')
                   2374:    {
                   2375:        set_prev = TRUE;
                   2376:        str++;
                   2377:    }
                   2378:    if (!isalnum(*str) && *str != '-')
                   2379:    {
1.2     ! downsj   2380:        if (viminfo_error("Illegal register name", line))
        !          2381:            return TRUE;        /* too many errors, pretend end-of-file */
1.1       downsj   2382:        do_it = FALSE;
                   2383:    }
                   2384:    yankbuffer = *str++;
                   2385:    get_yank_buffer(FALSE);
                   2386:    yankbuffer = 0;
                   2387:    if (!force && y_current->y_array != NULL)
                   2388:        do_it = FALSE;
                   2389:    size = 0;
                   2390:    limit = 100;        /* Optimized for registers containing <= 100 lines */
                   2391:    if (do_it)
                   2392:    {
                   2393:        if (set_prev)
                   2394:            y_previous = y_current;
                   2395:        vim_free(y_current->y_array);
                   2396:        array = y_current->y_array =
                   2397:                       (char_u **)alloc((unsigned)(limit * sizeof(char_u *)));
                   2398:        str = skipwhite(str);
                   2399:        if (STRNCMP(str, "CHAR", 4) == 0)
                   2400:            y_current->y_type = MCHAR;
                   2401:        else if (STRNCMP(str, "BLOCK", 5) == 0)
                   2402:            y_current->y_type = MBLOCK;
                   2403:        else
                   2404:            y_current->y_type = MLINE;
                   2405:    }
                   2406:    while (!(eof = vim_fgets(line, LSIZE, fp)) && line[0] == TAB)
                   2407:    {
                   2408:        if (do_it)
                   2409:        {
                   2410:            if (size >= limit)
                   2411:            {
                   2412:                y_current->y_array = (char_u **)
                   2413:                              alloc((unsigned)(limit * 2 * sizeof(char_u *)));
                   2414:                for (i = 0; i < limit; i++)
                   2415:                    y_current->y_array[i] = array[i];
                   2416:                vim_free(array);
                   2417:                limit *= 2;
                   2418:                array = y_current->y_array;
                   2419:            }
                   2420:            viminfo_readstring(line);
                   2421:            str = strsave(line + 1);
                   2422:            if (str != NULL)
                   2423:                array[size++] = str;
                   2424:            else
                   2425:                do_it = FALSE;
                   2426:        }
                   2427:    }
                   2428:    if (do_it)
                   2429:    {
                   2430:        if (size == 0)
                   2431:        {
                   2432:            vim_free(array);
                   2433:            y_current->y_array = NULL;
                   2434:        }
                   2435:        else if (size < limit)
                   2436:        {
                   2437:            y_current->y_array =
                   2438:                        (char_u **)alloc((unsigned)(size * sizeof(char_u *)));
                   2439:            for (i = 0; i < size; i++)
                   2440:                y_current->y_array[i] = array[i];
                   2441:            vim_free(array);
                   2442:        }
                   2443:        y_current->y_size = size;
                   2444:    }
                   2445:    return eof;
                   2446: }
                   2447:
                   2448:    void
                   2449: write_viminfo_registers(fp)
                   2450:    FILE    *fp;
                   2451: {
                   2452:    int     i, j;
                   2453:    char_u  *type;
                   2454:    char_u  c;
                   2455:    int     num_lines;
                   2456:    int     max_num_lines;
                   2457:
                   2458:    fprintf(fp, "\n# Registers:\n");
                   2459:
                   2460:    max_num_lines = get_viminfo_parameter('"');
                   2461:    if (max_num_lines == 0)
                   2462:        return;
                   2463:    for (i = 0; i < NUM_REGISTERS; i++)
                   2464:    {
                   2465:        if (y_buf[i].y_array == NULL)
                   2466:            continue;
                   2467: #ifdef USE_GUI
                   2468:        /* Skip '*' register, we don't want it back next time */
                   2469:        if (i == GUI_SELECTION_REGISTER)
                   2470:            continue;
                   2471: #endif
                   2472:        switch (y_buf[i].y_type)
                   2473:        {
                   2474:            case MLINE:
                   2475:                type = (char_u *)"LINE";
                   2476:                break;
                   2477:            case MCHAR:
                   2478:                type = (char_u *)"CHAR";
                   2479:                break;
                   2480:            case MBLOCK:
                   2481:                type = (char_u *)"BLOCK";
                   2482:                break;
                   2483:            default:
                   2484:                sprintf((char *)IObuff, "Unknown register type %d",
                   2485:                    y_buf[i].y_type);
                   2486:                emsg(IObuff);
                   2487:                type = (char_u *)"LINE";
                   2488:                break;
                   2489:        }
                   2490:        if (y_previous == &y_buf[i])
                   2491:            fprintf(fp, "\"");
                   2492:        if (i == DELETION_REGISTER)
                   2493:            c = '-';
                   2494:        else if (i < 10)
                   2495:            c = '0' + i;
                   2496:        else
                   2497:            c = 'a' + i - 10;
                   2498:        fprintf(fp, "\"%c\t%s\n", c, type);
                   2499:        num_lines = y_buf[i].y_size;
                   2500:
                   2501:        /* If max_num_lines < 0, then we save ALL the lines in the register */
                   2502:        if (max_num_lines > 0 && num_lines > max_num_lines)
                   2503:            num_lines = max_num_lines;
                   2504:        for (j = 0; j < num_lines; j++)
                   2505:        {
                   2506:            putc('\t', fp);
                   2507:            viminfo_writestring(fp, y_buf[i].y_array[j]);
                   2508:        }
                   2509:    }
                   2510: }
                   2511: #endif /* VIMINFO */
                   2512:
                   2513: #if defined(USE_GUI) || defined(PROTO)
                   2514: /*
                   2515:  * Text selection stuff that uses the GUI selection register '*'.  When using a
                   2516:  * GUI this may be text from another window, otherwise it is the last text we
                   2517:  * had highlighted with VIsual mode.  With mouse support, clicking the middle
                   2518:  * button performs the paste, otherwise you will need to do <"*p>.
                   2519:  */
                   2520:
                   2521:    void
                   2522: gui_free_selection()
                   2523: {
                   2524:    struct yankbuf *y_ptr = y_current;
                   2525:
                   2526:    y_current = &y_buf[GUI_SELECTION_REGISTER];     /* '*' register */
                   2527:    free_yank_all();
                   2528:    y_current->y_size = 0;
                   2529:    y_current = y_ptr;
                   2530: }
                   2531:
                   2532: /*
                   2533:  * Get the selected text and put it in the gui text register '*'.
                   2534:  */
                   2535:    void
                   2536: gui_get_selection()
                   2537: {
                   2538:    struct yankbuf *old_y_previous, *old_y_current;
                   2539:    char_u  old_yankbuffer;
                   2540:    FPOS    old_cursor, old_visual;
                   2541:    int     old_op_type;
                   2542:
                   2543:    if (gui.selection.owned)
                   2544:    {
                   2545:        if (y_buf[GUI_SELECTION_REGISTER].y_array != NULL)
                   2546:            return;
                   2547:
                   2548:        /* Get the text between gui.selection.start & gui.selection.end */
                   2549:        old_y_previous = y_previous;
                   2550:        old_y_current = y_current;
                   2551:        old_yankbuffer = yankbuffer;
                   2552:        old_cursor = curwin->w_cursor;
                   2553:        old_visual = VIsual;
                   2554:        old_op_type = op_type;
                   2555:        yankbuffer = '*';
                   2556:        op_type = YANK;
                   2557:        do_pending_operator('y', NUL, FALSE, NULL, NULL, 0, TRUE, TRUE);
                   2558:        y_previous = old_y_previous;
                   2559:        y_current = old_y_current;
                   2560:        yankbuffer = old_yankbuffer;
                   2561:        curwin->w_cursor = old_cursor;
                   2562:        VIsual = old_visual;
                   2563:        op_type = old_op_type;
                   2564:    }
                   2565:    else
                   2566:    {
                   2567:        gui_free_selection();
                   2568:
                   2569:        /* Try to get selected text from another window */
                   2570:        gui_request_selection();
                   2571:    }
                   2572: }
                   2573:
                   2574: /* Convert from the GUI selection string into the '*' register */
                   2575:    void
                   2576: gui_yank_selection(type, str, len)
                   2577:    int     type;
                   2578:    char_u  *str;
                   2579:    long_u  len;
                   2580: {
                   2581:    struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
                   2582:    int     lnum;
                   2583:    int     start;
                   2584:    int     i;
                   2585:
                   2586:    gui_free_selection();
                   2587:
                   2588:    /* Count the number of lines within the string */
                   2589:    y_ptr->y_size = 1;
                   2590:    for (i = 0; i < len; i++)
                   2591:        if (str[i] == '\n')
                   2592:            y_ptr->y_size++;
                   2593:
                   2594:    if (type != MCHAR && i > 0 && str[i - 1] == '\n')
                   2595:        y_ptr->y_size--;
                   2596:
                   2597:    y_ptr->y_array = (char_u **)lalloc(y_ptr->y_size * sizeof(char_u *), TRUE);
                   2598:    if (y_ptr->y_array == NULL)
                   2599:        return;
                   2600:    y_ptr->y_type = type;
                   2601:    lnum = 0;
                   2602:    start = 0;
                   2603:    for (i = 0; i < len; i++)
                   2604:    {
                   2605:        if (str[i] == NUL)
                   2606:            str[i] = '\n';
                   2607:        else if (str[i] == '\n')
                   2608:        {
                   2609:            str[i] = NUL;
                   2610:            if (type == MCHAR || i != len - 1)
                   2611:            {
                   2612:                if ((y_ptr->y_array[lnum] = strsave(str + start)) == NULL)
                   2613:                {
                   2614:                    y_ptr->y_size = lnum;
                   2615:                    return;
                   2616:                }
                   2617:                lnum++;
                   2618:                start = i + 1;
                   2619:            }
                   2620:        }
                   2621:    }
                   2622:    if ((y_ptr->y_array[lnum] = alloc(i - start + 1)) == NULL)
                   2623:        return;
                   2624:    if (i - start > 0)
                   2625:        STRNCPY(y_ptr->y_array[lnum], str + start, i - start);
                   2626:    y_ptr->y_array[lnum][i - start] = NUL;
                   2627:    y_ptr->y_size = lnum + 1;
                   2628: }
                   2629:
                   2630: /*
                   2631:  * Convert the '*' register into a GUI selection string returned in *str with
                   2632:  * length *len.
                   2633:  */
                   2634:    int
                   2635: gui_convert_selection(str, len)
                   2636:    char_u  **str;
                   2637:    long_u  *len;
                   2638: {
                   2639:    struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
                   2640:    char_u  *p;
                   2641:    int     lnum;
                   2642:    int     i, j;
                   2643:
                   2644:    *str = NULL;
                   2645:    *len = 0;
                   2646:    if (y_ptr->y_array == NULL)
                   2647:        return -1;
                   2648:
                   2649:    for (i = 0; i < y_ptr->y_size; i++)
                   2650:        *len += STRLEN(y_ptr->y_array[i]) + 1;
                   2651:
                   2652:    /*
                   2653:     * Don't want newline character at end of last line if we're in MCHAR mode.
                   2654:     */
                   2655:    if (y_ptr->y_type == MCHAR && *len > 1)
                   2656:        (*len)--;
                   2657:
                   2658:    p = *str = lalloc(*len, TRUE);
                   2659:    if (p == NULL)
                   2660:        return -1;
                   2661:    lnum = 0;
                   2662:    for (i = 0, j = 0; i < *len; i++, j++)
                   2663:    {
                   2664:        if (y_ptr->y_array[lnum][j] == '\n')
                   2665:            p[i] = NUL;
                   2666:        else if (y_ptr->y_array[lnum][j] == NUL)
                   2667:        {
                   2668:            p[i] = '\n';
                   2669:            lnum++;
                   2670:            j = -1;
                   2671:        }
                   2672:        else
                   2673:            p[i] = y_ptr->y_array[lnum][j];
                   2674:    }
                   2675:    return y_ptr->y_type;
                   2676: }
                   2677: #endif /* USE_GUI || PROTO */