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

Annotation of src/usr.bin/vim/cmdcmds.c, Revision 1.3

1.3     ! downsj      1: /* $OpenBSD: cmdcmds.c,v 1.2 1996/09/21 06:22:52 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:  * cmdcmds.c: functions for command line commands
                     12:  */
                     13:
                     14: #include "vim.h"
                     15: #include "globals.h"
                     16: #include "proto.h"
                     17: #include "option.h"
                     18:
1.2       downsj     19: static void do_filter __ARGS((linenr_t line1, linenr_t line2,
                     20:                                    char_u *buff, int do_in, int do_out));
1.1       downsj     21: #ifdef VIMINFO
                     22: static char_u *viminfo_filename __ARGS((char_u     *));
1.2       downsj     23: static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info,
                     24:                                             int want_marks, int force_read));
                     25: static int read_viminfo_up_to_marks __ARGS((char_u *line, FILE *fp,
                     26:                                                                int forceit));
1.1       downsj     27: #endif /* VIMINFO */
                     28:
                     29:    void
                     30: do_ascii()
                     31: {
                     32:    int     c;
                     33:    char    buf1[20];
                     34:    char    buf2[20];
                     35:    char_u  buf3[3];
                     36:
                     37:    c = gchar_cursor();
1.2       downsj     38:    if (c == NUL)
                     39:    {
                     40:        MSG("empty line");
                     41:        return;
                     42:    }
1.1       downsj     43:    if (c == NL)            /* NUL is stored as NL */
                     44:        c = NUL;
                     45:    if (isprintchar(c) && (c < ' ' || c > '~'))
                     46:    {
                     47:        transchar_nonprint(buf3, c);
                     48:        sprintf(buf1, "  <%s>", (char *)buf3);
                     49:    }
                     50:    else
                     51:        buf1[0] = NUL;
                     52:    if (c >= 0x80)
                     53:        sprintf(buf2, "  <M-%s>", transchar(c & 0x7f));
                     54:    else
                     55:        buf2[0] = NUL;
                     56:    sprintf((char *)IObuff, "<%s>%s%s  %d,  Hex %02x,  Octal %03o",
                     57:                                           transchar(c), buf1, buf2, c, c, c);
                     58:    msg(IObuff);
                     59: }
                     60:
                     61: /*
                     62:  * align text:
                     63:  * type = -1  left aligned
                     64:  * type = 0   centered
                     65:  * type = 1   right aligned
                     66:  */
                     67:    void
                     68: do_align(start, end, width, type)
                     69:    linenr_t    start;
                     70:    linenr_t    end;
                     71:    int         width;
                     72:    int         type;
                     73: {
                     74:    FPOS    pos;
                     75:    int     len;
                     76:    int     indent = 0;
                     77:    int     new_indent = 0;         /* init for GCC */
                     78:    char_u  *first;
                     79:    char_u  *last;
                     80:    int     save;
                     81:
                     82: #ifdef RIGHTLEFT
                     83:    if (curwin->w_p_rl)
                     84:        type = -type;   /* switch left and right aligning */
                     85: #endif
                     86:
                     87:    pos = curwin->w_cursor;
                     88:    if (type == -1)     /* left align: width is used for new indent */
                     89:    {
                     90:        if (width >= 0)
                     91:            indent = width;
                     92:    }
                     93:    else
                     94:    {
                     95:        /*
                     96:         * if 'textwidth' set, use it
                     97:         * else if 'wrapmargin' set, use it
                     98:         * if invalid value, use 80
                     99:         */
                    100:        if (width <= 0)
                    101:            width = curbuf->b_p_tw;
                    102:        if (width == 0 && curbuf->b_p_wm > 0)
                    103:            width = Columns - curbuf->b_p_wm;
                    104:        if (width <= 0)
                    105:            width = 80;
                    106:    }
                    107:
                    108:    if (u_save((linenr_t)(start - 1), (linenr_t)(end + 1)) == FAIL)
                    109:        return;
                    110:    for (curwin->w_cursor.lnum = start;
                    111:                        curwin->w_cursor.lnum <= end; ++curwin->w_cursor.lnum)
                    112:    {
                    113:            /* find the first non-blank character */
                    114:        first = skipwhite(ml_get_curline());
                    115:            /* find the character after the last non-blank character */
                    116:        for (last = first + STRLEN(first);
                    117:                                last > first && vim_iswhite(last[-1]); --last)
                    118:            ;
                    119:        save = *last;
                    120:        *last = NUL;
                    121:        len = linetabsize(first);                   /* get line length */
                    122:        *last = save;
                    123:        if (len == 0)                               /* skip blank lines */
                    124:            continue;
                    125:        switch (type)
                    126:        {
                    127:            case -1:    new_indent = indent;            /* left align */
                    128:                        break;
                    129:            case 0:     new_indent = (width - len) / 2; /* center */
                    130:                        break;
                    131:            case 1:     new_indent = width - len;       /* right align */
                    132:                        break;
                    133:        }
                    134:        if (new_indent < 0)
                    135:            new_indent = 0;
                    136:        set_indent(new_indent, TRUE);           /* set indent */
                    137:    }
                    138:    curwin->w_cursor = pos;
                    139:    beginline(TRUE);
                    140:    updateScreen(NOT_VALID);
                    141: }
                    142:
                    143:    void
1.2       downsj    144: do_retab(start, end, new_ts, forceit)
1.1       downsj    145:    linenr_t    start;
                    146:    linenr_t    end;
                    147:    int         new_ts;
