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

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