home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / vim / part06 < prev    next >
Encoding:
Text File  |  1993-04-22  |  44.8 KB  |  2,149 lines

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v37i006:  vim - Vi IMitation editor v1.27, Part06/24
  4. Message-ID: <1993Apr23.173036.16506@sparky.imd.sterling.com>
  5. X-Md4-Signature: 9a8343ff4f6fbeb3f25a5125f9a1c321
  6. Date: Fri, 23 Apr 1993 17:30:36 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mool@oce.nl (Bram Moolenaar)
  10. Posting-number: Volume 37, Issue 6
  11. Archive-name: vim/part06
  12. Environment: UNIX, AMIGA, MS-DOS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 6 (of 23)."
  21. # Contents:  vim/src/misccmds.c vim/src/msdos.c vim/src/undo.c
  22. # Wrapped by mool@oce-rd2 on Mon Apr 19 15:50:08 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'vim/src/misccmds.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'vim/src/misccmds.c'\"
  26. else
  27. echo shar: Extracting \"'vim/src/misccmds.c'\" \(13737 characters\)
  28. sed "s/^X//" >'vim/src/misccmds.c' <<'END_OF_FILE'
  29. X/* vi:ts=4:sw=4
  30. X *
  31. X * VIM - Vi IMitation
  32. X *
  33. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  34. X *                            Tim Thompson            twitch!tjt
  35. X *                            Tony Andrews            onecom!wldrdg!tony 
  36. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  37. X */
  38. X
  39. X/*
  40. X * misccmds.c: functions that didn't seem to fit elsewhere
  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
  48. Xstatic char *(si_tab[]) = {"if", "else", "while", "for", "do"};
  49. X
  50. X/*
  51. X * count the size of the indent in the current line
  52. X */
  53. X    int
  54. Xget_indent()
  55. X{
  56. X    register char *ptr;
  57. X    register int count = 0;
  58. X
  59. X    for (ptr = nr2ptr(Curpos.lnum); *ptr; ++ptr)
  60. X    {
  61. X        if (*ptr == TAB)    /* count a tab for what it is worth */
  62. X            count += p_ts - (count % p_ts);
  63. X        else if (*ptr == ' ')
  64. X            ++count;            /* count a space for one */
  65. X        else
  66. X            break;
  67. X    }
  68. X    return (count);
  69. X}
  70. X
  71. X/*
  72. X * set the indent of the current line
  73. X * leaves the cursor on the first non-blank in the line
  74. X */
  75. X    void
  76. Xset_indent(size, delete)
  77. X    register int size;
  78. X    int delete;
  79. X{
  80. X    int        oldstate = State;
  81. X
  82. X    State = INSERT;        /* don't want REPLACE for State */
  83. X    Curpos.col = 0;
  84. X    if (delete)
  85. X    {
  86. X        while (isspace(gcharCurpos()))    /* delete old indent */
  87. X            delchar(FALSE);
  88. X    }
  89. X    while (size >= p_ts)
  90. X    {
  91. X        inschar(TAB);
  92. X        size -= p_ts;
  93. X    }
  94. X    while (size)
  95. X    {
  96. X        inschar(' ');
  97. X        --size;
  98. X    }
  99. X    State = oldstate;
  100. X    script_winsize_pp();
  101. X}
  102. X
  103. X/*
  104. X * Opencmd
  105. X *
  106. X * Add a blank line below or above the current line.
  107. X */
  108. X
  109. X    int
  110. XOpencmd(dir, redraw)
  111. X    int         dir;
  112. X    int            redraw;
  113. X{
  114. X    char   *l;
  115. X    char   *ptr;
  116. X    FPOS    oldCurpos;             /* old cursor position */
  117. X    int        newcol = 0;            /* new cursor column */
  118. X    int     newindent = 0;        /* auto-indent of the new line */
  119. X    int     extra = 0;            /* number of bytes to be copied from current line */
  120. X    int        n;
  121. X    int        truncate = FALSE;    /* truncate current line afterwards */
  122. X    int        no_si = FALSE;        /* reset did_si afterwards */
  123. X
  124. X    ptr = nr2ptr(Curpos.lnum);
  125. X    u_clearline();        /* cannot do "U" command when adding lines */
  126. X    did_si = FALSE;
  127. X    if (p_ai || p_si)
  128. X    {
  129. X        /*
  130. X         * count white space on current line
  131. X         */
  132. X        newindent = get_indent();
  133. X
  134. X                /*
  135. X                 * If we just did an auto-indent, then we didn't type anything on the
  136. X                 * prior line, and it should be truncated.
  137. X                 */
  138. X        if (dir == FORWARD && did_ai)
  139. X                truncate = TRUE;
  140. X        else if (p_si)
  141. X        {
  142. X            char    *p;
  143. X            char    *pp;
  144. X            int        i, save;
  145. X
  146. X            p = ptr;
  147. X            skipspace(&p);
  148. X            if (dir == FORWARD)
  149. X            {
  150. X                if (*p == '{')
  151. X                {
  152. X                    did_si = TRUE;
  153. X                    no_si = TRUE;
  154. X                }
  155. X                else
  156. X                {
  157. X                    for (pp = p; islower(*pp); ++pp) ;
  158. X                    if (!isidchar(*pp))
  159. X                    {
  160. X                        save = *pp;
  161. X                        *pp = NUL;
  162. X                        for (i = sizeof(si_tab)/sizeof(char *); --i >= 0; )
  163. X                            if (strcmp(p, si_tab[i]) == 0)
  164. X                            {
  165. X                                did_si = TRUE;
  166. X                                break;
  167. X                            }
  168. X                        *pp = save;
  169. X                    }
  170. X                }
  171. X            }
  172. X            else
  173. X            {
  174. X                if (*p == '}')
  175. X                    did_si = TRUE;
  176. X            }
  177. X        }
  178. X        did_ai = TRUE;
  179. X        if (p_si)
  180. X            can_si = TRUE;
  181. X    }
  182. X    if (State == INSERT || State == REPLACE)    /* only when dir == FORWARD */
  183. X        extra = strlen(ptr + Curpos.col);
  184. X    if ((l = alloc_line(extra)) == NULL)
  185. X        return (FALSE);
  186. X    if (extra)
  187. X    {
  188. X        strcpy(l, ptr + Curpos.col);
  189. X        did_ai = FALSE;         /* don't trucate now */
  190. X    }
  191. X
  192. X    oldCurpos = Curpos;
  193. X    if (dir == BACKWARD)
  194. X        --Curpos.lnum;
  195. X    if (appendline(Curpos.lnum, l) == FALSE)
  196. X        return FALSE;
  197. X    if (newindent || did_si)
  198. X    {
  199. X        ++Curpos.lnum;
  200. X        if (did_si)
  201. X        {
  202. X            if (p_sr)
  203. X                newindent -= newindent % p_sw;
  204. X            newindent += p_sw;
  205. X        }
  206. X        set_indent(newindent, FALSE);
  207. X        newcol = Curpos.col;
  208. X        if (no_si)
  209. X            did_si = FALSE;
  210. X    }
  211. X    Curpos = oldCurpos;
  212. X
  213. X    if (dir == FORWARD)
  214. X    {
  215. X        if (truncate)
  216. X            *ptr = NUL;
  217. X        else if (extra)
  218. X        {
  219. X            truncate = TRUE;
  220. X            *(ptr + Curpos.col) = NUL;        /* truncate current line at cursor */
  221. X        }
  222. X        if (truncate)
  223. X            canincrease(0);
  224. X
  225. X        /*
  226. X         * Get the cursor to the start of the line, so that 'Cursrow' gets
  227. X         * set to the right physical line number for the stuff that
  228. X         * follows...
  229. X         */
  230. X        Curpos.col = 0;
  231. X
  232. X        if (redraw)
  233. X        {
  234. X            cursupdate();
  235. X
  236. X            /*
  237. X             * If we're doing an open on the last logical line, then go ahead and
  238. X             * scroll the screen up. Otherwise, just insert a blank line at the
  239. X             * right place. We use calls to plines() in case the cursor is
  240. X             * resting on a long line.
  241. X             */
  242. X            n = Cursrow + plines(Curpos.lnum);
  243. X            if (n == (Rows - 1))
  244. X                scrollup(1L);
  245. X            else
  246. X                s_ins(n, 1, TRUE);
  247. X        }
  248. X        ++Curpos.lnum;    /* cursor moves down */
  249. X    }
  250. X    else if (redraw)
  251. X        s_ins(Cursrow, 1, TRUE); /* insert physical line */
  252. X
  253. X    Curpos.col = newcol;
  254. X    if (redraw)
  255. X    {
  256. X        updateScreen(VALID_TO_CURSCHAR);
  257. X        cursupdate();        /* update Cursrow */
  258. X    }
  259. X    CHANGED;
  260. X
  261. X    return (TRUE);
  262. X}
  263. X
  264. X/*
  265. X * plines(p) - return the number of physical screen lines taken by line 'p'
  266. X */
  267. X    int
  268. Xplines(p)
  269. X    linenr_t p;
  270. X{
  271. X    register int    col = 0;
  272. X    register u_char  *s;
  273. X
  274. X#ifdef DEBUG
  275. X    if (p == 0)
  276. X    {
  277. X        emsg("plines(0) ????");
  278. X        return (0);
  279. X    }
  280. X#endif
  281. X    s = (u_char *)nr2ptr(p);
  282. X
  283. X    if (*s == NUL)                /* empty line */
  284. X        return 1;
  285. X
  286. X    while (*s != NUL)
  287. X        col += chartabsize(*s++, col);
  288. X
  289. X    /*
  290. X     * If list mode is on, then the '$' at the end of the line takes up one
  291. X     * extra column.
  292. X     */
  293. X    if (p_list)
  294. X        col += 1;
  295. X
  296. X    /*
  297. X     * If 'number' mode is on, add another 8.
  298. X     */
  299. X    if (p_nu)
  300. X        col += 8;
  301. X
  302. X    return ((col + ((int)Columns - 1)) / (int)Columns);
  303. X}
  304. X
  305. X/*
  306. X * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  307. X */
  308. X    int
  309. Xplines_m(first, last)
  310. X    linenr_t        first, last;
  311. X{
  312. X        int count = 0;
  313. X
  314. X        while (first <= last)
  315. X                count += plines(first++);
  316. X        return (count);
  317. X}
  318. X
  319. X    void
  320. Xfileinfo()
  321. X{
  322. X    if (bufempty())
  323. X    {
  324. X        msg("Buffer Empty");
  325. X        return;
  326. X    }
  327. X    sprintf(IObuff, "\"%s\"%s line %ld of %ld -- %d %% --",
  328. X            (Filename != NULL) ? Filename : "No File",
  329. X            Changed ? " [Modified]" : "",
  330. X            (long)Curpos.lnum,
  331. X            (long)line_count,
  332. X            (int)(((long)Curpos.lnum * 100L) / (long)line_count));
  333. X
  334. X    if (numfiles > 1)
  335. X        sprintf(IObuff + strlen(IObuff), " (file %d of %d)", curfile + 1, numfiles);
  336. X    msg(IObuff);
  337. X}
  338. X
  339. X    void
  340. Xsetfname(s)
  341. X    char *s;
  342. X{
  343. X    if (Filename != NULL)
  344. X        free(Filename);
  345. X    if (s == NULL || *s == NUL)
  346. X        Filename = NULL;
  347. X    else
  348. X    {
  349. X        FullName(s, IObuff, IOSIZE);
  350. X        Filename = (char *)strsave(IObuff);
  351. X    }
  352. X#ifndef MSDOS
  353. X    thisfile_sn = FALSE;
  354. X#endif
  355. X}
  356. X
  357. X/*
  358. X * return nonzero if "s" is not the same file as current file
  359. X */
  360. X    int
  361. Xotherfile(s)
  362. X    char *s;
  363. X{
  364. X    if (s == NULL || *s == NUL || Filename == NULL)        /* no name is different */
  365. X        return TRUE;
  366. X    FullName(s, IObuff, IOSIZE);
  367. X    return fnamecmp(IObuff, Filename);
  368. X}
  369. X    
  370. X/*
  371. X * put filename in title bar of window
  372. X */
  373. X    void
  374. Xmaketitle()
  375. X{
  376. X#ifdef AMIGA
  377. X        if (Filename == NULL)
  378. X                settitle("");
  379. X        else
  380. X        {
  381. X            if (numfiles == 1)
  382. X                settitle(Filename);
  383. X            else
  384. X            {
  385. X                    sprintf(IObuff, "%s (%d of %d)", Filename, curfile + 1, numfiles);
  386. X                    settitle(IObuff);
  387. X            }
  388. X        }
  389. X#endif
  390. X}
  391. X
  392. X    void
  393. Xinschar(c)
  394. X    int            c;
  395. X{
  396. X    register char  *p;
  397. X    register char  *pend;
  398. X
  399. X    p = nr2ptr(Curpos.lnum);
  400. X    pend = p + Curpos.col;
  401. X    if (State != REPLACE || *pend == NUL)
  402. X    {
  403. X            /* make room for the new char. */
  404. X            if (!canincrease(1))
  405. X                return;
  406. X
  407. X            p = nr2ptr(Curpos.lnum);
  408. X            pend = p + Curpos.col;
  409. X            p += strlen(p) + 1;
  410. X
  411. X            for (; p > pend; p--)
  412. X                *p = *(p - 1);
  413. X    }
  414. X    *pend = c;
  415. X
  416. X    /*
  417. X     * If we're in insert mode and showmatch mode is set, then check for
  418. X     * right parens and braces. If there isn't a match, then beep. If there
  419. X     * is a match AND it's on the screen, then flash to it briefly. If it
  420. X     * isn't on the screen, don't do anything.
  421. X     */
  422. X    if (p_sm && State == INSERT && (c == ')' || c == '}' || c == ']'))
  423. X    {
  424. X        FPOS           *lpos, csave;
  425. X
  426. X        if ((lpos = showmatch()) == NULL)        /* no match, so beep */
  427. X            beep();
  428. X        else if (lpos->lnum >= Topline)
  429. X        {
  430. X            updateScreen(VALID_TO_CURSCHAR); /* show the new char first */
  431. X            csave = Curpos;
  432. X            Curpos = *lpos;     /* move to matching char */
  433. X            cursupdate();
  434. X            setcursor();
  435. X            flushbuf();
  436. X            vim_delay();        /* brief pause */
  437. X            Curpos = csave;     /* restore cursor position */
  438. X            cursupdate();
  439. X        }
  440. X    }
  441. X    ++Curpos.col;
  442. X
  443. X    CHANGED;
  444. X}
  445. X
  446. X    void
  447. Xinsstr(s)
  448. X    register char  *s;
  449. X{
  450. X    register char  *p;
  451. X    register char  *pend;
  452. X    register int    n = strlen(s);
  453. X
  454. X    /* Move everything in the file over to make */
  455. X    /* room for the new string. */
  456. X    if (!canincrease(n))
  457. X        return;
  458. X
  459. X    p = nr2ptr(Curpos.lnum);
  460. X    pend = p + Curpos.col;
  461. X    p += strlen(p) + n;
  462. X
  463. X    for (; p > pend; p--)
  464. X        *p = *(p - n);
  465. X
  466. X    Curpos.col += n;
  467. X    while (--n >= 0)
  468. X        *p++ = *s++;
  469. X
  470. X    CHANGED;
  471. X}
  472. X
  473. X    int
  474. Xdelchar(fixpos)
  475. X    int            fixpos;     /* if TRUE fix the cursor position when done */
  476. X{
  477. X    char        *ptr;
  478. X    int            lastchar;
  479. X
  480. X    ptr = pos2ptr(&Curpos);
  481. X
  482. X    if (*ptr == NUL)    /* can't do anything */
  483. X        return FALSE;
  484. X
  485. X    lastchar = (*++ptr == NUL);
  486. X    /* Delete the char. at Curpos by shifting everything in the line down. */
  487. X    do
  488. X        *(ptr - 1) = *ptr;
  489. X    while (*ptr++);
  490. X
  491. X    /*
  492. X     * If we just took off the last character of a non-blank line, we don't
  493. X     * want to end up positioned at the newline.
  494. X     */
  495. X    if (fixpos && Curpos.col > 0 && lastchar && State != INSERT)
  496. X            --Curpos.col;
  497. X
  498. X    (void)canincrease(0);
  499. X    CHANGED;
  500. X    return TRUE;
  501. X}
  502. X
  503. X    void
  504. Xdellines(nlines, can_update)
  505. X    long             nlines;
  506. X    int                can_update;
  507. X{
  508. X    int             doscreen;    /* if true, update the screen */
  509. X    int             num_plines = 0;
  510. X
  511. X    doscreen = can_update;
  512. X    /*
  513. X     * There's no point in keeping the screen updated if we're deleting more
  514. X     * than a screen's worth of lines.
  515. X     */
  516. X    if (nlines > (Rows - 1) && can_update)
  517. X    {
  518. X        doscreen = FALSE;
  519. X        /* flaky way to clear rest of screen */
  520. X        s_del(Cursrow, (int)Rows - 1, TRUE);
  521. X    }
  522. X    while (nlines-- > 0)
  523. X    {
  524. X        if (bufempty())         /* nothing to delete */
  525. X            break;
  526. X
  527. X        /*
  528. X         * Set up to delete the correct number of physical lines on the
  529. X         * screen
  530. X         */
  531. X        if (doscreen)
  532. X            num_plines += plines(Curpos.lnum);
  533. X
  534. X        free_line(delsline(Curpos.lnum, TRUE));
  535. X
  536. X        CHANGED;
  537. X
  538. X        /* If we delete the last line in the file, stop */
  539. X        if (Curpos.lnum > line_count)
  540. X        {
  541. X            Curpos.lnum = line_count;
  542. X            break;
  543. X        }
  544. X    }
  545. X    Curpos.col = 0;
  546. X    /*
  547. X     * Delete the correct number of physical lines on the screen
  548. X     */
  549. X    if (doscreen && num_plines > 0)
  550. X        s_del(Cursrow, num_plines, TRUE);
  551. X}
  552. X
  553. X    int
  554. Xgchar(pos)
  555. X    FPOS *pos;
  556. X{
  557. X    return (int)(*(pos2ptr(pos)));
  558. X}
  559. X
  560. X    int
  561. XgcharCurpos()
  562. X{
  563. X    return (int)(*(pos2ptr(&Curpos)));
  564. X}
  565. X
  566. X/*
  567. X * return TRUE if the cursor is before or on the first non-blank in the line
  568. X */
  569. X    int
  570. Xinindent()
  571. X{
  572. X    register char *ptr;
  573. X    register int col;
  574. X
  575. X    for (col = 0, ptr = nr2ptr(Curpos.lnum); isspace(*ptr++); ++col)
  576. X        ;
  577. X    if (col >= Curpos.col)
  578. X        return TRUE;
  579. X    else
  580. X        return FALSE;
  581. X}
  582. X
  583. X/*
  584. X * skipspace: skip over ' ' and '\t'.
  585. X *
  586. X * note: you must give a pointer to a char pointer!
  587. X */
  588. X    void
  589. Xskipspace(pp)
  590. X    char **pp;
  591. X{
  592. X    register char *p;
  593. X    
  594. X    for (p = *pp; *p == ' ' || *p == '\t'; ++p)    /* skip to next non-white */
  595. X        ;
  596. X    *pp = p;
  597. X}
  598. X
  599. X/*
  600. X * skiptospace: skip over text until ' ' or '\t'.
  601. X *
  602. X * note: you must give a pointer to a char pointer!
  603. X */
  604. X    void
  605. Xskiptospace(pp)
  606. X    char **pp;
  607. X{
  608. X    register char *p;
  609. X
  610. X    for (p = *pp; *p != ' ' && *p != '\t' && *p != NUL; ++p)
  611. X        ;
  612. X    *pp = p;
  613. X}
  614. X
  615. X/*
  616. X * getdigits: get a number from a string and skip over it
  617. X *
  618. X * note: you must give a pointer to a char pointer!
  619. X */
  620. X
  621. X    long
  622. Xgetdigits(pp)
  623. X    char **pp;
  624. X{
  625. X    register char *p;
  626. X    long retval;
  627. X    
  628. X    p = *pp;
  629. X    retval = atol(p);
  630. X    while (isdigit(*p))    /* skip to next non-digit */
  631. X        ++p;
  632. X    *pp = p;
  633. X    return retval;
  634. X}
  635. X
  636. X    char *
  637. Xplural(n)
  638. X    long n;
  639. X{
  640. X    static char buf[2] = "s";
  641. X
  642. X    if (n == 1)
  643. X        return &(buf[1]);
  644. X    return &(buf[0]);
  645. X}
  646. X
  647. X/*
  648. X * set_Changed is called whenever something in the file is changed
  649. X * If the file is readonly, give a warning message with the first change.
  650. X */
  651. X    void
  652. Xset_Changed()
  653. X{
  654. X    if (Changed == 0 && p_ro)
  655. X        emsg("Warning: Changing a readonly file");
  656. X    Changed = 1;
  657. X    Updated = 1;
  658. X}
  659. X
  660. X    int
  661. Xask_yesno(str)
  662. X    char *str;
  663. X{
  664. X    int r = ' ';
  665. X
  666. X    while (r != 'y' && r != 'n')
  667. X    {
  668. X        smsg("%s (y/n)? ", str);
  669. X        r = vgetc();
  670. X        outchar(r);        /* show what you typed */
  671. X        flushbuf();
  672. X    }
  673. X    return r;
  674. X}
  675. X
  676. X    void
  677. Xmsgmore(n)
  678. X    long n;
  679. X{
  680. X    long pn;
  681. X
  682. X    if (n > 0)
  683. X        pn = n;
  684. X    else
  685. X        pn = -n;
  686. X
  687. X    if (pn > p_report)
  688. X        smsg("%ld %s line%s %s", pn, n > 0 ? "more" : "fewer", plural(pn),
  689. X                                            got_int ? "(Interrupted)" : "");
  690. X}
  691. X
  692. X/*
  693. X * give a warning for an error
  694. X */
  695. X    void
  696. Xbeep()
  697. X{
  698. X    flush_buffers();
  699. X    if (p_vb)
  700. X    {
  701. X        if (T_VB && *T_VB)
  702. X            outstr(T_VB);
  703. X        else
  704. X        {            /* very primitive visual bell */
  705. X            msg("    ^G");
  706. X            msg("     ^G");
  707. X            msg("    ^G ");
  708. X            msg("     ^G");
  709. X            msg("       ");
  710. X        }
  711. X    }
  712. X    else
  713. X        outchar('\007');
  714. X}
  715. X
  716. X/* 
  717. X * Expand environment variable with path name.
  718. X * If anything fails no expansion is done and dst equals src.
  719. X */
  720. X    void
  721. Xexpand_env(src, dst, dstlen)
  722. X    char    *src;            /* input string e.g. "$HOME/vim.hlp" */
  723. X    char    *dst;            /* where to put the result */
  724. X    int        dstlen;            /* maximum length of the result */
  725. X{
  726. X    char    *tail;
  727. X    int        c;
  728. X    char    *var;
  729. X
  730. X    if (*src == '$')
  731. X    {
  732. X/*
  733. X * The variable name is copied into dst temporarily, because it may be
  734. X * a string in read-only memory.
  735. X */
  736. X        tail = src + 1;
  737. X        var = dst;
  738. X        c = dstlen;
  739. X        while (c-- > 0 && *tail && *tail != PATHSEP)
  740. X            *var++ = *tail++;
  741. X        *var = NUL;
  742. X        var = (char *)vimgetenv(dst);
  743. X        if (*tail)
  744. X            ++tail;
  745. X        if (var && (strlen(var) + strlen(tail) + 1 < dstlen))
  746. X        {
  747. X            sprintf(dst, "%s%c%s", var, PATHSEP, tail);
  748. X            return;
  749. X        }
  750. X    }
  751. X    strncpy(dst, src, (size_t)dstlen);
  752. X}
  753. X
  754. X/*
  755. X * Compare two file names and return TRUE if they are different files.
  756. X * For the first name environment variables are expanded
  757. X */
  758. X    int
  759. Xfullpathcmp(s1, s2)
  760. X    char *s1, *s2;
  761. X{
  762. X#ifdef UNIX
  763. X    struct stat st1, st2;
  764. X    char buf1[MAXPATHL];
  765. X
  766. X    expand_env(s1, buf1, MAXPATHL);
  767. X    st1.st_dev = 99;        /* if stat fails, st1 and st2 will be different */
  768. X    st2.st_dev = 100;
  769. X    stat(buf1, &st1);
  770. X    stat(s2, &st2);
  771. X    if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
  772. X        return FALSE;
  773. X    return TRUE;
  774. X#else
  775. X    char buf1[MAXPATHL];
  776. X    char buf2[MAXPATHL];
  777. X
  778. X    expand_env(s1, buf2, MAXPATHL);
  779. X    if (FullName(buf2, buf1, MAXPATHL) && FullName(s2, buf2, MAXPATHL))
  780. X        return strcmp(buf1, buf2);
  781. X    /*
  782. X     * one of the FullNames() failed, file probably doesn't exist.
  783. X     */
  784. X    return TRUE;
  785. X#endif
  786. X}
  787. END_OF_FILE
  788. if test 13737 -ne `wc -c <'vim/src/misccmds.c'`; then
  789.     echo shar: \"'vim/src/misccmds.c'\" unpacked with wrong size!
  790. fi
  791. # end of 'vim/src/misccmds.c'
  792. fi
  793. if test -f 'vim/src/msdos.c' -a "${1}" != "-c" ; then 
  794.   echo shar: Will not clobber existing file \"'vim/src/msdos.c'\"
  795. else
  796. echo shar: Extracting \"'vim/src/msdos.c'\" \(13589 characters\)
  797. sed "s/^X//" >'vim/src/msdos.c' <<'END_OF_FILE'
  798. X/* vi:ts=4:sw=4
  799. X *
  800. X * VIM - Vi IMitation
  801. X *
  802. X * Code Contributions By:        Bram Moolenaar            mool@oce.nl
  803. X *                                Tim Thompson            twitch!tjt
  804. X *                                Tony Andrews            onecom!wldrdg!tony
  805. X *                                G. R. (Fred) Walter     watmath!watcgl!grwalter
  806. X */
  807. X
  808. X/*
  809. X * msdos.c
  810. X *
  811. X * MSDOS system-dependent routines.
  812. X * A cheap plastic imitation of the amiga dependent code.
  813. X * A lot in this file was made by Juergen Weigert (jw).
  814. X */
  815. X
  816. X#include "vim.h"
  817. X#include "globals.h"
  818. X#include "param.h"
  819. X#include "proto.h"
  820. X#include <conio.h>
  821. X#include <fcntl.h>
  822. X#include <bios.h>
  823. X
  824. Xstatic int WaitForChar __ARGS((int));
  825. Xstatic int cbrk_handler __ARGS(());
  826. X
  827. X#ifdef WILD_CARDS
  828. Xtypedef struct filelist
  829. X{
  830. X    char    **file;
  831. X    int        nfiles;
  832. X    int        maxfiles;
  833. X} FileList;
  834. X
  835. Xstatic void        addfile __ARGS((FileList *, char *));
  836. Xstatic int        pstrcmp __ARGS((char **, char **));
  837. Xstatic void        strlowcpy __ARGS((char *, char *));
  838. Xstatic int        expandpath __ARGS((FileList *, char *, int, int, int));
  839. X#endif
  840. X
  841. Xstatic int cbrk_pressed = FALSE;    /* set by ctrl-break interrupt */
  842. Xstatic int ctrlc_pressed = FALSE;    /* set when ctrl-C or ctrl-break detected */
  843. Xstatic int delayed_redraw = FALSE;    /* set when ctrl-C detected */
  844. X
  845. X/*
  846. X * the number of calls to Write is reduced by using the buffer "outbuf"
  847. X */
  848. X#define BSIZE    2048
  849. Xstatic u_char    outbuf[BSIZE];
  850. Xstatic int        bpos = 0;
  851. X
  852. X#ifdef DEBUG
  853. X/*
  854. X * Put two characters in the video buffer without calling BIOS or DOS.
  855. X */
  856. Xblink(n)
  857. X    int n;
  858. X{
  859. X    char far *p;
  860. X    static int counter;
  861. X
  862. X    p = MK_FP(0xb800, 0x10 + n);        /* p points in screen buffer */
  863. X    *p = counter;
  864. X    *(p + 1) = counter;
  865. X    *(p + 2) = counter;
  866. X    *(p + 3) = counter;
  867. X    ++counter;
  868. X}
  869. X#endif
  870. X
  871. X    void
  872. Xvim_delay()
  873. X{
  874. X    delay(500);
  875. X}
  876. X
  877. X/*
  878. X * this version of remove is not scared by a readonly (backup) file
  879. X */
  880. X    int
  881. Xremove(name)
  882. X    char *name;
  883. X{
  884. X    setperm(name, 0);    /* default permissions */
  885. X    return unlink(name);
  886. X}
  887. X
  888. X/*
  889. X * flushbuf(): flush the output buffer
  890. X */
  891. X    void
  892. Xflushbuf()
  893. X{
  894. X    if (bpos != 0)
  895. X    {
  896. X        write(1, (char *)outbuf, (long)bpos);
  897. X        bpos = 0;
  898. X    }
  899. X}
  900. X
  901. X/*
  902. X * outchar(c): put a character into the output buffer.
  903. X * Flush it if it becomes full.
  904. X */
  905. X    void
  906. Xoutchar(c)
  907. X    unsigned c;
  908. X{
  909. X    outbuf[bpos] = c;
  910. X    ++bpos;
  911. X    if (bpos >= BSIZE)
  912. X        flushbuf();
  913. X}
  914. X
  915. X/*
  916. X * outstr(s): put a string character at a time into the output buffer.
  917. X */
  918. X    void
  919. Xoutstr(s)
  920. X    register char *s;
  921. X{
  922. X    if (!s)            /* s is NULL in case of not defined termcap entry */
  923. X        return;
  924. X    /*
  925. X     * The prefix ESC| is used to emulate capabilities
  926. X     * missing in ansi.sys by direct calls to conio routines.
  927. X     * If we want to avoid this we need the nansi.sys driver. (jw)
  928. X     * Only works if the string starts with ESC!
  929. X     */
  930. X    if (s[0] == ESC && s[1] == '|')
  931. X    {
  932. X        flushbuf();
  933. X        switch (s[2])
  934. X        {
  935. X        case 'L':    insline();
  936. X                         return;
  937. X
  938. X        case 'M':    delline();
  939. X                    return;
  940. X
  941. X        default:    outstr("OOPS");
  942. X                    return;
  943. X        }
  944. X    }
  945. X#ifdef TERMCAP
  946. X    tputs(s, 1, outchar);
  947. X#else
  948. X    while (*s)
  949. X        outchar(*s++);
  950. X#endif
  951. X}
  952. X
  953. X#define POLL_SPEED 10    /* milliseconds between polls */
  954. X
  955. X/*
  956. X * Simulate WaitForChar() by slowly polling with bioskey(1).
  957. X *
  958. X * If Vim should work over the serial line after a 'ctty com1' we must use
  959. X * kbhit() and getch(). (jw)
  960. X * Usually kbhit() is not used, because then CTRL-C will be catched by DOS (mool).
  961. X */
  962. X
  963. X    static int
  964. XWaitForChar(msec)
  965. X    int msec;
  966. X{
  967. X    do
  968. X    {
  969. X#ifdef USE_KBHIT
  970. X        if (kbhit() || cbrk_pressed)
  971. X#else
  972. X        if (bioskey(1) || cbrk_pressed)
  973. X#endif
  974. X            return 1;
  975. X        delay(POLL_SPEED);
  976. X        msec -= POLL_SPEED;
  977. X    }
  978. X    while (msec >= 0);
  979. X    return 0;
  980. X}
  981. X
  982. X/*
  983. X * GetChars(): low level input function.
  984. X * Get characters from the keyboard.
  985. X * If type == T_PEEK do not wait for characters.
  986. X * If type == T_WAIT wait a short time for characters.
  987. X * If type == T_BLOCK wait for characters.
  988. X */
  989. X    int
  990. XGetChars(buf, maxlen, type)
  991. X    char        *buf;
  992. X    int         maxlen;
  993. X    int         type;
  994. X{
  995. X    int         len = 0;
  996. X    int         time = 1000;    /* one second */
  997. X    int            c;
  998. X
  999. X/*
  1000. X * if we got a ctrl-C when we were busy, there will be a "^C" somewhere
  1001. X * on the sceen, so we need to redisplay it.
  1002. X */
  1003. X    if (delayed_redraw)
  1004. X    {
  1005. X        delayed_redraw = FALSE;
  1006. X        updateScreen(CLEAR);
  1007. X        setcursor();
  1008. X        flushbuf();
  1009. X    }
  1010. X
  1011. X    switch (type)
  1012. X    {
  1013. X    case T_PEEK:
  1014. X        time = 1;
  1015. X         /* FALLTHROUGH */
  1016. X
  1017. X    case T_WAIT:
  1018. X        if (WaitForChar(time) == 0)     /* no character available */
  1019. X            return 0;
  1020. X        break;
  1021. X
  1022. X    case T_BLOCK:
  1023. X    /*
  1024. X     * If there is no character available within 2 seconds (default)
  1025. X     * write the autoscript file to disk
  1026. X     */
  1027. X        if (WaitForChar((int)p_ut) == 0)
  1028. X            updatescript(0);
  1029. X    }
  1030. X
  1031. X/*
  1032. X * Try to read as many characters as there are.
  1033. X * Works for the controlling tty only.
  1034. X */
  1035. X    --maxlen;        /* may get two chars at once */
  1036. X    /*
  1037. X     * we will get at least one key. Get more if they are available
  1038. X     * After a ctrl-break we have to read a 0 (!) from the buffer.
  1039. X     * bioskey(1) will return 0 if no key is available and when a
  1040. X     * ctrl-break was typed. When ctrl-break is hit, this does not always
  1041. X     * implies a key hit.
  1042. X     */
  1043. X    cbrk_pressed = FALSE;
  1044. X#ifdef USE_KBHIT
  1045. X    while ((len == 0 || kbhit()) && len < maxlen)
  1046. X    {
  1047. X        switch (c = getch())
  1048. X        {
  1049. X        case 0:
  1050. X                *buf++ = K_NUL;
  1051. X                break;
  1052. X        case 3:
  1053. X                cbrk_pressed = TRUE;
  1054. X                /*FALLTHROUGH*/
  1055. X        default:
  1056. X                *buf++ = c;
  1057. X        }
  1058. X        len++;
  1059. X    }
  1060. X#else
  1061. X    while ((len == 0 || bioskey(1)) && len < maxlen)
  1062. X    {
  1063. X        c = bioskey(0);            /* get the key */
  1064. X        if (c == 0)                /* ctrl-break */
  1065. X            c = 3;                /* return a CTRL-C */
  1066. X        if ((c & 0xff) == 0)
  1067. X        {
  1068. X            if (c == 0x0300)        /* CTRL-@ is 0x0300, translated into K_ZERO */
  1069. X                c = K_ZERO;
  1070. X            else        /* extended key code 0xnn00 translated into K_NUL, nn */
  1071. X            {
  1072. X                c >>= 8;
  1073. X                *buf++ = K_NUL;
  1074. X                ++len;
  1075. X            }
  1076. X        }
  1077. X
  1078. X        *buf++ = c;
  1079. X        len++;
  1080. X    }
  1081. X#endif
  1082. X    return len;
  1083. X}
  1084. X
  1085. Xextern int _fmode;
  1086. X
  1087. X    void
  1088. Xtextfile(on)
  1089. X    int on;
  1090. X{
  1091. X    /*
  1092. X     * in O_TEXT mode we read and write files with CR/LF translation.
  1093. X     */
  1094. X    _fmode = on ? O_TEXT : O_BINARY;
  1095. X}
  1096. X
  1097. X/*
  1098. X * We have no job control, fake it by starting a new shell.
  1099. X */
  1100. X    void
  1101. Xmch_suspend()
  1102. X{
  1103. X    outstr("new shell started\n");
  1104. X    stoptermcap();
  1105. X    call_shell(NULL, 0);
  1106. X    starttermcap();
  1107. X}
  1108. X
  1109. X/*
  1110. X * we do not use windows, there is not much to do here
  1111. X */
  1112. X    void
  1113. Xmch_windinit()
  1114. X{
  1115. X    textfile(p_tx);
  1116. X    flushbuf();
  1117. X}
  1118. X
  1119. X    void
  1120. Xcheck_win(argc, argv)
  1121. X    int        argc;
  1122. X    char    **argv;
  1123. X{
  1124. X    if (!isatty(0) || !isatty(1))
  1125. X    {
  1126. X        fprintf(stderr, "VIM: no controlling terminal\n");
  1127. X        exit(2);
  1128. X    }
  1129. X}
  1130. X
  1131. X/*
  1132. X * fname_case(): Set the case of the filename, if it already exists.
  1133. X *                 msdos filesystem is far to primitive for that. do nothing.
  1134. X */
  1135. X    void
  1136. Xfname_case(name)
  1137. X    char *name;
  1138. X{
  1139. X}
  1140. X
  1141. X/*
  1142. X * settitle(): set titlebar of our window.
  1143. X * Dos console has no title.
  1144. X */
  1145. X    void
  1146. Xsettitle(str)
  1147. X    char *str;
  1148. X{
  1149. X}
  1150. X
  1151. X    void
  1152. Xresettitle()
  1153. X{
  1154. X}
  1155. X
  1156. X/*
  1157. X * get name of current directory into buffer 'buf' of length 'len' bytes
  1158. X */
  1159. X    int
  1160. Xdirname(buf, len)
  1161. X    char    *buf;
  1162. X    int        len;
  1163. X{
  1164. X    return (int)getcwd(buf, len);
  1165. X}
  1166. X
  1167. X/*
  1168. X * get absolute filename into buffer 'buf' of length 'len' bytes
  1169. X */
  1170. X    int
  1171. XFullName(fname, buf, len)
  1172. X    char    *fname, *buf;
  1173. X    int        len;
  1174. X{
  1175. X    /* failed, because we are under MSDOS */
  1176. X    strncpy(buf, fname, len);
  1177. X    return 0;
  1178. X}
  1179. X
  1180. X/*
  1181. X * get file permissions for 'name'
  1182. X * -1 : error
  1183. X * else FA_attributes defined in dos.h
  1184. X */
  1185. X    long
  1186. Xgetperm(name)
  1187. X    char *name;
  1188. X{
  1189. X    int r;
  1190. X
  1191. X    r = _chmod(name, 0, 0);         /* get file mode */
  1192. X    return r;
  1193. X}
  1194. X
  1195. X/*
  1196. X * set file permission for 'name' to 'perm'
  1197. X */
  1198. X    int
  1199. Xsetperm(name, perm)
  1200. X    char    *name;
  1201. X    int        perm;
  1202. X{
  1203. X    perm &= ~FA_ARCH;
  1204. X    return _chmod(name, 1, perm);
  1205. X}
  1206. X
  1207. X/*
  1208. X * check if "name" is a directory
  1209. X */
  1210. X    int
  1211. Xisdir(name)
  1212. X    char *name;
  1213. X{
  1214. X    return (_chmod(name, 0, 0) & FA_DIREC) ? 1 : 0;
  1215. X}
  1216. X
  1217. X/*
  1218. X * Careful: mch_windexit() may be called before mch_windinit()!
  1219. X */
  1220. X    void
  1221. Xmch_windexit(r)
  1222. X    int r;
  1223. X{
  1224. X    settmode(0);
  1225. X    stoptermcap();
  1226. X    flushbuf();
  1227. X    stopscript();                 /* remove autoscript file */
  1228. X    exit(r);
  1229. X}
  1230. X
  1231. X/*
  1232. X * function for ctrl-break interrupt
  1233. X */
  1234. X    void interrupt
  1235. Xcatch_cbrk()
  1236. X{
  1237. X    cbrk_pressed = TRUE;
  1238. X    ctrlc_pressed = TRUE;
  1239. X}
  1240. X
  1241. X/*
  1242. X * ctrl-break handler for DOS. Never called when a ctrl-break is typed, because
  1243. X * we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a
  1244. X * character this function is not called. When a ctrl-C is typed while Vim is
  1245. X * busy this function may be called. By that time a ^C has been displayed on
  1246. X * the screen, so we have to redisplay the screen. We can't do that here,
  1247. X * because we may be called by DOS. The redraw is in GetChars().
  1248. X */
  1249. X    static int
  1250. Xcbrk_handler()
  1251. X{
  1252. X    delayed_redraw = TRUE;
  1253. X    return 1;                 /* resume operation after ctrl-break */
  1254. X}
  1255. X
  1256. X/*
  1257. X * function for critical error interrupt
  1258. X * For DOS 1 and 2 return 0 (Ignore).
  1259. X * For DOS 3 and later return 3 (Fail)
  1260. X */
  1261. X    void interrupt
  1262. Xcatch_cint(bp, di, si, ds, es, dx, cx, bx, ax)
  1263. X    unsigned bp, di, si, ds, es, dx, cx, bx, ax;
  1264. X{
  1265. X    ax = (ax & 0xff00);        /* set AL to 0 */
  1266. X    if (_osmajor >= 3)
  1267. X        ax |= 3;            /* set AL to 3 */
  1268. X}
  1269. X
  1270. X/*
  1271. X * set the tty in (raw) ? "raw" : "cooked" mode
  1272. X *
  1273. X * Does not change the tty, as bioskey() works raw all the time.
  1274. X */
  1275. X
  1276. Xextern void interrupt CINT_FUNC();
  1277. X
  1278. X    void
  1279. Xmch_settmode(raw)
  1280. X    int  raw;
  1281. X{
  1282. X    static int saved_cbrk;
  1283. X    static void interrupt (*old_cint)();
  1284. X    static void interrupt (*old_cbrk)();
  1285. X
  1286. X    if (raw)
  1287. X    {
  1288. X        saved_cbrk = getcbrk();            /* save old ctrl-break setting */
  1289. X        setcbrk(0);                        /* do not check for ctrl-break */
  1290. X        old_cint = getvect(0x24);         /* save old critical error interrupt */
  1291. X        setvect(0x24, catch_cint);        /* install our critical error interrupt */
  1292. X        old_cbrk = getvect(0x1B);         /* save old ctrl-break interrupt */
  1293. X        setvect(0x1B, catch_cbrk);        /* install our ctrl-break interrupt */
  1294. X        ctrlbrk(cbrk_handler);            /* vim's ctrl-break handler */
  1295. X    }
  1296. X    else
  1297. X    {
  1298. X        setcbrk(saved_cbrk);            /* restore ctrl-break setting */
  1299. X        setvect(0x24, old_cint);        /* restore critical error interrupt */
  1300. X        setvect(0x1B, old_cbrk);        /* restore ctrl-break interrupt */
  1301. X        /* restore ctrl-break handler, how ??? */
  1302. X    }
  1303. X}
  1304. X
  1305. X    int
  1306. Xmch_get_winsize()
  1307. X{
  1308. X    struct text_info ti;
  1309. X
  1310. X    debug("mch_get_winsize\n");
  1311. X    if (!term_console)
  1312. X        return 1;
  1313. X    gettextinfo(&ti);
  1314. X    Columns = ti.screenwidth;
  1315. X    Rows = ti.screenheight;
  1316. X    if (Columns < 5 || Columns > MAX_COLUMNS ||
  1317. X                    Rows < 2 || Rows > MAX_COLUMNS)
  1318. X    {
  1319. X        /* these values are not used. overwritten by termcap size or default */
  1320. X        Columns = 80;
  1321. X        Rows = 24;
  1322. X        return 1;
  1323. X    }
  1324. X    return 0;
  1325. X}
  1326. X
  1327. X    void
  1328. Xmch_set_winsize()
  1329. X{
  1330. X    /* should try to set the window size to Rows and Columns */
  1331. X    /* may involve switching display mode.... */
  1332. X}
  1333. X
  1334. X    int
  1335. Xcall_shell(cmd, filter)
  1336. X    char    *cmd;
  1337. X    int     filter;         /* if != 0: called by dofilter() */
  1338. X{
  1339. X    int        x;
  1340. X    char    newcmd[200];
  1341. X
  1342. X    flushbuf();
  1343. X
  1344. X    settmode(0);        /* set to cooked mode */
  1345. X
  1346. X    if (cmd == NULL)
  1347. X        x = system(p_sh);
  1348. X    else
  1349. X    {                     /* we use "command" to start the shell, slow but easy */
  1350. X        sprintf(newcmd, "%s /c %s", p_sh, cmd);
  1351. X        x = system(newcmd);
  1352. X    }
  1353. X    outchar('\n');
  1354. X    settmode(1);        /* set to raw mode */
  1355. X
  1356. X    if (x)
  1357. X    {
  1358. X        smsg("%d returned", x);
  1359. X        outchar('\n');
  1360. X    }
  1361. X
  1362. X    resettitle();
  1363. X    return x;
  1364. X}
  1365. X
  1366. X/*
  1367. X * check for an "interrupt signal": CTRL-break or CTRL-C
  1368. X */
  1369. X    void
  1370. Xbreakcheck()
  1371. X{
  1372. X    if (ctrlc_pressed)
  1373. X    {
  1374. X        ctrlc_pressed = FALSE;
  1375. X        got_int = TRUE;
  1376. X        flush_buffers();        /* remove all typeahead and macro stuff */
  1377. X    }
  1378. X}
  1379. X
  1380. X#ifdef WILD_CARDS
  1381. X#define FL_CHUNK 32
  1382. X
  1383. X    static void
  1384. Xaddfile(fl, f)
  1385. X    FileList    *fl;
  1386. X    char        *f;
  1387. X{
  1388. X    if (!fl->file)
  1389. X    {
  1390. X        fl->file = (char **)alloc(sizeof(char *) * FL_CHUNK);
  1391. X        if (!fl->file)
  1392. X            return;
  1393. X        fl->nfiles = 0;
  1394. X        fl->maxfiles = FL_CHUNK;
  1395. X    }
  1396. X    if (fl->nfiles >= fl->maxfiles)
  1397. X    {
  1398. X        char    **t;
  1399. X        int        i;
  1400. X
  1401. X        t = (char **)alloc(sizeof(char *) * (fl->maxfiles + FL_CHUNK));
  1402. X        if (!t)
  1403. X            return;
  1404. X        for (i = fl->nfiles - 1; i >= 0; i--)
  1405. X            t[i] = fl->file[i];
  1406. X        free(fl->file);
  1407. X        fl->file = t;
  1408. X        fl->maxfiles += FL_CHUNK;
  1409. X    }
  1410. X    fl->file[fl->nfiles++] = f;
  1411. X}
  1412. X
  1413. X    static int
  1414. Xpstrcmp(a, b)
  1415. X    char **a, **b;
  1416. X{
  1417. X    return (strcmp(*a, *b));
  1418. X}
  1419. X
  1420. X    int
  1421. Xhas_wildcard(s)
  1422. X    char *s;
  1423. X{
  1424. X    if (s)
  1425. X        for ( ; *s; ++s)
  1426. X            if (*s == '?' || *s == '*')
  1427. X                return 1;
  1428. X    return 0;
  1429. X}
  1430. X
  1431. X    static void
  1432. Xstrlowcpy(d, s)
  1433. X    char *d, *s;
  1434. X{
  1435. X    while (*s)
  1436. X        *d++ = tolower(*s++);
  1437. X    *d = '\0';
  1438. X}
  1439. X
  1440. X    static int
  1441. Xexpandpath(fl, path, fonly, donly, notf)
  1442. X    FileList    *fl;
  1443. X    char        *path;
  1444. X    int            fonly, donly, notf;
  1445. X{
  1446. X    char    buf[MAXPATH];
  1447. X    char    *p, *s, *e;
  1448. X    int        lastn, c, r;
  1449. X    struct    ffblk fb;
  1450. X
  1451. X    lastn = fl->nfiles;
  1452. X
  1453. X/*
  1454. X * Find the first part in the path name that contains a wildcard.
  1455. X * Copy it into buf, including the preceding characters.
  1456. X */
  1457. X    p = buf;
  1458. X    s = NULL;
  1459. X    e = NULL;
  1460. X    while (*path)
  1461. X    {
  1462. X        if (*path == '\\' || *path == ':' || *path == '/')
  1463. X        {
  1464. X            if (e)
  1465. X                break;
  1466. X            else
  1467. X                s = p;
  1468. X        }
  1469. X        if (*path == '*' || *path == '?')
  1470. X            e = p;
  1471. X        *p++ = *path++;
  1472. X    }
  1473. X    e = p;
  1474. X    if (s)
  1475. X        s++;
  1476. X    else
  1477. X        s = buf;
  1478. X
  1479. X    /* now we have one wildcard component between s and e */
  1480. X    *e = '\0';
  1481. X    r = 0;
  1482. X    if ((c = findfirst(buf, &fb, *path ? FA_DIREC : 0)) != 0)
  1483. X    {
  1484. X        /* not found */
  1485. X        strcpy(e, path);
  1486. X        if (notf)
  1487. X            addfile(fl, strsave(buf));
  1488. X        return 1; /* unexpanded or empty */
  1489. X    }
  1490. X    while (!c)
  1491. X    {
  1492. X        strlowcpy(s, fb.ff_name);
  1493. X        if (*s != '.' || (s[1] != '\0' && (s[1] != '.' || s[2] != '\0')))
  1494. X        {
  1495. X            strcat(buf, path);
  1496. X            if (!has_wildcard(path))
  1497. X                addfile(fl, strsave(buf));
  1498. X            else
  1499. X                r |= expandpath(fl, buf, fonly, donly, notf);
  1500. X        }
  1501. X        c = findnext(&fb);
  1502. X    }
  1503. X    qsort(fl->file + lastn, fl->nfiles - lastn, sizeof(char *), pstrcmp);
  1504. X    return r;
  1505. X}
  1506. X
  1507. X/*
  1508. X * MSDOS rebuilt of Scott Ballantynes ExpandWildCard for amiga/arp.
  1509. X * jw
  1510. X */
  1511. X
  1512. X    int
  1513. XExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  1514. X    int     num_pat;
  1515. X    char    **pat;
  1516. X    int     *num_file;
  1517. X    char    ***file;
  1518. X    int     files_only, list_notfound;
  1519. X{
  1520. X    int            i, r = 0;
  1521. X    FileList    f;
  1522. X
  1523. X    f.file = NULL;
  1524. X    f.nfiles = 0;
  1525. X    for (i = 0; i < num_pat; i++)
  1526. X    {
  1527. X        if (!has_wildcard(pat[i]))
  1528. X            addfile(&f, strsave(pat[i]));
  1529. X        else
  1530. X            r |= expandpath(&f, pat[i], files_only, 0, list_notfound);
  1531. X    }
  1532. X    if (r == 0)
  1533. X    {
  1534. X        *num_file = f.nfiles;
  1535. X        *file = f.file;
  1536. X    }
  1537. X    return r;
  1538. X}
  1539. X
  1540. X    void
  1541. XFreeWild(num, file)
  1542. X    int        num;
  1543. X    char    **file;
  1544. X{
  1545. X    if (file == NULL || num <= 0)
  1546. X        return;
  1547. X    while (num--)
  1548. X        free(file[num]);
  1549. X    free(file);
  1550. X}
  1551. X#endif /* WILD_CARDS */
  1552. END_OF_FILE
  1553. if test 13589 -ne `wc -c <'vim/src/msdos.c'`; then
  1554.     echo shar: \"'vim/src/msdos.c'\" unpacked with wrong size!
  1555. fi
  1556. # end of 'vim/src/msdos.c'
  1557. fi
  1558. if test -f 'vim/src/undo.c' -a "${1}" != "-c" ; then 
  1559.   echo shar: Will not clobber existing file \"'vim/src/undo.c'\"
  1560. else
  1561. echo shar: Extracting \"'vim/src/undo.c'\" \(13273 characters\)
  1562. sed "s/^X//" >'vim/src/undo.c' <<'END_OF_FILE'
  1563. X/* vi:ts=4:sw=4
  1564. X *
  1565. X * VIM - Vi IMitation
  1566. X *
  1567. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  1568. X *                            Tim Thompson            twitch!tjt
  1569. X *                            Tony Andrews            onecom!wldrdg!tony 
  1570. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  1571. X */
  1572. X
  1573. X/*
  1574. X * undo.c: multi level undo facility
  1575. X *
  1576. X * The saved lines are stored in a list of lists:
  1577. X *
  1578. X * u_oldhead----------------------------------------------+
  1579. X *                                                        |
  1580. X *                                                        V
  1581. X *              +--------------+    +--------------+    +--------------+
  1582. X * u_newhead--->| u_header     |    | u_header     |    | u_header     |
  1583. X *              |     uh_next------>|     uh_next------>|     uh_next---->NULL
  1584. X *       NULL<--------uh_prev  |<---------uh_prev  |<---------uh_prev  |
  1585. X *              |     uh_entry |    |     uh_entry |    |     uh_entry |
  1586. X *              +--------|-----+    +--------|-----+    +--------|-----+
  1587. X *                       |                   |                   |
  1588. X *                       V                   V                   V
  1589. X *              +--------------+    +--------------+    +--------------+
  1590. X *              | u_entry      |    | u_entry      |    | u_entry      |
  1591. X *              |     ue_next  |    |     ue_next  |    |     ue_next  |
  1592. X *              +--------|-----+    +--------|-----+    +--------|-----+
  1593. X *                       |                   |                   |
  1594. X *                       V                   V                   V
  1595. X *              +--------------+            NULL                NULL
  1596. X *              | u_entry      |
  1597. X *              |     ue_next  |
  1598. X *              +--------|-----+
  1599. X *                       |
  1600. X *                       V
  1601. X *                      etc.
  1602. X *
  1603. X * Each u_entry list contains the information for one undo or redo.
  1604. X * u_curhead points to the header of the last undo (the next redo), or is
  1605. X * NULL if nothing has been undone.
  1606. X *
  1607. X * All data is allocated with alloc_line(), thus it will be freed as soon as
  1608. X * we switch files!
  1609. X */
  1610. X
  1611. X#include "vim.h"
  1612. X#include "globals.h"
  1613. X#include "proto.h"
  1614. X#include "param.h"
  1615. X#include "ops.h"        /* for endop and startop */
  1616. X
  1617. Xstruct u_entry
  1618. X{
  1619. X    struct u_entry    *ue_next;    /* pointer to next entry in list */
  1620. X    linenr_t        ue_top;        /* number of line above undo block */
  1621. X    linenr_t        ue_bot;        /* number of line below undo block */
  1622. X    char            *ue_botptr;    /* pointer to line below undo block */
  1623. X    char            **ue_array;    /* array of lines in undo block */
  1624. X    long            ue_size;    /* number of lines in ue_array */
  1625. X};
  1626. X
  1627. Xstruct u_header
  1628. X{
  1629. X    struct u_header    *uh_next;    /* pointer to next header in list */
  1630. X    struct u_header    *uh_prev;    /* pointer to previous header in list */
  1631. X    struct u_entry    *uh_entry;    /* pointer to first entry */
  1632. X    FPOS             uh_curpos;    /* cursor position before saving */
  1633. X};
  1634. X
  1635. Xstatic struct u_header *u_oldhead = NULL;    /* pointer to oldest header */
  1636. Xstatic struct u_header *u_newhead = NULL;    /* pointer to newest header */
  1637. Xstatic struct u_header *u_curhead = NULL;    /* pointer to current header */
  1638. Xstatic int                u_numhead = 0;        /* current number of headers */
  1639. Xstatic int                u_synced = TRUE;    /* entry lists are synced */
  1640. X
  1641. X/*
  1642. X * variables for "U" command
  1643. X */
  1644. Xstatic char       *u_line_ptr = NULL;        /* saved line for "U" command */
  1645. Xstatic linenr_t u_line_lnum;            /* line number of line in u_line */
  1646. Xstatic colnr_t    u_line_colnr;            /* optional column number */
  1647. X
  1648. Xstatic void u_getbot __ARGS((void));
  1649. Xstatic int u_savecommon __ARGS((linenr_t, linenr_t, int, char *));
  1650. Xstatic void u_undoredo __ARGS((void));
  1651. Xstatic void u_freelist __ARGS((struct u_header *));
  1652. Xstatic void u_freeentry __ARGS((struct u_entry *, long));
  1653. X
  1654. X/*
  1655. X * save the current line for both the "u" and "U" command
  1656. X */
  1657. X    int
  1658. Xu_saveCurpos()
  1659. X{
  1660. X    return (u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + 1)));
  1661. X}
  1662. X
  1663. X/*
  1664. X * Save the lines between "top" and "bot" for both the "u" and "U" command.
  1665. X * "top" may be 0 and bot may be line_count + 1.
  1666. X * Returns FALSE when lines could not be saved.
  1667. X */
  1668. X    int
  1669. Xu_save(top, bot)
  1670. X    linenr_t top, bot;
  1671. X{
  1672. X    if (top > line_count || top >= bot || bot > line_count + 1)
  1673. X        return FALSE;    /* rely on caller to do error messages */
  1674. X
  1675. X    if (top + 2 == bot)
  1676. X        u_saveline((linenr_t)(top + 1));
  1677. X
  1678. X    return (u_savecommon(top, bot, 0, (char *)0));
  1679. X}
  1680. X
  1681. X/*
  1682. X * save the line "lnum", pointed at by "ptr" (used by :g//s commands)
  1683. X * "ptr" is handed over to the undo routines
  1684. X */
  1685. X    int
  1686. Xu_savesub(lnum, ptr)
  1687. X    linenr_t    lnum;
  1688. X    char        *ptr;
  1689. X{
  1690. X    return (u_savecommon(lnum - 1, lnum + 1, 1, ptr));
  1691. X}
  1692. X
  1693. X/*
  1694. X * save the line "lnum", pointed at by "ptr" (used by :g//d commands)
  1695. X * "ptr" is handed over to the undo routines
  1696. X */
  1697. X    int
  1698. Xu_savedel(lnum, ptr)
  1699. X    linenr_t    lnum;
  1700. X    char        *ptr;
  1701. X{
  1702. X    return (u_savecommon(lnum - 1, lnum, 1, ptr));
  1703. X}
  1704. X
  1705. X    static int 
  1706. Xu_savecommon(top, bot, flag, ptr)
  1707. X    linenr_t top, bot;
  1708. X    int flag;
  1709. X    char *ptr;
  1710. X{
  1711. X    linenr_t        lnum;
  1712. X    long            i;
  1713. X    struct u_header *uhp;
  1714. X    struct u_entry    *uep;
  1715. X    long            size;
  1716. X
  1717. X    /*
  1718. X     * if u_synced == TRUE make a new header
  1719. X     */
  1720. X    if (u_synced)
  1721. X    {
  1722. X        /*
  1723. X         * if we undid more than we redid, free the entry lists before and
  1724. X         * including u_curhead
  1725. X         */
  1726. X        while (u_curhead != NULL)
  1727. X            u_freelist(u_newhead);
  1728. X
  1729. X        /*
  1730. X         * free headers to keep the size right
  1731. X         */
  1732. X        while (u_numhead > p_ul && u_oldhead != NULL)
  1733. X            u_freelist(u_oldhead);
  1734. X
  1735. X        /*
  1736. X         * make a new header entry
  1737. X         */
  1738. X        uhp = (struct u_header *)alloc_line((unsigned)sizeof(struct u_header));
  1739. X        if (uhp == NULL)
  1740. X            goto nomem;
  1741. X        uhp->uh_prev = NULL;
  1742. X        uhp->uh_next = u_newhead;
  1743. X        if (u_newhead != NULL)
  1744. X            u_newhead->uh_prev = uhp;
  1745. X        uhp->uh_entry = NULL;
  1746. X        uhp->uh_curpos = Curpos;    /* save cursor position for undo */
  1747. X        u_newhead = uhp;
  1748. X        if (u_oldhead == NULL)
  1749. X            u_oldhead = uhp;
  1750. X        ++u_numhead;
  1751. X    }
  1752. X    else    /* find line number for ue_botptr for previous u_save() */
  1753. X        u_getbot();
  1754. X
  1755. X    /*
  1756. X     * add lines in front of entry list
  1757. X     */
  1758. X    uep = (struct u_entry *)alloc_line((unsigned)sizeof(struct u_entry));
  1759. X    if (uep == NULL)
  1760. X        goto nomem;
  1761. X
  1762. X    if (flag)
  1763. X        size = 1;
  1764. X    else
  1765. X        size = bot - top - 1;
  1766. X    uep->ue_size = size;
  1767. X    uep->ue_top = top;
  1768. X    uep->ue_botptr = NULL;
  1769. X    if (flag)
  1770. X        uep->ue_bot = bot;
  1771. X        /*
  1772. X         * use 0 for ue_bot if bot is below last line or if the buffer is empty, in
  1773. X         * which case the last line may be replaced (e.g. with 'O' command).
  1774. X         */
  1775. X    else if (bot > line_count || bufempty())
  1776. X        uep->ue_bot = 0;
  1777. X    else
  1778. X        uep->ue_botptr = nr2ptr(bot);    /* we have to do ptr2nr(ue_botptr) later */
  1779. X
  1780. X    if (size)
  1781. X    {
  1782. X        if ((uep->ue_array = (char **)alloc_line((unsigned)(sizeof(char *) * size))) == NULL)
  1783. X        {
  1784. X            u_freeentry(uep, 0L);
  1785. X            goto nomem;
  1786. X        }
  1787. X        if (flag)
  1788. X            uep->ue_array[0] = ptr;
  1789. X        else
  1790. X            for (i = 0, lnum = top + 1; i < size; ++i)
  1791. X                if ((uep->ue_array[i] = save_line(nr2ptr(lnum++))) == NULL)
  1792. X                {
  1793. X                    u_freeentry(uep, i);
  1794. X                    goto nomem;
  1795. X                }
  1796. X    }
  1797. X    uep->ue_next = u_newhead->uh_entry;
  1798. X    u_newhead->uh_entry = uep;
  1799. X    u_synced = FALSE;
  1800. X    return TRUE;
  1801. X
  1802. Xnomem:
  1803. X    if (flag)
  1804. X        free_line(ptr);
  1805. X    else if (ask_yesno("no undo possible; continue anyway") == 'y')
  1806. X        return TRUE;
  1807. X    return FALSE;
  1808. X}
  1809. X
  1810. X    void
  1811. Xu_undo(count)
  1812. X    int count;
  1813. X{
  1814. X    startop.lnum = 0;                /* unset '[ mark */
  1815. X    endop.lnum = 0;                /* unset '] mark */
  1816. X    while (count--)
  1817. X    {
  1818. X        if (u_curhead == NULL)                        /* first undo */
  1819. X            u_curhead = u_newhead;
  1820. X        else if (p_ul != 0)                        /* multi level undo */
  1821. X            u_curhead = u_curhead->uh_next;            /* get next undo */
  1822. X
  1823. X        if (u_numhead == 0 || u_curhead == NULL)    /* nothing to undo */
  1824. X        {
  1825. X            u_curhead = u_oldhead;                    /* stick u_curhead at end */
  1826. X            beep();
  1827. X            return;
  1828. X        }
  1829. X
  1830. X        u_undoredo();
  1831. X    }
  1832. X}
  1833. X
  1834. X    void
  1835. Xu_redo(count)
  1836. X    int count;
  1837. X{
  1838. X    while (count--)
  1839. X    {
  1840. X        if (u_curhead == NULL || p_ul == 0)        /* nothing to redo */
  1841. X        {
  1842. X            beep();
  1843. X            return;
  1844. X        }
  1845. X
  1846. X        u_undoredo();
  1847. X
  1848. X        u_curhead = u_curhead->uh_prev;            /* advance for next redo */
  1849. X    }
  1850. X}
  1851. X
  1852. X/*
  1853. X * u_undoredo: common code for undo and redo
  1854. X *
  1855. X * The lines in the file are replaced by the lines in the entry list at u_curhead.
  1856. X * The replaced lines in the file are saved in the entry list for the next undo/redo.
  1857. X */
  1858. X    static void
  1859. Xu_undoredo()
  1860. X{
  1861. X    char        **newarray = NULL;
  1862. X    linenr_t    oldsize;
  1863. X    linenr_t    newsize;
  1864. X    linenr_t    top, bot;
  1865. X    linenr_t    lnum = 0;
  1866. X    linenr_t    newlnum = INVLNUM;
  1867. X    long        i;
  1868. X    long        newcount = 0, oldcount = 0;
  1869. X    struct u_entry *uep, *nuep;
  1870. X    struct u_entry *newlist = NULL;
  1871. X
  1872. X    if (u_synced == FALSE)
  1873. X    {
  1874. X        emsg("undo not synced");
  1875. X        return;
  1876. X    }
  1877. X
  1878. X    CHANGED;
  1879. X    for (uep = u_curhead->uh_entry; uep != NULL; uep = nuep)
  1880. X    {
  1881. X            top = uep->ue_top;
  1882. X            bot = uep->ue_bot;
  1883. X            if (bot == 0)
  1884. X                bot = line_count + 1;
  1885. X            if (top > line_count || top >= bot)
  1886. X            {
  1887. X                emsg("u_undo: line numbers wrong");
  1888. X                return;
  1889. X            }
  1890. X
  1891. X            if (top < newlnum)
  1892. X            {
  1893. X                newlnum = top;
  1894. X                Curpos.lnum = top + 1;
  1895. X            }
  1896. X            oldsize = bot - top - 1;    /* number of lines before undo */
  1897. X
  1898. X            newsize = uep->ue_size;        /* number of lines after undo */
  1899. X
  1900. X            /* delete the lines between top and bot and save them in newarray */
  1901. X            if (oldsize)
  1902. X            {
  1903. X                if ((newarray = (char **)alloc_line((unsigned)(sizeof(char *) * oldsize))) == NULL)
  1904. X                {
  1905. X                    /*
  1906. X                     * We have messed up the entry list, repair is impossible.
  1907. X                     * we have to free the rest of the list.
  1908. X                     */
  1909. X                    while (uep != NULL)
  1910. X                    {
  1911. X                        nuep = uep->ue_next;
  1912. X                        u_freeentry(uep, uep->ue_size);
  1913. X                        uep = nuep;
  1914. X                    }
  1915. X                    break;
  1916. X                }
  1917. X                /* delete backwards, it goes faster in some cases */
  1918. X                for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum)
  1919. X                    newarray[i] = delsline(lnum, TRUE);
  1920. X            }
  1921. X            /* insert the lines in u_array between top and bot */
  1922. X            if (newsize)
  1923. X            {
  1924. X                for (lnum = top, i = 0; i < newsize; ++i, ++lnum)
  1925. X                    appendline(lnum, uep->ue_array[i]);
  1926. X                free_line((char *)uep->ue_array);
  1927. X            }
  1928. X            newcount += newsize;
  1929. X            oldcount += oldsize;
  1930. X            uep->ue_size = oldsize;
  1931. X            uep->ue_array = newarray;
  1932. X            uep->ue_bot = lnum + 1;
  1933. X
  1934. X            /*
  1935. X             * insert this entry in front of the new entry list
  1936. X             */
  1937. X            nuep = uep->ue_next;
  1938. X            uep->ue_next = newlist;
  1939. X            newlist = uep;
  1940. X    }
  1941. X
  1942. X    u_curhead->uh_entry = newlist;
  1943. X
  1944. X    /*
  1945. X     * If we deleted or added lines, report the number of less/more lines.
  1946. X     * Otherwise, report the number of changed lines (this may be incorrect
  1947. X     * in some cases, but it's better than nothing).
  1948. X     */
  1949. X    if ((oldcount -= newcount) != 0)
  1950. X        msgmore(-oldcount);
  1951. X    else if (newcount > p_report)
  1952. X        smsg("%ld line%s changed", newcount, plural(newcount));
  1953. X
  1954. X    if (u_curhead->uh_curpos.lnum == Curpos.lnum)
  1955. X        Curpos.col = u_curhead->uh_curpos.col;
  1956. X    else
  1957. X        Curpos.col = 0;
  1958. X    updateScreen(CURSUPD);
  1959. X}
  1960. X
  1961. X/*
  1962. X * u_sync: stop adding to the current entry list
  1963. X */
  1964. X    void
  1965. Xu_sync()
  1966. X{
  1967. X    if (u_synced)
  1968. X        return;                /* already synced */
  1969. X    u_getbot();                /* compute ue_bot of previous u_undo */
  1970. X    u_curhead = NULL;
  1971. X}
  1972. X
  1973. X/*
  1974. X * u_getbot(): compute the line number of the previous u_undo
  1975. X */
  1976. X    static void
  1977. Xu_getbot()
  1978. X{
  1979. X    register struct u_entry *uep;
  1980. X
  1981. X    if (u_newhead == NULL || (uep = u_newhead->uh_entry) == NULL)
  1982. X    {
  1983. X        emsg("undo list corrupt");
  1984. X        return;
  1985. X    }
  1986. X
  1987. X    if (uep->ue_botptr != NULL)
  1988. X        if ((uep->ue_bot = ptr2nr(uep->ue_botptr, uep->ue_top)) == 0)
  1989. X        {
  1990. X            emsg("undo line missing");
  1991. X            uep->ue_bot = uep->ue_top + 1;    /* guess what it is */
  1992. X        }
  1993. X
  1994. X    u_synced = TRUE;
  1995. X}
  1996. X
  1997. X/*
  1998. X * u_freelist: free one entry list and adjust the pointers
  1999. X */
  2000. X    static void
  2001. Xu_freelist(uhp)
  2002. X    struct u_header *uhp;
  2003. X{
  2004. X    register struct u_entry *uep, *nuep;
  2005. X
  2006. X    for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
  2007. X    {
  2008. X        nuep = uep->ue_next;
  2009. X        u_freeentry(uep, uep->ue_size);
  2010. X    }
  2011. X
  2012. X    if (u_curhead == uhp)
  2013. X        u_curhead = NULL;
  2014. X
  2015. X    if (uhp->uh_next == NULL)
  2016. X        u_oldhead = uhp->uh_prev;
  2017. X    else
  2018. X        uhp->uh_next->uh_prev = uhp->uh_prev;
  2019. X
  2020. X    if (uhp->uh_prev == NULL)
  2021. X        u_newhead = uhp->uh_next;
  2022. X    else
  2023. X        uhp->uh_prev->uh_next = uhp->uh_next;
  2024. X
  2025. X    free_line((char *)uhp);
  2026. X    --u_numhead;
  2027. X}
  2028. X
  2029. X/*
  2030. X * free entry 'uep' and 'n' lines in uep->ue_array[]
  2031. X */
  2032. X    static void
  2033. Xu_freeentry(uep, n)
  2034. X    struct u_entry *uep;
  2035. X    register long n;
  2036. X{
  2037. X    while (n)
  2038. X        free_line(uep->ue_array[--n]);
  2039. X    free_line((char *)uep);
  2040. X}
  2041. X
  2042. X/*
  2043. X * invalidate the undo buffer; called when storage has already been released
  2044. X */
  2045. X
  2046. X    void
  2047. Xu_clearall()
  2048. X{
  2049. X    u_newhead = u_oldhead = u_curhead = NULL;
  2050. X    u_synced = TRUE;
  2051. X    u_numhead = 0;
  2052. X    u_line_ptr = NULL;
  2053. X    u_line_lnum = 0;
  2054. X}
  2055. X
  2056. X/*
  2057. X * save the line "lnum" for the "U" command
  2058. X */
  2059. X    void
  2060. Xu_saveline(lnum)
  2061. X    linenr_t lnum;
  2062. X{
  2063. X    if (lnum == u_line_lnum)        /* line is already saved */
  2064. X        return;
  2065. X    if (lnum < 1 || lnum > line_count)    /* should never happen */
  2066. X        return;
  2067. X    u_clearline();
  2068. X    u_line_lnum = lnum;
  2069. X    if (Curpos.lnum == lnum)
  2070. X        u_line_colnr = Curpos.col;
  2071. X    else
  2072. X        u_line_colnr = 0;
  2073. X    u_line_ptr = save_line(nr2ptr(lnum));    /* when out of mem alloc() will give a warning */
  2074. X}
  2075. X
  2076. X/*
  2077. X * clear the line saved for the "U" command
  2078. X * (this is used externally for crossing a line while in insert mode)
  2079. X */
  2080. X    void
  2081. Xu_clearline()
  2082. X{
  2083. X    if (u_line_ptr != NULL)
  2084. X    {
  2085. X        free_line(u_line_ptr);
  2086. X        u_line_ptr = NULL;
  2087. X        u_line_lnum = 0;
  2088. X    }
  2089. X}
  2090. X
  2091. X/*
  2092. X * Implementation of the "U" command.
  2093. X * Differentiation from vi: "U" can be undone with the next "U".
  2094. X * We also allow the cursor to be in another line.
  2095. X */
  2096. X    void
  2097. Xu_undoline()
  2098. X{
  2099. X    colnr_t t;
  2100. X
  2101. X    if (u_line_ptr == NULL || u_line_lnum > line_count)
  2102. X    {
  2103. X        beep();
  2104. X        return;
  2105. X    }
  2106. X        /* first save the line for the 'u' command */
  2107. X    u_savecommon(u_line_lnum - 1, u_line_lnum + 1, 0, (char *)0);
  2108. X    u_line_ptr = replaceline(u_line_lnum, u_line_ptr);
  2109. X
  2110. X    t = u_line_colnr;
  2111. X    if (Curpos.lnum == u_line_lnum)
  2112. X        u_line_colnr = Curpos.col;
  2113. X    Curpos.col = t;
  2114. X    Curpos.lnum = u_line_lnum;
  2115. X    cursupdate();
  2116. X    updateScreen(VALID_TO_CURSCHAR);
  2117. X}
  2118. END_OF_FILE
  2119. if test 13273 -ne `wc -c <'vim/src/undo.c'`; then
  2120.     echo shar: \"'vim/src/undo.c'\" unpacked with wrong size!
  2121. fi
  2122. # end of 'vim/src/undo.c'
  2123. fi
  2124. echo shar: End of archive 6 \(of 23\).
  2125. cp /dev/null ark6isdone
  2126. MISSING=""
  2127. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  2128.     if test ! -f ark${I}isdone ; then
  2129.     MISSING="${MISSING} ${I}"
  2130.     fi
  2131. done
  2132. if test "${MISSING}" = "" ; then
  2133.     echo You have unpacked all 23 archives.
  2134.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2135. else
  2136.     echo You still need to unpack the following archives:
  2137.     echo "        " ${MISSING}
  2138. fi
  2139. ##  End of shell archive.
  2140. exit 0
  2141. -------------8<----------------8<----------------8<---------------8<--------
  2142. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  2143. Oce Nederland B.V., Research & Development | necessarily represent the position
  2144. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  2145. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  2146. UUCP: mool@oce.nl        fax +31 77 595450 | whatever will be accepted.
  2147.  
  2148. exit 0 # Just in case...
  2149.