1.2       downsj    148:    int         forceit;
1.1       downsj    149: {
                    150:    linenr_t    lnum;
                    151:    int         got_tab = FALSE;
                    152:    long        num_spaces = 0;
                    153:    long        num_tabs;
                    154:    long        len;
                    155:    long        col;
                    156:    long        vcol;
                    157:    long        start_col = 0;          /* For start of white-space string */
                    158:    long        start_vcol = 0;         /* For start of white-space string */
                    159:    int         temp;
                    160:    long        old_len;
                    161:    char_u      *ptr;
                    162:    char_u      *new_line = (char_u *)1;    /* init to non-NULL */
                    163:    int         did_something = FALSE;
                    164:    int         did_undo;               /* called u_save for current line */
                    165:
                    166:    if (new_ts == 0)
                    167:        new_ts = curbuf->b_p_ts;
                    168:    for (lnum = start; !got_int && lnum <= end; ++lnum)
                    169:    {
                    170:        ptr = ml_get(lnum);
                    171:        col = 0;
                    172:        vcol = 0;
                    173:        did_undo = FALSE;
                    174:        for (;;)
                    175:        {
                    176:            if (vim_iswhite(ptr[col]))
                    177:            {
                    178:                if (!got_tab && num_spaces == 0)
                    179:                {
                    180:                    /* First consecutive white-space */
                    181:                    start_vcol = vcol;
                    182:                    start_col = col;
                    183:                }
                    184:                if (ptr[col] == ' ')
                    185:                    num_spaces++;
                    186:                else
                    187:                    got_tab = TRUE;
                    188:            }
                    189:            else
                    190:            {
1.2       downsj    191:                if (got_tab || (forceit && num_spaces > 1))
1.1       downsj    192:                {
                    193:                    /* Retabulate this string of white-space */
                    194:
                    195:                    /* len is virtual length of white string */
                    196:                    len = num_spaces = vcol - start_vcol;
                    197:                    num_tabs = 0;
                    198:                    if (!curbuf->b_p_et)
                    199:                    {
                    200:                        temp = new_ts - (start_vcol % new_ts);
                    201:                        if (num_spaces >= temp)
                    202:                        {
                    203:                            num_spaces -= temp;
                    204:                            num_tabs++;
                    205:                        }
                    206:                        num_tabs += num_spaces / new_ts;
                    207:                        num_spaces -= (num_spaces / new_ts) * new_ts;
                    208:                    }
                    209:                    if (curbuf->b_p_et || got_tab ||
                    210:                                        (num_spaces + num_tabs < len))
                    211:                    {
                    212:                        if (did_undo == FALSE)
                    213:                        {
                    214:                            did_undo = TRUE;
                    215:                            if (u_save((linenr_t)(lnum - 1),
                    216:                                                (linenr_t)(lnum + 1)) == FAIL)
                    217:                            {
                    218:                                new_line = NULL;        /* flag out-of-memory */
                    219:                                break;
                    220:                            }
                    221:                        }
                    222:
                    223:                        /* len is actual number of white characters used */
                    224:                        len = num_spaces + num_tabs;
                    225:                        old_len = STRLEN(ptr);
                    226:                        new_line = lalloc(old_len - col + start_col + len + 1,
                    227:                                                                        TRUE);
                    228:                        if (new_line == NULL)
                    229:                            break;
                    230:                        if (start_col > 0)
                    231:                            vim_memmove(new_line, ptr, (size_t)start_col);
                    232:                        vim_memmove(new_line + start_col + len,
                    233:                                      ptr + col, (size_t)(old_len - col + 1));
                    234:                        ptr = new_line + start_col;
                    235:                        for (col = 0; col < len; col++)
                    236:                            ptr[col] = (col < num_tabs) ? '\t' : ' ';
                    237:                        ml_replace(lnum, new_line, FALSE);
                    238:                        did_something = TRUE;
                    239:                        ptr = new_line;
                    240:                        col = start_col + len;
                    241:                    }
                    242:                }
                    243:                got_tab = FALSE;
                    244:                num_spaces = 0;
                    245:            }
                    246:            if (ptr[col] == NUL)
                    247:                break;
                    248:            vcol += chartabsize(ptr[col++], (colnr_t)vcol);
                    249:        }
                    250:        if (new_line == NULL)               /* out of memory */
                    251:            break;
                    252:        line_breakcheck();
                    253:    }
                    254:    if (got_int)
                    255:        emsg(e_interr);
                    256:    if (did_something)
                    257:        CHANGED;
                    258:    curbuf->b_p_ts = new_ts;
                    259:    coladvance(curwin->w_curswant);
                    260: }
                    261:
                    262: /*
                    263:  * :move command - move lines line1-line2 to line n
                    264:  *
                    265:  * return FAIL for failure, OK otherwise
                    266:  */
                    267:    int
                    268: do_move(line1, line2, n)
                    269:    linenr_t    line1;
                    270:    linenr_t    line2;
                    271:    linenr_t    n;
                    272: {
                    273:    char_u      *str;
                    274:    linenr_t    l;
                    275:    linenr_t    extra;      /* Num lines added before line1 */
                    276:    linenr_t    num_lines;  /* Num lines moved */
                    277:    linenr_t    last_line;  /* Last line in file after adding new text */
                    278:    int         has_mark;
                    279:
                    280:    if (n >= line1 && n < line2)
                    281:    {
                    282:        EMSG("Move lines into themselves");
                    283:        return FAIL;
                    284:    }
                    285:
                    286:    num_lines = line2 - line1 + 1;
                    287:
                    288:    /*
                    289:     * First we copy the old text to its new location -- webb
                    290:     */
                    291:    if (u_save(n, n + 1) == FAIL)
                    292:        return FAIL;
                    293:    for (extra = 0, l = line1; l <= line2; l++)
                    294:    {
                    295:        str = strsave(ml_get(l + extra));
                    296:        if (str != NULL)
                    297:        {
                    298:            has_mark = ml_has_mark(l + extra);
                    299:            ml_append(n + l - line1, str, (colnr_t)0, FALSE);
                    300:            vim_free(str);
                    301:            if (has_mark)
                    302:                ml_setmarked(n + l - line1 + 1);
                    303:            if (n < line1)
                    304:                extra++;
                    305:        }
                    306:    }
                    307:
                    308:    /*
                    309:     * Now we must be careful adjusting our marks so that we don't overlap our
                    310:     * mark_adjust() calls.
                    311:     *
                    312:     * We adjust the marks within the old text so that they refer to the
                    313:     * last lines of the file (temporarily), because we know no other marks
                    314:     * will be set there since these line numbers did not exist until we added
                    315:     * our new lines.
                    316:     *
                    317:     * Then we adjust the marks on lines between the old and new text positions
                    318:     * (either forwards or backwards).
                    319:     *
                    320:     * And Finally we adjust the marks we put at the end of the file back to
                    321:     * their final destination at the new text position -- webb
                    322:     */
                    323:    last_line = curbuf->b_ml.ml_line_count;
                    324:    mark_adjust(line1, line2, last_line - line2, 0L);
                    325:    if (n >= line2)
                    326:        mark_adjust(line2 + 1, n, -num_lines, 0L);
                    327:    else
                    328:        mark_adjust(n + 1, line1 - 1, num_lines, 0L);
                    329:    mark_adjust(last_line - num_lines + 1, last_line,
                    330:                                                -(last_line - n - extra), 0L);
                    331:
                    332:    /*
                    333:     * Now we delete the original text -- webb
                    334:     */
                    335:    if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
                    336:        return FAIL;
                    337:
                    338:    for (l = line1; l <= line2; l++)
                    339:        ml_delete(line1 + extra, TRUE);
                    340:
                    341:    CHANGED;
                    342:    if (!global_busy && num_lines > p_report)
                    343:        smsg((char_u *)"%ld line%s moved", num_lines, plural(num_lines));
                    344:    return OK;
                    345: }
                    346:
                    347: /*
                    348:  * :copy command - copy lines line1-line2 to line n
                    349:  */
                    350:    void
                    351: do_copy(line1, line2, n)
                    352:    linenr_t    line1;
                    353:    linenr_t    line2;
                    354:    linenr_t    n;
                    355: {
                    356:    linenr_t        lnum;
                    357:    char_u          *p;
                    358:
                    359:    mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1, 0L);
                    360:
                    361:    /*
                    362:     * there are three situations:
                    363:     * 1. destination is above line1
                    364:     * 2. destination is between line1 and line2
                    365:     * 3. destination is below line2
                    366:     *
                    367:     * n = destination (when starting)
                    368:     * curwin->w_cursor.lnum = destination (while copying)
                    369:     * line1 = start of source (while copying)
                    370:     * line2 = end of source (while copying)
                    371:     */
                    372:    if (u_save(n, n + 1) == FAIL)
                    373:        return;
                    374:    curwin->w_cursor.lnum = n;
                    375:    lnum = line2 - line1 + 1;
                    376:    while (line1 <= line2)
                    377:    {
                    378:        /* need to use strsave() because the line will be unlocked
                    379:            within ml_append */
                    380:        p = strsave(ml_get(line1));
                    381:        if (p != NULL)
                    382:        {
                    383:            ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
                    384:            vim_free(p);
                    385:        }
                    386:                /* situation 2: skip already copied lines */
                    387:        if (line1 == n)
                    388:            line1 = curwin->w_cursor.lnum;
                    389:        ++line1;
                    390:        if (curwin->w_cursor.lnum < line1)
                    391:            ++line1;
                    392:        if (curwin->w_cursor.lnum < line2)
                    393:            ++line2;
                    394:        ++curwin->w_cursor.lnum;
                    395:    }
                    396:    CHANGED;
                    397:    msgmore((long)lnum);
                    398: }
                    399:
                    400: /*
                    401:  * Handle the ":!cmd" command.  Also for ":r !cmd" and ":w !cmd"
                    402:  * Bangs in the argument are replaced with the previously entered command.
                    403:  * Remember the argument.
                    404:  */
                    405:    void
                    406: do_bang(addr_count, line1, line2, forceit, arg, do_in, do_out)
                    407:    int         addr_count;
                    408:    linenr_t    line1, line2;
                    409:    int         forceit;
                    410:    char_u      *arg;
                    411:    int         do_in, do_out;
                    412: {
                    413:    static  char_u  *prevcmd = NULL;        /* the previous command */
                    414:    char_u          *newcmd = NULL;         /* the new command */
                    415:    int             ins_prevcmd;
                    416:    char_u          *t;
                    417:    char_u          *p;
                    418:    char_u          *trailarg;
                    419:    int             len;
                    420:    int             scroll_save = msg_scroll;
                    421:
                    422:    /*
                    423:     * Disallow shell commands from .exrc and .vimrc in current directory for
                    424:     * security reasons.
                    425:     */
                    426:    if (secure)
                    427:    {
                    428:        secure = 2;
                    429:        emsg(e_curdir);
                    430:        return;
                    431:    }
                    432:
                    433:    if (addr_count == 0)                /* :! */
                    434:    {
                    435:        msg_scroll = FALSE;         /* don't scroll here */
                    436:        autowrite_all();
                    437:        msg_scroll = scroll_save;
                    438:    }
                    439:
                    440:    /*
                    441:     * Try to find an embedded bang, like in :!<cmd> ! [args]
                    442:     * (:!! is indicated by the 'forceit' variable)
                    443:     */
                    444:    ins_prevcmd = forceit;
                    445:    trailarg = arg;
                    446:    do
                    447:    {
                    448:        len = STRLEN(trailarg) + 1;
                    449:        if (newcmd != NULL)
                    450:            len += STRLEN(newcmd);
                    451:        if (ins_prevcmd)
                    452:        {
                    453:            if (prevcmd == NULL)
                    454:            {
                    455:                emsg(e_noprev);
                    456:                vim_free(newcmd);
                    457:                return;
                    458:            }
                    459:            len += STRLEN(prevcmd);
                    460:        }
                    461:        if ((t = alloc(len)) == NULL)
                    462:        {
                    463:            vim_free(newcmd);
                    464:            return;
                    465:        }
                    466:        *t = NUL;
                    467:        if (newcmd != NULL)
                    468:            STRCAT(t, newcmd);
                    469:        if (ins_prevcmd)
                    470:            STRCAT(t, prevcmd);
                    471:        p = t + STRLEN(t);
                    472:        STRCAT(t, trailarg);
                    473:        vim_free(newcmd);
                    474:        newcmd = t;
                    475:
                    476:        /*
                    477:         * Scan the rest of the argument for '!', which is replaced by the
                    478:         * previous command.  "\!" is replaced by "!" (this is vi compatible).
                    479:         */
                    480:        trailarg = NULL;
                    481:        while (*p)
                    482:        {
                    483:            if (*p == '!')
                    484:            {
                    485:                if (p > newcmd && p[-1] == '\\')
                    486:                    vim_memmove(p - 1, p, (size_t)(STRLEN(p) + 1));
                    487:                else
                    488:                {
                    489:                    trailarg = p;
                    490:                    *trailarg++ = NUL;
                    491:                    ins_prevcmd = TRUE;
                    492:                    break;
                    493:                }
                    494:            }
                    495:            ++p;
                    496:        }
                    497:    } while (trailarg != NULL);
                    498:
                    499:    vim_free(prevcmd);
                    500:    prevcmd = newcmd;
                    501:
                    502:    if (bangredo)           /* put cmd in redo buffer for ! command */
                    503:    {
                    504:        AppendToRedobuff(prevcmd);
                    505:        AppendToRedobuff((char_u *)"\n");
                    506:        bangredo = FALSE;
                    507:    }
1.2       downsj    508:    /*
                    509:     * Add quotes around the command, for shells that need them.
                    510:     */
                    511:    if (*p_shq != NUL)
                    512:    {
                    513:        newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
                    514:        if (newcmd == NULL)
                    515:            return;
                    516:        STRCPY(newcmd, p_shq);
                    517:        STRCAT(newcmd, prevcmd);
                    518:        STRCAT(newcmd, p_shq);
                    519:    }
1.1       downsj    520:    if (addr_count == 0)                /* :! */
                    521:    {
                    522:            /* echo the command */
                    523:        msg_start();
                    524:        msg_outchar(':');
                    525:        msg_outchar('!');
1.2       downsj    526:        msg_outtrans(newcmd);
1.1       downsj    527:        msg_clr_eos();
                    528:        windgoto(msg_row, msg_col);
                    529:
1.2       downsj    530:        do_shell(newcmd);
1.1       downsj    531:    }
                    532:    else                                /* :range! */
1.2       downsj    533:        do_filter(line1, line2, newcmd, do_in, do_out);
                    534:    if (newcmd != prevcmd)
                    535:        vim_free(newcmd);
1.1       downsj    536: }
                    537:
                    538: /*
                    539:  * call a shell to execute a command
                    540:  */
                    541:    void
                    542: do_shell(cmd)
                    543:    char_u  *cmd;
                    544: {
                    545:    BUF     *buf;
                    546:    int     save_nwr;
                    547:
                    548:    /*
                    549:     * Disallow shell commands from .exrc and .vimrc in current directory for
                    550:     * security reasons.
                    551:     */
                    552:    if (secure)
                    553:    {
                    554:        secure = 2;
                    555:        emsg(e_curdir);
                    556:        msg_end();
                    557:        return;
                    558:    }
                    559:
                    560: #ifdef WIN32
                    561:    /*
                    562:     * Check if external commands are allowed now.
                    563:     */
                    564:    if (can_end_termcap_mode(TRUE) == FALSE)
                    565:        return;
                    566: #endif
                    567:
                    568:    /*
                    569:     * For autocommands we want to get the output on the current screen, to
                    570:     * avoid having to type return below.
                    571:     */
                    572:    msg_outchar('\r');                  /* put cursor at start of line */
                    573: #ifdef AUTOCMD
                    574:    if (!autocmd_busy)
                    575: #endif
                    576:        stoptermcap();
                    577:    msg_outchar('\n');                  /* may shift screen one line up */
                    578:
                    579:        /* warning message before calling the shell */
                    580:    if (p_warn
                    581: #ifdef AUTOCMD
                    582:                && !autocmd_busy
                    583: #endif
                    584:                                   )
                    585:        for (buf = firstbuf; buf; buf = buf->b_next)
                    586:            if (buf->b_changed)
                    587:            {
                    588:                MSG_OUTSTR("[No write since last change]\n");
                    589:                break;
                    590:            }
                    591:
                    592: /* This windgoto is required for when the '\n' resulted in a "delete line 1"
                    593:  * command to the terminal. */
                    594:
                    595:    windgoto(msg_row, msg_col);
                    596:    cursor_on();
                    597:    (void)call_shell(cmd, SHELL_COOKED);
                    598:    need_check_timestamps = TRUE;
                    599:
                    600: /*
                    601:  * put the message cursor at the end of the screen, avoids wait_return() to
                    602:  * overwrite the text that the external command showed
                    603:  */
                    604:    msg_pos((int)Rows - 1, 0);
                    605:
                    606: #ifdef AUTOCMD
1.2       downsj    607:    if (autocmd_busy)
                    608:        must_redraw = CLEAR;
                    609:    else
1.1       downsj    610: #endif
                    611:    {
                    612:        /*
                    613:         * If K_TI is defined, we assume that we switch screens when
                    614:         * starttermcap() is called. In that case we really want to wait for
                    615:         * "hit return to continue".
                    616:         */
                    617:        save_nwr = no_wait_return;
                    618:        if (*T_TI != NUL)
                    619:            no_wait_return = FALSE;
                    620: #ifdef AMIGA
                    621:        wait_return(term_console ? -1 : TRUE);      /* see below */
                    622: #else
                    623:        wait_return(TRUE);
                    624: #endif
                    625:        no_wait_return = save_nwr;
                    626:        starttermcap();     /* start termcap if not done by wait_return() */
                    627:
                    628:        /*
                    629:         * In an Amiga window redrawing is caused by asking the window size.
                    630:         * If we got an interrupt this will not work. The chance that the
                    631:         * window size is wrong is very small, but we need to redraw the
                    632:         * screen.  Don't do this if ':' hit in wait_return().  THIS IS UGLY
                    633:         * but it saves an extra redraw.
                    634:         */
                    635: #ifdef AMIGA
                    636:        if (skip_redraw)                /* ':' hit in wait_return() */
                    637:            must_redraw = CLEAR;
                    638:        else if (term_console)
                    639:        {
                    640:            OUTSTR("\033[0 q");         /* get window size */
                    641:            if (got_int)
                    642:                must_redraw = CLEAR;    /* if got_int is TRUE, redraw needed */
                    643:            else
                    644:                must_redraw = 0;        /* no extra redraw needed */
                    645:        }
                    646: #endif /* AMIGA */
                    647:    }
                    648: }
                    649:
                    650: /*
                    651:  * do_filter: filter lines through a command given by the user
                    652:  *
                    653:  * We use temp files and the call_shell() routine here. This would normally
                    654:  * be done using pipes on a UNIX machine, but this is more portable to
                    655:  * non-unix machines. The call_shell() routine needs to be able
                    656:  * to deal with redirection somehow, and should handle things like looking
                    657:  * at the PATH env. variable, and adding reasonable extensions to the
                    658:  * command name given by the user. All reasonable versions of call_shell()
                    659:  * do this.
                    660:  * We use input redirection if do_in is TRUE.
                    661:  * We use output redirection if do_out is TRUE.
                    662:  */
