home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / vim / part13 < prev    next >
Internet Message Format  |  1994-08-16  |  71KB

  1. From: mool@oce.nl (Bram Moolenaar)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i032:  vim - Vi IMproved editor, v3.0, Part13/26
  4. Date: 16 Aug 1994 21:18:28 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <32rs1k$kfa@sparky.sterling.com>
  9. X-Md4-Signature: e61c3596e86cdffc1808f95d9a9b0078
  10.  
  11. Submitted-by: mool@oce.nl (Bram Moolenaar)
  12. Posting-number: Volume 44, Issue 32
  13. Archive-name: vim/part13
  14. Environment: UNIX, AMIGA, MS-DOS, Windows NT
  15. Supersedes: vim: Volume 41, Issue 50-75
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  vim/src/cmdline.c.A vim/src/memfile.c
  22. # Wrapped by kent@sparky on Mon Aug 15 21:44:06 1994
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 13 (of 26)."'
  26. if test -f 'vim/src/cmdline.c.A' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'vim/src/cmdline.c.A'\"
  28. else
  29.   echo shar: Extracting \"'vim/src/cmdline.c.A'\" \(38908 characters\)
  30.   sed "s/^X//" >'vim/src/cmdline.c.A' <<'END_OF_FILE'
  31. X/* vi:ts=4:sw=4
  32. X *
  33. X * VIM - Vi IMproved        by Bram Moolenaar
  34. X *
  35. X * Read the file "credits.txt" for a list of people who contributed.
  36. X * Read the file "uganda.txt" for copying and usage conditions.
  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/*
  52. X * variables shared between getcmdline() and redrawcmdline()
  53. X */
  54. Xstatic int         cmdlen;        /* number of chars on command line */
  55. Xstatic int         cmdpos;        /* current cursor position */
  56. Xstatic int         cmdspos;        /* cursor column on screen */
  57. Xstatic int         cmdfirstc;     /* ':', '/' or '?' */
  58. Xstatic char_u    *cmdbuff;        /* pointer to command line buffer */
  59. X
  60. X/*
  61. X * The next two variables contain the bounds of any range given in a command.
  62. X * They are set by docmdline().
  63. X */
  64. Xstatic linenr_t     line1, line2;
  65. X
  66. Xstatic int            forceit;
  67. Xstatic int            regname;
  68. Xstatic int            quitmore = 0;
  69. Xstatic int          cmd_numfiles = -1;      /* number of files found by
  70. X                                                    filename completion */
  71. X
  72. Xstatic void        putcmdline __ARGS((int, char_u *));
  73. Xstatic void        cursorcmd __ARGS((void));
  74. Xstatic int        ccheck_abbr __ARGS((int));
  75. Xstatic char_u    *DoOneCmd __ARGS((char_u *));
  76. Xstatic int        buf_write_all __ARGS((BUF *));
  77. Xstatic int        dowrite __ARGS((char_u *, int));
  78. Xstatic char_u    *getargcmd __ARGS((char_u **));
  79. Xstatic char_u    *checknextcomm __ARGS((char_u *));
  80. Xstatic void        domake __ARGS((char_u *));
  81. Xstatic int        doarglist __ARGS((char_u *));
  82. Xstatic int        check_readonly __ARGS((void));
  83. Xstatic int        check_changed __ARGS((BUF *, int, int));
  84. Xstatic int        check_changed_any __ARGS((int));
  85. Xstatic int        check_more __ARGS((int));
  86. X#ifdef WEBB_COMPLETE
  87. Xstatic void        vim_strncpy __ARGS((char_u *, char_u *, int));
  88. Xstatic int        nextwild __ARGS((char_u *, int));
  89. Xstatic int        showmatches __ARGS((char_u *));
  90. Xstatic void        set_expand_context __ARGS((int, char_u *));
  91. Xstatic char_u    *set_one_cmd_context __ARGS((int, char_u *));
  92. Xstatic int        ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));
  93. X#else
  94. Xstatic void        nextwild __ARGS((char_u *, int));
  95. Xstatic void        showmatches __ARGS((char_u *, int));
  96. X#endif /* WEBB_COMPLETE */
  97. Xstatic char_u    *addstar __ARGS((char_u *, int));
  98. Xstatic linenr_t get_address __ARGS((char_u **));
  99. X
  100. X/*
  101. X * getcmdline() - accept a command line starting with ':', '!', '/', or '?'
  102. X *
  103. X * For searches the optional matching '?' or '/' is removed.
  104. X *
  105. X * Return OK if there is a commandline, FAIL if not
  106. X */
  107. X
  108. X    int
  109. Xgetcmdline(firstc, buff)
  110. X    int            firstc;     /* either ':', '/', or '?' */
  111. X    char_u        *buff;         /* buffer for command string */
  112. X{
  113. X    register char_u     c;
  114. X             int        cc;
  115. X             int        nextc = 0;
  116. X    register int        i;
  117. X             int        retval;
  118. X             int        hiscnt;                /* current history line in use */
  119. X    static     char_u        **history = NULL;    /* history table */
  120. X    static     int        hislen = 0;         /* actual lengt of history table */
  121. X             int        newlen;                /* new length of history table */
  122. X    static     int        hisidx = -1;        /* last entered entry */
  123. X             char_u        **temp;
  124. X             char_u        *lookfor = NULL;    /* string to match */
  125. X             int        j = -1;
  126. X             int        gotesc = FALSE;        /* TRUE when last char typed was <ESC> */
  127. X             int        do_abbr;            /* when TRUE check for abbr. */
  128. X
  129. X/*
  130. X * set some variables for redrawcmd()
  131. X */
  132. X    cmdfirstc = firstc;
  133. X    cmdbuff = buff;
  134. X    cmdlen = cmdpos = 0;
  135. X    cmdspos = 1;
  136. X    State = CMDLINE;
  137. X    gotocmdline(TRUE, firstc);
  138. X
  139. X/*
  140. X * if size of history table changed, reallocate it
  141. X */
  142. X    newlen = (int)p_hi;
  143. X    if (newlen != hislen)                        /* history length changed */
  144. X    {
  145. X        if (newlen)
  146. X            temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)), TRUE);
  147. X        else
  148. X            temp = NULL;
  149. X        if (newlen == 0 || temp != NULL)
  150. X        {
  151. X            if (newlen > hislen)            /* array becomes bigger */
  152. X            {
  153. X                for (i = 0; i <= hisidx; ++i)
  154. X                    temp[i] = history[i];
  155. X                j = i;
  156. X                for ( ; i <= newlen - (hislen - hisidx); ++i)
  157. X                    temp[i] = NULL;
  158. X                for ( ; j < hislen; ++i, ++j)
  159. X                    temp[i] = history[j];
  160. X            }
  161. X            else                            /* array becomes smaller */
  162. X            {
  163. X                j = hisidx;
  164. X                for (i = newlen - 1; ; --i)
  165. X                {
  166. X                    if (i >= 0)
  167. X                        temp[i] = history[j];    /* copy newest entries */
  168. X                    else
  169. X                        free(history[j]);        /* remove older entries */
  170. X                    if (--j < 0)
  171. X                        j = hislen - 1;
  172. X                    if (j == hisidx)
  173. X                        break;
  174. X                }
  175. X                hisidx = newlen - 1;
  176. X            }
  177. X            free(history);
  178. X            history = temp;
  179. X            hislen = newlen;
  180. X        }
  181. X    }
  182. X    hiscnt = hislen;            /* set hiscnt to impossible history value */
  183. X
  184. X#ifdef DIGRAPHS
  185. X    dodigraph(-1);                /* init digraph typahead */
  186. X#endif
  187. X
  188. X    /* collect the command string, handling '\b', @ and much more */
  189. X    for (;;)
  190. X    {
  191. X        cursorcmd();    /* set the cursor on the right spot */
  192. X        if (nextc)        /* character remaining from CTRL-V */
  193. X        {
  194. X            c = nextc;
  195. X            nextc = 0;
  196. X        }
  197. X        else
  198. X        {
  199. X            c = vgetc();
  200. X            if (c == Ctrl('C'))
  201. X                got_int = FALSE;
  202. X        }
  203. X
  204. X        if (lookfor && c != K_SDARROW && c != K_SUARROW)
  205. X        {
  206. X            free(lookfor);
  207. X            lookfor = NULL;
  208. X        }
  209. X
  210. X        if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
  211. X                        c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
  212. X            (void)ExpandOne(NULL, FALSE, -2);    /* may free expanded file names */
  213. X
  214. X#ifdef DIGRAPHS
  215. X        c = dodigraph(c);
  216. X#endif
  217. X
  218. X        if (c == '\n' || c == '\r' || (c == ESC && !KeyTyped))
  219. X        {
  220. X            if (ccheck_abbr(c + 0x100))
  221. X                continue;
  222. X            outchar('\r');        /* show that we got the return */
  223. X            flushbuf();
  224. X            break;
  225. X        }
  226. X
  227. X            /* hitting <ESC> twice means: abandon command line */
  228. X            /* wildcard expansion is only done when the key is really typed, not
  229. X               when it comes from a macro */
  230. X        if (c == p_wc && !gotesc && KeyTyped)
  231. X        {
  232. X#ifdef WEBB_COMPLETE
  233. X            if (cmd_numfiles > 0)    /* typed p_wc twice */
  234. X                i = nextwild(buff, 3);
  235. X            else                    /* typed p_wc first time */
  236. X                i = nextwild(buff, 0);
  237. X            if (c == ESC)
  238. X                gotesc = TRUE;
  239. X            if (i)
  240. X                continue;
  241. X#else
  242. X            if (cmd_numfiles > 0)    /* typed p_wc twice */
  243. X                nextwild(buff, 3);
  244. X            else                    /* typed p_wc first time */
  245. X                nextwild(buff, 0);
  246. X            if (c == ESC)
  247. X                gotesc = TRUE;
  248. X            continue;
  249. X#endif /* WEBB_COMPLETE */
  250. X        }
  251. X        gotesc = FALSE;
  252. X
  253. X        if (c == K_ZERO)        /* NUL is stored as NL */
  254. X            c = '\n';
  255. X
  256. X        do_abbr = TRUE;            /* default: check for abbreviation */
  257. X        switch (c)
  258. X        {
  259. X        case BS:
  260. X        case DEL:
  261. X        case Ctrl('W'):
  262. X                /*
  263. X                 * delete current character is the same as backspace on next
  264. X                 * character, except at end of line
  265. X                 */
  266. X                if (c == DEL && cmdpos != cmdlen)
  267. X                    ++cmdpos;
  268. X                if (cmdpos > 0)
  269. X                {
  270. X                    j = cmdpos;
  271. X                    if (c == Ctrl('W'))
  272. X                    {
  273. X                        while (cmdpos && isspace(buff[cmdpos - 1]))
  274. X                            --cmdpos;
  275. X                        i = isidchar(buff[cmdpos - 1]);
  276. X                        while (cmdpos && !isspace(buff[cmdpos - 1]) && isidchar(buff[cmdpos - 1]) == i)
  277. X                            --cmdpos;
  278. X                    }
  279. X                    else
  280. X                        --cmdpos;
  281. X                    cmdlen -= j - cmdpos;
  282. X                    i = cmdpos;
  283. X                    while (i < cmdlen)
  284. X                        buff[i++] = buff[j++];
  285. X                    redrawcmd();
  286. X                }
  287. X                else if (cmdlen == 0 && c != Ctrl('W'))
  288. X                {
  289. X                    retval = FAIL;
  290. X                    msg_pos(-1, 0);
  291. X                    msg_outchar(' ');    /* delete ':' */
  292. X                    goto returncmd;     /* back to cmd mode */
  293. X                }
  294. X                continue;
  295. X
  296. X/*        case '@':    only in very old vi */
  297. X        case Ctrl('U'):
  298. Xclearline:
  299. X                cmdpos = 0;
  300. X                cmdlen = 0;
  301. X                cmdspos = 1;
  302. X                redrawcmd();
  303. X                continue;
  304. X
  305. X        case ESC:            /* get here if p_wc != ESC or when ESC typed twice */
  306. X        case Ctrl('C'):
  307. Xdo_esc:
  308. X                retval = FAIL;
  309. X                MSG("");
  310. X                goto returncmd;     /* back to cmd mode */
  311. X
  312. X        case Ctrl('D'):
  313. X            {
  314. X#ifdef WEBB_COMPLETE
  315. X                /* set_expand_context() now finds start of the pattern, so
  316. X                 * don't do it here -- webb
  317. X                 */
  318. X                if (showmatches(buff) == FAIL)
  319. X                    break;        /* Use ^D as normal char instead */
  320. X#else
  321. X                for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  322. X                        ;
  323. X                showmatches(&buff[i], cmdpos - i);
  324. X#endif /* WEBB_COMPLETE */
  325. X
  326. X                redrawcmd();
  327. X                continue;
  328. X            }
  329. X
  330. X        case K_RARROW:
  331. X        case K_SRARROW:
  332. X                do
  333. X                {
  334. X                        if (cmdpos >= cmdlen)
  335. X                                break;
  336. X                        cmdspos += charsize(buff[cmdpos]);
  337. X                        ++cmdpos;
  338. X                }
  339. X                while (c == K_SRARROW && buff[cmdpos] != ' ');
  340. X                continue;
  341. X
  342. X        case K_LARROW:
  343. X        case K_SLARROW:
  344. X                do
  345. X                {
  346. X                        if (cmdpos <= 0)
  347. X                                break;
  348. X                        --cmdpos;
  349. X                        cmdspos -= charsize(buff[cmdpos]);
  350. X                }
  351. X                while (c == K_SLARROW && buff[cmdpos - 1] != ' ');
  352. X                continue;
  353. X
  354. X        case Ctrl('B'):        /* begin of command line */
  355. X                cmdpos = 0;
  356. X                cmdspos = 1;
  357. X                continue;
  358. X
  359. X        case Ctrl('E'):        /* end of command line */
  360. X                cmdpos = cmdlen;
  361. X                buff[cmdlen] = NUL;
  362. X                cmdspos = strsize(buff) + 1;
  363. X                continue;
  364. X
  365. X        case Ctrl('A'):        /* all matches */
  366. X#ifdef WEBB_COMPLETE
  367. X                if (!nextwild(buff, 4))
  368. X                    break;
  369. X#else
  370. X                nextwild(buff, 4);
  371. X#endif /* WEBB_COMPLETE */
  372. X                continue;
  373. X
  374. X        case Ctrl('L'):        /* longest common part */
  375. X#ifdef WEBB_COMPLETE
  376. X                if (!nextwild(buff, 5))
  377. X                    break;
  378. X#else
  379. X                nextwild(buff, 5);
  380. X#endif /* WEBB_COMPLETE */
  381. X                continue;
  382. X
  383. X        case Ctrl('N'):        /* next match */
  384. X        case Ctrl('P'):        /* previous match */
  385. X                if (cmd_numfiles > 0)
  386. X                {
  387. X#ifdef WEBB_COMPLETE
  388. X                    if (!nextwild(buff, (c == Ctrl('P')) ? 2 : 1))
  389. X                        break;
  390. X#else
  391. X                    nextwild(buff, (c == Ctrl('P')) ? 2 : 1);
  392. X#endif /* WEBB_COMPLETE */
  393. X                    continue;
  394. X                }
  395. X
  396. X        case K_UARROW:
  397. X        case K_DARROW:
  398. X        case K_SUARROW:
  399. X        case K_SDARROW:
  400. X                if (hislen == 0)        /* no history */
  401. X                    continue;
  402. X
  403. X                i = hiscnt;
  404. X            
  405. X                    /* save current command string */
  406. X                if (c == K_SUARROW || c == K_SDARROW)
  407. X                {
  408. X                    buff[cmdpos] = NUL;
  409. X                    if (lookfor == NULL && (lookfor = strsave(buff)) == NULL)
  410. X                        continue;
  411. X
  412. X                    j = STRLEN(lookfor);
  413. X                }
  414. X                for (;;)
  415. X                {
  416. X                        /* one step backwards */
  417. X                    if (c == K_UARROW || c == K_SUARROW || c == Ctrl('P'))
  418. X                    {
  419. X                        if (hiscnt == hislen)    /* first time */
  420. X                            hiscnt = hisidx;
  421. X                        else if (hiscnt == 0 && hisidx != hislen - 1)
  422. X                            hiscnt = hislen - 1;
  423. X                        else if (hiscnt != hisidx + 1)
  424. X                            --hiscnt;
  425. X                        else                    /* at top of list */
  426. X                            break;
  427. X                    }
  428. X                    else    /* one step forwards */
  429. X                    {
  430. X                        if (hiscnt == hisidx)    /* on last entry, clear the line */
  431. X                        {
  432. X                            hiscnt = hislen;
  433. X                            goto clearline;
  434. X                        }
  435. X                        if (hiscnt == hislen)    /* not on a history line, nothing to do */
  436. X                            break;
  437. X                        if (hiscnt == hislen - 1)    /* wrap around */
  438. X                            hiscnt = 0;
  439. X                        else
  440. X                            ++hiscnt;
  441. X                    }
  442. X                    if (hiscnt < 0 || history[hiscnt] == NULL)
  443. X                    {
  444. X                        hiscnt = i;
  445. X                        break;
  446. X                    }
  447. X                    if ((c != K_SUARROW && c != K_SDARROW) || hiscnt == i ||
  448. X                            STRNCMP(history[hiscnt], lookfor, (size_t)j) == 0)
  449. X                        break;
  450. X                }
  451. X
  452. X                if (hiscnt != i)        /* jumped to other entry */
  453. X                {
  454. X                    STRCPY(buff, history[hiscnt]);
  455. X                    cmdpos = cmdlen = STRLEN(buff);
  456. X                    redrawcmd();
  457. X                }
  458. X                continue;
  459. X
  460. X        case Ctrl('V'):
  461. X                putcmdline('^', buff);
  462. X                c = get_literal(&nextc);    /* get next (two) character(s) */
  463. X                do_abbr = FALSE;            /* don't do abbreviation now */
  464. X                break;
  465. X
  466. X#ifdef DIGRAPHS
  467. X        case Ctrl('K'):
  468. X                putcmdline('?', buff);
  469. X                  c = vgetc();
  470. X                if (c == ESC)
  471. X                    goto do_esc;
  472. X                if (charsize(c) == 1)
  473. X                    putcmdline(c, buff);
  474. X                cc = vgetc();
  475. X                if (cc == ESC)
  476. X                    goto do_esc;
  477. X                c = getdigraph(c, cc, TRUE);
  478. X                break;
  479. X#endif /* DIGRAPHS */
  480. X        }
  481. X
  482. X        /* we come here if we have a normal character */
  483. X
  484. X        if (do_abbr && !isidchar(c) && ccheck_abbr(c))
  485. X            continue;
  486. X
  487. X        if (cmdlen < CMDBUFFSIZE - 2)
  488. X        {
  489. X                for (i = cmdlen++; i > cmdpos; --i)
  490. X                        buff[i] = buff[i - 1];
  491. X                buff[cmdpos] = c;
  492. X                msg_outtrans(buff + cmdpos, cmdlen - cmdpos);
  493. X                ++cmdpos;
  494. X                i = charsize(c);
  495. X                cmdspos += i;
  496. X        }
  497. X        msg_check();
  498. X    }
  499. X    retval = OK;                /* when we get here we have a valid command line */
  500. X
  501. Xreturncmd:
  502. X    buff[cmdlen] = NUL;
  503. X    /*
  504. X     * put line in history buffer
  505. X     */
  506. X    if (cmdlen != 0)
  507. X    {
  508. X        if (hislen != 0)
  509. X        {
  510. X            if (++hisidx == hislen)
  511. X                hisidx = 0;
  512. X            free(history[hisidx]);
  513. X            history[hisidx] = strsave(buff);
  514. X        }
  515. X        if (firstc == ':')
  516. X        {
  517. X            free(new_last_cmdline);
  518. X            new_last_cmdline = strsave(buff);
  519. X        }
  520. X    }
  521. X
  522. X    /*
  523. X     * If the screen was shifted up, redraw the whole screen (later).
  524. X     * If the line is too long, clear it, so ruler and shown command do
  525. X     * not get printed in the middle of it.
  526. X     */
  527. X    msg_check();
  528. X    State = NORMAL;
  529. X    return retval;
  530. X}
  531. X
  532. X/*
  533. X * put a character on the command line.
  534. X * Used for CTRL-V and CTRL-K
  535. X */
  536. X    static void
  537. Xputcmdline(c, buff)
  538. X    int        c;
  539. X    char_u    *buff;
  540. X{
  541. X    char_u    buf[2];
  542. X
  543. X    buf[0] = c;
  544. X    buf[1] = 0;
  545. X    msg_outtrans(buf, 1);
  546. X    msg_outtrans(buff + cmdpos, cmdlen - cmdpos);
  547. X    cursorcmd();
  548. X}
  549. X
  550. X/*
  551. X * this fuction is called when the screen size changes
  552. X */
  553. X    void
  554. Xredrawcmdline()
  555. X{
  556. X    msg_scrolled = 0;
  557. X    compute_cmdrow();
  558. X    redrawcmd();
  559. X    cursorcmd();
  560. X}
  561. X
  562. X    void
  563. Xcompute_cmdrow()
  564. X{
  565. X    cmdline_row = lastwin->w_winpos + lastwin->w_height + lastwin->w_status_height;
  566. X}
  567. X
  568. X/*
  569. X * Redraw what is currently on the command line.
  570. X */
  571. X    void
  572. Xredrawcmd()
  573. X{
  574. X    register int    i;
  575. X
  576. X    msg_start();
  577. X    msg_outchar(cmdfirstc);
  578. X    msg_outtrans(cmdbuff, cmdlen);
  579. X    msg_ceol();
  580. X
  581. X    cmdspos = 1;
  582. X    for (i = 0; i < cmdlen && i < cmdpos; ++i)
  583. X        cmdspos += charsize(cmdbuff[i]);
  584. X}
  585. X
  586. X    static void
  587. Xcursorcmd()
  588. X{
  589. X    msg_pos(cmdline_row + (cmdspos / (int)Columns), cmdspos % (int)Columns);
  590. X    windgoto(msg_row, msg_col);
  591. X}
  592. X
  593. X/*
  594. X * Check the word in front of the cursor for an abbreviation.
  595. X * Called when the non-id character "c" has been entered.
  596. X * When an abbreviation is recognized it is removed from the text with
  597. X * backspaces and the replacement string is inserted, followed by "c".
  598. X */
  599. X    static int
  600. Xccheck_abbr(c)
  601. X    int c;
  602. X{
  603. X    if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  604. X        return FALSE;
  605. X    
  606. X    return check_abbr(c, cmdbuff, cmdpos, 0);
  607. X}
  608. X
  609. X/*
  610. X * docmdline(): execute an Ex command line
  611. X *
  612. X * 1. If no line given, get one.
  613. X * 2. Split up in parts separated with '|'.
  614. X *
  615. X * This function may be called recursively!
  616. X *
  617. X * return FAIL if commandline could not be executed, OK otherwise
  618. X */
  619. X    int
  620. Xdocmdline(cmdline)
  621. X    char_u        *cmdline;
  622. X{
  623. X    char_u        buff[CMDBUFFSIZE];        /* command line */
  624. X    char_u        *nextcomm;
  625. X
  626. X/*
  627. X * 1. If no line given: get one.
  628. X */
  629. X    if (cmdline == NULL)
  630. X    {
  631. X        if (getcmdline(':', buff) == FAIL)
  632. X            return FAIL;
  633. X    }
  634. X    else
  635. X    {
  636. X        if (STRLEN(cmdline) > (size_t)(CMDBUFFSIZE - 2))
  637. X        {
  638. X            emsg(e_toolong);
  639. X            return FAIL;
  640. X        }
  641. X        /* Make a copy of the command so we can mess with it. */
  642. X        STRCPY(buff, cmdline);
  643. X    }
  644. X
  645. X/*
  646. X * 2. Loop for each '|' separated command.
  647. X *    DoOneCmd will set nextcommand to NULL if there is no trailing '|'.
  648. X */
  649. X    for (;;)
  650. X    {
  651. X        nextcomm = DoOneCmd(buff);
  652. X        if (nextcomm == NULL)
  653. X            break;
  654. X        STRCPY(buff, nextcomm);
  655. X    }
  656. X/*
  657. X * If the command was typed, remember it for register :
  658. X * Do this AFTER executing the command to make :@: work.
  659. X */
  660. X    if (cmdline == NULL && new_last_cmdline != NULL)
  661. X    {
  662. X        free(last_cmdline);
  663. X        last_cmdline = new_last_cmdline;
  664. X        new_last_cmdline = NULL;
  665. X    }
  666. X    return OK;
  667. X}
  668. X
  669. X/*
  670. X * Execute one Ex command.
  671. X *
  672. X * 2. skip comment lines and leading space
  673. X * 3. parse range
  674. X * 4. parse command
  675. X * 5. parse arguments
  676. X * 6. switch on command name
  677. X *
  678. X * This function may be called recursively!
  679. X */
  680. X    static char_u *
  681. XDoOneCmd(buff)
  682. X    char_u *buff;
  683. X{
  684. X    char_u                cmdbuf[CMDBUFFSIZE];    /* for '%' and '#' expansion */
  685. X    char_u                c;
  686. X    register char_u        *p;
  687. X    char_u                *q;
  688. X    char_u                *cmd, *arg;
  689. X    char_u                *editcmd = NULL;        /* +command arg. for doecmd() */
  690. X    linenr_t             doecmdlnum = 0;            /* lnum in new file for doecmd() */
  691. X    int                 i = 0;                    /* init to shut up gcc */
  692. X    int                    cmdidx;
  693. X    int                    argt;
  694. X    register linenr_t    lnum;
  695. X    long                n;
  696. X    int                    addr_count;    /* number of address specifications */
  697. X    FPOS                pos;
  698. X    int                    append = FALSE;            /* write with append */
  699. X    int                    usefilter = FALSE;        /* filter instead of file name */
  700. X    char_u                *nextcomm = NULL;        /* no next command yet */
  701. X    int                    amount = 0;                /* for ":>" and ":<"; init for gcc */
  702. X
  703. X    if (quitmore)
  704. X        --quitmore;        /* when not editing the last file :q has to be typed twice */
  705. X/*
  706. X * 2. skip comment lines and leading space, colons or bars
  707. X */
  708. X    for (cmd = buff; *cmd && strchr(" \t:|", *cmd) != NULL; cmd++)
  709. X        ;
  710. X
  711. X    if (*cmd == '"' || *cmd == NUL)    /* ignore comment and empty lines */
  712. X        goto doend;
  713. X
  714. X/*
  715. X * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  716. X *
  717. X * where 'addr' is:
  718. X *
  719. X * %          (entire file)
  720. X * $  [+-NUM]
  721. X * 'x [+-NUM] (where x denotes a currently defined mark)
  722. X * .  [+-NUM]
  723. X * [+-NUM]..
  724. X * NUM
  725. X *
  726. X * The cmd pointer is updated to point to the first character following the
  727. X * range spec. If an initial address is found, but no second, the upper bound
  728. X * is equal to the lower.
  729. X */
  730. X
  731. X    addr_count = 0;
  732. X    --cmd;
  733. X    do
  734. X    {
  735. X        ++cmd;                            /* skip ',' or ';' */
  736. X        line1 = line2;
  737. X        line2 = curwin->w_cursor.lnum;            /* default is current line number */
  738. X        skipspace(&cmd);
  739. X        lnum = get_address(&cmd);
  740. X        if (lnum == MAXLNUM)
  741. X        {
  742. X            if (*cmd == '%')            /* '%' - all lines */
  743. X            {
  744. X                ++cmd;
  745. X                line1 = 1;
  746. X                line2 = curbuf->b_ml.ml_line_count;
  747. X                ++addr_count;
  748. X            }
  749. X        }
  750. X        else
  751. X            line2 = lnum;
  752. X        addr_count++;
  753. X
  754. X        if (*cmd == ';')
  755. X        {
  756. X            if (line2 == 0)
  757. X                curwin->w_cursor.lnum = 1;
  758. X            else
  759. X                curwin->w_cursor.lnum = line2;
  760. X        }
  761. X    } while (*cmd == ',' || *cmd == ';');
  762. X
  763. X    /* One address given: set start and end lines */
  764. X    if (addr_count == 1)
  765. X    {
  766. X        line1 = line2;
  767. X            /* ... but only implicit: really no address given */
  768. X        if (lnum == MAXLNUM)
  769. X            addr_count = 0;
  770. X    }
  771. X
  772. X/*
  773. X * 4. parse command
  774. X */
  775. X
  776. X    skipspace(&cmd);
  777. X
  778. X    /*
  779. X     * If we got a line, but no command, then go to the line.
  780. X     * If we find a '|' or '\n' we set nextcomm.
  781. X     */
  782. X    if (*cmd == NUL || *cmd == '"' ||
  783. X            ((*cmd == '|' || *cmd == '\n') &&
  784. X                    (nextcomm = cmd + 1) != NULL))        /* just an assignment */
  785. X    {
  786. X        if (addr_count != 0)
  787. X        {
  788. X            /*
  789. X             * strange vi behaviour: ":3" jumps to line 3
  790. X             * ":3|..." prints line 3
  791. X             */
  792. X            if (*cmd == '|')
  793. X            {
  794. X                cmdidx = CMD_print;
  795. X                goto cmdswitch;            /* UGLY goto */
  796. X            }
  797. X            if (line2 == 0)
  798. X                curwin->w_cursor.lnum = 1;
  799. X            else if (line2 > curbuf->b_ml.ml_line_count)
  800. X                curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  801. X            else
  802. X                curwin->w_cursor.lnum = line2;
  803. X            curwin->w_cursor.col = 0;
  804. X            cursupdate();
  805. X        }
  806. X        goto doend;
  807. X    }
  808. X
  809. X    /*
  810. X     * Isolate the command and search for it in the command table.
  811. X     * Exeptions:
  812. X     * - the 'k' command can directly be followed by any character.
  813. X     * - the 's' command can be followed directly by 'c', 'g' or 'r'
  814. X     *        but :sre[wind] is another command.
  815. X     */
  816. X    if (*cmd == 'k')
  817. X    {
  818. X        cmdidx = CMD_k;
  819. X        p = cmd + 1;
  820. X    }
  821. X    else if (*cmd == 's' && strchr("cgr", cmd[1]) != NULL && STRNCMP("sre", cmd, (size_t)3) != 0)
  822. X    {
  823. X        cmdidx = CMD_substitute;
  824. X        p = cmd + 1;
  825. X    }
  826. X    else
  827. X    {
  828. X        p = cmd;
  829. X        while (isalpha(*p))
  830. X            ++p;
  831. X        if (p == cmd && strchr("@!=><&~#", *p) != NULL)    /* non-alpha command */
  832. X            ++p;
  833. X        i = (int)(p - cmd);
  834. X
  835. X        for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
  836. X            if (STRNCMP(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
  837. X                break;
  838. X        if (i == 0 || cmdidx == CMD_SIZE)
  839. X        {
  840. X            emsg(e_invcmd);
  841. X            goto doend;
  842. X        }
  843. X    }
  844. X
  845. X    if (*p == '!')                    /* forced commands */
  846. X    {
  847. X        ++p;
  848. X        forceit = TRUE;
  849. X    }
  850. X    else
  851. X        forceit = FALSE;
  852. X
  853. X/*
  854. X * 5. parse arguments
  855. X */
  856. X    argt = cmdnames[cmdidx].cmd_argt;
  857. X
  858. X    if (!(argt & RANGE) && addr_count)
  859. X    {
  860. X        emsg(e_norange);
  861. X        goto doend;
  862. X    }
  863. X
  864. X/*
  865. X * If the range is backwards, ask for confirmation and, if given, swap
  866. X * line1 & line2 so it's forwards again.
  867. X * When global command is busy, don't ask, will fail below.
  868. X */
  869. X    if (!global_busy && line1 > line2)
  870. X    {
  871. X        if (ask_yesno((char_u *)"Backwards range given, OK to swap") != 'y')
  872. X            goto doend;
  873. X        lnum = line1;
  874. X        line1 = line2;
  875. X        line2 = lnum;
  876. X    }
  877. X    /*
  878. X     * don't complain about the range if it is not used
  879. X     * (could happen if line_count is accidently set to 0)
  880. X     */
  881. X    if (line1 < 0 || line2 < 0  || line1 > line2 || ((argt & RANGE) &&
  882. X                    !(argt & NOTADR) && line2 > curbuf->b_ml.ml_line_count))
  883. X    {
  884. X        emsg(e_invrange);
  885. X        goto doend;
  886. X    }
  887. X
  888. X    if ((argt & NOTADR) && addr_count == 0)        /* default is 1, not cursor */
  889. X        line2 = 1;
  890. X
  891. X    if (!(argt & ZEROR))            /* zero in range not allowed */
  892. X    {
  893. X        if (line1 == 0)
  894. X            line1 = 1;
  895. X        if (line2 == 0)
  896. X            line2 = 1;
  897. X    }
  898. X
  899. X    /*
  900. X     * for the :make command we insert the 'makeprg' option here,
  901. X     * so things like % get expanded
  902. X     */
  903. X    if (cmdidx == CMD_make)
  904. X    {
  905. X        if (STRLEN(p_mp) + STRLEN(p) + 2 >= (unsigned)CMDBUFFSIZE)
  906. X        {
  907. X            emsg(e_toolong);
  908. X            goto doend;
  909. X        }
  910. X        STRCPY(cmdbuf, p_mp);
  911. X        STRCAT(cmdbuf, " ");
  912. X        STRCAT(cmdbuf, p);
  913. X        STRCPY(buff,   cmdbuf);
  914. X        p = buff;
  915. X    }
  916. X
  917. X    arg = p;                        /* remember start of argument */
  918. X    skipspace(&arg);
  919. X
  920. X    if ((argt & NEEDARG) && *arg == NUL)
  921. X    {
  922. X        emsg(e_argreq);
  923. X        goto doend;
  924. X    }
  925. X
  926. X    if (cmdidx == CMD_write)
  927. X    {
  928. X        if (*arg == '>')                        /* append */
  929. X        {
  930. X            if (*++arg != '>')                /* typed wrong */
  931. X            {
  932. X                EMSG("Use w or w>>");
  933. X                goto doend;
  934. X            }
  935. X            ++arg;
  936. X            skipspace(&arg);
  937. X            append = TRUE;
  938. X        }
  939. X        else if (*arg == '!')                    /* :w !filter */
  940. X        {
  941. X            ++arg;
  942. X            usefilter = TRUE;
  943. X        }
  944. X    }
  945. X
  946. X    if (cmdidx == CMD_read)
  947. X    {
  948. X        usefilter = forceit;                    /* :r! filter if forceit */
  949. X        if (*arg == '!')                        /* :r !filter */
  950. X        {
  951. X            ++arg;
  952. X            usefilter = TRUE;
  953. X        }
  954. X    }
  955. X
  956. X    if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
  957. X    {
  958. X        amount = 1;
  959. X        while (*arg == *cmd)        /* count number of '>' or '<' */
  960. X        {
  961. X            ++arg;
  962. X            ++amount;
  963. X        }
  964. X        skipspace(&arg);
  965. X    }
  966. X
  967. X    /*
  968. X     * Check for '|' to separate commands and '"' to start comments.
  969. X     * Don't do this for ":read !cmd" and ":write !cmd".
  970. X     */
  971. X    if ((argt & TRLBAR) && !usefilter)
  972. X    {
  973. X        p = arg;
  974. X        while (*p)
  975. X        {
  976. X            if (*p == Ctrl('V'))
  977. X            {
  978. X                if ((argt & USECTRLV) && p[1] != NUL)    /* skip CTRL-V and next char */
  979. X                    ++p;
  980. X                else                    /* remove CTRL-V and skip next char */
  981. X                    STRCPY(p, p + 1);
  982. X            }
  983. X            else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
  984. X            {
  985. X                if (*(p - 1) == '\\')    /* remove the backslash */
  986. X                {
  987. X                    STRCPY(p - 1, p);
  988. X                    --p;
  989. X                }
  990. X                else
  991. X                {
  992. X                    if (*p == '|' || *p == '\n')
  993. X                        nextcomm = p + 1;
  994. X                    *p = NUL;
  995. X                    break;
  996. X                }
  997. X            }
  998. X            ++p;
  999. X        }
  1000. X        if (!(argt & NOTRLCOM))            /* remove trailing spaces */
  1001. X            del_spaces(arg);
  1002. X    }
  1003. X
  1004. X    if ((argt & DFLALL) && addr_count == 0)
  1005. X    {
  1006. X        line1 = 1;
  1007. X        line2 = curbuf->b_ml.ml_line_count;
  1008. X    }
  1009. X
  1010. X    regname = 0;
  1011. X        /* accept numbered register only when no count allowed (:put) */
  1012. X    if ((argt & REGSTR) && *arg != NUL && is_yank_buffer(*arg, FALSE) && !((argt & COUNT) && isdigit(*arg)))
  1013. X    {
  1014. X        regname = *arg;
  1015. X        ++arg;
  1016. X        skipspace(&arg);
  1017. X    }
  1018. X
  1019. X    if ((argt & COUNT) && isdigit(*arg))
  1020. X    {
  1021. X        n = getdigits(&arg);
  1022. X        skipspace(&arg);
  1023. X        if (n <= 0)
  1024. X        {
  1025. X            emsg(e_zerocount);
  1026. X            goto doend;
  1027. X        }
  1028. X        if (argt & NOTADR)        /* e.g. :buffer 2, :sleep 3 */
  1029. X        {
  1030. X            line2 = n;
  1031. X            if (addr_count == 0)
  1032. X                addr_count = 1;
  1033. X        }
  1034. X        else
  1035. X        {
  1036. X            line1 = line2;
  1037. X            line2 += n - 1;
  1038. X            ++addr_count;
  1039. X        }
  1040. X    }
  1041. X
  1042. X    if (!(argt & EXTRA) && strchr("|\"", *arg) == NULL)    /* no arguments allowed */
  1043. X    {
  1044. X        emsg(e_trailing);
  1045. X        goto doend;
  1046. X    }
  1047. X
  1048. X    /*
  1049. X     * change '%' to curbuf->b_filename, '#' to curwin->w_altfile
  1050. X     */
  1051. X    if (argt & XFILE)
  1052. X    {
  1053. X        for (p = arg; *p; ++p)
  1054. X        {
  1055. X            c = *p;
  1056. X            if (c != '%' && c != '#')    /* nothing to expand */
  1057. X                continue;
  1058. X            if (*(p - 1) == '\\')        /* remove escaped char */
  1059. X            {
  1060. X                STRCPY(p - 1, p);
  1061. X                --p;
  1062. X                continue;
  1063. X            }
  1064. X
  1065. X            if (c == '%')                /* current file */
  1066. X            {
  1067. X                if (check_fname() == FAIL)
  1068. X                    goto doend;
  1069. X                q = curbuf->b_xfilename;
  1070. X                n = 1;                    /* length of what we expand */
  1071. X            }
  1072. X            else                        /* '#': alternate file */
  1073. X            {
  1074. X                q = p + 1;
  1075. X                i = (int)getdigits(&q);
  1076. X                n = q - p;                /* length of what we expand */
  1077. X
  1078. X                if (buflist_name_nr(i, &q, &doecmdlnum) == FAIL)
  1079. X                {
  1080. X                    emsg(e_noalt);
  1081. X                    goto doend;
  1082. X                }
  1083. X            }
  1084. X            i = STRLEN(arg) + STRLEN(q) + 3;
  1085. X            if (nextcomm)
  1086. X                i += STRLEN(nextcomm);
  1087. X            if (i > CMDBUFFSIZE)
  1088. X            {
  1089. X                emsg(e_toolong);
  1090. X                goto doend;
  1091. X            }
  1092. X            /*
  1093. X             * we built the new argument in cmdbuf[], then copy it back to buff[]
  1094. X             */
  1095. X            *p = NUL;                            /* truncate at the '#' or '%' */
  1096. X            STRCPY(cmdbuf, arg);                /* copy up to there */
  1097. X            i = p - arg;                        /* remember the lenght */
  1098. X            STRCAT(cmdbuf, q);                    /* append the file name */
  1099. X            if (*(p + n) == '<')                /* may remove extension */
  1100. X            {
  1101. X                ++n;
  1102. X                if ((arg = (char_u *)strrchr((char *)q, '.')) != NULL &&
  1103. X                                arg >= gettail(q))
  1104. X                    *(cmdbuf + (arg - q) + i) = NUL;
  1105. X            }
  1106. X            i = STRLEN(cmdbuf);                    /* remember the end of the filename */
  1107. X            STRCAT(cmdbuf, p+n);                /* append what is after '#' or '%' */
  1108. X            p = buff + i - 1;                    /* remember where to continue */
  1109. X            if (nextcomm)                        /* append next command */
  1110. X            {
  1111. X                i = STRLEN(cmdbuf) + 1;
  1112. X                STRCPY(cmdbuf + i, nextcomm);
  1113. X                nextcomm = buff + i;
  1114. X            }
  1115. X            STRCPY(buff, cmdbuf);                /* copy back to buff[] */
  1116. X            arg = buff;
  1117. X        }
  1118. X
  1119. X        /*
  1120. X         * One file argument: expand wildcards.
  1121. X         * Don't do this with ":r !command" or ":w !command".
  1122. X         */
  1123. X        if (argt & NOSPC)
  1124. X        {
  1125. X            if (has_wildcard(arg) && !usefilter)
  1126. X            {
  1127. X                if ((p = ExpandOne(arg, TRUE, -1)) == NULL)
  1128. X                    goto doend;
  1129. X                if (STRLEN(p) + arg - buff < CMDBUFFSIZE - 2)
  1130. X                    STRCPY(arg, p);
  1131. X                else
  1132. X                    emsg(e_toolong);
  1133. X                free(p);
  1134. X            }
  1135. X        }
  1136. X    }
  1137. X
  1138. X/*
  1139. X * 6. switch on command name
  1140. X */
  1141. Xcmdswitch:
  1142. X    switch (cmdidx)
  1143. X    {
  1144. X        /*
  1145. X         * quit current window, quit Vim if closed the last window
  1146. X         */
  1147. X        case CMD_quit:
  1148. X                        /* if more files or windows we won't exit */
  1149. X                if (check_more(FALSE) == OK && firstwin == lastwin)
  1150. X                    exiting = TRUE;
  1151. X                if (check_changed(curbuf, FALSE, FALSE) ||
  1152. X                            check_more(TRUE) == FAIL ||
  1153. X                            (firstwin == lastwin && check_changed_any(FALSE)))
  1154. X                {
  1155. X                    exiting = FALSE;
  1156. X                    settmode(1);
  1157. X                    break;
  1158. X                }
  1159. X                if (firstwin == lastwin)    /* quit last window */
  1160. X                    getout(0);
  1161. X                close_window(TRUE);            /* may free buffer */
  1162. X                break;
  1163. X
  1164. X        /*
  1165. X         * try to quit all windows
  1166. X         */
  1167. X        case CMD_qall:
  1168. X                exiting = TRUE;
  1169. X                if (!check_changed_any(FALSE))
  1170. X                    getout(0);
  1171. X                exiting = FALSE;
  1172. X                settmode(1);
  1173. X                break;
  1174. X
  1175. X        /*
  1176. X         * close current window, unless it is the last one
  1177. X         */
  1178. X        case CMD_close:
  1179. X                close_window(FALSE);        /* don't free buffer */
  1180. X                break;
  1181. X
  1182. X        /*
  1183. X         * close all but current window, unless it is the last one
  1184. X         */
  1185. X        case CMD_only:
  1186. X                close_others(TRUE);
  1187. X                break;
  1188. X
  1189. X        case CMD_stop:
  1190. X        case CMD_suspend:
  1191. X                if (!forceit)
  1192. X                    autowrite_all();
  1193. X                gotocmdend();
  1194. X                flushbuf();
  1195. X                stoptermcap();
  1196. X                mch_restore_title(3);    /* restore window titles */
  1197. X                mch_suspend();            /* call machine specific function */
  1198. X                maketitle();
  1199. X                starttermcap();
  1200. X                if (T_CVV != NULL && *T_CVV)
  1201. X                {
  1202. X                    /* Scroll screen down before drawing over it */
  1203. X                    outstr(T_CVV);
  1204. X                    outstr(T_CV);
  1205. X                }
  1206. X                must_redraw = CLEAR;
  1207. X                break;
  1208. X
  1209. X        case CMD_exit:
  1210. X        case CMD_xit:
  1211. X        case CMD_wq:
  1212. X                            /* if more files or windows we won't exit */
  1213. X                if (check_more(FALSE) == OK && firstwin == lastwin)
  1214. X                    exiting = TRUE;
  1215. X                if (((cmdidx == CMD_wq ||
  1216. X                        (curbuf->b_nwindows == 1 && curbuf->b_changed)) &&
  1217. X                        (check_readonly() || dowrite(arg, FALSE) == FAIL)) ||
  1218. X                    check_more(TRUE) == FAIL || 
  1219. X                    (firstwin == lastwin && check_changed_any(FALSE)))
  1220. X                {
  1221. X                    exiting = FALSE;
  1222. X                    settmode(1);
  1223. X                    break;
  1224. X                }
  1225. X                if (firstwin == lastwin)    /* quit last window, exit Vim */
  1226. X                    getout(0);
  1227. X                close_window(TRUE);            /* quit current window, may free buffer */
  1228. X                break;
  1229. X
  1230. X        case CMD_xall:        /* write all changed files and exit */
  1231. X        case CMD_wqall:        /* write all changed files and quit */
  1232. X                exiting = TRUE;
  1233. X                /* FALLTHROUGH */
  1234. X
  1235. X        case CMD_wall:        /* write all changed files */
  1236. X                {
  1237. X                    BUF        *buf;
  1238. X                    int        error = 0;
  1239. X
  1240. X                    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1241. X                    {
  1242. X                        if (buf->b_changed)
  1243. X                        {
  1244. X                            if (buf->b_filename == NULL)
  1245. X                            {
  1246. X                                emsg(e_noname);
  1247. X                                ++error;
  1248. X                            }
  1249. X                            else if (!forceit && buf->b_p_ro)
  1250. X                            {
  1251. X                                EMSG2("\"%s\" is readonly, use ! to write anyway", buf->b_xfilename);
  1252. X                                ++error;
  1253. X                            }
  1254. X                            else if (buf_write_all(buf) == FAIL)
  1255. X                                ++error;
  1256. X                        }
  1257. X                    }
  1258. X                    if (exiting)
  1259. X                    {
  1260. X                        if (!error)
  1261. X                            getout(0);            /* exit Vim */
  1262. X                        exiting = FALSE;
  1263. X                        settmode(1);
  1264. X                    }
  1265. X                }
  1266. X                break;
  1267. X
  1268. X        case CMD_preserve:                    /* put everything in .swp file */
  1269. X                ml_preserve(curbuf, TRUE);
  1270. X                break;
  1271. X
  1272. X        case CMD_args:        
  1273. X                    /*
  1274. X                     * ":args file": handle like :next
  1275. X                     */
  1276. X                if (*arg != NUL && *arg != '|' && *arg != '\n')
  1277. X                    goto do_next;
  1278. X
  1279. X                nextcomm = checknextcomm(arg);    /* check for trailing command */
  1280. X                if (arg_count == 0)            /* no file name list */
  1281. X                {
  1282. X                    if (check_fname() == OK)        /* check for no file name at all */
  1283. X                        smsg((char_u *)"[%s]", curbuf->b_filename);
  1284. X                    break;
  1285. X                }
  1286. X                gotocmdline(TRUE, NUL);
  1287. X                for (i = 0; i < arg_count; ++i)
  1288. X                {
  1289. X                    if (i == curwin->w_arg_idx)
  1290. X                        msg_outchar('[');
  1291. X                    msg_outstr(arg_files[i]);
  1292. X                    if (i == curwin->w_arg_idx)
  1293. X                        msg_outchar(']');
  1294. X                    msg_outchar(' ');
  1295. X                }
  1296. X                if (msg_check())        /* if message too long */
  1297. X                {
  1298. X                    msg_outchar('\n');
  1299. X                    wait_return(FALSE);
  1300. X                }
  1301. X                break;
  1302. X
  1303. X        case CMD_wnext:
  1304. X        case CMD_wNext:
  1305. X        case CMD_wprevious:
  1306. X                if (cmd[1] == 'n')
  1307. X                    i = curwin->w_arg_idx + (int)line2;
  1308. X                else
  1309. X                    i = curwin->w_arg_idx - (int)line2;
  1310. X                line1 = 1;
  1311. X                line2 = curbuf->b_ml.ml_line_count;
  1312. X                if (dowrite(arg, FALSE) == FAIL)
  1313. X                    break;
  1314. X                goto donextfile;
  1315. X
  1316. X        case CMD_next:
  1317. X        case CMD_snext:
  1318. Xdo_next:
  1319. X                    /*
  1320. X                     * check for changed buffer now, if this fails the
  1321. X                     * argument list is not redefined.
  1322. X                     */
  1323. X                if (!(p_hid || cmdidx == CMD_snext) &&
  1324. X                                check_changed(curbuf, TRUE, FALSE))
  1325. X                    break;
  1326. X
  1327. X                editcmd = getargcmd(&arg);        /* get +command argument */
  1328. X                nextcomm = checknextcomm(arg);    /* check for trailing command */
  1329. X                if (*arg != NUL)                /* redefine file list */
  1330. X                {
  1331. X                    if (doarglist(arg) == FAIL)
  1332. X                        break;
  1333. X                    i = 0;
  1334. X                }
  1335. X                else
  1336. X                    i = curwin->w_arg_idx + (int)line2;
  1337. X
  1338. Xdonextfile:        if (i < 0 || i >= arg_count)
  1339. X                {
  1340. X                    if (arg_count == 1)
  1341. X                        EMSG("There is only one file to edit");
  1342. X                    else if (i < 0)
  1343. X                        EMSG("Cannot go before first file");
  1344. X                    else
  1345. X                        EMSG2("No more than %ld files to edit", (char_u *)(long)arg_count);
  1346. X                    break;
  1347. X                }
  1348. X                if (*cmd == 's')        /* split window first */
  1349. X                {
  1350. X                    if (win_split(0L, FALSE) == FAIL)
  1351. X                        break;
  1352. X                }
  1353. X                else
  1354. X                {
  1355. X                    register int other = FALSE;
  1356. X
  1357. X                    /*
  1358. X                     * if 'hidden' set, only check for changed file when re-editing
  1359. X                     * the same buffer
  1360. X                     */
  1361. X                    other = TRUE;
  1362. X                    if (p_hid)
  1363. X                        other = otherfile(fix_fname(arg_files[i]));
  1364. X                    if ((!p_hid || !other) && check_changed(curbuf, TRUE, !other))
  1365. X                    break;
  1366. X                }
  1367. X                curwin->w_arg_idx = i;
  1368. X                (void)doecmd(arg_files[curwin->w_arg_idx], NULL, editcmd, p_hid, (linenr_t)0);
  1369. X                break;
  1370. X
  1371. X        case CMD_previous:
  1372. X        case CMD_sprevious:
  1373. X        case CMD_Next:
  1374. X        case CMD_sNext:
  1375. X                i = curwin->w_arg_idx - (int)line2;
  1376. X                goto doargument;
  1377. X
  1378. X        case CMD_rewind:
  1379. X        case CMD_srewind:
  1380. X                i = 0;
  1381. X                goto doargument;
  1382. X
  1383. X        case CMD_last:
  1384. X        case CMD_slast:
  1385. X                i = arg_count - 1;
  1386. X                goto doargument;
  1387. X
  1388. X        case CMD_argument:
  1389. X        case CMD_sargument:
  1390. X                if (addr_count)
  1391. X                    i = line2 - 1;
  1392. X                else
  1393. X                    i = curwin->w_arg_idx;
  1394. Xdoargument:
  1395. X                editcmd = getargcmd(&arg);        /* get +command argument */
  1396. X                nextcomm = checknextcomm(arg);    /* check for trailing command */
  1397. X                goto donextfile;
  1398. X
  1399. X        case CMD_all:
  1400. X        case CMD_sall:
  1401. X                do_arg_all();        /* open a window for each argument */
  1402. X                break;
  1403. X
  1404. X        case CMD_buffer:            /* :[N]buffer [N]     to buffer N */
  1405. X        case CMD_sbuffer:            /* :[N]sbuffer [N]     to buffer N */
  1406. X                if (addr_count == 0)        /* default is current buffer */
  1407. X                    (void)do_buffer(*cmd == 's', 0, FORWARD, 0, 0);
  1408. X                else
  1409. X                    (void)do_buffer(*cmd == 's', 1, FORWARD, (int)line2, 0);
  1410. X                break;
  1411. X
  1412. X        case CMD_bmodified:            /* :[N]bmod    [N]         to next modified buffer */
  1413. X        case CMD_sbmodified:        /* :[N]sbmod [N]      to next modified buffer */
  1414. X                (void)do_buffer(*cmd == 's', 3, FORWARD, (int)line2, 0);
  1415. X                break;
  1416. X
  1417. X        case CMD_bnext:                /* :[N]bnext [N]     to next buffer */
  1418. X        case CMD_sbnext:            /* :[N]sbnext [N]      to next buffer */
  1419. X                (void)do_buffer(*cmd == 's', 0, FORWARD, (int)line2, 0);
  1420. X                break;
  1421. X
  1422. X        case CMD_bNext:                /* :[N]bNext [N]     to previous buffer */
  1423. X        case CMD_bprevious:            /* :[N]bprevious [N] to previous buffer */
  1424. X        case CMD_sbNext:            /* :[N]sbNext [N]      to previous buffer */
  1425. X        case CMD_sbprevious:        /* :[N]sbprevious [N] to previous buffer */
  1426. X                (void)do_buffer(*cmd == 's', 0, BACKWARD, (int)line2, 0);
  1427. X                break;
  1428. X
  1429. X        case CMD_brewind:            /* :brewind             to first buffer */
  1430. X        case CMD_sbrewind:            /* :sbrewind         to first buffer */
  1431. X                (void)do_buffer(*cmd == 's', 1, FORWARD, 0, 0);
  1432. X                break;
  1433. X
  1434. X        case CMD_blast:                /* :blast             to last buffer */
  1435. X        case CMD_sblast:            /* :sblast             to last buffer */
  1436. X                (void)do_buffer(*cmd == 's', 2, FORWARD, 0, 0);
  1437. X                break;
  1438. X
  1439. X        case CMD_bunload:            /* :[N]bunload[!] [N] unload buffer */
  1440. X                i = 2;
  1441. X        case CMD_bdelete:            /* :[N]bdelete[!] [N] delete buffer */
  1442. X                if (cmdidx == CMD_bdelete)
  1443. X                    i = 3;
  1444. X                /*
  1445. X                 * addr_count == 0: ":bdel" - delete current buffer
  1446. X                 * addr_count == 1: ":N bdel" or ":bdel N [N ..] - first delete
  1447. X                 *                    buffer 'line2', then any other arguments.
  1448. X                 * addr_count == 2: ":N,N bdel" - delete buffers in range
  1449. X                 */
  1450. X                if (addr_count == 0)
  1451. X                    (void)do_buffer(i, 0, FORWARD, 0, forceit);
  1452. X                else
  1453. X                {
  1454. X                    int do_current = FALSE;        /* delete current buffer? */
  1455. X
  1456. X                    if (addr_count == 2)
  1457. X                        n = line1;
  1458. X                    else
  1459. X                        n = line2;
  1460. X                    for ( ;!got_int; breakcheck())
  1461. X                    {
  1462. X                        /*
  1463. X                         * delete the current buffer last, otherwise when the
  1464. X                         * current buffer is deleted, the next buffer becomes
  1465. X                         * the current one and will be loaded, which may then
  1466. X                         * also be deleted, etc.
  1467. X                         */
  1468. X                        if (n == curbuf->b_fnum)
  1469. X                            do_current = TRUE;
  1470. X                        else
  1471. X                            (void)do_buffer(i, 1, FORWARD, (int)n, forceit);
  1472. X                        if (addr_count == 2)
  1473. X                        {
  1474. X                            if (++n > line2)
  1475. X                                break;
  1476. X                        }
  1477. X                        else
  1478. X                        {
  1479. X                            skipspace(&arg);
  1480. X                            if (*arg == NUL)
  1481. X                                break;
  1482. X                            if (!isdigit(*arg))
  1483. X                            {
  1484. X                                emsg(e_trailing);
  1485. X                                break;
  1486. X                            }
  1487. X                            n = getdigits(&arg);
  1488. X                        }
  1489. X                    }
  1490. X                    if (!got_int && do_current)
  1491. X                        (void)do_buffer(i, 1, FORWARD, (int)curbuf->b_fnum, forceit);
  1492. X                }
  1493. X                break;
  1494. X
  1495. X        case CMD_unhide:
  1496. X        case CMD_sunhide:
  1497. X                (void)do_buffer_all(FALSE);    /* open a window for loaded buffers */
  1498. X                break;
  1499. X
  1500. X        case CMD_ball:
  1501. X        case CMD_sball:
  1502. X                (void)do_buffer_all(TRUE);    /* open a window for every buffer */
  1503. X                break;
  1504. X
  1505. X        case CMD_buffers:
  1506. X        case CMD_files:
  1507. X                buflist_list();
  1508. X                break;
  1509. X
  1510. X        case CMD_write:
  1511. X                if (usefilter)        /* input lines to shell command */
  1512. X                    dofilter(line1, line2, arg, TRUE, FALSE);
  1513. X                else
  1514. X                    (void)dowrite(arg, append);
  1515. X                break;
  1516. X
  1517. X            /*
  1518. X             * set screen mode
  1519. X             * if no argument given, just get the screen size and redraw
  1520. X             */
  1521. X        case CMD_mode:
  1522. X                if (*arg == NUL || mch_screenmode(arg) != FAIL)
  1523. X                    set_winsize(0, 0, FALSE);
  1524. X                break;
  1525. X
  1526. X                /*
  1527. X                 * set, increment or decrement current window height
  1528. X                 */
  1529. X        case CMD_resize:
  1530. X                n = atol((char *)arg);
  1531. X                if (*arg == '-' || *arg == '+')
  1532. X                    win_setheight(curwin->w_height + (int)n);
  1533. X                else
  1534. X                {
  1535. X                    if (n == 0)        /* default is very high */
  1536. X                        n = 9999;
  1537. X                    win_setheight((int)n);
  1538. X                }
  1539. X                break;
  1540. X
  1541. X                /*
  1542. X                 * :split [[+command] file]  split window with current or new file
  1543. X                 * :new [[+command] file]    split window with no or new file
  1544. X                 */
  1545. X        case CMD_split:
  1546. X        case CMD_new:
  1547. X                if (win_split(addr_count ? line2 : 0L, FALSE) == FAIL)
  1548. X                    break;
  1549. X                /*FALLTHROUGH*/
  1550. X
  1551. X        case CMD_edit:
  1552. X        case CMD_ex:
  1553. X        case CMD_visual:
  1554. X                editcmd = getargcmd(&arg);        /* get +command argument */
  1555. X                nextcomm = checknextcomm(arg);    /* check for trailing command */
  1556. X                if ((cmdidx == CMD_new) && *arg == NUL)
  1557. X                    (void)doecmd(NULL, NULL, editcmd, TRUE, (linenr_t)1);
  1558. X                else if (cmdidx != CMD_split || *arg != NUL)
  1559. X                    (void)doecmd(arg, NULL, editcmd, p_hid, doecmdlnum);
  1560. X                else
  1561. X                    updateScreen(NOT_VALID);
  1562. X                break;
  1563. X
  1564. X        case CMD_file:
  1565. X                if (*arg != NUL)
  1566. X                {
  1567. X                    if (setfname(arg, NULL, TRUE) == FAIL)
  1568. X                        break;
  1569. X                    curbuf->b_notedited = TRUE;
  1570. X                    maketitle();
  1571. X                }
  1572. X                fileinfo(did_cd);        /* print full filename if :cd used */
  1573. X                break;
  1574. X
  1575. X        case CMD_swapname:
  1576. X                p = curbuf->b_ml.ml_mfp->mf_fname;
  1577. X                if (p == NULL)
  1578. X                    MSG("No swap file");
  1579. X                else
  1580. X                    msg(p);
  1581. X                break;
  1582. X
  1583. X        case CMD_mfstat:        /* print memfile statistics, for debugging */
  1584. X                mf_statistics();
  1585. X                break;
  1586. X
  1587. X        case CMD_read:
  1588. X                if (usefilter)
  1589. X                {
  1590. X                    dofilter(line1, line2, arg, FALSE, TRUE);            /* :r!cmd */
  1591. X                    break;
  1592. X                }
  1593. X                if (!u_save(line2, (linenr_t)(line2 + 1)))
  1594. X                    break;
  1595. X                if (*arg == NUL)
  1596. X                {
  1597. X                    if (check_fname() == FAIL)    /* check for no file name at all */
  1598. X                        break;
  1599. X                    i = readfile(curbuf->b_filename, curbuf->b_sfilename, line2, FALSE, (linenr_t)0, MAXLNUM);
  1600. X                }
  1601. X                else
  1602. X                    i = readfile(arg, NULL, line2, FALSE, (linenr_t)0, MAXLNUM);
  1603. X                if (i == FAIL)
  1604. X                {
  1605. X                    emsg2(e_notopen, arg);
  1606. X                    break;
  1607. X                }
  1608. X                updateScreen(NOT_VALID);
  1609. X                break;
  1610. X
  1611. X        case CMD_cd:
  1612. X        case CMD_chdir:
  1613. X#ifdef UNIX
  1614. X                /*
  1615. X                 * for UNIX ":cd" means: go to home directory
  1616. X                 */
  1617. X                if (*arg == NUL)     /* use cmdbuf for home directory name */
  1618. X                {
  1619. X                    expand_env("$HOME", cmdbuf, CMDBUFFSIZE);
  1620. X                    arg = cmdbuf;
  1621. X                }
  1622. X#endif
  1623. X                if (*arg != NUL)
  1624. X                {
  1625. X                    if (!did_cd)
  1626. X                    {
  1627. X                        BUF        *buf;
  1628. X
  1629. X                            /* use full path from now on for names of files
  1630. X                             * being edited and swap files */
  1631. X                        for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1632. X                        {
  1633. X                            buf->b_xfilename = buf->b_filename;
  1634. X                            mf_fullname(buf->b_ml.ml_mfp);
  1635. X                        }
  1636. X                        status_redraw_all();
  1637. X                    }
  1638. X                    did_cd = TRUE;
  1639. X                    if (chdir((char *)arg))
  1640. X                        emsg(e_failed);
  1641. X                    break;
  1642. X                }
  1643. X                /*FALLTHROUGH*/
  1644. X
  1645. X        case CMD_pwd:
  1646. X                if (vim_dirname(NameBuff, MAXPATHL) == OK)
  1647. X                    msg(NameBuff);
  1648. X                else
  1649. X                    emsg(e_unknown);
  1650. X                break;
  1651. X
  1652. X        case CMD_equal:
  1653. X                smsg((char_u *)"line %ld", (long)line2);
  1654. X                break;
  1655. X
  1656. X        case CMD_list:
  1657. X                i = curwin->w_p_list;
  1658. X                curwin->w_p_list = 1;
  1659. X        case CMD_number:                /* :nu */
  1660. X        case CMD_pound:                    /* :# */
  1661. X        case CMD_print:                    /* :p */
  1662. X                gotocmdline(TRUE, NUL);
  1663. X                cursor_off();
  1664. X                for ( ;!got_int; breakcheck())
  1665. X                {
  1666. X                    if (curwin->w_p_nu || cmdidx == CMD_number || cmdidx == CMD_pound)
  1667. X                    {
  1668. X                        sprintf((char *)IObuff, "%7ld ", (long)line1);
  1669. X                        msg_outstr(IObuff);
  1670. X                    }
  1671. X                    msg_prt_line(ml_get(line1));
  1672. X                    if (++line1 > line2)
  1673. X                        break;
  1674. X                    msg_outchar('\n');
  1675. X                    flushbuf();            /* show one line at a time */
  1676. X                }
  1677. X
  1678. X                if (cmdidx == CMD_list)
  1679. X                    curwin->w_p_list = i;
  1680. X
  1681. X                    /*
  1682. X                     * if we have one line that runs into the shown command,
  1683. X                     * or more than one line, call wait_return()
  1684. X                     * also do this when global_busy, so we remember to call
  1685. X                     * wait_return at the end of the global command.
  1686. X                     */
  1687. X                if (msg_check() || global_busy)
  1688. X                {
  1689. X                    msg_outchar('\n');
  1690. X                    wait_return(FALSE);
  1691. X                }
  1692. X                break;
  1693. X
  1694. X        case CMD_shell:
  1695. X                doshell(NULL);
  1696. X                break;
  1697. X
  1698. X        case CMD_sleep:
  1699. X                sleep((int)line2);
  1700. X                break;
  1701. X
  1702. X        case CMD_tag:
  1703. X                dotag(arg, 0, addr_count ? (int)line2 : 1);
  1704. X                break;
  1705. X
  1706. X        case CMD_pop:
  1707. X                dotag((char_u *)"", 1, addr_count ? (int)line2 : 1);
  1708. X                break;
  1709. X
  1710. X        case CMD_tags:
  1711. X                dotags();
  1712. X                break;
  1713. X
  1714. X        case CMD_marks:
  1715. X                domarks();
  1716. X                break;
  1717. X
  1718. X        case CMD_jumps:
  1719. X                dojumps();
  1720. X                break;
  1721. X
  1722. X        case CMD_digraphs:
  1723. X#ifdef DIGRAPHS
  1724. X                if (*arg)
  1725. X                    putdigraph(arg);
  1726. X                else
  1727. X                    listdigraphs();
  1728. X#else
  1729. X                EMSG("No digraphs in this version");
  1730. X#endif /* DIGRAPHS */
  1731. END_OF_FILE
  1732.   if test 38908 -ne `wc -c <'vim/src/cmdline.c.A'`; then
  1733.     echo shar: \"'vim/src/cmdline.c.A'\" unpacked with wrong size!
  1734.   elif test -f 'vim/src/cmdline.c.B'; then
  1735.     echo shar: Combining  \"'vim/src/cmdline.c'\" \(82989 characters\)
  1736.     cat 'vim/src/cmdline.c.A' 'vim/src/cmdline.c.B' > 'vim/src/cmdline.c'
  1737.     if test 82989 -ne `wc -c <'vim/src/cmdline.c'`; then
  1738.       echo shar: \"'vim/src/cmdline.c'\" combined with wrong size!
  1739.     else
  1740.       rm vim/src/cmdline.c.A vim/src/cmdline.c.B 
  1741.     fi
  1742.   fi
  1743.   # end of 'vim/src/cmdline.c.A'
  1744. fi
  1745. if test -f 'vim/src/memfile.c' -a "${1}" != "-c" ; then 
  1746.   echo shar: Will not clobber existing file \"'vim/src/memfile.c'\"
  1747. else
  1748.   echo shar: Extracting \"'vim/src/memfile.c'\" \(26671 characters\)
  1749.   sed "s/^X//" >'vim/src/memfile.c' <<'END_OF_FILE'
  1750. X/* vi:ts=4:sw=4
  1751. X *
  1752. X * VIM - Vi IMproved        by Bram Moolenaar
  1753. X *
  1754. X * Read the file "credits.txt" for a list of people who contributed.
  1755. X * Read the file "uganda.txt" for copying and usage conditions.
  1756. X */
  1757. X
  1758. X/* for debugging */
  1759. X#define CHECK(c, s)    if (c) printf(s)
  1760. X
  1761. X/*
  1762. X * memfile.c: Contains the functions for handling blocks of memory which can
  1763. X * be stored in a file. This is the implementation of a sort of virtual memory.
  1764. X *
  1765. X * A memfile consists of a sequence of blocks. The blocks numbered from 0
  1766. X * upwards have been assigned a place in the actual file. The block number
  1767. X * is equal to the page number in the file. The
  1768. X * blocks with negative numbers are currently in memory only. They can be
  1769. X * assigned a place in the file when too much memory is being used. At that
  1770. X * moment they get a new, positive, number. A list is used for translation of
  1771. X * negative to positive numbers.
  1772. X *
  1773. X * The size of a block is a multiple of a page size, normally the page size of
  1774. X * the device the file is on. Most blocks are 1 page long. A Block of multiple
  1775. X * pages is used for a line that does not fit in a single page.
  1776. X *
  1777. X * Each block can be in memory and/or in a file. The blocks stays in memory
  1778. X * as long as it is locked. If it is no longer locked it can be swapped out to
  1779. X * the file. It is only written to the file if it has been changed.
  1780. X *
  1781. X * Under normal operation the file is created when opening the memory file and
  1782. X * deleted when closing the memory file. Only with recovery an existing memory
  1783. X * file is opened.
  1784. X */
  1785. X
  1786. X#ifdef MSDOS
  1787. X# include <io.h>        /* for lseek(), must be before vim.h */
  1788. X#endif
  1789. X
  1790. X#include "vim.h"
  1791. X#include "globals.h"
  1792. X#include "proto.h"
  1793. X#include "param.h"
  1794. X#include <fcntl.h>
  1795. X
  1796. X/* 
  1797. X * Some systems have the page size in statfs, some in stat
  1798. X */
  1799. X#if defined(SCO) || defined(_SEQUENT_) || defined(__sgi) || defined(MIPS) || defined(MIPSEB) || defined(m88k)
  1800. X# include <sys/types.h>
  1801. X# include <sys/statfs.h>
  1802. X# define STATFS statfs
  1803. X# define F_BSIZE f_bsize
  1804. Xint  fstatfs __ARGS((int, struct statfs *, int, int));
  1805. X#else
  1806. X# define STATFS stat
  1807. X# define F_BSIZE st_blksize
  1808. X# define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  1809. X#endif
  1810. X
  1811. X/*
  1812. X * for Amiga Dos 2.0x we use Flush
  1813. X */
  1814. X#ifdef AMIGA
  1815. X# ifndef NO_ARP
  1816. Xextern int dos2;                    /* this is in amiga.c */
  1817. X# endif
  1818. X# ifdef SASC
  1819. X#  include <proto/dos.h>
  1820. X#  include <ios1.h>                    /* for chkufb() */
  1821. X# endif
  1822. X#endif
  1823. X
  1824. X#define MEMFILE_PAGE_SIZE 4096        /* default page size */
  1825. X
  1826. Xstatic long total_mem_used = 0;    /* total memory used for memfiles */
  1827. X
  1828. Xstatic void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
  1829. Xstatic void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
  1830. Xstatic BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
  1831. Xstatic void mf_ins_used __ARGS((MEMFILE *, BHDR *));
  1832. Xstatic void mf_rem_used __ARGS((MEMFILE *, BHDR *));
  1833. Xstatic BHDR *mf_release __ARGS((MEMFILE *, int));
  1834. Xstatic BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
  1835. Xstatic void mf_free_bhdr __ARGS((BHDR *));
  1836. Xstatic void mf_ins_free __ARGS((MEMFILE *, BHDR *));
  1837. Xstatic BHDR *mf_rem_free __ARGS((MEMFILE *));
  1838. Xstatic int    mf_read __ARGS((MEMFILE *, BHDR *));
  1839. Xstatic int    mf_write __ARGS((MEMFILE *, BHDR *));
  1840. Xstatic int    mf_trans_add __ARGS((MEMFILE *, BHDR *));
  1841. Xstatic void mf_do_open __ARGS((MEMFILE *, char_u *, int));
  1842. X
  1843. X/*
  1844. X * The functions for using a memfile:
  1845. X *
  1846. X * mf_open()        open a new or existing memfile
  1847. X * mf_close()        close (and delete) a memfile
  1848. X * mf_new()            create a new block in a memfile and lock it
  1849. X * mf_get()            get an existing block and lock it
  1850. X * mf_put()            unlock a block, may be marked for writing
  1851. X * mf_free()        remove a block
  1852. X * mf_sync()        sync changed parts of memfile to disk
  1853. X * mf_release_all()    release as much memory as possible
  1854. X * mf_trans_del()    may translate negative to positive block number
  1855. X * mf_fullname()    make file name full path (use before first :cd)
  1856. X */
  1857. X
  1858. X/*
  1859. X * mf_open: open an existing or new memory block file
  1860. X *
  1861. X *    fname:        name of file to use (NULL means no file at all)
  1862. X *                Note: fname must have been allocated, it is not copied!
  1863. X *                        If opening the file fails, fname is freed.
  1864. X *  new:        if TRUE: file should be truncated when opening
  1865. X *  fail_nofile:    if TRUE: if file cannot be opened, fail.
  1866. X *
  1867. X * return value: identifier for this memory block file.
  1868. X */
  1869. X    MEMFILE *
  1870. Xmf_open(fname, new, fail_nofile)
  1871. X    char_u    *fname;
  1872. X    int        new;
  1873. X    int        fail_nofile;
  1874. X{
  1875. X    MEMFILE            *mfp;
  1876. X    int                i;
  1877. X    long            size;
  1878. X#ifdef UNIX
  1879. X    struct STATFS     stf;
  1880. X#endif
  1881. X
  1882. X    if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
  1883. X    {
  1884. X        free(fname);
  1885. X        return NULL;
  1886. X    }
  1887. X
  1888. X    if (fname == NULL)        /* no file for this memfile, use memory only */
  1889. X    {
  1890. X        mfp->mf_fname = NULL;
  1891. X        mfp->mf_xfname = NULL;
  1892. X        mfp->mf_fd = -1;
  1893. X    }
  1894. X    else
  1895. X        mf_do_open(mfp, fname, new);        /* try to open the file */
  1896. X
  1897. X    /*
  1898. X     * if fail_nofile is set and there is no file, return here
  1899. X     */
  1900. X    if (mfp->mf_fd < 0 && fail_nofile)
  1901. X    {
  1902. X        free(mfp);
  1903. X        return NULL;
  1904. X    }
  1905. X
  1906. X    mfp->mf_free_first = NULL;            /* free list is empty */
  1907. X    mfp->mf_used_first = NULL;            /* used list is empty */
  1908. X    mfp->mf_used_last = NULL;
  1909. X    mfp->mf_dirty = FALSE;
  1910. X    mfp->mf_used_count = 0;
  1911. X    for (i = 0; i < MEMHASHSIZE; ++i)
  1912. X    {
  1913. X        mfp->mf_hash[i] = NULL;            /* hash lists are empty */
  1914. X        mfp->mf_trans[i] = NULL;        /* trans lists are empty */
  1915. X    }
  1916. X    mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  1917. X
  1918. X#ifdef UNIX
  1919. X    /*
  1920. X     * Try to set the page size equal to the block size of the device.
  1921. X     * Speeds up I/O a lot.
  1922. X     * NOTE: minimal block size depends on size of block 0 data!
  1923. X     * The maximal block size is arbitrary.
  1924. X     */
  1925. X    if (mfp->mf_fd >= 0 &&
  1926. X                    fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
  1927. X                    stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
  1928. X        mfp->mf_page_size = stf.F_BSIZE;
  1929. X#endif
  1930. X
  1931. X    if (mfp->mf_fd < 0 || new || (size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
  1932. X        mfp->mf_blocknr_max = 0;        /* no file or empty file */
  1933. X    else
  1934. X        mfp->mf_blocknr_max = size / mfp->mf_page_size;
  1935. X    mfp->mf_blocknr_min = -1;
  1936. X    mfp->mf_neg_count = 0;
  1937. X    mfp->mf_infile_count = mfp->mf_blocknr_max;
  1938. X    if (mfp->mf_fd < 0)
  1939. X        mfp->mf_used_count_max = 0;            /* no limit */
  1940. X    else
  1941. X        mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
  1942. X
  1943. X    return mfp;
  1944. X}
  1945. X
  1946. X/*
  1947. X * mf_open_file: open a file for an existing memfile. Used when updatecount
  1948. X *                 set from 0 to some value.
  1949. X *
  1950. X *    fname:        name of file to use (NULL means no file at all)
  1951. X *                Note: fname must have been allocated, it is not copied!
  1952. X *                        If opening the file fails, fname is freed.
  1953. X *
  1954. X * return value: FAIL if file could not be opened, OK otherwise
  1955. X */
  1956. X    int
  1957. Xmf_open_file(mfp, fname)
  1958. X    MEMFILE        *mfp;
  1959. X    char_u        *fname;
  1960. X{
  1961. X    mf_do_open(mfp, fname, TRUE);                /* try to open the file */
  1962. X
  1963. X    if (mfp->mf_fd < 0)
  1964. X        return FAIL;
  1965. X
  1966. X    mfp->mf_dirty = TRUE;
  1967. X    return OK;
  1968. X}
  1969. X
  1970. X/*
  1971. X * close a memory file and delete the associated file if 'delete' is TRUE
  1972. X */
  1973. X    void
  1974. Xmf_close(mfp, delete)
  1975. X    MEMFILE    *mfp;
  1976. X    int        delete;
  1977. X{
  1978. X    BHDR        *hp, *nextp;
  1979. X    NR_TRANS    *tp, *tpnext;
  1980. X    int            i;
  1981. X
  1982. X    if (mfp == NULL)                /* safety check */
  1983. X        return;
  1984. X    if (mfp->mf_fd >= 0)
  1985. X    {
  1986. X        if (close(mfp->mf_fd) < 0)
  1987. X            EMSG("Close error on swap file");
  1988. X    }
  1989. X    if (delete && mfp->mf_fname != NULL)
  1990. X        remove((char *)mfp->mf_fname);
  1991. X                                            /* free entries in used list */
  1992. X    for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
  1993. X    {
  1994. X        nextp = hp->bh_next;
  1995. X        mf_free_bhdr(hp);
  1996. X    }
  1997. X    while (mfp->mf_free_first != NULL)        /* free entries in free list */
  1998. X        (void)free(mf_rem_free(mfp));
  1999. X    for (i = 0; i < MEMHASHSIZE; ++i)        /* free entries in trans lists */
  2000. X        for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
  2001. X        {
  2002. X            tpnext = tp->nt_next;
  2003. X            free(tp);
  2004. X        }
  2005. X    free(mfp->mf_fname);
  2006. X    free(mfp->mf_xfname);
  2007. X    free(mfp);
  2008. X}
  2009. X
  2010. X/*
  2011. X * get a new block
  2012. X *
  2013. X *   negative: TRUE if negative block number desired (data block)
  2014. X */
  2015. X    BHDR *
  2016. Xmf_new(mfp, negative, page_count)
  2017. X    MEMFILE        *mfp;
  2018. X    int            negative;
  2019. X    int            page_count;
  2020. X{
  2021. X    BHDR    *hp;            /* new BHDR */
  2022. X    BHDR    *freep;            /* first block in free list */
  2023. X    char_u    *p;
  2024. X
  2025. X    /*
  2026. X     * If we reached the maximum size for the used memory blocks, release one
  2027. X     * If a BHDR is returned, use it and adjust the page_count if necessary.
  2028. X     */
  2029. X    hp = mf_release(mfp, page_count);
  2030. X
  2031. X/*
  2032. X * Decide on the number to use:
  2033. X * If there is a free block, use its number.
  2034. X * Otherwise use mf_block_min for a negative number, mf_block_max for
  2035. X * a positive number.
  2036. X */
  2037. X    freep = mfp->mf_free_first;
  2038. X    if (!negative && freep != NULL && freep->bh_page_count >= page_count)
  2039. X    {
  2040. X        /*
  2041. X         * If the block in the free list has more pages, take only the number
  2042. X         * of pages needed and allocate a new BHDR with data
  2043. X         *
  2044. X         * If the number of pages matches and mf_release did not return a BHDR,
  2045. X         * use the BHDR from the free list and allocate the data
  2046. X         *
  2047. X         * If the number of pages matches and mf_release returned a BHDR,
  2048. X         * just use the number and free the BHDR from the free list
  2049. X         */
  2050. X        if (freep->bh_page_count > page_count)
  2051. X        {
  2052. X            if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  2053. X                return NULL;
  2054. X            hp->bh_bnum = freep->bh_bnum;
  2055. X            freep->bh_bnum += page_count;
  2056. X            freep->bh_page_count -= page_count;
  2057. X        }
  2058. X        else if (hp == NULL)        /* need to allocate memory for this block */
  2059. X        {
  2060. X            if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  2061. X                return NULL;
  2062. X            hp = mf_rem_free(mfp);
  2063. X            hp->bh_data = p;
  2064. X        }
  2065. X        else                /* use the number, remove entry from free list */
  2066. X        {
  2067. X            freep = mf_rem_free(mfp);
  2068. X            hp->bh_bnum = freep->bh_bnum;
  2069. X            free(freep);
  2070. X        }
  2071. X    }
  2072. X    else        /* get a new number */
  2073. X    {
  2074. X        if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  2075. X            return NULL;
  2076. X        if (negative)
  2077. X        {
  2078. X            hp->bh_bnum = mfp->mf_blocknr_min--;
  2079. X            mfp->mf_neg_count++;
  2080. X        }
  2081. X        else
  2082. X        {
  2083. X            hp->bh_bnum = mfp->mf_blocknr_max;
  2084. X            mfp->mf_blocknr_max += page_count;
  2085. X        }
  2086. X    }
  2087. X    hp->bh_flags = BH_LOCKED | BH_DIRTY;        /* new block is always dirty */
  2088. X    mfp->mf_dirty = TRUE;
  2089. X    hp->bh_page_count = page_count;
  2090. X    mf_ins_used(mfp, hp);
  2091. X    mf_ins_hash(mfp, hp);
  2092. X
  2093. X    return hp;
  2094. X}
  2095. X
  2096. X/*
  2097. X * get existing block 'nr' with 'page_count' pages
  2098. X *
  2099. X * Note: The caller should first check a negative nr with mf_trans_del()
  2100. X */
  2101. X    BHDR *
  2102. Xmf_get(mfp, nr, page_count)
  2103. X    MEMFILE        *mfp;
  2104. X    blocknr_t    nr;
  2105. X    int            page_count;
  2106. X{
  2107. X    BHDR    *hp;
  2108. X                                                /* doesn't exist */
  2109. X    if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
  2110. X        return NULL;
  2111. X
  2112. X    /*
  2113. X     * see if it is in the cache
  2114. X     */
  2115. X    hp = mf_find_hash(mfp, nr);
  2116. X    if (hp == NULL)        /* not in the hash list */
  2117. X    {
  2118. X        if (nr < 0 || nr >= mfp->mf_infile_count)    /* can't be in the file */
  2119. X            return NULL;
  2120. X
  2121. X        /* could check here if the block is in the free list */
  2122. X
  2123. X        /*
  2124. X         * Check if we need to flush an existing block.
  2125. X         * If so, use that block.
  2126. X         * If not, allocate a new block.
  2127. X         */
  2128. X        hp = mf_release(mfp, page_count);
  2129. X        if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  2130. X            return NULL;
  2131. X
  2132. X        hp->bh_bnum = nr;
  2133. X        hp->bh_flags = 0;
  2134. X        hp->bh_page_count = page_count;
  2135. X        if (mf_read(mfp, hp) == FAIL)        /* cannot read the block! */
  2136. X        {
  2137. X            mf_free_bhdr(hp);
  2138. X            return NULL;
  2139. X        }
  2140. X    }
  2141. X    else
  2142. X    {
  2143. X        mf_rem_used(mfp, hp);    /* remove from list, insert in front below */
  2144. X        mf_rem_hash(mfp, hp);
  2145. X    }
  2146. X
  2147. X    hp->bh_flags |= BH_LOCKED;
  2148. X    mf_ins_used(mfp, hp);        /* put in front of used list */
  2149. X    mf_ins_hash(mfp, hp);        /* put in front of hash list */
  2150. X
  2151. X    return hp;
  2152. X}
  2153. X
  2154. X/*
  2155. X * release the block *hp
  2156. X *
  2157. X *   dirty: Block must be written to file later
  2158. X *     infile: Block should be in file (needed for recovery)
  2159. X *
  2160. X *  no return value, function cannot fail
  2161. X */
  2162. X    void
  2163. Xmf_put(mfp, hp, dirty, infile)
  2164. X    MEMFILE    *mfp;
  2165. X    BHDR    *hp;
  2166. X    int        dirty;
  2167. X    int        infile;
  2168. X{
  2169. X    int        flags;
  2170. X
  2171. X    flags = hp->bh_flags;
  2172. X    CHECK((flags & BH_LOCKED) == 0, "block was not locked");
  2173. X    flags &= ~BH_LOCKED;
  2174. X    if (dirty)
  2175. X    {
  2176. X        flags |= BH_DIRTY;
  2177. X        mfp->mf_dirty = TRUE;
  2178. X    }
  2179. X    hp->bh_flags = flags;
  2180. X    if (infile)
  2181. X        mf_trans_add(mfp, hp);        /* may translate negative in positive nr */
  2182. X}
  2183. X
  2184. X/*
  2185. X * block *hp is no longer in used, may put it in the free list of memfile *mfp
  2186. X */
  2187. X    void
  2188. Xmf_free(mfp, hp)
  2189. X    MEMFILE    *mfp;
  2190. X    BHDR    *hp;
  2191. X{
  2192. X    free(hp->bh_data);            /* free the memory */
  2193. X    mf_rem_hash(mfp, hp);        /* get *hp out of the hash list */
  2194. X    mf_rem_used(mfp, hp);        /* get *hp out of the used list */
  2195. X    if (hp->bh_bnum < 0)
  2196. X    {
  2197. X        free(hp);                /* don't want negative numbers in free list */
  2198. X        mfp->mf_neg_count--;
  2199. X    }
  2200. X    else
  2201. X        mf_ins_free(mfp, hp);    /* put *hp in the free list */
  2202. X}
  2203. X
  2204. X/*
  2205. X * sync the memory file *mfp to disk
  2206. X *    if 'all' is FALSE blocks with negative numbers are not synced, even when
  2207. X *  they are dirty!
  2208. X *  if 'check_char' is TRUE, stop syncing when a character becomes available,
  2209. X *  but sync at least one block.
  2210. X *
  2211. X * Return FAIL for failure, OK otherwise
  2212. X */
  2213. X    int
  2214. Xmf_sync(mfp, all, check_char)
  2215. X    MEMFILE    *mfp;
  2216. X    int        all;
  2217. X    int        check_char;
  2218. X{
  2219. X    int        status;
  2220. X    BHDR    *hp;
  2221. X#if defined(MSDOS) || defined(SCO)
  2222. X    int        fd;
  2223. X#endif
  2224. X
  2225. X    if (mfp->mf_fd < 0)        /* there is no file, nothing to do */
  2226. X    {
  2227. X        mfp->mf_dirty = FALSE;
  2228. X        return FAIL;
  2229. X    }
  2230. X
  2231. X    /*
  2232. X     * sync from last to first (may reduce the probability of an inconsistent file)
  2233. X     * If a write fails, it is very likely caused by a full filesystem. Then we
  2234. X     * only try to write blocks within the existing file. If that also fails then
  2235. X     * we give up.
  2236. X     */
  2237. X    status = OK;
  2238. X    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  2239. X        if ((all || hp->bh_bnum >= 0) && (hp->bh_flags & BH_DIRTY) &&
  2240. X                    (status == OK || (hp->bh_bnum >= 0 &&
  2241. X                        hp->bh_bnum < mfp->mf_infile_count)))
  2242. X        {
  2243. X            if (mf_write(mfp, hp) == FAIL)
  2244. X            {
  2245. X                if (status == FAIL)        /* double error: quit syncing */
  2246. X                    break;
  2247. X                status = FAIL;
  2248. X            }
  2249. X            if (check_char && mch_char_avail())    /* char available now */
  2250. X                break;
  2251. X        }
  2252. X    
  2253. X    /*
  2254. X     * If the whole list is flushed, the memfile is not dirty anymore.
  2255. X     * In case of an error this flag is also set, to avoid trying all the time.
  2256. X     */
  2257. X    if (hp == NULL || status == FAIL)
  2258. X        mfp->mf_dirty = FALSE;
  2259. X
  2260. X#if defined(UNIX) && !defined(SCO)
  2261. X# if !defined(SVR4) && (defined(MIPS) || defined(MIPSEB) || defined(m88k))         
  2262. X     sync();         /* Do we really need to sync()?? (jw) */   
  2263. X# else
  2264. X    /*
  2265. X     * Unix has the very useful fsync() function, just what we need.
  2266. X     */
  2267. X    if (fsync(mfp->mf_fd))
  2268. X        status = FAIL;
  2269. X# endif
  2270. X#endif
  2271. X#if defined(MSDOS) || defined(SCO)
  2272. X    /*
  2273. X     * MSdos is a bit more work: Duplicate the file handle and close it.
  2274. X     * This should flush the file to disk.
  2275. X     * Also use this for SCO, which has no fsync().
  2276. X     */
  2277. X    if ((fd = dup(mfp->mf_fd)) >= 0)
  2278. X        close(fd);
  2279. X#endif
  2280. X#ifdef AMIGA
  2281. X    /*
  2282. X     * Flush() only exists for AmigaDos 2.0.
  2283. X     * For 1.3 it should be done with close() + open(), but then the risk
  2284. X     * is that the open() may fail and loose the file....
  2285. X     */
  2286. X# ifndef NO_ARP
  2287. X    if (dos2)
  2288. X# endif
  2289. X# ifdef SASC
  2290. X    {
  2291. X        struct UFB *fp = chkufb(mfp->mf_fd);
  2292. X
  2293. X        if (fp != NULL)
  2294. X            Flush(fp->ufbfh);
  2295. X    }
  2296. X# else
  2297. X        Flush(_devtab[mfp->mf_fd].fd);
  2298. X# endif
  2299. X#endif
  2300. X
  2301. X    return status;
  2302. X}
  2303. X
  2304. X/*
  2305. X * insert block *hp in front of hashlist of memfile *mfp
  2306. X */
  2307. X    static void
  2308. Xmf_ins_hash(mfp, hp)
  2309. X    MEMFILE    *mfp;
  2310. X    BHDR    *hp;
  2311. X{
  2312. X    BHDR    *hhp;
  2313. X    int        hash;
  2314. X
  2315. X    hash = MEMHASH(hp->bh_bnum);
  2316. X    hhp = mfp->mf_hash[hash];
  2317. X    hp->bh_hash_next = hhp;
  2318. X    hp->bh_hash_prev = NULL;
  2319. X    if (hhp != NULL)
  2320. X        hhp->bh_hash_prev = hp;
  2321. X    mfp->mf_hash[hash] = hp;
  2322. X}
  2323. X
  2324. X/*
  2325. X * remove block *hp from hashlist of memfile list *mfp
  2326. X */
  2327. X    static void
  2328. Xmf_rem_hash(mfp, hp)
  2329. X    MEMFILE    *mfp;
  2330. X    BHDR    *hp;
  2331. X{
  2332. X    if (hp->bh_hash_prev == NULL)
  2333. X        mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
  2334. X    else
  2335. X        hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
  2336. X    
  2337. X    if (hp->bh_hash_next)
  2338. X        hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
  2339. X}
  2340. X
  2341. X/*
  2342. X * look in hash lists of memfile *mfp for block header with number 'nr'
  2343. X */
  2344. X    static BHDR *
  2345. Xmf_find_hash(mfp, nr)
  2346. X    MEMFILE        *mfp;
  2347. X    blocknr_t    nr;
  2348. X{
  2349. X    BHDR        *hp;
  2350. X
  2351. X    for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
  2352. X        if (hp->bh_bnum == nr)
  2353. X            break;
  2354. X    return hp;
  2355. X}
  2356. X
  2357. X/*
  2358. X * insert block *hp in front of used list of memfile *mfp
  2359. X */
  2360. X    static void
  2361. Xmf_ins_used(mfp, hp)
  2362. X    MEMFILE    *mfp;
  2363. X    BHDR    *hp;
  2364. X{
  2365. X    hp->bh_next = mfp->mf_used_first;
  2366. X    mfp->mf_used_first = hp;
  2367. X    hp->bh_prev = NULL;
  2368. X    if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
  2369. X        mfp->mf_used_last = hp;
  2370. X    else
  2371. X        hp->bh_next->bh_prev = hp;
  2372. X    mfp->mf_used_count += hp->bh_page_count;
  2373. X    total_mem_used += hp->bh_page_count * mfp->mf_page_size;
  2374. X}
  2375. X
  2376. X/*
  2377. X * remove block *hp from used list of memfile *mfp
  2378. X */
  2379. X    static void
  2380. Xmf_rem_used(mfp, hp)
  2381. X    MEMFILE    *mfp;
  2382. X    BHDR    *hp;
  2383. X{
  2384. X    if (hp->bh_next == NULL)        /* last block in used list */
  2385. X        mfp->mf_used_last = hp->bh_prev;
  2386. X    else
  2387. X        hp->bh_next->bh_prev = hp->bh_prev;
  2388. X    if (hp->bh_prev == NULL)        /* first block in used list */
  2389. X        mfp->mf_used_first = hp->bh_next;
  2390. X    else
  2391. X        hp->bh_prev->bh_next = hp->bh_next;
  2392. X    mfp->mf_used_count -= hp->bh_page_count;
  2393. X    total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  2394. X}
  2395. X
  2396. X/*
  2397. X * Release the least recently used block from the used list if the number
  2398. X * of used memory blocks gets to big.
  2399. X *
  2400. X * Return the block header to the caller, including the memory block, so
  2401. X * it can be re-used. Make sure the page_count is right.
  2402. X */
  2403. X    static BHDR *
  2404. Xmf_release(mfp, page_count)
  2405. X    MEMFILE        *mfp;
  2406. X    int            page_count;
  2407. X{
  2408. X    BHDR        *hp;
  2409. X
  2410. X        /*
  2411. X         * don't release a block if
  2412. X         *        there is no file for this memfile
  2413. X         * or
  2414. X         *         there is no limit to the number of blocks for this memfile or
  2415. X         *        the maximum is not reached yet
  2416. X         *    and
  2417. X         *        total memory used is not up to 'maxmemtot'
  2418. X         */
  2419. X    if (mfp->mf_fd < 0 || ((mfp->mf_used_count < mfp->mf_used_count_max ||
  2420. X                        mfp->mf_used_count_max == 0) &&
  2421. X                        (total_mem_used >> 10) < p_mmt))
  2422. X        return NULL;
  2423. X
  2424. X    for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  2425. X        if (!(hp->bh_flags & BH_LOCKED))
  2426. X            break;
  2427. X    if (hp == NULL)        /* not a single one that can be released */
  2428. X        return NULL;
  2429. X
  2430. X        /*
  2431. X         * If the block is dirty, write it.
  2432. X         * If the write fails we don't free it.
  2433. X         */
  2434. X    if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
  2435. X        return NULL;
  2436. X
  2437. X    mf_rem_used(mfp, hp);
  2438. X    mf_rem_hash(mfp, hp);
  2439. X
  2440. X/*
  2441. X * If a BHDR is returned, make sure that the page_count of bh_data is right
  2442. X */
  2443. X    if (hp->bh_page_count != page_count)
  2444. X    {
  2445. X        free(hp->bh_data);
  2446. X        if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
  2447. X        {
  2448. X            free(hp);
  2449. X            return NULL;
  2450. X        }
  2451. X        hp->bh_page_count = page_count;
  2452. X    }
  2453. X    return hp;
  2454. X}
  2455. X
  2456. X/*
  2457. X * release as many blocks as possible
  2458. X * Used in case of out of memory
  2459. X *
  2460. X * return TRUE if any memory was released
  2461. X */
  2462. X    int
  2463. Xmf_release_all()
  2464. X{
  2465. X    BUF            *buf;
  2466. X    MEMFILE        *mfp;
  2467. X    BHDR        *hp;
  2468. X    int            retval = FALSE;
  2469. X
  2470. X    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  2471. X    {
  2472. X        mfp = buf->b_ml.ml_mfp;
  2473. X        if (mfp != NULL && mfp->mf_fd >= 0)        /* only if there is a memfile with a file */
  2474. X            for (hp = mfp->mf_used_last; hp != NULL; )
  2475. X            {
  2476. X                if (!(hp->bh_flags & BH_LOCKED) &&
  2477. X                        (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL))
  2478. X                {
  2479. X                    mf_rem_used(mfp, hp);
  2480. X                    mf_rem_hash(mfp, hp);
  2481. X                    mf_free_bhdr(hp);
  2482. X                    hp = mfp->mf_used_last;        /* re-start, list was changed */
  2483. X                    retval = TRUE;
  2484. X                }
  2485. X                else
  2486. X                    hp = hp->bh_prev;
  2487. X            }
  2488. X    }
  2489. X    return retval;
  2490. X}
  2491. X
  2492. X/*
  2493. X * Allocate a block header and a block of memory for it
  2494. X */
  2495. X    static BHDR *
  2496. Xmf_alloc_bhdr(mfp, page_count)
  2497. X    MEMFILE        *mfp;
  2498. X    int            page_count;
  2499. X{
  2500. X    BHDR    *hp;
  2501. X
  2502. X    if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
  2503. X    {
  2504. X        if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  2505. X        {
  2506. X            free(hp);            /* not enough memory */
  2507. X            hp = NULL;
  2508. X        }
  2509. X        hp->bh_page_count = page_count;
  2510. X    }
  2511. X    return hp;
  2512. X}
  2513. X
  2514. X/*
  2515. X * Free a block header and the block of memory for it
  2516. X */
  2517. X    static void
  2518. Xmf_free_bhdr(hp)
  2519. X    BHDR        *hp;
  2520. X{
  2521. X    free(hp->bh_data);
  2522. X    free(hp);
  2523. X}
  2524. X
  2525. X/*
  2526. X * insert entry *hp in the free list
  2527. X */
  2528. X    static void
  2529. Xmf_ins_free(mfp, hp)
  2530. X    MEMFILE    *mfp;
  2531. X    BHDR    *hp;
  2532. X{
  2533. X    hp->bh_next = mfp->mf_free_first;
  2534. X    mfp->mf_free_first = hp;
  2535. X}
  2536. X
  2537. X/*
  2538. X * remove the first entry from the free list and return a pointer to it
  2539. X * Note: caller must check that mfp->mf_free_first is not NULL!
  2540. X */
  2541. X    static BHDR *
  2542. Xmf_rem_free(mfp)
  2543. X    MEMFILE    *mfp;
  2544. X{
  2545. X    BHDR    *hp;
  2546. X
  2547. X    hp = mfp->mf_free_first;
  2548. X    mfp->mf_free_first = hp->bh_next;
  2549. X    return hp;
  2550. X}
  2551. X
  2552. X/*
  2553. X * read a block from disk
  2554. X * 
  2555. X * Return FAIL for failure, OK otherwise
  2556. X */
  2557. X    static int
  2558. Xmf_read(mfp, hp)
  2559. X    MEMFILE        *mfp;
  2560. X    BHDR        *hp;
  2561. X{
  2562. X    long_u        offset;
  2563. X    unsigned    page_size;
  2564. X    unsigned    size;
  2565. X
  2566. X    if (mfp->mf_fd < 0)        /* there is no file, can't read */
  2567. X        return FAIL;
  2568. X
  2569. X    page_size = mfp->mf_page_size;
  2570. X    offset = page_size * hp->bh_bnum;
  2571. X    size = page_size * hp->bh_page_count;
  2572. X    if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  2573. X    {
  2574. X        EMSG("Seek error in swap file read");
  2575. X        return FAIL;
  2576. X    }
  2577. X    if (read(mfp->mf_fd, hp->bh_data, (size_t)size) != size)
  2578. X    {
  2579. X        EMSG("Read error in swap file");
  2580. X        return FAIL;
  2581. X    }
  2582. X    return OK;
  2583. X}
  2584. X
  2585. X/*
  2586. X * write a block to disk
  2587. X * 
  2588. X * Return FAIL for failure, OK otherwise
  2589. X */
  2590. X    static int
  2591. Xmf_write(mfp, hp)
  2592. X    MEMFILE        *mfp;
  2593. X    BHDR        *hp;
  2594. X{
  2595. X    long_u        offset;        /* offset in the file */
  2596. X    blocknr_t    nr;            /* block nr which is being written */
  2597. X    BHDR        *hp2;
  2598. X    unsigned    page_size;    /* number of bytes in a page */
  2599. X    unsigned    page_count;    /* number of pages written */
  2600. X    unsigned    size;        /* number of bytes written */
  2601. X
  2602. X    if (mfp->mf_fd < 0)        /* there is no file, can't write */
  2603. X        return FAIL;
  2604. X
  2605. X    if (hp->bh_bnum < 0)        /* must assign file block number */
  2606. X        if (mf_trans_add(mfp, hp) == FAIL)
  2607. X            return FAIL;
  2608. X
  2609. X    page_size = mfp->mf_page_size;
  2610. X
  2611. X    /*
  2612. X     * We don't want gaps in the file. Write the blocks in front of *hp
  2613. X     * to extend the file.
  2614. X     * If block 'mf_infile_count' is not in the hash list, it has been
  2615. X     * freed. Fill the space in the file with data from the current block.
  2616. X     */
  2617. X    for (;;)
  2618. X    {
  2619. X        nr = hp->bh_bnum;
  2620. X        if (nr > mfp->mf_infile_count)            /* beyond end of file */
  2621. X        {
  2622. X            nr = mfp->mf_infile_count;
  2623. X            hp2 = mf_find_hash(mfp, nr);        /* NULL catched below */
  2624. X        }
  2625. X        else
  2626. X            hp2 = hp;
  2627. X
  2628. X        offset = page_size * nr;
  2629. X        if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  2630. X        {
  2631. X            EMSG("Seek error in swap file write");
  2632. X            return FAIL;
  2633. X        }
  2634. X        if (hp2 == NULL)            /* freed block, fill with dummy data */
  2635. X            page_count = 1;
  2636. X        else
  2637. X            page_count = hp2->bh_page_count;
  2638. X        size = page_size * page_count;
  2639. X        if (write(mfp->mf_fd, (hp2 == NULL ? hp : hp2)->bh_data,
  2640. X                                                    (size_t)size) != size)
  2641. X        {
  2642. X            EMSG("Write error in swap file");
  2643. X            return FAIL;
  2644. X        }
  2645. X        if (hp2 != NULL)                    /* written a non-dummy block */
  2646. X            hp2->bh_flags &= ~BH_DIRTY;
  2647. X
  2648. X        if (nr + page_count > mfp->mf_infile_count)        /* appended to the file */
  2649. X            mfp->mf_infile_count = nr + page_count;
  2650. X        if (nr == hp->bh_bnum)                /* written the desired block */
  2651. X            break;
  2652. X        nr += page_count;
  2653. X    }
  2654. X    return OK;
  2655. X}
  2656. X
  2657. X/*
  2658. X * Make block number for *hp positive and add it to the translation list
  2659. X * 
  2660. X * Return FAIL for failure, OK otherwise
  2661. X */
  2662. X    static int
  2663. Xmf_trans_add(mfp, hp)
  2664. X    MEMFILE    *mfp;
  2665. X    BHDR    *hp;
  2666. X{
  2667. X    BHDR        *freep;
  2668. X    blocknr_t    new;
  2669. X    int            hash;
  2670. X    NR_TRANS    *np;
  2671. X    int            page_count;
  2672. X
  2673. X    if (hp->bh_bnum >= 0)                    /* it's already positive */
  2674. X        return OK;
  2675. X
  2676. X    if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
  2677. X        return FAIL;
  2678. X
  2679. X/*
  2680. X * get a new number for the block.
  2681. X * If the first item in the free list has sufficient pages, use its number
  2682. X * Otherwise use mf_blocknr_max.
  2683. X */
  2684. X    freep = mfp->mf_free_first;
  2685. X    page_count = hp->bh_page_count;
  2686. X    if (freep != NULL && freep->bh_page_count >= page_count)
  2687. X    {
  2688. X        new = freep->bh_bnum;
  2689. X        /*
  2690. X         * If the page count of the free block was larger, recude it.
  2691. X         * If the page count matches, remove the block from the free list
  2692. X         */
  2693. X        if (freep->bh_page_count > page_count)
  2694. X        {
  2695. X            freep->bh_bnum += page_count;
  2696. X            freep->bh_page_count -= page_count;
  2697. X        }
  2698. X        else
  2699. X        {
  2700. X            freep = mf_rem_free(mfp);
  2701. X            free(freep);
  2702. X        }
  2703. X    }
  2704. X    else
  2705. X    {
  2706. X        new = mfp->mf_blocknr_max;
  2707. X        mfp->mf_blocknr_max += page_count;
  2708. X    }
  2709. X
  2710. X    np->nt_old_bnum = hp->bh_bnum;            /* adjust number */
  2711. X    np->nt_new_bnum = new;
  2712. X
  2713. X    mf_rem_hash(mfp, hp);                    /* remove from old hash list */
  2714. X    hp->bh_bnum = new;
  2715. X    mf_ins_hash(mfp, hp);                    /* insert in new hash list */
  2716. X
  2717. X    hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
  2718. X    np->nt_next = mfp->mf_trans[hash];
  2719. X    mfp->mf_trans[hash] = np;
  2720. X    if (np->nt_next != NULL)
  2721. X        np->nt_next->nt_prev = np;
  2722. X    np->nt_prev = NULL;    
  2723. X
  2724. X    return OK;
  2725. X}
  2726. X
  2727. X/*
  2728. X * Lookup a tranlation from the trans lists and delete the entry
  2729. X * 
  2730. X * Return the positive new number when found, the old number when not found
  2731. X */
  2732. X     blocknr_t
  2733. Xmf_trans_del(mfp, old)
  2734. X    MEMFILE        *mfp;
  2735. X    blocknr_t    old;
  2736. X{
  2737. X    int            hash;
  2738. X    NR_TRANS    *np;
  2739. X    blocknr_t    new;
  2740. X
  2741. X    hash = MEMHASH(old);
  2742. X    for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
  2743. X        if (np->nt_old_bnum == old)
  2744. X            break;
  2745. X    if (np == NULL)                /* not found */
  2746. X        return old;
  2747. X
  2748. X    mfp->mf_neg_count--;
  2749. X    new = np->nt_new_bnum;
  2750. X    if (np->nt_prev != NULL)            /* remove entry from the trans list */
  2751. X        np->nt_prev->nt_next = np->nt_next;
  2752. X    else
  2753. X        mfp->mf_trans[hash] = np->nt_next;
  2754. X    if (np->nt_next != NULL)
  2755. X        np->nt_next->nt_prev = np->nt_prev;
  2756. X    free(np);
  2757. X
  2758. X    return new;
  2759. X}
  2760. X
  2761. X/*
  2762. X * Make the name of the file used for the memfile a full path.
  2763. X * Used before doing a :cd
  2764. X */
  2765. X    void
  2766. Xmf_fullname(mfp)
  2767. X    MEMFILE        *mfp;
  2768. X{
  2769. X    if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_xfname != NULL)
  2770. X    {
  2771. X        free(mfp->mf_fname);
  2772. X        mfp->mf_fname = mfp->mf_xfname;
  2773. X        mfp->mf_xfname = NULL;
  2774. X    }
  2775. X}
  2776. X
  2777. X/*
  2778. X * return TRUE if there are any translations pending for 'mfp'
  2779. X */
  2780. X    int
  2781. Xmf_need_trans(mfp)
  2782. X    MEMFILE        *mfp;
  2783. X{
  2784. X    return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
  2785. X}
  2786. X
  2787. X#if 1            /* included for beta release, TODO: remove later */
  2788. X/*
  2789. X * print statistics for a memfile (for debugging)
  2790. X */
  2791. X    void
  2792. Xmf_statistics()
  2793. X{
  2794. X    MEMFILE        *mfp;
  2795. X    BHDR        *hp;
  2796. X    int            used = 0;
  2797. X    int            locked = 0;
  2798. X    int            dirty = 0;
  2799. X    int            nfree = 0;
  2800. X    int            negative = 0;
  2801. X
  2802. X    mfp = curbuf->b_ml.ml_mfp;
  2803. X    if (mfp == NULL)
  2804. X        MSG("No memfile");
  2805. X    else
  2806. X    {
  2807. X        for (hp = mfp->mf_used_first; hp != NULL; hp = hp->bh_next)
  2808. X        {
  2809. X            ++used;
  2810. X            if (hp->bh_flags & BH_LOCKED)
  2811. X                ++locked;
  2812. X            if (hp->bh_flags & BH_DIRTY)
  2813. X                ++dirty;
  2814. X            if (hp->bh_bnum < 0)
  2815. X                ++negative;
  2816. X        }
  2817. X        for (hp = mfp->mf_free_first; hp != NULL; hp = hp->bh_next)
  2818. X            ++nfree;
  2819. X        sprintf((char *)IObuff, "%d used (%d locked, %d dirty, %d (%d) negative), %d free",
  2820. X                        used, locked, dirty, negative, (int)mfp->mf_neg_count, nfree);
  2821. X        msg(IObuff);
  2822. X    }
  2823. X}
  2824. X#endif
  2825. X
  2826. X/*
  2827. X * open a file for a memfile
  2828. X */
  2829. X    static void
  2830. Xmf_do_open(mfp, fname, new)
  2831. X    MEMFILE        *mfp;
  2832. X    char_u        *fname;
  2833. X    int            new;
  2834. X{
  2835. X    mfp->mf_fname = fname;
  2836. X    /*
  2837. X     * get the full path name before the open, because this is
  2838. X     * not possible after the open on the Amiga.
  2839. X     * fname cannot be NameBuff, because it has been allocated.
  2840. X     */
  2841. X    if (FullName(fname, NameBuff, MAXPATHL) == FAIL)
  2842. X        mfp->mf_xfname = NULL;
  2843. X    else
  2844. X        mfp->mf_xfname = strsave(NameBuff);
  2845. X
  2846. X    /*
  2847. X     * try to open the file
  2848. X     */
  2849. X    mfp->mf_fd = open((char *)fname, new ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)
  2850. X
  2851. X#ifdef AMIGA                /* Amiga has no mode argument */
  2852. X                    );
  2853. X#endif
  2854. X#ifdef UNIX                    /* open in rw------- mode */
  2855. X# ifdef SCO
  2856. X                    , (mode_t)0600);
  2857. X# else
  2858. X                    , 0600);
  2859. X# endif
  2860. X#endif
  2861. X#ifdef MSDOS                /* open read/write */
  2862. X                    , S_IREAD | S_IWRITE);
  2863. X#endif
  2864. X    /*
  2865. X     * If the file cannot be opened, use memory only
  2866. X     */
  2867. X    if (mfp->mf_fd < 0)
  2868. X    {
  2869. X        free(fname);
  2870. X        free(mfp->mf_xfname);
  2871. X        mfp->mf_fname = NULL;
  2872. X        mfp->mf_xfname = NULL;
  2873. X    }
  2874. X}
  2875. END_OF_FILE
  2876.   if test 26671 -ne `wc -c <'vim/src/memfile.c'`; then
  2877.     echo shar: \"'vim/src/memfile.c'\" unpacked with wrong size!
  2878.   fi
  2879.   # end of 'vim/src/memfile.c'
  2880. fi
  2881. echo shar: End of archive 13 \(of 26\).
  2882. cp /dev/null ark13isdone
  2883. MISSING=""
  2884. 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 24 25 26 ; do
  2885.     if test ! -f ark${I}isdone ; then
  2886.     MISSING="${MISSING} ${I}"
  2887.     fi
  2888. done
  2889. if test "${MISSING}" = "" ; then
  2890.     echo You have unpacked all 26 archives.
  2891.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2892. else
  2893.     echo You still must unpack the following archives:
  2894.     echo "        " ${MISSING}
  2895. fi
  2896. exit 0
  2897. exit 0 # Just in case...
  2898.