home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume37 / vim / part21 < prev    next >
Text File  |  1993-04-24  |  51KB  |  2,448 lines

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v37i021:  vim - Vi IMitation editor v1.27, Part21/24
  4. Message-ID: <1993Apr25.013839.23354@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4614f0bcd8b4553a74a4ec0e21d64743
  6. Date: Sun, 25 Apr 1993 01:38:39 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mool@oce.nl (Bram Moolenaar)
  10. Posting-number: Volume 37, Issue 21
  11. Archive-name: vim/part21
  12. Environment: UNIX, AMIGA, MS-DOS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 21 (of 23)."
  21. # Contents:  vim/src/cmdline.c
  22. # Wrapped by mool@oce-rd2 on Mon Apr 19 15:50:13 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'vim/src/cmdline.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'vim/src/cmdline.c'\"
  26. else
  27. echo shar: Extracting \"'vim/src/cmdline.c'\" \(46721 characters\)
  28. sed "s/^X//" >'vim/src/cmdline.c' <<'END_OF_FILE'
  29. X/* vi:ts=4:sw=4
  30. X *
  31. X * VIM - Vi IMitation
  32. X *
  33. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  34. X *                            Tim Thompson            twitch!tjt
  35. X *                            Tony Andrews            onecom!wldrdg!tony 
  36. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  37. X */
  38. X
  39. X/*
  40. X * cmdline.c: functions for reading in the command line and executing it
  41. X */
  42. X
  43. X#include "vim.h"
  44. X#include "globals.h"
  45. X#include "proto.h"
  46. X#include "param.h"
  47. X#include "cmdtab.h"
  48. X#include "ops.h"            /* included because we call functions in ops.c */
  49. X#include "fcntl.h"            /* for chdir() */
  50. X
  51. X#ifdef LATTICE
  52. X# define mktemp(a)    tmpnam(a)
  53. X#endif
  54. X
  55. X/*
  56. X * the history list of alternate files
  57. X */
  58. X#define NUMALTFILES 20
  59. X
  60. Xstatic char    *altfiles[NUMALTFILES];    /* alternate files */
  61. Xstatic linenr_t altlnum[NUMALTFILES];    /* line # in alternate file */
  62. Xstatic linenr_t doecmdlnum = 0;            /* line # in new file for doecmd() */
  63. X
  64. X/*
  65. X * variables shared between getcmdline() and redrawcmdline()
  66. X */
  67. Xstatic int         cmdlen;        /* number of chars on command line */
  68. Xstatic int         cmdpos;        /* current cursor position */
  69. Xstatic int         cmdslen;        /* lenght of command line on screen */
  70. Xstatic int         cmdspos;        /* cursor position on screen */
  71. Xstatic int         cmdredraw;     /* max. number of lines of the command - 1 */
  72. Xstatic int         cmdfirstc;     /* ':', '/' or '?' */
  73. Xstatic u_char    *cmdbuff;        /* pointer to command line buffer */
  74. X
  75. X/*
  76. X * The next two variables contain the bounds of any range given in a command.
  77. X * They are set by docmdline().
  78. X */
  79. Xstatic linenr_t     line1, line2;
  80. Xstatic int            forceit;
  81. Xstatic int            regname;
  82. X
  83. Xstatic void        cmdchecklen __ARGS((void));
  84. Xstatic void        cursorcmd __ARGS((void));
  85. Xstatic u_char    *DoOneCmd __ARGS((u_char *));
  86. Xstatic void        dobang __ARGS((int, u_char *));
  87. Xstatic int        autowrite __ARGS((void));
  88. Xstatic int        dowrite __ARGS((u_char *, int));
  89. Xstatic int        doecmd __ARGS((char *));
  90. Xstatic void        doshell __ARGS((char *));
  91. Xstatic void        dofilter __ARGS((u_char *, int, int));
  92. Xstatic int        check_readonly __ARGS((void));
  93. Xstatic int        check_changed __ARGS((int));
  94. Xstatic int        check_fname __ARGS((void));
  95. Xstatic int        check_more __ARGS((void));
  96. Xstatic void        setaltfname __ARGS((char *, linenr_t, int));
  97. X#ifdef WILD_CARDS
  98. Xstatic char        *ExpandOne __ARGS((u_char *, int, int));
  99. Xstatic void        showmatches __ARGS((char *, int));
  100. Xstatic char        *addstar __ARGS((char *, int));
  101. X#endif
  102. Xstatic linenr_t get_address __ARGS((u_char **));
  103. X
  104. Xextern char        *mktemp __ARGS((char *));
  105. X
  106. Xextern int global_busy, global_wait;    /* shared with csearch.c */
  107. X
  108. X/*
  109. X * variable shared with quickfix.c
  110. X */
  111. Xextern int qf_index;
  112. X
  113. X/*
  114. X * getcmdline() - accept a command line starting with ':', '!', '/', or '?'
  115. X *
  116. X * For searches the optional matching '?' or '/' is removed.
  117. X */
  118. X
  119. X    int
  120. Xgetcmdline(firstc, buff)
  121. X    int            firstc;     /* either ':', '/', or '?' */
  122. X    u_char        *buff;         /* buffer for command string */
  123. X{
  124. X    register u_char     c;
  125. X             int        nextc = 0;
  126. X    register int        i;
  127. X             int        retval;
  128. X             int        hiscnt;                /* current history line in use */
  129. X    static     char         **history = NULL;    /* history table */
  130. X    static     int        hislen = 0;         /* actual lengt of history table */
  131. X             int        newlen;                /* new length of history table */
  132. X    static     int        hisidx = -1;        /* last entered entry */
  133. X             char        **temp;
  134. X             int        j;
  135. X
  136. X#ifdef WILD_CARDS
  137. X             int        gotesc = FALSE;        /* TRUE when last char typed was <ESC> */
  138. X             char        *p1, *p2;
  139. X             int        oldlen;
  140. X             int        difflen;
  141. X             int        findex;
  142. X#endif
  143. X
  144. X
  145. X
  146. X/*
  147. X * set some variables for redrawcmd()
  148. X */
  149. X    cmdfirstc = firstc;
  150. X    cmdbuff = buff;
  151. X    cmdlen = cmdpos = 0;
  152. X    cmdslen = cmdspos = 1;
  153. X    cmdredraw = 0;
  154. X    State = CMDLINE;
  155. X    gotocmdline(TRUE, firstc);
  156. X
  157. X/*
  158. X * if size of history table changed, reallocate it
  159. X */
  160. X    newlen = p_hi;
  161. X    if (newlen != hislen)                        /* history length changed */
  162. X    {
  163. X        if (newlen)
  164. X            temp = (char **)alloc((int)(newlen * sizeof(char *)));
  165. X        else
  166. X            temp = NULL;
  167. X        if (newlen == 0 || temp != NULL)
  168. X        {
  169. X            if (newlen > hislen)            /* array becomes bigger */
  170. X            {
  171. X                for (i = 0; i <= hisidx; ++i)
  172. X                    temp[i] = history[i];
  173. X                j = i;
  174. X                for ( ; i <= newlen - (hislen - hisidx); ++i)
  175. X                    temp[i] = NULL;
  176. X                for ( ; j < hislen; ++i, ++j)
  177. X                    temp[i] = history[j];
  178. X            }
  179. X            else                            /* array becomes smaller */
  180. X            {
  181. X                j = hisidx;
  182. X                for (i = newlen - 1; ; --i)
  183. X                {
  184. X                    if (i >= 0)
  185. X                        temp[i] = history[j];    /* copy newest entries */
  186. X                    else
  187. X                        free(history[j]);        /* remove older entries */
  188. X                    if (--j < 0)
  189. X                        j = hislen - 1;
  190. X                    if (j == hisidx)
  191. X                        break;
  192. X                }
  193. X                hisidx = newlen - 1;
  194. X            }
  195. X            free(history);
  196. X            history = temp;
  197. X            hislen = newlen;
  198. X        }
  199. X    }
  200. X    hiscnt = hislen;            /* set hiscnt to impossible history value */
  201. X
  202. X    /* collect the command string, handling '\b', @ and much more */
  203. X    for (;;)
  204. X    {
  205. X        cursorcmd();    /* set the cursor on the right spot */
  206. X        if (nextc)        /* character remaining from CTRL-V */
  207. X        {
  208. X            c = nextc;
  209. X            nextc = 0;
  210. X        }
  211. X        else
  212. X            c = vgetc();
  213. X
  214. X#ifdef WILD_CARDS
  215. X        if (c != ESC && c != Ctrl('N') && c != Ctrl('P') && gotesc)
  216. X        {
  217. X            (void)ExpandOne(NULL, FALSE, -2);    /* may free expanded file names */
  218. X            gotesc = FALSE;
  219. X        }
  220. X#endif
  221. X
  222. X        if (c == '\n' || c == '\r')
  223. X        {
  224. X                outchar('\r');
  225. X                flushbuf();
  226. X                break;
  227. X        }
  228. X
  229. X        switch (c)
  230. X        {
  231. X        case BS:
  232. X        case DEL:
  233. X                /*
  234. X                 * delete current character is the same as backspace on next
  235. X                 * character, except at end of line
  236. X                 */
  237. X                if (c == DEL && cmdpos != cmdlen)
  238. X                    ++cmdpos;
  239. X                if (cmdpos > 0)
  240. X                {
  241. X                    --cmdpos;
  242. X                    --cmdlen;
  243. X                    for (i = cmdpos; i < cmdlen; ++i)
  244. X                        buff[i] = buff[i + 1];
  245. X                    redrawcmd();
  246. X                }
  247. X                else if (cmdlen == 0)
  248. X                {
  249. X                    retval = FALSE;
  250. X                    msg("");
  251. X                    goto returncmd;     /* back to cmd mode */
  252. X                }
  253. X                continue;
  254. X
  255. X/*        case '@':    only in very old vi */
  256. X        case Ctrl('U'):
  257. Xclearline:
  258. X                cmdpos = 0;
  259. X                cmdlen = 0;
  260. X                cmdslen = 1;
  261. X                cmdspos = 1;
  262. X                gotocmdline(TRUE, firstc);
  263. X                continue;
  264. X
  265. X        case ESC:
  266. X#ifndef WILD_CARDS
  267. X                retval = FALSE;
  268. X                msg("");
  269. X                goto returncmd;     /* back to cmd mode */
  270. X#else
  271. X            /*
  272. X             * hitting <ESC> twice means: abandon command line
  273. X             */
  274. X            if (gotesc)
  275. X            {
  276. X                retval = FALSE;
  277. X                msg("");
  278. X                goto returncmd;     /* back to cmd mode */
  279. X            }
  280. X            gotesc = TRUE;
  281. X            findex = 0;
  282. X
  283. Xdoexpand:
  284. X            outstr("...");        /* show that we are busy */
  285. X            flushbuf();
  286. X            i = cmdslen;
  287. X            cmdslen = cmdpos + 4;
  288. X            cmdchecklen();        /* check if we caused a scrollup */
  289. X            cmdslen = i;
  290. X
  291. X            for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  292. X                ;
  293. X            oldlen = cmdpos - i;
  294. X
  295. X                /* add a "*" to the file name and expand it */
  296. X            if ((p1 = addstar((char *)&buff[i], oldlen)) != NULL)
  297. X            {
  298. X                if ((p2 = ExpandOne((u_char *)p1, FALSE, findex)) != NULL)
  299. X                {
  300. X                    if (cmdlen + (difflen = strlen(p2) - oldlen) > CMDBUFFSIZE - 4)
  301. X                        emsg(e_toolong);
  302. X                    else
  303. X                    {
  304. X                        strncpy((char *)&buff[cmdpos + difflen], (char *)&buff[cmdpos], (size_t)(cmdlen - cmdpos));
  305. X                        strncpy((char *)&buff[i], p2, strlen(p2));
  306. X                        cmdlen += difflen;
  307. X                        cmdpos += difflen;
  308. X                    }
  309. X                    free(p2);
  310. X                }
  311. X                free(p1);
  312. X            }
  313. X            redrawcmd();
  314. X            continue;
  315. X
  316. X        case Ctrl('D'):
  317. X            {
  318. X                for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  319. X                        ;
  320. X                showmatches((char *)&buff[i], cmdpos - i);
  321. X
  322. X                redrawcmd();
  323. X                continue;
  324. X            }
  325. X#endif
  326. X
  327. X        case K_RARROW:
  328. X        case K_SRARROW:
  329. X                do
  330. X                {
  331. X                        if (cmdpos >= cmdlen)
  332. X                                break;
  333. X                        cmdspos += charsize(buff[cmdpos]);
  334. X                        ++cmdpos;
  335. X                }
  336. X                while (c == K_SRARROW && buff[cmdpos] != ' ');
  337. X                continue;
  338. X
  339. X        case K_LARROW:
  340. X        case K_SLARROW:
  341. X                do
  342. X                {
  343. X                        if (cmdpos <= 0)
  344. X                                break;
  345. X                        --cmdpos;
  346. X                        cmdspos -= charsize(buff[cmdpos]);
  347. X                }
  348. X                while (c == K_SLARROW && buff[cmdpos - 1] != ' ');
  349. X                continue;
  350. X
  351. X        case Ctrl('N'):        /* next match */
  352. X        case Ctrl('P'):        /* previous match */
  353. X#ifdef WILD_CARDS
  354. X                if (gotesc)
  355. X                {
  356. X                    findex = (c == Ctrl('P')) ? 2 : 1;
  357. X                    goto doexpand;
  358. X                }
  359. X#endif
  360. X        case K_UARROW:
  361. X        case K_DARROW:
  362. X                if (hislen == 0)        /* no history */
  363. X                    continue;
  364. X
  365. X                i = hiscnt;
  366. X                if (c == K_UARROW || c == Ctrl('P'))
  367. X                {
  368. X                    if (hiscnt == hislen)
  369. X                        hiscnt = hisidx;
  370. X                    else if (hiscnt == 0 && hisidx != hislen - 1)
  371. X                        hiscnt = hislen - 1;
  372. X                    else if (hiscnt != hisidx + 1)
  373. X                        --hiscnt;
  374. X                }
  375. X                else
  376. X                {
  377. X                    if (hiscnt == hisidx)    /* on last entry, clear the line */
  378. X                    {
  379. X                        hiscnt = hislen;
  380. X                        goto clearline;
  381. X                    }
  382. X                    if (hiscnt == hislen)    /* not on a history line, nothing to do */
  383. X                        continue;
  384. X                    if (hiscnt == hislen - 1)
  385. X                        hiscnt = 0;
  386. X                    else
  387. X                        ++hiscnt;
  388. X                }
  389. X                if (hiscnt < 0 || history[hiscnt] == NULL)
  390. X                    hiscnt = i;
  391. X                else
  392. X                {
  393. X                    strcpy((char *)buff, history[hiscnt]);
  394. X                    cmdpos = cmdlen = strlen((char *)buff);
  395. X                    redrawcmd();
  396. X                }
  397. X                continue;
  398. X
  399. X        case Ctrl('V'):
  400. X                outchar('^');
  401. X                outtrans((char *)(buff + cmdpos), cmdlen - cmdpos);
  402. X                ++cmdslen;
  403. X                cmdchecklen();
  404. X                --cmdslen;
  405. X                cursorcmd();
  406. X                c = get_literal(&nextc);    /* get next (two) character(s) */
  407. X        }
  408. X
  409. X        /* we come here if we have entered a normal character */
  410. X        if (cmdlen < CMDBUFFSIZE - 2)
  411. X        {
  412. X                for (i = cmdlen++; i > cmdpos; --i)
  413. X                        buff[i] = buff[i - 1];
  414. X                buff[cmdpos] = c;
  415. X                outtrans((char *)(buff + cmdpos), cmdlen - cmdpos);
  416. X                ++cmdpos;
  417. X                i = charsize(c);
  418. X                cmdslen += i;
  419. X                cmdspos += i;
  420. X        }
  421. X        cmdchecklen();
  422. X    }
  423. X    buff[cmdlen] = NUL;
  424. X
  425. X    if (hislen != 0)
  426. X    {
  427. X        if (++hisidx == hislen)
  428. X            hisidx = 0;
  429. X        free(history[hisidx]);
  430. X        history[hisidx] = strsave((char *)buff);
  431. X    }
  432. X    retval = TRUE;
  433. X
  434. Xreturncmd:
  435. X    if (cmdredraw)
  436. X        updateScreen(CLEAR);
  437. X    State = NORMAL;
  438. X    script_winsize_pp();
  439. X    return retval;
  440. X}
  441. X
  442. X/*
  443. X * Check if the command line spans more than one screen line.
  444. X * The maximum number of lines is remembered.
  445. X */
  446. X    static void
  447. Xcmdchecklen()
  448. X{
  449. X        if (cmdslen / Columns > cmdredraw)
  450. X                cmdredraw = cmdslen / Columns;
  451. X}
  452. X
  453. X/*
  454. X * this fuction is called when the screen size changes
  455. X */
  456. X    void
  457. Xredrawcmdline()
  458. X{
  459. X        cmdredraw = 0;
  460. X        redrawcmd();
  461. X        cursorcmd();
  462. X}
  463. X
  464. X/*
  465. X * Redraw what is currently on the command line.
  466. X */
  467. X    void
  468. Xredrawcmd()
  469. X{
  470. X    register int i;
  471. X
  472. X    windgoto((int)Rows - 1 - cmdredraw, 0);
  473. X    outchar(cmdfirstc);
  474. X    cmdslen = 1;
  475. X    cmdspos = 1;
  476. X    outtrans((char *)cmdbuff, cmdlen);
  477. X    for (i = 0; i < cmdlen; )
  478. X    {
  479. X        cmdslen += charsize(cmdbuff[i]);
  480. X        if (++i == cmdpos)
  481. X                cmdspos = cmdslen;
  482. X    }
  483. X    for (i = (cmdredraw + 1) * Columns - cmdslen; --i > 0; )
  484. X        outchar(' ');
  485. X    cmdchecklen();
  486. X}
  487. X
  488. X    static void
  489. Xcursorcmd()
  490. X{
  491. X    windgoto((int)Rows - 1 - cmdredraw + (cmdspos / (int)Columns), cmdspos % (int)Columns);
  492. X}
  493. X
  494. X/*
  495. X * docmdline(): execute an Ex command line
  496. X *
  497. X * 1. If no line given, get one.
  498. X * 2. Split up in parts separated with '|'.
  499. X *
  500. X * This function may be called recursively!
  501. X */
  502. X    void
  503. Xdocmdline(cmdline)
  504. X    u_char        *cmdline;
  505. X{
  506. X    u_char        buff[CMDBUFFSIZE];        /* command line */
  507. X    u_char        *nextcomm;
  508. X
  509. X/*
  510. X * 1. If no line given: get one.
  511. X */
  512. X    if (cmdline == NULL)
  513. X    {
  514. X        if (!getcmdline(':', buff))
  515. X                return;
  516. X    }
  517. X    else
  518. X    {
  519. X        if (strlen((char *)cmdline) > (size_t)(CMDBUFFSIZE - 2))
  520. X        {
  521. X                emsg(e_toolong);
  522. X                return;
  523. X        }
  524. X        /* Make a copy of the command so we can mess with it. */
  525. X        strcpy((char *)buff, (char *)cmdline);
  526. X    }
  527. X
  528. X/*
  529. X * 2. Loop for each '|' separated command.
  530. X *    DoOneCmd will set nextcommand to NULL if there is no trailing '|'.
  531. X */
  532. X    for (;;)
  533. X    {
  534. X        nextcomm = DoOneCmd(buff);
  535. X        if (nextcomm == NULL)
  536. X            break;
  537. X        strcpy((char *)buff, (char *)nextcomm);
  538. X    }
  539. X}
  540. X
  541. X/*
  542. X * Execute one Ex command.
  543. X *
  544. X * 2. skip comment lines and leading space
  545. X * 3. parse range
  546. X * 4. parse command
  547. X * 5. parse arguments
  548. X * 6. switch on command name
  549. X *
  550. X * This function may be called recursively!
  551. X */
  552. X    static u_char *
  553. XDoOneCmd(buff)
  554. X    u_char *buff;
  555. X{
  556. X    u_char                cmdbuf[CMDBUFFSIZE];    /* for '%' and '#' expansion */
  557. X    u_char                c;
  558. X    register u_char        *p;
  559. X    char                *q;
  560. X    u_char                *cmd, *arg;
  561. X    int                 i;
  562. X    int                    cmdidx;
  563. X    int                    argt;
  564. X    register linenr_t    lnum;
  565. X    long                n;
  566. X    int                    addr_count;    /* number of address specifications */
  567. X    FPOS                pos;
  568. X    int                    append = FALSE;            /* write with append */
  569. X    u_char                *nextcomm;
  570. X
  571. X
  572. X/*
  573. X * 2. skip comment lines and leading space, colons or bars
  574. X */
  575. X    for (cmd = buff; *cmd && strchr(" \t:|", *cmd) != NULL; cmd++)
  576. X        ;
  577. X
  578. X    nextcomm = NULL;        /* default: no next command */
  579. X    if (strchr("#\"", *cmd) != NULL)    /* ignore comment and empty lines */
  580. X        goto doend;
  581. X
  582. X/*
  583. X * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  584. X *
  585. X * where 'addr' is:
  586. X *
  587. X * %          (entire file)
  588. X * $  [+-NUM]
  589. X * 'x [+-NUM] (where x denotes a currently defined mark)
  590. X * .  [+-NUM]
  591. X * [+-NUM]..
  592. X * NUM
  593. X *
  594. X * The cmd pointer is updated to point to the first character following the
  595. X * range spec. If an initial address is found, but no second, the upper bound
  596. X * is equal to the lower.
  597. X */
  598. X
  599. X    addr_count = 0;
  600. X    --cmd;
  601. X    do {
  602. X        ++cmd;                            /* skip ',' or ';' */
  603. X        line1 = line2;
  604. X        line2 = Curpos.lnum;            /* default is current line number */
  605. X        skipspace((char **)&cmd);
  606. X        lnum = get_address(&cmd);
  607. X        if (lnum == INVLNUM)
  608. X        {
  609. X            if (*cmd == '%')            /* '%' - all lines */
  610. X            {
  611. X                ++cmd;
  612. X                line1 = 1;
  613. X                line2 = line_count;
  614. X                ++addr_count;
  615. X            }
  616. X        } else
  617. X            line2 = lnum;
  618. X        addr_count++;
  619. X
  620. X        if (*cmd == ';')
  621. X        {
  622. X            if (line2 == 0)
  623. X                Curpos.lnum = 1;
  624. X            else
  625. X                Curpos.lnum = line2;
  626. X        }
  627. X    } while (*cmd == ',' || *cmd == ';');
  628. X
  629. X    /* One address given: set start and end lines */
  630. X    if (addr_count == 1) {
  631. X        line1 = line2;
  632. X        /* ... but only implicit: really no address given */
  633. X        if (lnum == INVLNUM) {
  634. X            addr_count = 0;
  635. X        }
  636. X    }
  637. X
  638. X    if (line1 > line2 || line2 > line_count)
  639. X    {
  640. X        emsg(e_invrange);
  641. X        goto doend;
  642. X    }
  643. X
  644. X/*
  645. X * 4. parse command
  646. X */
  647. X
  648. X    skipspace((char **)&cmd);
  649. X
  650. X    /*
  651. X     * If we got a line, but no command, then go to the line.
  652. X     */
  653. X    if (*cmd == NUL || *cmd == '"' || (*cmd == '|' && (nextcomm = cmd) != NULL))
  654. X    {
  655. X        if (addr_count != 0)
  656. X        {
  657. X            if (line2 == 0)
  658. X                Curpos.lnum = 1;
  659. X            else
  660. X                Curpos.lnum = line2;
  661. X            Curpos.col = 0;
  662. X            cursupdate();
  663. X        }
  664. X        goto doend;
  665. X    }
  666. X
  667. X    /*
  668. X     * isolate the command and search for it in the command table
  669. X     */
  670. X    p = cmd;
  671. X    if (*cmd != 'k')
  672. X        while (isalpha(*p))
  673. X            ++p;
  674. X    if (p == cmd && strchr("@!=><&k", *p) != NULL)    /* non-alpha or 'k' command */
  675. X        ++p;
  676. X    i = p - cmd;
  677. X
  678. X    for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
  679. X        if (strncmp(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
  680. X            break;
  681. X
  682. X    if (i == 0 || cmdidx == CMD_SIZE)
  683. X    {
  684. X        emsg(e_invcmd);
  685. X        goto doend;
  686. X    }
  687. X
  688. X    if (*p == '!')                    /* forced commands */
  689. X    {
  690. X        ++p;
  691. X        forceit = TRUE;
  692. X    }
  693. X    else
  694. X        forceit = FALSE;
  695. X
  696. X/*
  697. X * 5. parse arguments
  698. X */
  699. X    argt = cmdnames[cmdidx].cmd_argt;
  700. X
  701. X    if (!(argt & RANGE) && addr_count)
  702. X    {
  703. X        emsg(e_norange);
  704. X        goto doend;
  705. X    }
  706. X
  707. X    if (!(argt & ZEROR))            /* zero in range not allowed */
  708. X    {
  709. X        if (line1 == 0)
  710. X            line1 = 1;
  711. X        if (line2 == 0)
  712. X            line2 = 1;
  713. X    }
  714. X
  715. X    arg = p;                        /* remember start of argument */
  716. X    skipspace((char **)&arg);
  717. X
  718. X    if ((argt & NEEDARG) && *arg == NUL)
  719. X    {
  720. X        emsg(e_argreq);
  721. X        goto doend;
  722. X    }
  723. X
  724. X    /*
  725. X     * check for '|' to separate commands and '"' to start comments
  726. X     */
  727. X    if (argt & TRLBAR)
  728. X    {
  729. X        while (*p)
  730. X        {
  731. X            if (*p == Ctrl('V'))
  732. X            {
  733. X                if (argt & USECTRLV)    /* skip the CTRL-V and next char */
  734. X                    ++p;
  735. X                else                    /* remove CTRL-V and skip next char */
  736. X                    strcpy((char *)p, (char *)p + 1);
  737. X            }
  738. X            else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|')
  739. X            {                        /* remove the backslash or ^V */
  740. X                if (*(p - 1) == '\\')
  741. X                {
  742. X                    strcpy((char *)p - 1, (char *)p);
  743. X                    --p;
  744. X                }
  745. X                else
  746. X                {
  747. X                    if (*p == '|')
  748. X                        nextcomm = p + 1;
  749. X                    *p = NUL;
  750. X                    break;
  751. X                }
  752. X            }
  753. X            ++p;
  754. X        }
  755. X    }
  756. X
  757. X    if ((argt & DFLALL) && addr_count == 0)
  758. X    {
  759. X        line1 = 1;
  760. X        line2 = line_count;
  761. X    }
  762. X
  763. X    regname = 0;
  764. X        /* accept numbered register only when no count allowed (:put) */
  765. X    if ((argt & REGSTR) && (isalpha(*arg) || *arg == '.' || (!(argt & COUNT) && isdigit(*arg))))
  766. X    {
  767. X        regname = *arg;
  768. X        ++arg;
  769. X        skipspace((char **)&arg);
  770. X    }
  771. X
  772. X    if ((argt & COUNT) && isdigit(*arg))
  773. X    {
  774. X        i = getdigits((char **)&arg);
  775. X        skipspace((char **)&arg);
  776. X        if (i <= 0)
  777. X        {
  778. X            emsg(e_zerocount);
  779. X            goto doend;
  780. X        }
  781. X        line1 = line2;
  782. X        line2 += i - 1;
  783. X    }
  784. X
  785. X    if (!(argt & EXTRA) && strchr("|\"#", *arg) == NULL)    /* no arguments allowed */
  786. X    {
  787. X        emsg(e_trailing);
  788. X        goto doend;
  789. X    }
  790. X
  791. X    if (cmdidx == CMD_write && *arg == '>' && *(arg + 1) == '>')    /* append */
  792. X    {
  793. X        arg += 2;
  794. X        skipspace((char **)&arg);
  795. X        append = TRUE;
  796. X    }
  797. X
  798. X    /*
  799. X     * change '%' to Filename, '#' to altfile
  800. X     */
  801. X    if (argt & XFILE)
  802. X    {
  803. X        for (p = arg; *p; ++p)
  804. X        {
  805. X            c = *p;
  806. X            if (c != '%' && c != '#')    /* nothing to expand */
  807. X                continue;
  808. X            if (*(p - 1) == '\\')        /* remove escaped char */
  809. X            {
  810. X                strcpy((char *)p - 1, (char *)p);
  811. X                --p;
  812. X                continue;
  813. X            }
  814. X
  815. X            n = 1;                /* length of what we expand */
  816. X            if (c == '%')
  817. X            {
  818. X                if (check_fname())
  819. X                    goto doend;
  820. X                q = Filename;
  821. X            }
  822. X            else
  823. X            {
  824. X                q = (char *)p + 1;
  825. X                i = getdigits(&q);
  826. X                n = q - (char *)p;
  827. X
  828. X                if (i >= NUMALTFILES || altfiles[i] == NULL)
  829. X                {
  830. X                        emsg(e_noalt);
  831. X                        goto doend;
  832. X                }
  833. X                doecmdlnum = altlnum[i];
  834. X                q = altfiles[i];
  835. X            }
  836. X            i = strlen((char *)arg) + strlen(q) + 3;
  837. X            if (nextcomm)
  838. X                i += strlen((char *)nextcomm);
  839. X            if (i > CMDBUFFSIZE)
  840. X            {
  841. X                emsg(e_toolong);
  842. X                goto doend;
  843. X            }
  844. X            /*
  845. X             * we built the new argument in cmdbuf[], then copy it back to buff[]
  846. X             */
  847. X            *p = NUL;
  848. X            strcpy((char *)cmdbuf, (char *)arg);
  849. X            strcat((char *)cmdbuf, q);
  850. X            i = strlen((char *)cmdbuf);
  851. X            strcat((char *)cmdbuf, (char *)p+n);
  852. X            p = buff + i - 1;
  853. X            if (nextcomm)
  854. X            {
  855. X                i = strlen((char *)cmdbuf) + 1;
  856. X                strcpy((char *)cmdbuf + i, (char *)nextcomm);
  857. X                nextcomm = buff + i;
  858. X            }
  859. X            strcpy((char *)buff, (char *)cmdbuf);
  860. X            arg = buff;
  861. X        }
  862. X#ifdef WILD_CARDS
  863. X        if (argt & NOSPC)        /* one file argument: expand wildcards */
  864. X        {
  865. X            if (has_wildcard((char *)arg))
  866. X            {
  867. X                if ((p = (u_char *)ExpandOne(arg, TRUE, -1)) == NULL)
  868. X                    goto doend;
  869. X                if (strlen((char *)p) + arg - buff < CMDBUFFSIZE - 2)
  870. X                    strcpy((char *)arg, (char *)p);
  871. X                else
  872. X                    emsg(e_toolong);
  873. X                free(p);
  874. X            }
  875. X        }
  876. X#endif
  877. X    }
  878. X
  879. X/*
  880. X * 6. switch on command name
  881. X */
  882. X    switch (cmdidx)
  883. X    {
  884. X        case CMD_quit:
  885. X                exiting = TRUE;
  886. X                settmode(0);        /* allows typeahead */
  887. X                if (check_changed(FALSE) || check_more())
  888. X                {
  889. X                    exiting = FALSE;
  890. X                    settmode(1);
  891. X                    break;
  892. X                }
  893. X                getout(0);
  894. X
  895. X        case CMD_stop:
  896. X                if (!forceit && Changed)
  897. X                    autowrite();
  898. X                gotocmdline(TRUE, NUL);
  899. X                flushbuf();
  900. X                mch_suspend();        /* call machine specific function */
  901. X                updateScreen(CLEAR);
  902. X                break;
  903. X
  904. X        case CMD_xit:
  905. X        case CMD_wq:
  906. X                exiting = TRUE;
  907. X                settmode(0);        /* allows typeahead */
  908. X                if (((cmdidx == CMD_wq || Changed) &&
  909. X                     (check_readonly() || !dowrite(arg, FALSE))) ||
  910. X                    check_more())
  911. X                {
  912. X                    exiting = FALSE;
  913. X                    settmode(1);
  914. X                    break;
  915. X                }
  916. X                getout(0);
  917. X
  918. X        case CMD_args:
  919. X                gotocmdline(TRUE, NUL);
  920. X                for (i = 0; i < numfiles; ++i)
  921. X                {
  922. X                    if (i == curfile)
  923. X                        outchar('[');
  924. X                    outstrn(files[i]);
  925. X                    if (i == curfile)
  926. X                        outchar(']');
  927. X                    outchar(' ');
  928. X                }
  929. X                outchar('\n');
  930. X                wait_return(TRUE);
  931. X                break;
  932. X
  933. X        case CMD_wnext:
  934. X                n = line2;
  935. X                line1 = 1;
  936. X                line2 = line_count;
  937. X                dowrite(arg, FALSE);
  938. X                line2 = n;
  939. X                arg = (u_char *)"";        /* no file list */
  940. X                /*FALLTHROUGH*/
  941. X
  942. X        case CMD_next:
  943. X                if (check_changed(TRUE))
  944. X                        break;
  945. X                if (*arg != NUL)        /* redefine file list */
  946. X                {
  947. X                    if (doarglist((char *)arg))
  948. X                        break;
  949. X                    i = 0;
  950. X                }
  951. X                else
  952. X                {
  953. X                    if (addr_count == 0)
  954. X                        i = curfile + 1;
  955. X                    else
  956. X                        i = curfile + line2;
  957. X                }
  958. X
  959. Xdonextfile:        if (i < 0 || i >= numfiles)
  960. X                {
  961. X                    emsg(e_nomore);
  962. X                    break;
  963. X                }
  964. X                if (check_changed(TRUE))
  965. X                        break;
  966. X                curfile = i;
  967. X                doecmd(files[curfile]);
  968. X                break;
  969. X
  970. X        case CMD_previous:
  971. X        case CMD_Next:
  972. X                if (addr_count == 0)
  973. X                    i = curfile - 1;
  974. X                else
  975. X                    i = curfile - line2;
  976. X                goto donextfile;
  977. X
  978. X        case CMD_rewind:
  979. X                i = 0;
  980. X                goto donextfile;
  981. X
  982. X        case CMD_write:
  983. X                if (*arg == '!')        /* input lines to shell command */
  984. X                    dofilter(arg + 1, TRUE, FALSE);
  985. X                else
  986. X                    dowrite(arg, append);
  987. X                break;
  988. X
  989. X        case CMD_edit:
  990. X        case CMD_ex:
  991. X        case CMD_visual:
  992. X                doecmd((char *)arg);
  993. X                break;
  994. X
  995. X        case CMD_file:
  996. X                if (*arg == NUL)
  997. X                    fileinfo();
  998. X                else
  999. X                {
  1000. X                    setfname((char *)arg);
  1001. X                    filemess(Filename, "");
  1002. X                    maketitle();
  1003. X                }
  1004. X                break;
  1005. X
  1006. X        case CMD_files:
  1007. X#ifdef AMIGA
  1008. X                settmode(0);            /* set cooked mode, so output can be halted */
  1009. X#endif
  1010. X                for (i = 0; i < NUMALTFILES; ++i)
  1011. X                {
  1012. X                    if (altfiles[i])
  1013. X                    {
  1014. X                        sprintf(IObuff, "%2d \"%s\" line %ld\n", i, altfiles[i], (long)altlnum[i]);
  1015. X                        outstrn(IObuff);
  1016. X                    }
  1017. X                    flushbuf();
  1018. X                }
  1019. X#ifdef AMIGA
  1020. X                settmode(1);
  1021. X#endif
  1022. X                wait_return(TRUE);
  1023. X                break;
  1024. X
  1025. X        case CMD_read:
  1026. X                if (forceit || (*arg == '!' && ++arg))
  1027. X                {
  1028. X                        dofilter(arg, FALSE, TRUE);            /* :r!cmd */
  1029. X                        break;
  1030. X                }
  1031. X                if (!u_save(line2, (linenr_t)(line2 + 1)))
  1032. X                        break;
  1033. X                if (readfile((char *)arg, line2, FALSE))
  1034. X                {
  1035. X                    emsg(e_notopen);
  1036. X                    break;
  1037. X                }
  1038. X                updateScreen(NOT_VALID);
  1039. X                CHANGED;
  1040. X                break;
  1041. X
  1042. X        case CMD_cd:
  1043. X        case CMD_chdir:
  1044. X                if (*arg == NUL)
  1045. X                {
  1046. X                    if (dirname(IObuff, IOSIZE))
  1047. X                        msg(IObuff);
  1048. X                    else
  1049. X                        emsg(e_unknown);
  1050. X                }
  1051. X                else
  1052. X                {
  1053. X                    if (chdir((char *)arg))
  1054. X                        emsg(e_failed);
  1055. X                }
  1056. X                break;
  1057. X
  1058. X        case CMD_equal:
  1059. X                smsg("line %ld", (long)line2);
  1060. X                break;
  1061. X
  1062. X        case CMD_list:
  1063. X                i = p_list;
  1064. X                p_list = 1;
  1065. X        case CMD_number:
  1066. X        case CMD_print:
  1067. X#ifdef AMIGA
  1068. X                settmode(0);            /* set cooked mode, so output can be halted */
  1069. X#endif
  1070. X                gotocmdline(TRUE, NUL);    /* clear command line */
  1071. X                n = 0;
  1072. X                for (;;)
  1073. X                {
  1074. X                    if (p_nu || cmdidx == CMD_number)
  1075. X                    {
  1076. X                        sprintf(IObuff, "%7ld ", (long)line1);
  1077. X                        outstrn(IObuff);
  1078. X                    }
  1079. X                    n += prt_line(nr2ptr(line1));
  1080. X                    if (++line1 > line2)
  1081. X                        break;
  1082. X                    outchar('\n');
  1083. X                    flushbuf();
  1084. X                    n = Columns;
  1085. X                }
  1086. X#ifdef AMIGA
  1087. X                settmode(1);
  1088. X#endif
  1089. X
  1090. X                if (cmdidx == CMD_list)
  1091. X                    p_list = i;
  1092. X
  1093. X                if (n >= Columns - (p_ru ? 22 : p_sc ? 12 : 0))
  1094. X                {
  1095. X                    outchar('\n');
  1096. X                    if (global_busy)
  1097. X                        global_wait = 1;
  1098. X                    else
  1099. X                        wait_return(TRUE);
  1100. X                }
  1101. X                break;
  1102. X
  1103. X        case CMD_shell:
  1104. X                doshell(NULL);
  1105. X                break;
  1106. X
  1107. X        case CMD_tag:
  1108. X                dotag((char *)arg, 0, addr_count ? (int)line2 : 1);
  1109. X                break;
  1110. X
  1111. X        case CMD_pop:
  1112. X                dotag("", 1, addr_count ? (int)line2 : 1);
  1113. X                break;
  1114. X
  1115. X        case CMD_tags:
  1116. X                dotags();
  1117. X                break;
  1118. X
  1119. X        case CMD_marks:
  1120. X                domarks();
  1121. X                break;
  1122. X
  1123. X        case CMD_jumps:
  1124. X                dojumps();
  1125. X                break;
  1126. X
  1127. X        case CMD_digraph:
  1128. X#ifdef DIGRAPHS
  1129. X                if (*arg)
  1130. X                    putdigraph((char *)arg);
  1131. X                else
  1132. X                    listdigraphs();
  1133. X#else
  1134. X                emsg("No digraphs in this version");
  1135. X#endif /* DIGRAPHS */
  1136. X                break;
  1137. X
  1138. X        case CMD_set:
  1139. X                doset((char *)arg);
  1140. X                break;
  1141. X
  1142. X        case CMD_map:
  1143. X        case CMD_noremap:
  1144. X                /*
  1145. X                 * If we are sourcing .exrc or .vimrc in current directory we
  1146. X                 * print the mappings for security reasons.
  1147. X                 */
  1148. X                if (secure)
  1149. X                {
  1150. X                    secure = 2;
  1151. X                    outtrans((char *)cmd, -1);
  1152. X                    outchar('\n');
  1153. X                }
  1154. X        case CMD_unmap:
  1155. X                switch (domap((*cmd == 'n') ? 2 : (*cmd == 'u'), (char *)arg,
  1156. X                                    forceit ? INSERT : NORMAL))
  1157. X                {
  1158. X                    case 1: emsg(e_invarg);
  1159. X                            break;
  1160. X                    case 2: emsg(e_nomap);
  1161. X                            break;
  1162. X                    case 3: emsg(e_ambmap);
  1163. X                            break;
  1164. X                }
  1165. X                break;
  1166. X
  1167. X        case CMD_display:
  1168. X                dodis();        /* display buffer contents */
  1169. X                break;
  1170. X
  1171. X        case CMD_help:
  1172. X                help();
  1173. X                break;
  1174. X
  1175. X        case CMD_version:
  1176. X                msg(longVersion);
  1177. X                break;
  1178. X
  1179. X        case CMD_winsize:
  1180. X                line1 = getdigits((char **)&arg);
  1181. X                skipspace((char **)&arg);
  1182. X                line2 = getdigits((char **)&arg);
  1183. X                set_winsize((int)line1, (int)line2, TRUE);
  1184. X                break;
  1185. X
  1186. X        case CMD_delete:
  1187. X        case CMD_yank:
  1188. X        case CMD_rshift:
  1189. X        case CMD_lshift:
  1190. X                yankbuffer = regname;
  1191. X                startop.lnum = line1;
  1192. X                endop.lnum = line2;
  1193. X                nlines = line2 - line1 + 1;
  1194. X                mtype = MLINE;
  1195. X                Curpos.lnum = line1;
  1196. X                switch (cmdidx)
  1197. X                {
  1198. X                case CMD_delete:
  1199. X                    dodelete();
  1200. X                    break;
  1201. X                case CMD_yank:
  1202. X                    doyank(FALSE);
  1203. X                    break;
  1204. X                case CMD_rshift:
  1205. X                    doshift(RSHIFT);
  1206. X                    break;
  1207. X                case CMD_lshift:
  1208. X                    doshift(LSHIFT);
  1209. X                    break;
  1210. X                }
  1211. X                break;
  1212. X
  1213. X        case CMD_put:
  1214. X                yankbuffer = regname;
  1215. X                Curpos.lnum = line2;
  1216. X                doput(forceit ? BACKWARD : FORWARD, -1L);
  1217. X                break;
  1218. X
  1219. X        case CMD_t:
  1220. X        case CMD_copy:        /* copy: first yank, then put */
  1221. X        case CMD_move:        /* move: first delete, then put */
  1222. X                n = get_address(&arg);
  1223. X                if (n == INVLNUM)
  1224. X                {
  1225. X                    emsg(e_invaddr);
  1226. X                    break;
  1227. X                }
  1228. X
  1229. X                if (cmdidx == CMD_move)
  1230. X                {
  1231. X                    if (n >= line1)
  1232. X                    {
  1233. X                        --n;
  1234. X                        Curpos.lnum = n - (line2 - line1) + 1;
  1235. X                    }
  1236. X                    else
  1237. X                        Curpos.lnum = n + 1;
  1238. X                    while (line1 <= line2)
  1239. X                    {
  1240. X                            /* this undo is not efficient, but it works */
  1241. X                        u_save(line1 - 1, line1 + 1);
  1242. X                        q = delsline(line1, FALSE);
  1243. X                        u_save(n, n + 1);
  1244. X                        appendline(n, q);
  1245. X                        if (n < line1)
  1246. X                        {
  1247. X                            ++n;
  1248. X                            ++line1;
  1249. X                        }
  1250. X                        else
  1251. X                            --line2;
  1252. X                    }
  1253. X                }
  1254. X                else
  1255. X                {
  1256. X                    u_save(n, n + 1);
  1257. X                    Curpos.lnum = n + 1;
  1258. X                    lnum = line2 - line1 + 1;
  1259. X                    while (line1 <= line2)
  1260. X                    {
  1261. X                        appendline(n, save_line(nr2ptr(line1)));
  1262. X                        ++n;
  1263. X                        ++line1;
  1264. X                        if (n < line1)
  1265. X                        {
  1266. X                            ++line1;
  1267. X                            ++line2;
  1268. X                        }
  1269. X                    }
  1270. X                    msgmore((long)lnum);
  1271. X                }
  1272. X                u_clearline();
  1273. X                Curpos.col = 0;
  1274. X                updateScreen(NOT_VALID);
  1275. X                break;
  1276. X
  1277. X        case CMD_and:
  1278. X        case CMD_substitute:
  1279. X                dosub(line1, line2, (char *)arg, &nextcomm);
  1280. X                break;
  1281. X
  1282. X        case CMD_join:
  1283. X                Curpos.lnum = line1;
  1284. X                if (line1 == line2)
  1285. X                {
  1286. X                    if (line2 == line_count)
  1287. X                    {
  1288. X                        beep();
  1289. X                        break;
  1290. X                    }
  1291. X                    ++line2;
  1292. X                }
  1293. X                dodojoin(line2 - line1 + 1, !forceit, TRUE);
  1294. X                break;
  1295. X
  1296. X        case CMD_global:
  1297. X                if (forceit)
  1298. X                    *cmd = 'v';
  1299. X        case CMD_vglobal:
  1300. X                doglob(*cmd, line1, line2, (char *)arg);
  1301. X                break;
  1302. X
  1303. X        case CMD_at:                /* :[addr]@r */
  1304. X                Curpos.lnum = line2;
  1305. X                if (!doexecbuf(*arg))        /* put the register in mapbuf */
  1306. X                    beep();
  1307. X                else
  1308. X                    docmdline(NULL);        /* execute from the mapbuf */
  1309. X                break;
  1310. X
  1311. X        case CMD_bang:
  1312. X                dobang(addr_count, arg);
  1313. X                break;
  1314. X
  1315. X        case CMD_undo:
  1316. X                u_undo(1);
  1317. X                break;
  1318. X
  1319. X        case CMD_source:
  1320. X                if (forceit)    /* :so! read vi commands */
  1321. X                    openscript((char *)arg);
  1322. X                else if (dosource((char *)arg))        /* :so read ex commands */
  1323. X                    emsg(e_notopen);
  1324. X                break;
  1325. X
  1326. X        case CMD_mkvimrc:
  1327. X                if (*arg == NUL)
  1328. X                    arg = (u_char *)VIMRC_FILE;
  1329. X                /*FALLTHROUGH*/
  1330. X
  1331. X        case CMD_mkexrc:
  1332. X                {
  1333. X                    FILE    *fd;
  1334. X
  1335. X                    if (*arg == NUL)
  1336. X                        arg = (u_char *)EXRC_FILE;
  1337. X                    if (!forceit && (fd = fopen((char *)arg, "r")) != NULL)
  1338. X                    {
  1339. X                        fclose(fd);
  1340. X                        emsg(e_exists);
  1341. X                        break;
  1342. X                    }
  1343. X
  1344. X                    if ((fd = fopen((char *)arg, "w")) == NULL)
  1345. X                    {
  1346. X                        emsg(e_notcreate);
  1347. X                        break;
  1348. X                    }
  1349. X                    if (makemap(fd) || makeset(fd))
  1350. X                        emsg(e_write);
  1351. X                    fclose(fd);
  1352. X                    break;
  1353. X                }
  1354. X
  1355. X        case CMD_cc:
  1356. X                    qf_jump(atoi((char *)arg));
  1357. X                    break;
  1358. X
  1359. X        case CMD_cf:
  1360. X                    if (*arg == NUL)
  1361. X                        arg = (u_char *)p_ef;
  1362. X                    if (!qf_init((char *)arg))
  1363. X                        qf_jump(0);
  1364. X                    break;
  1365. X
  1366. X        case CMD_cl:
  1367. X                    qf_list();
  1368. X                    break;
  1369. X
  1370. X        case CMD_cn:
  1371. X                    qf_jump(qf_index + 1);
  1372. X                    break;
  1373. X
  1374. X        case CMD_cp:
  1375. X                    qf_jump(qf_index - 1);
  1376. X                    break;
  1377. X
  1378. X        case CMD_cq:
  1379. X                    getout(1);        /* this does not always work. why? */
  1380. X
  1381. X        case CMD_mark:
  1382. X        case CMD_k:
  1383. X                    pos = Curpos;            /* save Curpos */
  1384. X                    Curpos.lnum = line2;
  1385. X                    Curpos.col = 0;
  1386. X                    setmark(*arg);            /* set mark */
  1387. X                    Curpos = pos;            /* restore Curpos */
  1388. X                    break;
  1389. X
  1390. X#ifdef SETKEYMAP
  1391. X        case CMD_setkeymap:
  1392. X                    set_keymap(arg);
  1393. X                    break;
  1394. X#endif
  1395. X
  1396. X        default:
  1397. X                    emsg(e_invcmd);
  1398. X    }
  1399. X
  1400. X
  1401. Xdoend:
  1402. X    return nextcomm;
  1403. X}
  1404. X
  1405. X/*
  1406. X * handle the :! command.
  1407. X * We replace the extra bangs by the previously entered command and remember
  1408. X * the command.
  1409. X */
  1410. X    static void
  1411. Xdobang(addr_count, arg)
  1412. X    int        addr_count;
  1413. X    u_char    *arg;
  1414. X{
  1415. X    static    char    *prevcmd = NULL;        /* the previous command */
  1416. X    char            *t;
  1417. X    char            *trailarg;
  1418. X    int             len;
  1419. X
  1420. X    /*
  1421. X     * Disallow shell commands from .exrc and .vimrc in current directory for
  1422. X     * security reasons.
  1423. X     */
  1424. X    if (secure)
  1425. X    {
  1426. X        secure = 2;
  1427. X        emsg(e_curdir);
  1428. X        return;
  1429. X    }
  1430. X    len = strlen((char *)arg) + 1;
  1431. X
  1432. X    if (Changed)
  1433. X        autowrite();
  1434. X    /*
  1435. X     * try to find an embedded bang, like in :!<cmd> ! [args]
  1436. X     * (:!! is indicated by the 'forceit' variable)
  1437. X     */
  1438. X    trailarg = (char *)arg;
  1439. X    skiptospace(&trailarg);
  1440. X    skipspace(&trailarg);
  1441. X    if (*trailarg == '!')
  1442. X        *trailarg++ = NUL;
  1443. X    else
  1444. X        trailarg = NULL;
  1445. X
  1446. X    if (forceit || trailarg != NULL)            /* use the previous command */
  1447. X    {
  1448. X        if (prevcmd == NULL)
  1449. X        {
  1450. X            emsg(e_noprev);
  1451. X            return;
  1452. X        }
  1453. X        len += strlen(prevcmd) * (trailarg != NULL && forceit ? 2 : 1);
  1454. X    }
  1455. X
  1456. X    if (len > CMDBUFFSIZE)
  1457. X    {
  1458. X        emsg(e_toolong);
  1459. X        return;
  1460. X    }
  1461. X    if ((t = alloc(len)) == NULL)
  1462. X        return;
  1463. X    *t = NUL;
  1464. X    if (forceit)
  1465. X        strcpy(t, prevcmd);
  1466. X    strcat(t, (char *)arg);
  1467. X    if (trailarg != NULL)
  1468. X    {
  1469. X        strcat(t, prevcmd);
  1470. X        strcat(t, trailarg);
  1471. X    }
  1472. X    free(prevcmd);
  1473. X    prevcmd = t;
  1474. X
  1475. X    if (bangredo)            /* put cmd in redo buffer for ! command */
  1476. X    {
  1477. X        AppendToRedobuff(prevcmd);
  1478. X        AppendToRedobuff("\n");
  1479. X        bangredo = FALSE;
  1480. X    }
  1481. X    if (addr_count == 0)
  1482. X    {
  1483. X        smsg(":!%s", prevcmd);
  1484. X        doshell(prevcmd);                 /* :! */
  1485. X    }
  1486. X    else
  1487. X    {
  1488. X        smsg(":%ld,%ld!%s", (long)line1, (long)line2, prevcmd);
  1489. X        dofilter((u_char *)prevcmd, TRUE, TRUE);        /* :range! */
  1490. X    }
  1491. X}
  1492. X
  1493. X    static int
  1494. Xautowrite()
  1495. X{
  1496. X    if (!p_aw || check_readonly() || check_fname())
  1497. X        return FALSE;
  1498. X    return (writeit(Filename, (linenr_t)1, line_count, 0, 0));
  1499. X}
  1500. X
  1501. X    static int
  1502. Xdowrite(arg, append)
  1503. X    u_char    *arg;
  1504. X    int        append;
  1505. X{
  1506. X    FILE    *f;
  1507. X    int        other;
  1508. X
  1509. X    /*
  1510. X     * if we have a new file name put it in the list of alternate file names
  1511. X     */
  1512. X    other = otherfile((char *)arg);
  1513. X    if (*arg != NUL && other)
  1514. X        setaltfname(strsave((char *)arg), (linenr_t)1, TRUE);
  1515. X
  1516. X    /*
  1517. X     * writing to the current file is not allowed in readonly mode
  1518. X     */
  1519. X    if ((*arg == NUL || !other) && check_readonly())
  1520. X        return FALSE;
  1521. X
  1522. X    /*
  1523. X     * write to current file
  1524. X     */
  1525. X    if (*arg == NUL)
  1526. X    {
  1527. X        if (check_fname())
  1528. X            return FALSE;
  1529. X        return (writeit(Filename, line1, line2, append, forceit));
  1530. X    }
  1531. X
  1532. X    /*
  1533. X     * write to other file; overwriting only allowed with '!'
  1534. X     */
  1535. X    if (!forceit && !append && !p_wa && (f = fopen((char *)arg, "r")) != NULL)
  1536. X    {                                /* don't overwrite existing file */
  1537. X            fclose(f);
  1538. X            emsg(e_exists);
  1539. X            return 0;
  1540. X    }
  1541. X    return (writeit((char *)arg, line1, line2, append, forceit));
  1542. X}
  1543. X
  1544. X    static int
  1545. Xdoecmd(arg)
  1546. X    char        *arg;
  1547. X{
  1548. X    int            setalt;
  1549. X    char        *command = NULL;
  1550. X    int            redraw_save;
  1551. X    linenr_t    newlnum;
  1552. X
  1553. X    newlnum = doecmdlnum;
  1554. X    doecmdlnum = 0;                        /* reset it for next time */
  1555. X
  1556. X    if (*arg == '+')
  1557. X    {
  1558. X        ++arg;
  1559. X        if (isspace(*arg))
  1560. X            command = "$";
  1561. X        else
  1562. X        {
  1563. X            command = arg;
  1564. X            while (*arg && !isspace(*arg))
  1565. X                ++arg;
  1566. X        }
  1567. X        if (*arg)
  1568. X            *arg++ = NUL;
  1569. X        
  1570. X        skipspace(&arg);
  1571. X    }
  1572. X
  1573. X#ifdef AMIGA
  1574. X    fname_case(arg);        /* set correct case for filename */
  1575. X#endif
  1576. X    setalt = (*arg != NUL && otherfile(arg));
  1577. X    if (check_changed(FALSE))
  1578. X    {
  1579. X        if (setalt)
  1580. X            setaltfname(strsave(arg), (linenr_t)1, TRUE);
  1581. X        return FALSE;
  1582. X    }
  1583. X    if (setalt)
  1584. X    {
  1585. X        setaltfname(Filename, Curpos.lnum, FALSE);
  1586. X        Filename = NULL;
  1587. X        setfname(arg);
  1588. X    }
  1589. X    else if (newlnum == 0)
  1590. X        newlnum = Curpos.lnum;
  1591. X    maketitle();
  1592. X    if (check_fname())
  1593. X        return FALSE;
  1594. X
  1595. X    /* clear mem and read file */
  1596. X    freeall();
  1597. X    filealloc();
  1598. X    UNCHANGED;
  1599. X    startscript();        /* re-start auto script file */
  1600. X    startop.lnum = 0;    /* clear '[ and '] marks */
  1601. X    endop.lnum = 0;
  1602. X
  1603. X    redraw_save = RedrawingDisabled;
  1604. X    RedrawingDisabled = TRUE;        /* don't redraw until the cursor is in
  1605. X                                     * the right line */
  1606. X    readfile(Filename, (linenr_t)0, TRUE);
  1607. X    if (newlnum && command == NULL)
  1608. X    {
  1609. X        if (newlnum != INVLNUM)
  1610. X            Curpos.lnum = newlnum;
  1611. X        else
  1612. X            Curpos.lnum = line_count;
  1613. X        Curpos.col = 0;
  1614. X    }
  1615. X    if (command)
  1616. X        docmdline((u_char *)command);
  1617. X    RedrawingDisabled = redraw_save;            /* cursupdate() will redraw the screen */
  1618. X    if (p_im)
  1619. X        stuffReadbuff("i");            /* start editing in insert mode */
  1620. X    return TRUE;
  1621. X}
  1622. X
  1623. X    static void
  1624. Xdoshell(cmd)
  1625. X    char    *cmd;
  1626. X{
  1627. X    /*
  1628. X     * Disallow shell commands from .exrc and .vimrc in current directory for
  1629. X     * security reasons.
  1630. X     */
  1631. X    if (secure)
  1632. X    {
  1633. X        secure = 2;
  1634. X        emsg(e_curdir);
  1635. X        return;
  1636. X    }
  1637. X    gotocmdline(FALSE, '\n');
  1638. X
  1639. X    stoptermcap();
  1640. X    call_shell(cmd, 0);
  1641. X
  1642. X    if (global_busy)
  1643. X        global_wait = 1;
  1644. X    else
  1645. X#ifdef AMIGA
  1646. X        wait_return(!term_console);
  1647. X#else
  1648. X        wait_return(TRUE);
  1649. X#endif
  1650. X    starttermcap();
  1651. X
  1652. X    /* in an Amiga window redrawing is caused by asking the window size */
  1653. X#ifdef AMIGA
  1654. X    if (term_console)
  1655. X        outstr("\033[0 q");     /* get window size */
  1656. X#endif /* AMIGA */
  1657. X}
  1658. X
  1659. X/*
  1660. X * dofilter: filter lines through a command given by the user
  1661. X *
  1662. X * We use temp files and the call_shell() routine here. This would normally
  1663. X * be done using pipes on a UNIX machine, but this is more portable to
  1664. X * the machines we usually run on. The call_shell() routine needs to be able
  1665. X * to deal with redirection somehow, and should handle things like looking
  1666. X * at the PATH env. variable, and adding reasonable extensions to the
  1667. X * command name given by the user. All reasonable versions of call_shell()
  1668. X * do this.
  1669. X * We use input redirection if do_in is TRUE.
  1670. X * We use output redirection if do_out is TRUE.
  1671. X */
  1672. X    static void
  1673. Xdofilter(buff, do_in, do_out)
  1674. X    u_char        *buff;
  1675. X    int            do_in, do_out;
  1676. X{
  1677. X#ifdef LATTICE
  1678. X    char        itmp[L_tmpnam];        /* use tmpnam() */
  1679. X    char        otmp[L_tmpnam];
  1680. X#else
  1681. X    char        itmp[TMPNAMELEN];
  1682. X    char        otmp[TMPNAMELEN];
  1683. X#endif
  1684. X    linenr_t     linecount;
  1685. X    char        *p;
  1686. X
  1687. X    /*
  1688. X     * Disallow shell commands from .exrc and .vimrc in current directory for
  1689. X     * security reasons.
  1690. X     */
  1691. X    if (secure)
  1692. X    {
  1693. X        secure = 2;
  1694. X        emsg(e_curdir);
  1695. X        return;
  1696. X    }
  1697. X    if (*buff == NUL)        /* no filter command */
  1698. X        return;
  1699. X    linecount = line2 - line1 + 1;
  1700. X    Curpos.lnum = line1;
  1701. X    Curpos.col = 0;
  1702. X    cursupdate();
  1703. X    gotocmdline(FALSE, NUL);
  1704. X
  1705. X    /*
  1706. X     * 1. Form temp file names
  1707. X     * 2. Write the lines to a temp file
  1708. X     * 3. Run the filter command on the temp file
  1709. X     * 4. Read the output of the command into the buffer
  1710. X     * 5. Delete the original lines to be filtered
  1711. X     * 6. Remove the temp files
  1712. X     */
  1713. X
  1714. X#ifndef LATTICE
  1715. X    /* for lattice we use tmpnam(), which will make its own name */
  1716. X    strcpy(itmp, TMPNAME1);
  1717. X    strcpy(otmp, TMPNAME2);
  1718. X#endif
  1719. X
  1720. X    if ((do_in && *mktemp(itmp) == NUL) || (do_out && *mktemp(otmp) == NUL))
  1721. X    {
  1722. X        emsg(e_notmp);
  1723. X        return;
  1724. X    }
  1725. X
  1726. X    outchar('\n');                /* ! command not overwritten by next mesages */
  1727. X    if (do_in && !writeit(itmp, line1, line2, FALSE, 0))
  1728. X    {
  1729. X        outchar ('\n');
  1730. X        emsg(e_notcreate);
  1731. X        updateScreen(CLEAR);    /* screen has been shifted up one line */
  1732. X        return;
  1733. X    }
  1734. X    if (!do_out)
  1735. X        outchar('\n');
  1736. X
  1737. X    strcpy(IObuff, (char *)buff);
  1738. X    if (do_in)
  1739. X    {
  1740. X    /*
  1741. X     * If there is a pipe, we have to put the '<' in front of it
  1742. X     */
  1743. X        p = strchr(IObuff, '|');
  1744. X        if (p)
  1745. X            *p = NUL;
  1746. X        strcat(IObuff, " < ");
  1747. X        strcat(IObuff, itmp);
  1748. X        p = strchr((char *)buff, '|');
  1749. X        if (p)
  1750. X            strcat(IObuff, p);
  1751. X    }
  1752. X    if (do_out)
  1753. X    {
  1754. X        strcat(IObuff, " > ");
  1755. X        strcat(IObuff, otmp);
  1756. X    }
  1757. X
  1758. X    if (call_shell(IObuff, 1))
  1759. X    {
  1760. X        linecount = 0;
  1761. X        goto error;
  1762. X    }
  1763. X
  1764. X    if (do_out)
  1765. X    {
  1766. X        if (!u_save((linenr_t)(line1 - 1), (linenr_t)(line2 + 1)))
  1767. X        {
  1768. X            linecount = 0;
  1769. X            goto error;
  1770. X        }
  1771. X        if (readfile(otmp, line2, FALSE))
  1772. X        {
  1773. X            outchar ('\n');
  1774. X            emsg(e_notread);
  1775. X            linecount = 0;
  1776. X            goto error;
  1777. X        }
  1778. X
  1779. X        if (do_in)
  1780. X        {
  1781. X            Curpos.lnum = line1;
  1782. X            dellines(linecount, TRUE);
  1783. X        }
  1784. X    }
  1785. X    else
  1786. X    {
  1787. Xerror:
  1788. X        if (global_busy)
  1789. X            global_wait = 1;
  1790. X        else
  1791. X            wait_return(FALSE);
  1792. X    }
  1793. X    updateScreen(CLEAR);
  1794. X
  1795. X    if (linecount > p_report)
  1796. X    {
  1797. X        if (!do_in && do_out)
  1798. X            msgmore(linecount);
  1799. X        else
  1800. X            smsg("%ld lines filtered", (long)linecount);
  1801. X    }
  1802. X    remove(itmp);
  1803. X    remove(otmp);
  1804. X    return;
  1805. X}
  1806. X
  1807. X/* 
  1808. X * Redefine the argument list to 'str'.
  1809. X * Return TRUE for failure.
  1810. X */
  1811. X    int
  1812. Xdoarglist(str)
  1813. X    char *str;
  1814. X{
  1815. X    int        new_numfiles = 0;
  1816. X    char    **new_files = NULL;
  1817. X#ifdef WILD_CARDS
  1818. X    int        exp_numfiles;
  1819. X    char    **exp_files;
  1820. X#endif
  1821. X    char    **t;
  1822. X    char    *p;
  1823. X    int        inquote;
  1824. X    int        i;
  1825. X
  1826. X    while (*str)
  1827. X    {
  1828. X        /*
  1829. X         * create a new entry in new_files[]
  1830. X         */
  1831. X        t = (char **)alloc((unsigned)(sizeof(char *) * (new_numfiles + 1)));
  1832. X        if (t != NULL)
  1833. X            for (i = new_numfiles; --i >= 0; )
  1834. X                t[i] = new_files[i];
  1835. X        free(new_files);
  1836. X        if (t == NULL)
  1837. X            return TRUE;
  1838. X        new_files = t;
  1839. X        new_files[new_numfiles++] = str;
  1840. X
  1841. X        /*
  1842. X         * isolate one argument, taking quotes
  1843. X         */
  1844. X        inquote = FALSE;
  1845. X        for (p = str; *str; ++str)
  1846. X        {
  1847. X            if (*str == '\\' && *(str + 1) != NUL)
  1848. X                *p++ = *++str;
  1849. X            else
  1850. X            {
  1851. X                if (!inquote && isspace(*str))
  1852. X                    break;
  1853. X                if (*str == '"')
  1854. X                    inquote ^= TRUE;
  1855. X                else
  1856. X                    *p++ = *str;
  1857. X            }
  1858. X        }
  1859. X        skipspace(&str);
  1860. X        *p = NUL;
  1861. X    }
  1862. X    
  1863. X#ifdef WILD_CARDS
  1864. X    if (ExpandWildCards(new_numfiles, new_files, &exp_numfiles, &exp_files, FALSE, TRUE) != 0)
  1865. X        return TRUE;
  1866. X    else if (exp_numfiles == 0)
  1867. X    {
  1868. X        emsg(e_nomatch);
  1869. X        return TRUE;
  1870. X    }
  1871. X    FreeWild(numfiles, files);
  1872. X    files = exp_files;
  1873. X    numfiles = exp_numfiles;
  1874. X
  1875. X#else
  1876. X    files = new_files;
  1877. X    numfiles = new_numfiles;
  1878. X#endif
  1879. X
  1880. X    return FALSE;
  1881. X}
  1882. X
  1883. Xextern int redraw_msg;        /* this is in screen.c */
  1884. X
  1885. X    void
  1886. Xgotocmdline(clr, firstc)
  1887. X    int                clr;
  1888. X    int                firstc;
  1889. X{
  1890. X    windgoto((int)Rows - 1, 0);
  1891. X    if (clr)
  1892. X    {
  1893. X        clear_line();            /* clear the bottom line */
  1894. X        windgoto((int)Rows - 1, 0);
  1895. X        redraw_msg = TRUE;
  1896. X    }
  1897. X    if (firstc)
  1898. X        outchar(firstc);
  1899. X}
  1900. X
  1901. X    static int
  1902. Xcheck_readonly()
  1903. X{
  1904. X    if (!forceit && p_ro)
  1905. X    {
  1906. X        emsg(e_readonly);
  1907. X        return TRUE;
  1908. X    }
  1909. X    return FALSE;
  1910. X}
  1911. X
  1912. X    static int
  1913. Xcheck_changed(checkaw)
  1914. X    int        checkaw;
  1915. X{
  1916. X    if (!forceit && Changed && (!checkaw || !autowrite()))
  1917. X    {
  1918. X        if (exiting)
  1919. X            settmode(1);        /* set raw again for typeahead */
  1920. X        emsg(e_nowrtmsg);
  1921. X        return TRUE;
  1922. X    }
  1923. X    return FALSE;
  1924. X}
  1925. X
  1926. X    static int
  1927. Xcheck_fname()
  1928. X{
  1929. X    if (Filename == NULL)
  1930. X    {
  1931. X        emsg(e_noname);
  1932. X        return TRUE;
  1933. X    }
  1934. X    return FALSE;
  1935. X}
  1936. X
  1937. X    static int
  1938. Xcheck_more()
  1939. X{
  1940. X    if (!forceit && curfile + 1 < numfiles)
  1941. X    {
  1942. X        if (exiting)
  1943. X            settmode(1);        /* set raw again for typeahead */
  1944. X        emsg(e_more);
  1945. X        return TRUE;
  1946. X    }
  1947. X    return FALSE;
  1948. X}
  1949. X
  1950. X/*
  1951. X * try to abandon current file and edit "fname"
  1952. X * return 1 for "normal" error, 2 for "not written" error, 0 for success
  1953. X * -1 for succesfully opening another file
  1954. X */
  1955. X    int
  1956. Xgetfile(fname, setpm)
  1957. X    char    *fname;
  1958. X    int        setpm;
  1959. X{
  1960. X    int other;
  1961. X
  1962. X    FullName(fname, IObuff, IOSIZE);
  1963. X    if (Filename == NULL)
  1964. X        other = TRUE;
  1965. X    else
  1966. X        other = fnamecmp(IObuff, Filename);
  1967. X    if (other && !forceit && Changed && !autowrite())
  1968. X    {
  1969. X        emsg(e_nowrtmsg);
  1970. X        return 2;        /* file has been changed */
  1971. X    }
  1972. X    if (setpm)
  1973. X        setpcmark();
  1974. X    if (!other)
  1975. X        return 0;        /* it's in the same file */
  1976. X    if (doecmd(fname))
  1977. X        return -1;        /* opened another file */
  1978. X    return 1;            /* error encountered */
  1979. X}
  1980. X
  1981. X/*
  1982. X * return TRUE if alternate file n is the same as the current file
  1983. X */
  1984. X    int
  1985. Xsamealtfile(n)
  1986. X    int            n;
  1987. X{
  1988. X    if (n < NUMALTFILES && altfiles[n] != NULL && Filename != NULL &&
  1989. X                    fnamecmp(altfiles[n], Filename) == 0)
  1990. X        return TRUE;
  1991. X    return FALSE;
  1992. X}
  1993. X
  1994. X/*
  1995. X * get alternate file n
  1996. X * set linenr to lnum or altlnum if lnum == 0
  1997. X * if (setpm) setpcmark
  1998. X * return 1 for failure, 0 for success
  1999. X */
  2000. X    int
  2001. Xgetaltfile(n, lnum, setpm)
  2002. X    int            n;
  2003. X    linenr_t    lnum;
  2004. X    int            setpm;
  2005. X{
  2006. X    if (n < 0 || n >= NUMALTFILES || altfiles[n] == NULL)
  2007. X        return 1;
  2008. X    if (lnum == 0)
  2009. X        lnum = altlnum[n];        /* altlnum may be changed by getfile() */
  2010. X    RedrawingDisabled = TRUE;
  2011. X    if (getfile(altfiles[n], setpm) <= 0)
  2012. X    {
  2013. X        RedrawingDisabled = FALSE;
  2014. X        if (lnum == 0 || lnum > line_count)        /* check for valid lnum */
  2015. X            Curpos.lnum = 1;
  2016. X        else
  2017. X            Curpos.lnum = lnum;
  2018. X
  2019. X        Curpos.col = 0;
  2020. X        return 0;
  2021. X    }
  2022. X    RedrawingDisabled = FALSE;
  2023. X    return 1;
  2024. X}
  2025. X
  2026. X/*
  2027. X * get name of "n"th alternate file
  2028. X */
  2029. X     char *
  2030. Xgetaltfname(n)
  2031. X    int n;
  2032. X{
  2033. X    if (n >= NUMALTFILES)
  2034. X        return NULL;
  2035. X    return altfiles[n];
  2036. X}
  2037. X
  2038. X/*
  2039. X * put name "arg" in the list of alternate files.
  2040. X * "arg" must have been allocated
  2041. X * "lnum" is the default line number when jumping to the file
  2042. X * "newfile" must be TRUE when "arg" != current file
  2043. X */
  2044. X    static void
  2045. Xsetaltfname(arg, lnum, newfile)
  2046. X    char        *arg;
  2047. X    linenr_t    lnum;
  2048. X    int            newfile;
  2049. X{
  2050. X    int i;
  2051. X
  2052. X    free(altfiles[NUMALTFILES - 1]);
  2053. X    for (i = NUMALTFILES - 1; i > 0; --i)
  2054. X    {
  2055. X        altfiles[i] = altfiles[i - 1];
  2056. X        altlnum[i] = altlnum[i - 1];
  2057. X    }
  2058. X    incrmarks();        /* increment file number for all jumpmarks */
  2059. X    incrtags();            /* increment file number for all tags */
  2060. X    if (newfile)
  2061. X    {
  2062. X        decrmarks();        /* decrement file number for jumpmarks in current file */
  2063. X        decrtags();            /* decrement file number for tags in current file */
  2064. X    }
  2065. X
  2066. X    altfiles[0] = arg;
  2067. X    altlnum[0] = lnum;
  2068. X}
  2069. X
  2070. X#ifdef WILD_CARDS
  2071. X/*
  2072. X * Do wildcard expansion on the string 'str'.
  2073. X * Return a pointer to alloced memory containing the new string.
  2074. X * Return NULL for failure.
  2075. X *
  2076. X * mode = -2: only release file names
  2077. X * mode = -1: normal expansion, do not keep file names
  2078. X * mode =  0: normal expansion, keep file names
  2079. X * mode =  1: use next match in multiple match
  2080. X * mode =  2: use previous match in multiple match
  2081. X */
  2082. X    static char *
  2083. XExpandOne(str, list_notfound, mode)
  2084. X    u_char    *str;
  2085. X    int        list_notfound;
  2086. X    int        mode;
  2087. X{
  2088. X    char        *ss = NULL;
  2089. X    static char **cmd_files = NULL;      /* list of input files */
  2090. X    static int  cmd_numfiles = -1;      /* number of input files */
  2091. X    static int    findex;
  2092. X    int            i, found = 0;
  2093. X    char        *filesuf, *setsuf, *nextsetsuf;
  2094. X    int            filesuflen, setsuflen;
  2095. X
  2096. X/*
  2097. X * first handle the case of using an old match
  2098. X */
  2099. X    if (mode >= 1)
  2100. X    {
  2101. X        if (cmd_numfiles > 0)
  2102. X        {
  2103. X            if (mode == 1)
  2104. X                ++findex;
  2105. X            else    /* mode == 2 */
  2106. X                --findex;
  2107. X            if (findex < 0)
  2108. X                findex = 0;
  2109. X            if (findex > cmd_numfiles - 1)
  2110. X                findex = cmd_numfiles - 1;
  2111. X            return strsave(cmd_files[findex]);
  2112. X        }
  2113. X        else
  2114. X            return NULL;
  2115. X    }
  2116. X
  2117. X/* free old names */
  2118. X    if (cmd_numfiles != -1)
  2119. X        FreeWild(cmd_numfiles, cmd_files);
  2120. X    cmd_numfiles = -1;
  2121. X    findex = -1;
  2122. X
  2123. X    if (mode == -2)        /* only release file name */
  2124. X        return NULL;
  2125. X
  2126. X    if (ExpandWildCards(1, (char **)&str, &cmd_numfiles, &cmd_files, FALSE, list_notfound) != 0)
  2127. X        /* error: do nothing */;
  2128. X    else if (cmd_numfiles == 0)
  2129. X        emsg(e_nomatch);
  2130. X    else
  2131. X    {
  2132. X        if (cmd_numfiles > 1)        /* more than one match; check suffixes */
  2133. X        {
  2134. X            found = -2;
  2135. X            for (i = 0; i < cmd_numfiles; ++i)
  2136. X            {
  2137. X                if ((filesuf = strrchr(cmd_files[i], '.')) != NULL)
  2138. X                {
  2139. X                    filesuflen = strlen(filesuf);
  2140. X                    for (setsuf = p_su; *setsuf; setsuf = nextsetsuf)
  2141. X                    {
  2142. X                        if ((nextsetsuf = strchr(setsuf + 1, '.')) == NULL)
  2143. X                            nextsetsuf = setsuf + strlen(setsuf);
  2144. X                        setsuflen = nextsetsuf - setsuf;
  2145. X                        if (filesuflen == setsuflen &&
  2146. X                                    strncmp(setsuf, filesuf, (size_t)setsuflen) == 0)
  2147. X                            break;
  2148. X                    }
  2149. X                    if (*setsuf)                /* suffix matched: ignore file */
  2150. X                        continue;
  2151. X                }
  2152. X                if (found >= 0)
  2153. X                {
  2154. X                    found = -2;
  2155. X                    break;
  2156. X                }
  2157. X                found = i;
  2158. X            }
  2159. X        }
  2160. X        if (found < 0)
  2161. X            emsg(e_toomany);
  2162. X        else
  2163. X            ss = strsave(cmd_files[found]);
  2164. X    }
  2165. X        
  2166. X    if (found != -2 || mode == -1)
  2167. X    {
  2168. X        FreeWild(cmd_numfiles, cmd_files);
  2169. X        cmd_numfiles = -1;
  2170. X    }
  2171. X    return ss;
  2172. X}
  2173. X
  2174. X/*
  2175. X * show all filenames that match the string "file" with length "len"
  2176. X */
  2177. X    static void
  2178. Xshowmatches(file, len)
  2179. X    char *file;
  2180. X    int    len;
  2181. X{
  2182. X    char *file_str;
  2183. X    int num_files;
  2184. X    char **files_found;
  2185. X    int i, j, k;
  2186. X    int maxlen;
  2187. X    int lines;
  2188. X    int columns;
  2189. X
  2190. X    file_str = addstar(file, len);        /* add star to file name */
  2191. X    if (file_str != NULL)
  2192. X    {
  2193. X        outchar('\n');
  2194. X        flushbuf();
  2195. X
  2196. X        /* find all files that match the description */
  2197. X        ExpandWildCards(1, &file_str, &num_files, &files_found, FALSE, FALSE);
  2198. X
  2199. X        /* find the maximum length of the file names */
  2200. X        maxlen = 0;
  2201. X        for (i = 0; i < num_files; ++i)
  2202. X        {
  2203. X            j = strlen(files_found[i]);
  2204. X            if (j > maxlen)
  2205. X                maxlen = j;
  2206. X        }
  2207. X
  2208. X        /* compute the number of columns and lines for the listing */
  2209. X        maxlen += 2;    /* two spaces between file names */
  2210. X        columns = (Columns + 2) / maxlen;
  2211. X        if (columns < 1)
  2212. X            columns = 1;
  2213. X        lines = (num_files + columns - 1) / columns;
  2214. X
  2215. X        /* list the files line by line */
  2216. X#ifdef AMIGA
  2217. X        settmode(0);        /* allow output to be halted */
  2218. X#endif
  2219. X        for (i = 0; i < lines; ++i)
  2220. X        {
  2221. X            for (k = i; k < num_files; k += lines)
  2222. X            {
  2223. X                if (k > i)
  2224. X                    for (j = maxlen - strlen(files_found[k - lines]); --j >= 0; )
  2225. X                        outchar(' ');
  2226. X                j = isdir(files_found[k]);    /* highlight directories */
  2227. X                if (j)
  2228. X                {
  2229. X#ifdef AMIGA
  2230. X                    if (term_console)
  2231. X                        outstr("\033[33m");        /* use highlight color */
  2232. X                    else
  2233. X#endif /* AMIGA */
  2234. X                        outstr(T_TI);
  2235. X                }
  2236. X                outstrn(files_found[k]);
  2237. X                if (j)
  2238. X                {
  2239. X#ifdef AMIGA
  2240. X                    if (term_console)
  2241. X                        outstr("\033[0m");        /* use normal color */
  2242. X                    else
  2243. X#endif /* AMIGA */
  2244. X                        outstr(T_TP);
  2245. X                }
  2246. X            }
  2247. X            outchar('\n');
  2248. X            flushbuf();
  2249. X        }
  2250. X        free(file_str);
  2251. X        FreeWild(num_files, files_found);
  2252. X#ifdef AMIGA
  2253. X        settmode(1);
  2254. X#endif
  2255. X
  2256. X        wait_return(TRUE);
  2257. X    }
  2258. X}
  2259. X
  2260. X/*
  2261. X * copy the file name into allocated memory and add a '*' at the end
  2262. X */
  2263. X    static char *
  2264. Xaddstar(fname, len)
  2265. X    char    *fname;
  2266. X    int        len;
  2267. X{
  2268. X    char    *retval;
  2269. X#ifdef MSDOS
  2270. X    int        i;
  2271. X#endif
  2272. X
  2273. X    retval = alloc(len + 4);
  2274. X    if (retval != NULL)
  2275. X    {
  2276. X        strncpy(retval, fname, (size_t)len);
  2277. X#ifdef MSDOS
  2278. X    /*
  2279. X     * if there is no dot in the file name, add "*.*" instead of "*".
  2280. X     */
  2281. X        for (i = len - 1; i >= 0; --i)
  2282. X            if (retval[i] == '.' || retval[i] == '\\' || retval[i] == ':')
  2283. X                break;
  2284. X        if (retval[i] != '.')
  2285. X        {
  2286. X            retval[len++] = '*';
  2287. X            retval[len++] = '.';
  2288. X        }
  2289. X#endif
  2290. X        retval[len] = '*';
  2291. X        retval[len + 1] = 0;
  2292. X    }
  2293. X    return retval;
  2294. X}
  2295. X#endif /* WILD_CARDS */
  2296. X
  2297. X/*
  2298. X * dosource: read the file "fname" and execute its lines as EX commands
  2299. X *
  2300. X * This function may be called recursively!
  2301. X */
  2302. X    int
  2303. Xdosource(fname)
  2304. X    register char *fname;
  2305. X{
  2306. X    register FILE    *fp;
  2307. X    register int    len;
  2308. X
  2309. X    expand_env(fname, IObuff, IOSIZE);        /* use IObuff for expanded name */
  2310. X    if ((fp = fopen(IObuff, READBIN)) == NULL)
  2311. X        return 1;
  2312. X
  2313. X    while (fgets(IObuff, IOSIZE, fp) != NULL && !got_int)
  2314. X    {
  2315. X        len = strlen(IObuff) - 1;
  2316. X        if (len >= 0 && IObuff[len] == '\n')    /* remove trailing newline */
  2317. X        {
  2318. X#ifdef MSDOS
  2319. X            if (len > 0 && IObuff[len - 1] == '\r') /* trailing CR-LF */
  2320. X                --len;
  2321. X#endif
  2322. X            IObuff[len] = NUL;
  2323. X        }
  2324. X        docmdline((u_char *)IObuff);
  2325. X        breakcheck();
  2326. X    }
  2327. X    fclose(fp);
  2328. X    if (got_int)
  2329. X        emsg(e_interr);
  2330. X    return 0;
  2331. X}
  2332. X
  2333. X/*
  2334. X * get single EX address
  2335. X */
  2336. X    static linenr_t
  2337. Xget_address(ptr)
  2338. X    u_char        **ptr;
  2339. X{
  2340. X    linenr_t    curpos_lnum = Curpos.lnum;
  2341. X    int            c;
  2342. X    int            i;
  2343. X    long        n;
  2344. X    u_char      *cmd;
  2345. X    FPOS        pos;
  2346. X    FPOS        *fp;
  2347. X    linenr_t    lnum;
  2348. X
  2349. X    cmd = *ptr;
  2350. X    skipspace((char **)&cmd);
  2351. X    lnum = INVLNUM;
  2352. X    do
  2353. X    {
  2354. X        switch (*cmd)
  2355. X        {
  2356. X            case '.':                         /* '.' - Cursor position */
  2357. X                        ++cmd;
  2358. X                        lnum = curpos_lnum;
  2359. X                        break;
  2360. X
  2361. X            case '$':                         /* '$' - last line */
  2362. X                        ++cmd;
  2363. X                        lnum = line_count;
  2364. X                        break;
  2365. X
  2366. X            case '\'':                         /* ''' - mark */
  2367. X                        if (*++cmd == NUL || (fp = getmark(*cmd++, FALSE)) == NULL)
  2368. X                        {
  2369. X                            emsg(e_umark);
  2370. X                            goto error;
  2371. X                        }
  2372. X                        lnum = fp->lnum;
  2373. X                        break;
  2374. X
  2375. X            case '/':
  2376. X            case '?':                        /* '/' or '?' - search */
  2377. X                        c = *cmd++;
  2378. X                        pos = Curpos;        /* save Curpos */
  2379. X                        Curpos.col = -1;    /* searchit() will increment the col */
  2380. X                        if (c == '/')
  2381. X                            ++Curpos.lnum;
  2382. X                        searchcmdlen = 0;
  2383. X                        if (dosearch(c == '/' ? FORWARD : BACKWARD, (char *)cmd, FALSE, (long)1, FALSE))
  2384. X                            lnum = Curpos.lnum;
  2385. X                        Curpos = pos;
  2386. X                
  2387. X                        cmd += searchcmdlen;    /* adjust command string pointer */
  2388. X                        break;
  2389. X
  2390. X            default:
  2391. X                        if (isdigit(*cmd))                /* absolute line number */
  2392. X                            lnum = getdigits((char **)&cmd);
  2393. X        }
  2394. X        
  2395. X        while (*cmd == '-' || *cmd == '+')
  2396. X        {
  2397. X            if (lnum == INVLNUM)
  2398. X                lnum = curpos_lnum;
  2399. X            i = *cmd++;
  2400. X            if (!isdigit(*cmd))    /* '+' is '+1', but '+0' is not '+1' */
  2401. X                n = 1;
  2402. X            else 
  2403. X                n = getdigits((char **)&cmd);
  2404. X            if (i == '-')
  2405. X                lnum -= n;
  2406. X            else
  2407. X                lnum += n;
  2408. X        }
  2409. X
  2410. X        curpos_lnum = lnum;
  2411. X    } while (*cmd == '/' || *cmd == '?');
  2412. X
  2413. Xerror:
  2414. X    *ptr = cmd;
  2415. X    return lnum;
  2416. X}
  2417. END_OF_FILE
  2418. if test 46721 -ne `wc -c <'vim/src/cmdline.c'`; then
  2419.     echo shar: \"'vim/src/cmdline.c'\" unpacked with wrong size!
  2420. fi
  2421. # end of 'vim/src/cmdline.c'
  2422. fi
  2423. echo shar: End of archive 21 \(of 23\).
  2424. cp /dev/null ark21isdone
  2425. MISSING=""
  2426. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  2427.     if test ! -f ark${I}isdone ; then
  2428.     MISSING="${MISSING} ${I}"
  2429.     fi
  2430. done
  2431. if test "${MISSING}" = "" ; then
  2432.     echo You have unpacked all 23 archives.
  2433.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2434. else
  2435.     echo You still need to unpack the following archives:
  2436.     echo "        " ${MISSING}
  2437. fi
  2438. ##  End of shell archive.
  2439. exit 0
  2440. -------------8<----------------8<----------------8<---------------8<--------
  2441. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  2442. Oce Nederland B.V., Research & Development | necessarily represent the position
  2443. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  2444. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  2445. UUCP: mool@oce.nl        fax +31 77 595450 | whatever will be accepted.
  2446.  
  2447. exit 0 # Just in case...
  2448.