1.2       downsj    663:    static void
1.1       downsj    664: do_filter(line1, line2, buff, do_in, do_out)
                    665:    linenr_t    line1, line2;
                    666:    char_u      *buff;
                    667:    int         do_in, do_out;
                    668: {
1.2       downsj    669:    char_u      *itmp = NULL;
                    670:    char_u      *otmp = NULL;
1.1       downsj    671:    linenr_t    linecount;
                    672:    FPOS        cursor_save;
1.2       downsj    673: #ifdef AUTOCMD
                    674:    BUF         *old_curbuf = curbuf;
                    675: #endif
1.1       downsj    676:
                    677:    /*
                    678:     * Disallow shell commands from .exrc and .vimrc in current directory for
                    679:     * security reasons.
                    680:     */
                    681:    if (secure)
                    682:    {
                    683:        secure = 2;
                    684:        emsg(e_curdir);
                    685:        return;
                    686:    }
                    687:    if (*buff == NUL)       /* no filter command */
                    688:        return;
                    689:
                    690: #ifdef WIN32
                    691:    /*
                    692:     * Check if external commands are allowed now.
                    693:     */
                    694:    if (can_end_termcap_mode(TRUE) == FALSE)
                    695:        return;
                    696: #endif
                    697:
                    698:    cursor_save = curwin->w_cursor;
                    699:    linecount = line2 - line1 + 1;
                    700:    curwin->w_cursor.lnum = line1;
                    701:    curwin->w_cursor.col = 0;
                    702:
                    703:    /*
                    704:     * 1. Form temp file names
                    705:     * 2. Write the lines to a temp file
                    706:     * 3. Run the filter command on the temp file
                    707:     * 4. Read the output of the command into the buffer
                    708:     * 5. Delete the original lines to be filtered
                    709:     * 6. Remove the temp files
                    710:     */
                    711:
1.2       downsj    712:    if ((do_in && (itmp = vim_tempname('i')) == NULL) ||
                    713:                               (do_out && (otmp = vim_tempname('o')) == NULL))
1.1       downsj    714:    {
                    715:        emsg(e_notmp);
1.2       downsj    716:        goto filterend;
1.1       downsj    717:    }
                    718:
                    719: /*
                    720:  * The writing and reading of temp files will not be shown.
                    721:  * Vi also doesn't do this and the messages are not very informative.
                    722:  */
                    723:    ++no_wait_return;           /* don't call wait_return() while busy */
                    724:    if (do_in && buf_write(curbuf, itmp, NULL, line1, line2,
1.2       downsj    725:                                           FALSE, FALSE, FALSE, TRUE) == FAIL)
1.1       downsj    726:    {
                    727:        msg_outchar('\n');                  /* keep message from buf_write() */
                    728:        --no_wait_return;
                    729:        (void)emsg2(e_notcreate, itmp);     /* will call wait_return */
                    730:        goto filterend;
                    731:    }
1.2       downsj    732: #ifdef AUTOCMD
                    733:    if (curbuf != old_curbuf)
                    734:        goto filterend;
                    735: #endif
                    736:
1.1       downsj    737:    if (!do_out)
                    738:        msg_outchar('\n');
                    739:
                    740: #if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
                    741: /*
                    742:  * put braces around the command (for concatenated commands)
                    743:  */
                    744:    sprintf((char *)IObuff, "(%s)", (char *)buff);
                    745:    if (do_in)
                    746:    {
                    747:        STRCAT(IObuff, " < ");
                    748:        STRCAT(IObuff, itmp);
                    749:    }
                    750: #else
                    751: /*
                    752:  * for shells that don't understand braces around commands, at least allow
                    753:  * the use of commands in a pipe.
                    754:  */
                    755:    STRCPY(IObuff, buff);
                    756:    if (do_in)
                    757:    {
                    758:        char_u      *p;
                    759:    /*
1.2       downsj    760:     * If there is a pipe, we have to put the '<' in front of it.
                    761:     * Don't do this when 'shellquote' is not empty, otherwise the redirection
                    762:     * would be inside the quotes.
1.1       downsj    763:     */
                    764:        p = vim_strchr(IObuff, '|');
1.2       downsj    765:        if (p && *p_shq == NUL)
1.1       downsj    766:            *p = NUL;
                    767:        STRCAT(IObuff, " < ");
                    768:        STRCAT(IObuff, itmp);
                    769:        p = vim_strchr(buff, '|');
1.2       downsj    770:        if (p && *p_shq == NUL)
1.1       downsj    771:            STRCAT(IObuff, p);
                    772:    }
                    773: #endif
                    774:    if (do_out)
                    775:    {
                    776:        char_u *p;
                    777:
                    778:        if ((p = vim_strchr(p_srr, '%')) != NULL && p[1] == 's')
                    779:        {
                    780:            p = IObuff + STRLEN(IObuff);
                    781:            *p++ = ' '; /* not really needed? Not with sh, ksh or bash */
                    782:            sprintf((char *)p, (char *)p_srr, (char *)otmp);
                    783:        }
                    784:        else
                    785:            sprintf((char *)IObuff + STRLEN(IObuff), " %s %s",
                    786:                                                 (char *)p_srr, (char *)otmp);
                    787:    }
                    788:
                    789:    windgoto((int)Rows - 1, 0);
                    790:    cursor_on();
                    791:
                    792:    /*
                    793:     * When not redirecting the output the command can write anything to the
                    794:     * screen. If 'shellredir' is equal to ">", screen may be messed up by
                    795:     * stderr output of external command. Clear the screen later.
                    796:     * If do_in is FALSE, this could be something like ":r !cat", which may
                    797:     * also mess up the screen, clear it later.
                    798:     */
                    799:    if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
                    800:        must_redraw = CLEAR;
                    801:    else
                    802:        redraw_later(NOT_VALID);
                    803:
                    804:    /*
                    805:     * When call_shell() fails wait_return() is called to give the user a
                    806:     * chance to read the error messages. Otherwise errors are ignored, so you
                    807:     * can see the error messages from the command that appear on stdout; use
                    808:     * 'u' to fix the text
                    809:     * Switch to cooked mode when not redirecting stdin, avoids that something
                    810:     * like ":r !cat" hangs.
                    811:     */
                    812:    if (call_shell(IObuff, SHELL_FILTER | SHELL_COOKED) == FAIL)
                    813:    {
                    814:        must_redraw = CLEAR;
                    815:        wait_return(FALSE);
                    816:    }
                    817:    need_check_timestamps = TRUE;
                    818:
                    819:    if (do_out)
                    820:    {
                    821:        if (u_save((linenr_t)(line2), (linenr_t)(line2 + 1)) == FAIL)
                    822:        {
                    823:            goto error;
                    824:        }
                    825:        if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM, TRUE)
                    826:                                                                      == FAIL)
                    827:        {
                    828:            msg_outchar('\n');
                    829:            emsg2(e_notread, otmp);
                    830:            goto error;
                    831:        }
1.2       downsj    832: #ifdef AUTOCMD
                    833:        if (curbuf != old_curbuf)
                    834:            goto filterend;
                    835: #endif
1.1       downsj    836:
                    837:        if (do_in)
                    838:        {
                    839:            /* put cursor on first filtered line for ":range!cmd" */
                    840:            curwin->w_cursor.lnum = line1;
                    841:            dellines(linecount, TRUE, TRUE);
                    842:            curbuf->b_op_start.lnum -= linecount;       /* adjust '[ */
                    843:            curbuf->b_op_end.lnum -= linecount;         /* adjust '] */
1.2       downsj    844:            write_lnum_adjust(-linecount);              /* adjust last line
                    845:                                                           for next write */
1.1       downsj    846:        }
                    847:        else
                    848:        {
                    849:            /* put cursor on last new line for ":r !cmd" */
                    850:            curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
                    851:            linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
                    852:        }
                    853:        beginline(TRUE);                /* cursor on first non-blank */
                    854:        --no_wait_return;
                    855:
                    856:        if (linecount > p_report)
                    857:        {
                    858:            if (do_in)
                    859:            {
                    860:                sprintf((char *)msg_buf, "%ld lines filtered", (long)linecount);
                    861:                if (msg(msg_buf) && !msg_scroll)
                    862:                    keep_msg = msg_buf;     /* display message after redraw */
                    863:            }
                    864:            else
                    865:                msgmore((long)linecount);
                    866:        }
                    867:    }
                    868:    else
                    869:    {
                    870: error:
                    871:        /* put cursor back in same position for ":w !cmd" */
                    872:        curwin->w_cursor = cursor_save;
                    873:        --no_wait_return;
                    874:        wait_return(FALSE);
                    875:    }
                    876:
                    877: filterend:
                    878:
1.2       downsj    879: #ifdef AUTOCMD
                    880:    if (curbuf != old_curbuf)
1.1       downsj    881:    {
1.2       downsj    882:        --no_wait_return;
                    883:        EMSG("*Filter* Autocommands must not change current buffer");
1.1       downsj    884:    }
1.2       downsj    885: #endif
                    886:    if (itmp != NULL)
                    887:        vim_remove(itmp);
                    888:    if (otmp != NULL)
                    889:        vim_remove(otmp);
                    890:    vim_free(itmp);
                    891:    vim_free(otmp);
1.1       downsj    892: }
                    893:
                    894: #ifdef VIMINFO
                    895:
                    896: static int no_viminfo __ARGS((void));
1.2       downsj    897: static int viminfo_errcnt;
1.1       downsj    898:
                    899:    static int
                    900: no_viminfo()
                    901: {
                    902:    /* "vim -i NONE" does not read or write a viminfo file */
                    903:    return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
                    904: }
                    905:
                    906: /*
1.2       downsj    907:  * Report an error for reading a viminfo file.
                    908:  * Count the number of errors.  When there are more than 10, return TRUE.
                    909:  */
                    910:    int
                    911: viminfo_error(message, line)
                    912:    char    *message;
                    913:    char_u  *line;
                    914: {
                    915:    sprintf((char *)IObuff, "viminfo: %s in line: ", message);
                    916:    STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff));
                    917:    emsg(IObuff);
                    918:    if (++viminfo_errcnt >= 10)
                    919:    {
                    920:        EMSG("viminfo: Too many errors, skipping rest of file");
                    921:        return TRUE;
                    922:    }
                    923:    return FALSE;
                    924: }
                    925:
                    926: /*
1.1       downsj    927:  * read_viminfo() -- Read the viminfo file.  Registers etc. which are already
                    928:  * set are not over-written unless force is TRUE. -- webb
                    929:  */
                    930:    int
1.2       downsj    931: read_viminfo(file, want_info, want_marks, forceit)
1.1       downsj    932:    char_u  *file;
                    933:    int     want_info;
                    934:    int     want_marks;
1.2       downsj    935:    int     forceit;
1.1       downsj    936: {
                    937:    FILE    *fp;
                    938:
                    939:    if (no_viminfo())
                    940:        return FAIL;
                    941:
                    942:    file = viminfo_filename(file);          /* may set to default if NULL */
                    943:    if ((fp = fopen((char *)file, READBIN)) == NULL)
                    944:        return FAIL;
                    945:
1.2       downsj    946:    viminfo_errcnt = 0;
                    947:    do_viminfo(fp, NULL, want_info, want_marks, forceit);
1.1       downsj    948:
                    949:    fclose(fp);
                    950:
                    951:    return OK;
                    952: }
                    953:
                    954: /*
                    955:  * write_viminfo() -- Write the viminfo file.  The old one is read in first so
                    956:  * that effectively a merge of current info and old info is done.  This allows
                    957:  * multiple vims to run simultaneously, without losing any marks etc.  If
1.2       downsj    958:  * forceit is TRUE, then the old file is not read in, and only internal info is
1.1       downsj    959:  * written to the file. -- webb
                    960:  */
                    961:    void
1.2       downsj    962: write_viminfo(file, forceit)
1.1       downsj    963:    char_u  *file;
1.2       downsj    964:    int     forceit;
1.1       downsj    965: {
                    966:    FILE    *fp_in = NULL;
                    967:    FILE    *fp_out = NULL;
1.2       downsj    968:    char_u  *tempname = NULL;
1.1       downsj    969:
                    970:    if (no_viminfo())
                    971:        return;
                    972:
                    973:    file = viminfo_filename(file);      /* may set to default if NULL */
                    974:    file = strsave(file);               /* make a copy, don't want NameBuff */
                    975:    if (file != NULL)
                    976:    {
                    977:        fp_in = fopen((char *)file, READBIN);
                    978:        if (fp_in == NULL)
                    979:            fp_out = fopen((char *)file, WRITEBIN);
1.2       downsj    980:        else if ((tempname = vim_tempname('o')) != NULL)
                    981:            fp_out = fopen((char *)tempname, WRITEBIN);
1.1       downsj    982:    }
                    983:    if (file == NULL || fp_out == NULL)
                    984:    {
                    985:        EMSG2("Can't write viminfo file %s!", file == NULL ? (char_u *)"" :
1.2       downsj    986:                                              fp_in == NULL ? file : tempname);
1.1       downsj    987:        if (fp_in != NULL)
                    988:            fclose(fp_in);
1.2       downsj    989:        goto end;
1.1       downsj    990:    }
                    991:
1.2       downsj    992:    viminfo_errcnt = 0;
                    993:    do_viminfo(fp_in, fp_out, !forceit, !forceit, FALSE);
1.1       downsj    994:
                    995:    fclose(fp_out);         /* errors are ignored !? */
                    996:    if (fp_in != NULL)
                    997:    {
                    998:        fclose(fp_in);
1.2       downsj    999:        /*
                   1000:         * In case of an error, don't overwrite the original viminfo file.
                   1001:         */
                   1002:        if (viminfo_errcnt || vim_rename(tempname, file) == -1)
                   1003:            vim_remove(tempname);
1.1       downsj   1004:    }
1.2       downsj   1005: end:
1.1       downsj   1006:    vim_free(file);
1.2       downsj   1007:    vim_free(tempname);
1.1       downsj   1008: }
                   1009:
                   1010:    static char_u *
                   1011: viminfo_filename(file)
                   1012:    char_u      *file;
                   1013: {
                   1014:    if (file == NULL || *file == NUL)
                   1015:    {
                   1016:        expand_env(use_viminfo == NULL ? (char_u *)VIMINFO_FILE : use_viminfo,
                   1017:                                                          NameBuff, MAXPATHL);
                   1018:        return NameBuff;
                   1019:    }
                   1020:    return file;
                   1021: }
                   1022:
                   1023: /*
                   1024:  * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
                   1025:  */
                   1026:    static void
                   1027: do_viminfo(fp_in, fp_out, want_info, want_marks, force_read)
                   1028:    FILE    *fp_in;
                   1029:    FILE    *fp_out;
                   1030:    int     want_info;
                   1031:    int     want_marks;
                   1032:    int     force_read;
                   1033: {
                   1034:    int     count = 0;
                   1035:    int     eof = FALSE;
                   1036:    char_u  *line;
                   1037:
                   1038:    if ((line = alloc(LSIZE)) == NULL)
                   1039:        return;
                   1040:
                   1041:    if (fp_in != NULL)
                   1042:    {
                   1043:        if (want_info)
                   1044:            eof = read_viminfo_up_to_marks(line, fp_in, force_read);
                   1045:        else
                   1046:            /* Skip info, find start of marks */
                   1047:            while (!(eof = vim_fgets(line, LSIZE, fp_in)) && line[0] != '>')
                   1048:                ;
                   1049:    }
                   1050:    if (fp_out != NULL)
                   1051:    {
                   1052:        /* Write the info: */
                   1053:        fprintf(fp_out, "# This viminfo file was generated by vim\n");
                   1054:        fprintf(fp_out, "# You may edit it if you're careful!\n\n");
                   1055:        write_viminfo_search_pattern(fp_out);
                   1056:        write_viminfo_sub_string(fp_out);
                   1057:        write_viminfo_history(fp_out);
                   1058:        write_viminfo_registers(fp_out);
                   1059:        write_viminfo_filemarks(fp_out);
                   1060:        count = write_viminfo_marks(fp_out);
                   1061:    }
                   1062:    if (fp_in != NULL && want_marks)
                   1063:        copy_viminfo_marks(line, fp_in, fp_out, count, eof);
                   1064:    vim_free(line);
                   1065: }
                   1066:
                   1067: /*
                   1068:  * read_viminfo_up_to_marks() -- Only called from do_viminfo().  Reads in the
                   1069:  * first part of the viminfo file which contains everything but the marks that
                   1070:  * are local to a file.  Returns TRUE when end-of-file is reached. -- webb
                   1071:  */
                   1072:    static int
1.2       downsj   1073: read_viminfo_up_to_marks(line, fp, forceit)
1.1       downsj   1074:    char_u  *line;
                   1075:    FILE    *fp;
1.2       downsj   1076:    int     forceit;
1.1       downsj   1077: {
                   1078:    int     eof;
                   1079:
1.2       downsj   1080:    prepare_viminfo_history(forceit ? 9999 : 0);
1.1       downsj   1081:    eof = vim_fgets(line, LSIZE, fp);
                   1082:    while (!eof && line[0] != '>')
                   1083:    {
                   1084:        switch (line[0])
                   1085:        {
                   1086:            case NUL:
                   1087:            case '\r':
                   1088:            case '\n':
                   1089:            case '#':       /* A comment */
                   1090:                eof = vim_fgets(line, LSIZE, fp);
                   1091:                break;
                   1092:            case '"':
1.2       downsj   1093:                eof = read_viminfo_register(line, fp, forceit);
1.1       downsj   1094:                break;
                   1095:            case '/':       /* Search string */
                   1096:            case '&':       /* Substitute search string */
                   1097:            case '~':       /* Last search string, followed by '/' or '&' */
1.2       downsj   1098:                eof = read_viminfo_search_pattern(line, fp, forceit);
1.1       downsj   1099:                break;
                   1100:            case '$':
1.2       downsj   1101:                eof = read_viminfo_sub_string(line, fp, forceit);
1.1       downsj   1102:                break;
                   1103:            case ':':
                   1104:            case '?':
                   1105:                eof = read_viminfo_history(line, fp);
                   1106:                break;
                   1107:            case '\'':
                   1108:                /* How do we have a file mark when the file is not in the
                   1109:                 * buffer list?
                   1110:                 */
1.2       downsj   1111:                eof = read_viminfo_filemark(line, fp, forceit);
1.1       downsj   1112:                break;
                   1113: #if 0
                   1114:            case '+':
                   1115:                /* eg: "+40 /path/dir file", for running vim with no args */
                   1116:                eof = vim_fgets(line, LSIZE, fp);
                   1117:                break;
                   1118: #endif
                   1119:            default:
1.2       downsj   1120:                if (viminfo_error("Illegal starting char", line))
                   1121:                    eof = TRUE;
                   1122:                else
                   1123:                    eof = vim_fgets(line, LSIZE, fp);
1.1       downsj   1124:                break;
                   1125:        }
                   1126:    }
                   1127:    finish_viminfo_history();
                   1128:    return eof;
                   1129: }
                   1130:
                   1131: /*
                   1132:  * check string read from viminfo file
                   1133:  * remove '\n' at the end of the line
                   1134:  * - replace CTRL-V CTRL-V with CTRL-V
                   1135:  * - replace CTRL-V 'n'    with '\n'
                   1136:  */
                   1137:    void
                   1138: viminfo_readstring(p)
                   1139:    char_u      *p;
                   1140: {
                   1141:    while (*p != NUL && *p != '\n')
                   1142:    {
                   1143:        if (*p == Ctrl('V'))
                   1144:        {
                   1145:            if (p[1] == 'n')
                   1146:                p[0] = '\n';
                   1147:            vim_memmove(p + 1, p + 2, STRLEN(p));
                   1148:        }
                   1149:        ++p;
                   1150:    }
                   1151:    *p = NUL;
                   1152: }
                   1153:
                   1154: /*
                   1155:  * write string to viminfo file
                   1156:  * - replace CTRL-V with CTRL-V CTRL-V
                   1157:  * - replace '\n'   with CTRL-V 'n'
                   1158:  * - add a '\n' at the end
                   1159:  */
                   1160:    void
                   1161: viminfo_writestring(fd, p)
                   1162:    FILE    *fd;
                   1163:    char_u  *p;
                   1164: {
                   1165:    register int    c;
                   1166:
                   1167:    while ((c = *p++) != NUL)
                   1168:    {
                   1169:        if (c == Ctrl('V') || c == '\n')
                   1170:        {
                   1171:            putc(Ctrl('V'), fd);
                   1172:            if (c == '\n')
                   1173:                c = 'n';
                   1174:        }
                   1175:        putc(c, fd);
                   1176:    }
                   1177:    putc('\n', fd);
                   1178: }
                   1179: #endif /* VIMINFO */
                   1180:
                   1181: /*
                   1182:  * Implementation of ":fixdel", also used by get_stty().
                   1183:  *  <BS>    resulting <Del>
                   1184:  *   ^?        ^H
                   1185:  * not ^?      ^?
                   1186:  */
                   1187:    void
                   1188: do_fixdel()
                   1189: {
                   1190:    char_u  *p;
                   1191:
                   1192:    p = find_termcode((char_u *)"kb");
                   1193:    add_termcode((char_u *)"kD", p != NULL && *p == 0x7f ?
                   1194:                                         (char_u *)"\010" : (char_u *)"\177");
                   1195: }
                   1196:
1.3     ! downsj   1197:    static void
        !          1198: print_line_no_prefix(lnum, use_number)
1.1       downsj   1199:    linenr_t    lnum;
                   1200:    int         use_number;
                   1201: {
                   1202:    char_u      numbuf[20];
                   1203:
                   1204:    if (curwin->w_p_nu || use_number)
                   1205:    {
                   1206:        sprintf((char *)numbuf, "%7ld ", (long)lnum);
                   1207:        set_highlight('n');     /* Highlight line numbers */
                   1208:        start_highlight();
                   1209:        msg_outstr(numbuf);
                   1210:        stop_highlight();
                   1211:    }
                   1212:    msg_prt_line(ml_get(lnum));
                   1213: }
                   1214:
1.3     ! downsj   1215:     void
        !          1216: print_line(lnum, use_number)
        !          1217:    linenr_t    lnum;
        !          1218:    int         use_number;
        !          1219: {
        !          1220:    msg_outchar('\n');
        !          1221:    print_line_no_prefix (lnum, use_number);
        !          1222: }
        !          1223:
        !          1224:     void
        !          1225: print_line_cr(lnum, use_number)
        !          1226:    linenr_t    lnum;
        !          1227:    int         use_number;
        !          1228: {
        !          1229:    msg_outchar('\r');
        !          1230:    print_line_no_prefix (lnum, use_number);
        !          1231: }
        !          1232:
1.1       downsj   1233: /*
1.2       downsj   1234:  * Implementation of ":file[!] [fname]".
1.1       downsj   1235:  */
                   1236:    void
                   1237: do_file(arg, forceit)
                   1238:    char_u  *arg;
                   1239:    int     forceit;
                   1240: {
                   1241:    char_u      *fname, *sfname;
                   1242:    BUF         *buf;
                   1243:
                   1244:    if (*arg != NUL)
                   1245:    {
                   1246:        /*
                   1247:         * The name of the current buffer will be changed.
                   1248:         * A new buffer entry needs to be made to hold the old
                   1249:         * file name, which will become the alternate file name.
                   1250:         */
                   1251:        fname = curbuf->b_filename;
                   1252:        sfname = curbuf->b_sfilename;
                   1253:        curbuf->b_filename = NULL;
                   1254:        curbuf->b_sfilename = NULL;
                   1255:        if (setfname(arg, NULL, TRUE) == FAIL)
                   1256:        {
                   1257:            curbuf->b_filename = fname;
                   1258:            curbuf->b_sfilename = sfname;
                   1259:            return;
                   1260:        }
                   1261:        curbuf->b_notedited = TRUE;
                   1262:        buf = buflist_new(fname, sfname, curwin->w_cursor.lnum, FALSE);
                   1263:        if (buf != NULL)
                   1264:            curwin->w_alt_fnum = buf->b_fnum;
                   1265:        vim_free(fname);
                   1266:        vim_free(sfname);
                   1267:    }
                   1268:    /* print full filename if :cd used */
                   1269:    fileinfo(did_cd, FALSE, forceit);
1.3     ! downsj   1270: }
        !          1271:
        !          1272: /*
        !          1273:  * do the Ex mode :insert and :append commands
        !          1274:  */
        !          1275:
        !          1276: void
        !          1277: ex_insert (int before, linenr_t whatline)
        !          1278: {
        !          1279:    /* put the cursor somewhere sane if we insert nothing */
        !          1280:
        !          1281:    if (whatline > curbuf->b_ml.ml_line_count) {
        !          1282:        curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          1283:    } else {
        !          1284:        curwin->w_cursor.lnum = whatline;
        !          1285:    }
        !          1286:
        !          1287:    while (1) {
        !          1288:        char_u *theline;
        !          1289:
        !          1290:        if (((theline = getcmdline (' ', 1L)) == 0) ||
        !          1291:            ((theline[0] == '.') && (theline[1] == 0))) {
        !          1292:            break;
        !          1293:        }
        !          1294:
        !          1295:        if (before) {
        !          1296:            mark_adjust (whatline, MAXLNUM, 1, 0L);
        !          1297:            ml_append (whatline - 1, theline, (colnr_t) 0, FALSE);
        !          1298:            curwin->w_cursor.lnum = whatline;
        !          1299:        } else {
        !          1300:            mark_adjust (whatline + 1, MAXLNUM, 1, 0L);
        !          1301:            ml_append (whatline, theline, (colnr_t) 0, FALSE);
        !          1302:            curwin->w_cursor.lnum = whatline + 1;
        !          1303:        }
        !          1304:
        !          1305:        vim_free (theline);
        !          1306:        whatline++;
        !          1307:    }
        !          1308:
        !          1309:    CHANGED;
        !          1310:    beginline (MAYBE);
        !          1311:    updateScreen (NOT_VALID);
        !          1312: }
        !          1313:
        !          1314: /*
        !          1315:  * do the Ex mode :change command
        !          1316:  */
        !          1317:
        !          1318: void
        !          1319: ex_change (linenr_t start, linenr_t end)
        !          1320: {
        !          1321:    while (end >= start) {
        !          1322:        ml_delete (start, FALSE);
        !          1323:        end--;
        !          1324:    }
        !          1325:
        !          1326:    ex_insert (TRUE, start);
        !          1327: }
        !          1328:
        !          1329: void
        !          1330: ex_z (linenr_t line, char_u *arg)
        !          1331: {
        !          1332:    char_u *x;
        !          1333:    int bigness = curwin->w_height - 3;
        !          1334:    char_u kind;
        !          1335:    int minus = 0;
        !          1336:    linenr_t start, end, curs, i;
        !          1337:
        !          1338:    if (arg == 0) { /* is this possible?  I don't remember */
        !          1339:        arg = "";
        !          1340:    }
        !          1341:
        !          1342:    if (bigness < 1) {
        !          1343:        bigness = 1;
        !          1344:    }
        !          1345:
        !          1346:    x = arg;
        !          1347:    if (*x == '-' || *x == '+' || *x == '=' || *x == '^' || *x == '.') x++;
        !          1348:
        !          1349:    if (*x != 0) {
        !          1350:        if (!isdigit (*x)) {
        !          1351:            EMSG ("non-numeric argument to :z");
        !          1352:            return;
        !          1353:        } else {
        !          1354:            bigness = atoi (x);
        !          1355:        }
        !          1356:    }
        !          1357:
        !          1358:    kind = *arg;
        !          1359:
        !          1360:    switch (kind) {
        !          1361:        case '-':
        !          1362:            start = line - bigness;
        !          1363:            end = line;
        !          1364:            curs = line;
        !          1365:            break;
        !          1366:
        !          1367:        case '=':
        !          1368:            start = line - bigness / 2 + 1;
        !          1369:            end = line + bigness / 2 - 1;
        !          1370:            curs = line;
        !          1371:            minus = 1;
        !          1372:            break;
        !          1373:
        !          1374:        case '^':
        !          1375:            start = line - bigness * 2;
        !          1376:            end = line - bigness;
        !          1377:            curs = line - bigness;
        !          1378:            break;
        !          1379:
        !          1380:        case '.':
        !          1381:            start = line - bigness / 2;
        !          1382:            end = line + bigness / 2;
        !          1383:            curs = end;
        !          1384:            break;
        !          1385:
        !          1386:        default:  /* '+' */
        !          1387:            start = line;
        !          1388:            end = line + bigness;
        !          1389:            curs = end;
        !          1390:            break;
        !          1391:    }
        !          1392:
        !          1393:    if (start < 1) {
        !          1394:        start = 1;
        !          1395:    }
        !          1396:
        !          1397:    if (end > curbuf->b_ml.ml_line_count) {
        !          1398:        end = curbuf->b_ml.ml_line_count;
        !          1399:    }
        !          1400:
        !          1401:    if (curs > curbuf->b_ml.ml_line_count) {
        !          1402:        curs = curbuf->b_ml.ml_line_count;
        !          1403:    }
        !          1404:
        !          1405:    for (i = start; i <= end; i++) {
        !          1406:        int j;
        !          1407:
        !          1408:        if (minus && (i == line)) {
        !          1409:            msg_outchar ('\n');
        !          1410:
        !          1411:            for (j = 1; j < Columns; j++) {
        !          1412:                msg_outchar ('-');
        !          1413:            }
        !          1414:        }
        !          1415:
        !          1416:        print_line (i, FALSE);
        !          1417:
        !          1418:        if (minus && (i == line)) {
        !          1419:            msg_outchar ('\n');
        !          1420:
        !          1421:            for (j = 1; j < Columns; j++) {
        !          1422:                msg_outchar ('-');
        !          1423:            }
        !          1424:        }
        !          1425:    }
        !          1426:
        !          1427:    curwin->w_cursor.lnum = curs;
1.1       downsj   1428: }