home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / vim / part18 < prev    next >
Encoding:
Internet Message Format  |  1994-08-18  |  68.8 KB

  1. From: mool@oce.nl (Bram Moolenaar)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i037:  vim - Vi IMproved editor, v3.0, Part18/26
  4. Date: 18 Aug 1994 14:03:07 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <330b9b$e6c@sparky.sterling.com>
  9. X-Md4-Signature: 6253b2430ecefae3017729cc92c0314a
  10.  
  11. Submitted-by: mool@oce.nl (Bram Moolenaar)
  12. Posting-number: Volume 44, Issue 37
  13. Archive-name: vim/part18
  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/search.c vim/src/unix.c vim/tools/readme
  22. #   vim/uganda.txt
  23. # Wrapped by kent@sparky on Mon Aug 15 21:44:10 1994
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 18 (of 26)."'
  27. if test -f 'vim/src/search.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'vim/src/search.c'\"
  29. else
  30.   echo shar: Extracting \"'vim/src/search.c'\" \(30917 characters\)
  31.   sed "s/^X//" >'vim/src/search.c' <<'END_OF_FILE'
  32. X/* vi:ts=4:sw=4
  33. X *
  34. X * VIM - Vi IMproved        by Bram Moolenaar
  35. X *
  36. X * Read the file "credits.txt" for a list of people who contributed.
  37. X * Read the file "uganda.txt" for copying and usage conditions.
  38. X */
  39. X/*
  40. X * search.c: code for normal mode searching commands
  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 "ops.h"        /* for mincl */
  48. X
  49. X/* modified Henry Spencer's regular expression routines */
  50. X#include "regexp.h"
  51. X
  52. Xstatic int inmacro __ARGS((char_u *, char_u *));
  53. Xstatic int cls __ARGS((void));
  54. X
  55. Xstatic char_u *top_bot_msg = (char_u *)"search hit TOP, continuing at BOTTOM";
  56. Xstatic char_u *bot_top_msg = (char_u *)"search hit BOTTOM, continuing at TOP";
  57. X
  58. X/*
  59. X * This file contains various searching-related routines. These fall into
  60. X * three groups:
  61. X * 1. string searches (for /, ?, n, and N)
  62. X * 2. character searches within a single line (for f, F, t, T, etc)
  63. X * 3. "other" kinds of searches like the '%' command, and 'word' searches.
  64. X */
  65. X
  66. X/*
  67. X * String searches
  68. X *
  69. X * The string search functions are divided into two levels:
  70. X * lowest:    searchit(); called by dosearch() and edit().
  71. X * Highest: dosearch(); changes curwin->w_cursor, called by normal().
  72. X *
  73. X * The last search pattern is remembered for repeating the same search.
  74. X * This pattern is shared between the :g, :s, ? and / commands.
  75. X * This is in myregcomp().
  76. X *
  77. X * The actual string matching is done using a heavily modified version of
  78. X * Henry Spencer's regular expression library.
  79. X */
  80. X
  81. X/*
  82. X * Two search patterns are remembered: One for the :substitute command and
  83. X * one for other searches. last_pattern points to the one that was
  84. X * used the last time.
  85. X */
  86. Xstatic char_u     *search_pattern = NULL;
  87. Xstatic char_u     *subst_pattern = NULL;
  88. Xstatic char_u     *last_pattern = NULL;
  89. X
  90. Xstatic int        want_start;                /* looking for start of line? */
  91. X
  92. X/*
  93. X * translate search pattern for regcomp()
  94. X *
  95. X * sub_cmd == 0: save pat in search_pattern (normal search command)
  96. X * sub_cmd == 1: save pat in subst_pattern (:substitute command)
  97. X * sub_cmd == 2: save pat in both patterns (:global command)
  98. X * which_pat == 0: use previous search pattern if "pat" is NULL
  99. X * which_pat == 1: use previous sustitute pattern if "pat" is NULL
  100. X * which_pat == 2: use last used pattern if "pat" is NULL
  101. X * 
  102. X */
  103. X    regexp *
  104. Xmyregcomp(pat, sub_cmd, which_pat)
  105. X    char_u    *pat;
  106. X    int        sub_cmd;
  107. X    int        which_pat;
  108. X{
  109. X    regexp *retval;
  110. X
  111. X    if (pat == NULL || *pat == NUL)     /* use previous search pattern */
  112. X    {
  113. X        if (which_pat == 0)
  114. X        {
  115. X            if (search_pattern == NULL)
  116. X            {
  117. X                emsg(e_noprevre);
  118. X                return (regexp *) NULL;
  119. X            }
  120. X            pat = search_pattern;
  121. X        }
  122. X        else if (which_pat == 1)
  123. X        {
  124. X            if (subst_pattern == NULL)
  125. X            {
  126. X                emsg(e_nopresub);
  127. X                return (regexp *) NULL;
  128. X            }
  129. X            pat = subst_pattern;
  130. X        }
  131. X        else    /* which_pat == 2 */
  132. X        {
  133. X            if (last_pattern == NULL)
  134. X            {
  135. X                emsg(e_noprevre);
  136. X                return (regexp *) NULL;
  137. X            }
  138. X            pat = last_pattern;
  139. X        }
  140. X    }
  141. X
  142. X    /*
  143. X     * save the currently used pattern in the appropriate place,
  144. X     * unless the pattern should not be remembered
  145. X     */
  146. X    if (!keep_old_search_pattern)
  147. X    {
  148. X        if (sub_cmd == 0 || sub_cmd == 2)    /* search or global command */
  149. X        {
  150. X            if (search_pattern != pat)
  151. X            {
  152. X                free(search_pattern);
  153. X                search_pattern = strsave(pat);
  154. X                last_pattern = search_pattern;
  155. X                reg_magic = p_magic;        /* Magic sticks with the r.e. */
  156. X            }
  157. X        }
  158. X        if (sub_cmd == 1 || sub_cmd == 2)    /* substitute or global command */
  159. X        {
  160. X            if (subst_pattern != pat)
  161. X            {
  162. X                free(subst_pattern);
  163. X                subst_pattern = strsave(pat);
  164. X                last_pattern = subst_pattern;
  165. X                reg_magic = p_magic;        /* Magic sticks with the r.e. */
  166. X            }
  167. X        }
  168. X    }
  169. X
  170. X    want_start = (*pat == '^');        /* looking for start of line? */
  171. X    reg_ic = p_ic;                    /* tell the regexec routine how to search */
  172. X    retval = regcomp(pat);
  173. X    return retval;
  174. X}
  175. X
  176. X/*
  177. X * lowest level search function.
  178. X * Search for 'count'th occurrence of 'str' in direction 'dir'.
  179. X * Start at position 'pos' and return the found position in 'pos'.
  180. X * Return OK for success, FAIL for failure.
  181. X */
  182. X    int
  183. Xsearchit(pos, dir, str, count, end, message)
  184. X    FPOS    *pos;
  185. X    int     dir;
  186. X    char_u    *str;
  187. X    long    count;
  188. X    int        end;
  189. X    int        message;
  190. X{
  191. X    int                 found;
  192. X    linenr_t            lnum = 0;            /* init to shut up gcc */
  193. X    linenr_t            startlnum;
  194. X    regexp                *prog;
  195. X    register char_u        *s;
  196. X    char_u                *ptr;
  197. X    register int        i;
  198. X    register char_u        *match, *matchend;
  199. X    int                 loop;
  200. X
  201. X    if ((prog = myregcomp(str, 0, 2)) == NULL)
  202. X    {
  203. X        if (message)
  204. X            emsg(e_invstring);
  205. X        return FAIL;
  206. X    }
  207. X/*
  208. X * find the string
  209. X */
  210. X    found = 1;
  211. X    while (count-- && found)    /* stop after count matches, or no more matches */
  212. X    {
  213. X        startlnum = pos->lnum;    /* remember start of search for detecting no match */
  214. X        found = 0;                /* default: not found */
  215. X
  216. X        i = pos->col + dir;     /* search starts one postition away */
  217. X        lnum = pos->lnum;
  218. X
  219. X        if (dir == BACKWARD && i < 0)
  220. X            --lnum;
  221. X
  222. X        for (loop = 0; loop != 2; ++loop)   /* do this twice if 'wrapscan' is set */
  223. X        {
  224. X            for ( ; lnum > 0 && lnum <= curbuf->b_ml.ml_line_count; lnum += dir, i = -1)
  225. X            {
  226. X                s = ptr = ml_get(lnum);
  227. X                if (dir == FORWARD && i > 0)    /* first line for forward search */
  228. X                {
  229. X                    if (want_start || STRLEN(s) <= (size_t)i)   /* match not possible */
  230. X                        continue;
  231. X                    s += i;
  232. X                }
  233. X
  234. X                if (regexec(prog, s, dir == BACKWARD || i <= 0))
  235. X                {                            /* match somewhere on line */
  236. X                    match = prog->startp[0];
  237. X                    matchend = prog->endp[0];
  238. X                    if (dir == BACKWARD && !want_start)
  239. X                    {
  240. X                        /*
  241. X                         * Now, if there are multiple matches on this line,
  242. X                         * we have to get the last one. Or the last one before
  243. X                         * the cursor, if we're on that line.
  244. X                         */
  245. X                        while (*match != NUL && regexec(prog, match + 1, (int)FALSE))
  246. X                        {
  247. X                            if ((i >= 0) && ((prog->startp[0] - s) > i))
  248. X                                break;
  249. X                            match = prog->startp[0];
  250. X                            matchend = prog->endp[0];
  251. X                        }
  252. X
  253. X                        if ((i >= 0) && ((match - s) > i))
  254. X                            continue;
  255. X                    }
  256. X
  257. X                    pos->lnum = lnum;
  258. X                    if (end)
  259. X                        pos->col = (int) (matchend - ptr - 1);
  260. X                    else
  261. X                        pos->col = (int) (match - ptr);
  262. X                    found = 1;
  263. X                    break;
  264. X                }
  265. X                /* breakcheck is slow, do it only once in 16 lines */
  266. X                if ((lnum & 15) == 0)
  267. X                    breakcheck();       /* stop if ctrl-C typed */
  268. X                if (got_int)
  269. X                    break;
  270. X
  271. X                if (loop && lnum == startlnum)  /* if second loop stop where started */
  272. X                    break;
  273. X            }
  274. X    /* stop the search if wrapscan isn't set, after an interrupt and after a match */
  275. X            if (!p_ws || got_int || found)
  276. X                break;
  277. X
  278. X            /*
  279. X             * If 'wrapscan' is set we continue at the other end of the file.
  280. X             * If 'terse' is not set, we give a message.
  281. X             * This message is also remembered in keep_msg for when the screen
  282. X             * is redrawn. The keep_msg is cleared whenever another message is
  283. X             * written.
  284. X             */
  285. X            if (dir == BACKWARD)    /* start second loop at the other end */
  286. X            {
  287. X                lnum = curbuf->b_ml.ml_line_count;
  288. X                if (!p_terse && message)
  289. X                {
  290. X                    msg(top_bot_msg);
  291. X                    keep_msg = top_bot_msg;
  292. X                }
  293. X            }
  294. X            else
  295. X            {
  296. X                lnum = 1;
  297. X                if (!p_terse && message)
  298. X                {
  299. X                    msg(bot_top_msg);
  300. X                    keep_msg = bot_top_msg;
  301. X                }
  302. X            }
  303. X        }
  304. X        if (got_int)
  305. X            break;
  306. X    }
  307. X
  308. X    free(prog);
  309. X
  310. X    if (!found)             /* did not find it */
  311. X    {
  312. X        if (got_int)
  313. X            emsg(e_interr);
  314. X        else if (message)
  315. X        {
  316. X            if (p_ws)
  317. X                emsg(e_patnotf);
  318. X            else if (lnum == 0)
  319. X                EMSG("search hit TOP without match");
  320. X            else
  321. X                EMSG("search hit BOTTOM without match");
  322. X        }
  323. X        return FAIL;
  324. X    }
  325. X
  326. X    return OK;
  327. X}
  328. X
  329. X/*
  330. X * Highest level string search function.
  331. X * Search for the 'count'th occurence of string 'str' in direction 'dirc'
  332. X *                    If 'dirc' is 0: use previous dir.
  333. X * If 'str' is 0 or 'str' is empty: use previous string.
  334. X *              If 'reverse' is TRUE: go in reverse of previous dir.
  335. X *                 If 'echo' is TRUE: echo the search command and handle options
  336. X *              If 'message' is TRUE: may give error message
  337. X *
  338. X * return 0 for failure, 1 for found, 2 for found and line offset added
  339. X */
  340. X    int
  341. Xdosearch(dirc, str, reverse, count, echo, message)
  342. X    int                dirc;
  343. X    char_u           *str;
  344. X    int                reverse;
  345. X    long            count;
  346. X    int                echo;
  347. X    int                message;
  348. X{
  349. X    FPOS            pos;        /* position of the last match */
  350. X    char_u            *searchstr;
  351. X    static int        lastsdir = '/';    /* previous search direction */
  352. X    static int        lastoffline;/* previous/current search has line offset */
  353. X    static int        lastend;    /* previous/current search set cursor at end */
  354. X    static long     lastoff;    /* previous/current line or char offset */
  355. X    int                old_lastsdir;
  356. X    int                old_lastoffline;
  357. X    int                old_lastend;
  358. X    long            old_lastoff;
  359. X    int                ret;        /* Return value */
  360. X    register char_u    *p;
  361. X    register long    c;
  362. X    char_u            *dircp = NULL;
  363. X
  364. X    /*
  365. X     * save the values for when keep_old_search_pattern is set
  366. X     * (no if around this because gcc wants them initialized)
  367. X     */
  368. X    old_lastsdir = lastsdir;
  369. X    old_lastoffline = lastoffline;
  370. X    old_lastend = lastend;
  371. X    old_lastoff = lastoff;
  372. X
  373. X    if (dirc == 0)
  374. X        dirc = lastsdir;
  375. X    else
  376. X        lastsdir = dirc;
  377. X    if (reverse)
  378. X    {
  379. X        if (dirc == '/')
  380. X            dirc = '?';
  381. X        else
  382. X            dirc = '/';
  383. X    }
  384. X    searchstr = str;
  385. X                                    /* use previous string */
  386. X    if (str == NULL || *str == NUL || *str == dirc)
  387. X    {
  388. X        if (search_pattern == NULL)
  389. X        {
  390. X            emsg(e_noprevre);
  391. X            ret = 0;
  392. X            goto end_dosearch;
  393. X        }
  394. X        searchstr = (char_u *)"";    /* will use search_pattern in myregcomp() */
  395. X    }
  396. X    if (str != NULL && *str != NUL)    /* look for (new) offset */
  397. X    {
  398. X        /*
  399. X         * Find end of regular expression.
  400. X         * If there is a matching '/' or '?', toss it.
  401. X         */
  402. X        p = skip_regexp(str, dirc);
  403. X        if (*p == dirc)
  404. X        {
  405. X            dircp = p;        /* remember where we put the NUL */
  406. X            *p++ = NUL;
  407. X        }
  408. X        lastoffline = FALSE;
  409. X        lastend = FALSE;
  410. X        lastoff = 0;
  411. X        /*
  412. X         * Check for a line offset or a character offset.
  413. X         * for get_address (echo off) we don't check for a character offset,
  414. X         * because it is meaningless and the 's' could be a substitute command.
  415. X         */
  416. X        if (*p == '+' || *p == '-' || isdigit(*p))
  417. X            lastoffline = TRUE;
  418. X        else if (echo && (*p == 'e' || *p == 's' || *p == 'b'))
  419. X        {
  420. X            if (*p == 'e')            /* end */
  421. X                lastend = TRUE;
  422. X            ++p;
  423. X        }
  424. X        if (isdigit(*p) || *p == '+' || *p == '-')     /* got an offset */
  425. X        {
  426. X            if (isdigit(*p) || isdigit(*(p + 1)))
  427. X                lastoff = atol((char *)p);        /* 'nr' or '+nr' or '-nr' */
  428. X            else if (*p == '-')            /* single '-' */
  429. X                lastoff = -1;
  430. X            else                        /* single '+' */
  431. X                lastoff = 1;
  432. X            ++p;
  433. X            while (isdigit(*p))            /* skip number */
  434. X                ++p;
  435. X        }
  436. X        searchcmdlen = p - str;            /* compute lenght of search command
  437. X                                                        for get_address() */
  438. X    }
  439. X
  440. X    if (echo)
  441. X    {
  442. X        msg_start();
  443. X        msg_outchar(dirc);
  444. X        msg_outtrans(*searchstr == NUL ? search_pattern : searchstr, -1);
  445. X        if (lastoffline || lastend || lastoff)
  446. X        {
  447. X            msg_outchar(dirc);
  448. X            if (lastend)
  449. X                msg_outchar('e');
  450. X            else if (!lastoffline)
  451. X                msg_outchar('s');
  452. X            if (lastoff < 0)
  453. X            {
  454. X                msg_outchar('-');
  455. X                msg_outnum((long)-lastoff);
  456. X            }
  457. X            else if (lastoff > 0 || lastoffline)
  458. X            {
  459. X                msg_outchar('+');
  460. X                msg_outnum((long)lastoff);
  461. X            }
  462. X        }
  463. X        msg_ceol();
  464. X        (void)msg_check();
  465. X
  466. X        gotocmdline(FALSE, NUL);
  467. X        flushbuf();
  468. X    }
  469. X
  470. X    pos = curwin->w_cursor;
  471. X
  472. X    c = searchit(&pos, dirc == '/' ? FORWARD : BACKWARD, searchstr, count, lastend, message);
  473. X    if (dircp)
  474. X        *dircp = dirc;            /* put second '/' or '?' back for normal() */
  475. X    if (c == FAIL)
  476. X    {
  477. X        ret = 0;
  478. X        goto end_dosearch;
  479. X    }
  480. X    if (lastend)
  481. X        mincl = TRUE;            /* 'e' includes last character */
  482. X
  483. X    if (!lastoffline)           /* add the character offset to the column */
  484. X    {
  485. X        if (lastoff > 0)        /* offset to the right, check for end of line */
  486. X        {
  487. X            p = ml_get_pos(&pos) + 1;
  488. X            c = lastoff;
  489. X            while (c-- && *p++ != NUL)
  490. X                ++pos.col;
  491. X        }
  492. X        else                    /* offset to the left, check for start of line */
  493. X        {
  494. X            if ((c = pos.col + lastoff) < 0)
  495. X                c = 0;
  496. X            pos.col = c;
  497. X        }
  498. X    }
  499. X
  500. X    if (!tag_busy)
  501. X        setpcmark();
  502. X    curwin->w_cursor = pos;
  503. X    curwin->w_set_curswant = TRUE;
  504. X
  505. X    if (!lastoffline)
  506. X    {
  507. X        ret = 1;
  508. X        goto end_dosearch;
  509. X    }
  510. X
  511. X/*
  512. X * add the offset to the line number.
  513. X */
  514. X    c = curwin->w_cursor.lnum + lastoff;
  515. X    if (c < 1)
  516. X        curwin->w_cursor.lnum = 1;
  517. X    else if (c > curbuf->b_ml.ml_line_count)
  518. X        curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  519. X    else
  520. X        curwin->w_cursor.lnum = c;
  521. X    curwin->w_cursor.col = 0;
  522. X
  523. X    ret = 2;
  524. X
  525. Xend_dosearch:
  526. X    if (keep_old_search_pattern)
  527. X    {
  528. X        lastsdir = old_lastsdir;
  529. X        lastoffline = old_lastoffline;
  530. X        lastend = old_lastend;
  531. X        lastoff = old_lastoff;
  532. X    }
  533. X    return ret;
  534. X}
  535. X
  536. X
  537. X/*
  538. X * Character Searches
  539. X */
  540. X
  541. X/*
  542. X * searchc(c, dir, type, count)
  543. X *
  544. X * Search for character 'c', in direction 'dir'. If 'type' is 0, move to the
  545. X * position of the character, otherwise move to just before the char.
  546. X * Repeat this 'count' times.
  547. X */
  548. X    int
  549. Xsearchc(c, dir, type, count)
  550. X    int             c;
  551. X    register int    dir;
  552. X    int             type;
  553. X    long            count;
  554. X{
  555. X    static int         lastc = NUL;    /* last character searched for */
  556. X    static int        lastcdir;        /* last direction of character search */
  557. X    static int        lastctype;        /* last type of search ("find" or "to") */
  558. X    register int    col;
  559. X    char_u            *p;
  560. X    int             len;
  561. X
  562. X    if (c != NUL)       /* normal search: remember args for repeat */
  563. X    {
  564. X        lastc = c;
  565. X        lastcdir = dir;
  566. X        lastctype = type;
  567. X    }
  568. X    else                /* repeat previous search */
  569. X    {
  570. X        if (lastc == NUL)
  571. X            return FALSE;
  572. X        if (dir)        /* repeat in opposite direction */
  573. X            dir = -lastcdir;
  574. X        else
  575. X            dir = lastcdir;
  576. X    }
  577. X
  578. X    p = ml_get(curwin->w_cursor.lnum);
  579. X    col = curwin->w_cursor.col;
  580. X    len = STRLEN(p);
  581. X
  582. X    /*
  583. X     * On 'to' searches, skip one to start with so we can repeat searches in
  584. X     * the same direction and have it work right.
  585. X     * REMOVED to get vi compatibility
  586. X     * if (lastctype)
  587. X     *    col += dir;
  588. X     */
  589. X
  590. X    while (count--)
  591. X    {
  592. X            for (;;)
  593. X            {
  594. X                if ((col += dir) < 0 || col >= len)
  595. X                    return FALSE;
  596. X                if (p[col] == lastc)
  597. X                        break;
  598. X            }
  599. X    }
  600. X    if (lastctype)
  601. X        col -= dir;
  602. X    curwin->w_cursor.col = col;
  603. X    return TRUE;
  604. X}
  605. X
  606. X/*
  607. X * "Other" Searches
  608. X */
  609. X
  610. X/*
  611. X * showmatch - move the cursor to the matching paren or brace
  612. X *
  613. X * Improvement over vi: Braces inside quotes are ignored.
  614. X */
  615. X    FPOS           *
  616. Xshowmatch(initc)
  617. X    int        initc;
  618. X{
  619. X    static FPOS        pos;                /* current search position */
  620. X    int                findc;                /* matching brace */
  621. X    int                c;
  622. X    int             count = 0;            /* cumulative number of braces */
  623. X    int             idx = 0;            /* init for gcc */
  624. X    static char_u     table[6] = {'(', ')', '[', ']', '{', '}'};
  625. X    int             inquote = 0;        /* non-zero when inside quotes */
  626. X    register char_u    *linep;                /* pointer to current line */
  627. X    register char_u    *ptr;
  628. X    int                do_quotes;            /* check for quotes in current line */
  629. X    int                hash_dir = 0;        /* Direction searched for # things */
  630. X    int                comment_dir = 0;    /* Direction searched for comments */
  631. X
  632. X    pos = curwin->w_cursor;
  633. X    linep = ml_get(pos.lnum); 
  634. X
  635. X    /*
  636. X     * if initc given, look in the table for the matching character
  637. X     */
  638. X    if (initc != NUL)
  639. X    {
  640. X        for (idx = 0; idx < 6; ++idx)
  641. X            if (table[idx] == initc)
  642. X            {
  643. X                initc = table[idx = idx ^ 1];
  644. X                break;
  645. X            }
  646. X        if (idx == 6)            /* invalid initc! */
  647. X            return NULL;
  648. X    }
  649. X    /*
  650. X     * no initc given, look under the cursor
  651. X     */
  652. X    else
  653. X    {
  654. X        if (linep[0] == '#' && pos.col == 0)
  655. X            hash_dir = 1;
  656. X
  657. X        /*
  658. X         * Are we on a comment?
  659. X         */
  660. X        if (linep[pos.col] == '/')
  661. X        {
  662. X            if (linep[pos.col + 1] == '*')
  663. X            {
  664. X                comment_dir = 1;
  665. X                idx = 0;
  666. X            }
  667. X            else if (pos.col > 0 && linep[pos.col - 1] == '*')
  668. X            {
  669. X                comment_dir = -1;
  670. X                idx = 1;
  671. X            }
  672. X        }
  673. X        if (linep[pos.col] == '*')
  674. X        {
  675. X            if (linep[pos.col + 1] == '/')
  676. X            {
  677. X                comment_dir = -1;
  678. X                idx = 1;
  679. X            }
  680. X            else if (pos.col > 0 && linep[pos.col - 1] == '/')
  681. X            {
  682. X                comment_dir = 1;
  683. X                idx = 0;
  684. X            }
  685. X        }
  686. X
  687. X        /*
  688. X         * If we are not on a comment or the # at the start of a line, then
  689. X         * look for brace anywhere on this line after the cursor.
  690. X         */
  691. X        if (!hash_dir && !comment_dir)
  692. X        {
  693. X            /*
  694. X             * find the brace under or after the cursor
  695. X             */
  696. X            linep = ml_get(pos.lnum); 
  697. X            for (;;)
  698. X            {
  699. X                initc = linep[pos.col];
  700. X                if (initc == NUL)
  701. X                    break;
  702. X
  703. X                for (idx = 0; idx < 6; ++idx)
  704. X                    if (table[idx] == initc)
  705. X                        break;
  706. X                if (idx != 6)
  707. X                    break;
  708. X                ++pos.col;
  709. X            }
  710. X            if (idx == 6)
  711. X            {
  712. X                if (linep[0] == '#')
  713. X                    hash_dir = 1;
  714. X                else
  715. X                    return NULL;
  716. X            }
  717. X        }
  718. X        if (hash_dir)
  719. X        {
  720. X            /*
  721. X             * Look for matching #if, #else, #elif, or #endif
  722. X             */
  723. X            mtype = MLINE;        /* Linewise for this case only */
  724. X            ptr = linep + 1;
  725. X            while (*ptr == ' ' || *ptr == TAB)
  726. X                ptr++;
  727. X            if (STRNCMP(ptr, "if", (size_t)2) == 0 || STRNCMP(ptr, "el", (size_t)2) == 0)
  728. X                hash_dir = 1;
  729. X            else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
  730. X                hash_dir = -1;
  731. X            else
  732. X                return NULL;
  733. X            pos.col = 0;
  734. X            while (!got_int)
  735. X            {
  736. X                if (hash_dir > 0)
  737. X                {
  738. X                    if (pos.lnum == curbuf->b_ml.ml_line_count)
  739. X                        break;
  740. X                }
  741. X                else if (pos.lnum == 1)
  742. X                    break;
  743. X                pos.lnum += hash_dir;
  744. X                linep = ml_get(pos.lnum);
  745. X                if ((pos.lnum & 15) == 0)
  746. X                    breakcheck();
  747. X                if (linep[0] != '#')
  748. X                    continue;
  749. X                ptr = linep + 1;
  750. X                while (*ptr == ' ' || *ptr == TAB)
  751. X                    ptr++;
  752. X                if (hash_dir > 0)
  753. X                {
  754. X                    if (STRNCMP(ptr, "if", (size_t)2) == 0)
  755. X                        count++;
  756. X                    else if (STRNCMP(ptr, "el", (size_t)2) == 0)
  757. X                    {
  758. X                        if (count == 0)
  759. X                            return &pos;
  760. X                    }
  761. X                    else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
  762. X                    {
  763. X                        if (count == 0)
  764. X                            return &pos;
  765. X                        count--;
  766. X                    }
  767. X                }
  768. X                else
  769. X                {
  770. X                    if (STRNCMP(ptr, "if", (size_t)2) == 0)
  771. X                    {
  772. X                        if (count == 0)
  773. X                            return &pos;
  774. X                        count--;
  775. X                    }
  776. X                    else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
  777. X                        count++;
  778. X                }
  779. X            }
  780. X            return NULL;
  781. X        }
  782. X    }
  783. X
  784. X    findc = table[idx ^ 1];        /* get matching brace */
  785. X    idx &= 1;
  786. X
  787. X    do_quotes = -1;
  788. X    while (!got_int)
  789. X    {
  790. X        /*
  791. X         * Go to the next position, forward or backward. We could use
  792. X         * inc() and dec() here, but that is much slower
  793. X         */
  794. X        if (idx)                          /* backward search */
  795. X        {
  796. X            if (pos.col == 0)           /* at start of line, go to previous one */
  797. X            {
  798. X                if (pos.lnum == 1)      /* start of file */
  799. X                    break;
  800. X                --pos.lnum;
  801. X                linep = ml_get(pos.lnum);
  802. X                pos.col = STRLEN(linep);    /* put pos.col on trailing NUL */
  803. X                do_quotes = -1;
  804. X                    /* we only do a breakcheck() once for every 16 lines */
  805. X                if ((pos.lnum & 15) == 0)
  806. X                    breakcheck();
  807. X            }
  808. X            else
  809. X                --pos.col;
  810. X        }
  811. X        else                            /* forward search */
  812. X        {
  813. X            if (linep[pos.col] == NUL)  /* at end of line, go to next one */
  814. X            {
  815. X                if (pos.lnum == curbuf->b_ml.ml_line_count) /* end of file */
  816. X                    break;
  817. X                ++pos.lnum;
  818. X                linep = ml_get(pos.lnum);
  819. X                pos.col = 0;
  820. X                do_quotes = -1;
  821. X                    /* we only do a breakcheck() once for every 16 lines */
  822. X                if ((pos.lnum & 15) == 0)
  823. X                    breakcheck();
  824. X            }
  825. X            else
  826. X                ++pos.col;
  827. X        }
  828. X
  829. X        if (comment_dir)
  830. X        {
  831. X            /* Note: comments do not nest, and we ignore quotes in them */
  832. X            if (linep[pos.col] != '/' ||
  833. X                            (comment_dir == 1 && pos.col == 0) ||
  834. X                            linep[pos.col - comment_dir] != '*')
  835. X                continue;
  836. X            return &pos;
  837. X        }
  838. X
  839. X        if (do_quotes == -1)        /* count number of quotes in this line */
  840. X        {
  841. X            /*
  842. X             * count the number of quotes in the line, skipping \" and '"'
  843. X             */
  844. X            for (ptr = linep; *ptr; ++ptr)
  845. X                if (*ptr == '"' && (ptr == linep || ptr[-1] != '\\') &&
  846. X                            (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
  847. X                    ++do_quotes;
  848. X            do_quotes &= 1;            /* result is 1 with even number of quotes */
  849. X
  850. X            /*
  851. X             * If we find an uneven count, check current line and previous
  852. X             * one for a '\' at the end.
  853. X             */
  854. X            if (!do_quotes)
  855. X            {
  856. X                inquote = FALSE;
  857. X                if (ptr[-1] == '\\')
  858. X                {
  859. X                    do_quotes = 1;
  860. X                    if (idx)                    /* backward search */
  861. X                        inquote = TRUE;
  862. X                }
  863. X                if (pos.lnum > 1)
  864. X                {
  865. X                    ptr = ml_get(pos.lnum - 1);
  866. X                    if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
  867. X                    {
  868. X                        do_quotes = 1;
  869. X                        if (!idx)                /* forward search */
  870. X                            inquote = TRUE;
  871. X                    }
  872. X                }
  873. X            }
  874. X        }
  875. X
  876. X        /*
  877. X         * Things inside quotes are ignored by setting 'inquote'.
  878. X         * If we find a quote without a preceding '\' invert 'inquote'.
  879. X         * At the end of a line not ending in '\' we reset 'inquote'.
  880. X         *
  881. X         * In lines with an uneven number of quotes (without preceding '\')
  882. X         * we do not know which part to ignore. Therefore we only set
  883. X         * inquote if the number of quotes in a line is even,
  884. X         * unless this line or the previous one ends in a '\'.
  885. X         * Complicated, isn't it?
  886. X         */
  887. X        switch (c = linep[pos.col])
  888. X        {
  889. X        case NUL:
  890. X            inquote = FALSE;
  891. X            break;
  892. X
  893. X        case '"':
  894. X                /* a quote that is preceded with a backslash is ignored */
  895. X            if (do_quotes && (pos.col == 0 || linep[pos.col - 1] != '\\'))
  896. X                inquote = !inquote;
  897. X            break;
  898. X
  899. X        /*
  900. X         * Skip things in single quotes: 'x' or '\x'.
  901. X         * Be careful for single single quotes, eg jon's.
  902. X         * Things like '\233' or '\x3f' are not skipped, there is never a
  903. X         * brace in them.
  904. X         */
  905. X        case '\'':
  906. X            if (idx)                        /* backward search */
  907. X            {
  908. X                if (pos.col > 1)
  909. X                {
  910. X                    if (linep[pos.col - 2] == '\'')
  911. X                        pos.col -= 2;
  912. X                    else if (linep[pos.col - 2] == '\\' && pos.col > 2 && linep[pos.col - 3] == '\'')
  913. X                        pos.col -= 3;
  914. X                }
  915. X            }
  916. X            else if (linep[pos.col + 1])    /* forward search */
  917. X            {
  918. X                if (linep[pos.col + 1] == '\\' && linep[pos.col + 2] && linep[pos.col + 3] == '\'')
  919. X                    pos.col += 3;
  920. X                else if (linep[pos.col + 2] == '\'')
  921. X                    pos.col += 2;
  922. X            }
  923. X            break;
  924. X
  925. X        default:
  926. X            if (!inquote)      /* only check for match outside of quotes */
  927. X            {
  928. X                if (c == initc)
  929. X                    count++;
  930. X                else if (c == findc)
  931. X                {
  932. X                    if (count == 0)
  933. X                        return &pos;
  934. X                    count--;
  935. X                }
  936. X            }
  937. X        }
  938. X    }
  939. X    return (FPOS *) NULL;       /* never found it */
  940. X}
  941. X
  942. X/*
  943. X * findfunc(dir, what) - Find the next line starting with 'what' in direction 'dir'
  944. X *
  945. X * Return TRUE if a line was found.
  946. X */
  947. X    int
  948. Xfindfunc(dir, what, count)
  949. X    int         dir;
  950. X    int            what;
  951. X    long        count;
  952. X{
  953. X    linenr_t    curr;
  954. X
  955. X    curr = curwin->w_cursor.lnum;
  956. X
  957. X    for (;;)
  958. X    {
  959. X        if (dir == FORWARD)
  960. X        {
  961. X                if (curr++ == curbuf->b_ml.ml_line_count)
  962. X                        break;
  963. X        }
  964. X        else
  965. X        {
  966. X                if (curr-- == 1)
  967. X                        break;
  968. X        }
  969. X
  970. X        if (*ml_get(curr) == what)
  971. X        {
  972. X            if (--count > 0)
  973. X                continue;
  974. X            setpcmark();
  975. X            curwin->w_cursor.lnum = curr;
  976. X            curwin->w_cursor.col = 0;
  977. X            return TRUE;
  978. X        }
  979. X    }
  980. X
  981. X    return FALSE;
  982. X}
  983. X
  984. X/*
  985. X * findsent(dir, count) - Find the start of the next sentence in direction 'dir'
  986. X * Sentences are supposed to end in ".", "!" or "?" followed by white space or
  987. X * a line break. Also stop at an empty line.
  988. X * Return TRUE if the next sentence was found.
  989. X */
  990. X    int
  991. Xfindsent(dir, count)
  992. X        int     dir;
  993. X        long    count;
  994. X{
  995. X    FPOS            pos, tpos;
  996. X    register int    c;
  997. X    int             (*func) __PARMS((FPOS *));
  998. X    int             startlnum;
  999. X    int                noskip = FALSE;            /* do not skip blanks */
  1000. X
  1001. X    pos = curwin->w_cursor;
  1002. X    if (dir == FORWARD)
  1003. X        func = incl;
  1004. X    else
  1005. X        func = decl;
  1006. X
  1007. X    while (count--)
  1008. X    {
  1009. X        /* if on an empty line, skip upto a non-empty line */
  1010. X        if (gchar(&pos) == NUL)
  1011. X        {
  1012. X            do
  1013. X                if ((*func)(&pos) == -1)
  1014. X                    break;
  1015. X            while (gchar(&pos) == NUL);
  1016. X            if (dir == FORWARD)
  1017. X                goto found;
  1018. X        }
  1019. X        /* if on the start of a paragraph or a section and searching
  1020. X         * forward, go to the next line */
  1021. X        else if (dir == FORWARD && pos.col == 0 && startPS(pos.lnum, NUL, FALSE))
  1022. X        {
  1023. X            if (pos.lnum == curbuf->b_ml.ml_line_count)
  1024. X                return FALSE;
  1025. X            ++pos.lnum;
  1026. X            goto found;
  1027. X        }
  1028. X        else if (dir == BACKWARD)
  1029. X            decl(&pos);
  1030. X
  1031. X        /* go back to the previous non-blank char */
  1032. X        while ((c = gchar(&pos)) == ' ' || c == '\t' ||
  1033. X                    (dir == BACKWARD && strchr(".!?)]\"'", c) != NULL && c != NUL))
  1034. X            if (decl(&pos) == -1)
  1035. X                break;
  1036. X
  1037. X        /* remember the line where the search started */
  1038. X        startlnum = pos.lnum;
  1039. X
  1040. X        for (;;)                /* find end of sentence */
  1041. X        {
  1042. X            if ((c = gchar(&pos)) == NUL ||
  1043. X                            (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
  1044. X            {
  1045. X                if (dir == BACKWARD && pos.lnum != startlnum)
  1046. X                    ++pos.lnum;
  1047. X                break;
  1048. X            }
  1049. X            if (c == '.' || c == '!' || c == '?')
  1050. X            {
  1051. X                tpos = pos;
  1052. X                do
  1053. X                    if ((c = inc(&tpos)) == -1)
  1054. X                        break;
  1055. X                while (strchr(")}\"'", c = gchar(&tpos)) != NULL && c != NUL);
  1056. X                if (c == -1  || c == ' ' || c == '\t' || c == NUL)
  1057. X                {
  1058. X                    pos = tpos;
  1059. X                    if (gchar(&pos) == NUL) /* skip NUL at EOL */
  1060. X                        inc(&pos);
  1061. X                    break;
  1062. X                }
  1063. X            }
  1064. X            if ((*func)(&pos) == -1)
  1065. X            {
  1066. X                if (count)
  1067. X                    return FALSE;
  1068. X                noskip = TRUE;
  1069. X                break;
  1070. X            }
  1071. X        }
  1072. Xfound:
  1073. X            /* skip white space */
  1074. X        while (!noskip && ((c = gchar(&pos)) == ' ' || c == '\t'))
  1075. X            if (incl(&pos) == -1)
  1076. X                break;
  1077. X    }
  1078. X
  1079. X    setpcmark();
  1080. X    curwin->w_cursor = pos;
  1081. X    return TRUE;
  1082. X}
  1083. X
  1084. X/*
  1085. X * findpar(dir, count, what) - Find the next paragraph in direction 'dir'
  1086. X * Paragraphs are currently supposed to be separated by empty lines.
  1087. X * Return TRUE if the next paragraph was found.
  1088. X * If 'what' is '{' or '}' we go to the next section.
  1089. X * If 'both' is TRUE also stop at '}'.
  1090. X */
  1091. X    int
  1092. Xfindpar(dir, count, what, both)
  1093. X    register int    dir;
  1094. X    long            count;
  1095. X    int             what;
  1096. X    int                both;
  1097. X{
  1098. X    register linenr_t    curr;
  1099. X    int                    did_skip;        /* TRUE after separating lines have
  1100. X                                                been skipped */
  1101. X    int                    first;            /* TRUE on first line */
  1102. X
  1103. X    curr = curwin->w_cursor.lnum;
  1104. X
  1105. X    while (count--)
  1106. X    {
  1107. X        did_skip = FALSE;
  1108. X        for (first = TRUE; ; first = FALSE)
  1109. X        {
  1110. X                if (*ml_get(curr) != NUL)
  1111. X                    did_skip = TRUE;
  1112. X
  1113. X                if (!first && did_skip && startPS(curr, what, both))
  1114. X                    break;
  1115. X
  1116. X                if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
  1117. X                {
  1118. X                        if (count)
  1119. X                                return FALSE;
  1120. X                        curr -= dir;
  1121. X                        break;
  1122. X                }
  1123. X        }
  1124. X    }
  1125. X    setpcmark();
  1126. X    if (both && *ml_get(curr) == '}')    /* include line with '}' */
  1127. X        ++curr;
  1128. X    curwin->w_cursor.lnum = curr;
  1129. X    if (curr == curbuf->b_ml.ml_line_count)
  1130. X    {
  1131. X        if ((curwin->w_cursor.col = STRLEN(ml_get(curr))) != 0)
  1132. X            --curwin->w_cursor.col;
  1133. X        mincl = TRUE;
  1134. X    }
  1135. X    else
  1136. X        curwin->w_cursor.col = 0;
  1137. X    return TRUE;
  1138. X}
  1139. X
  1140. X/*
  1141. X * check if the string 's' is a nroff macro that is in option 'opt'
  1142. X */
  1143. X    static int
  1144. Xinmacro(opt, s)
  1145. X        char_u *opt;
  1146. X        register char_u *s;
  1147. X{
  1148. X        register char_u *macro;
  1149. X
  1150. X        for (macro = opt; macro[0]; ++macro)
  1151. X        {
  1152. X                if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ')
  1153. X                        && (macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
  1154. X                        break;
  1155. X                ++macro;
  1156. X                if (macro[0] == NUL)
  1157. X                        break;
  1158. X        }
  1159. X        return (macro[0] != NUL);
  1160. X}
  1161. X
  1162. X/*
  1163. X * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
  1164. X * If 'para' is '{' or '}' only check for sections.
  1165. X * If 'both' is TRUE also stop at '}'
  1166. X */
  1167. X    int
  1168. XstartPS(lnum, para, both)
  1169. X    linenr_t    lnum;
  1170. X    int         para;
  1171. X    int            both;
  1172. X{
  1173. X    register char_u *s;
  1174. X
  1175. X    s = ml_get(lnum);
  1176. X    if (*s == para || *s == '\f' || (both && *s == '}'))
  1177. X        return TRUE;
  1178. X    if (*s == '.' && (inmacro(p_sections, s + 1) || (!para && inmacro(p_para, s + 1))))
  1179. X        return TRUE;
  1180. X    return FALSE;
  1181. X}
  1182. X
  1183. X/*
  1184. X * The following routines do the word searches performed by the 'w', 'W',
  1185. X * 'b', 'B', 'e', and 'E' commands.
  1186. X */
  1187. X
  1188. X/*
  1189. X * To perform these searches, characters are placed into one of three
  1190. X * classes, and transitions between classes determine word boundaries.
  1191. X *
  1192. X * The classes are:
  1193. X *
  1194. X * 0 - white space
  1195. X * 1 - letters, digits and underscore
  1196. X * 2 - everything else
  1197. X */
  1198. X
  1199. Xstatic int        stype;            /* type of the word motion being performed */
  1200. X
  1201. X/*
  1202. X * cls() - returns the class of character at curwin->w_cursor
  1203. X *
  1204. X * The 'type' of the current search modifies the classes of characters if a 'W',
  1205. X * 'B', or 'E' motion is being done. In this case, chars. from class 2 are
  1206. X * reported as class 1 since only white space boundaries are of interest.
  1207. X */
  1208. X    static int
  1209. Xcls()
  1210. X{
  1211. X    register int c;
  1212. X
  1213. X    c = gchar_cursor();
  1214. X    if (c == ' ' || c == '\t' || c == NUL)
  1215. X        return 0;
  1216. X
  1217. X    if (isidchar(c))
  1218. X        return 1;
  1219. X
  1220. X    /*
  1221. X     * If stype is non-zero, report these as class 1.
  1222. X     */
  1223. X    return (stype == 0) ? 2 : 1;
  1224. X}
  1225. X
  1226. X
  1227. X/*
  1228. X * fwd_word(count, type, eol) - move forward one word
  1229. X *
  1230. X * Returns TRUE if the cursor was already at the end of the file.
  1231. X * If eol is TRUE, last word stops at end of line (for operators).
  1232. X */
  1233. X    int
  1234. Xfwd_word(count, type, eol)
  1235. X    long        count;
  1236. X    int         type;
  1237. X    int            eol;
  1238. X{
  1239. X    int         sclass;     /* starting class */
  1240. X    int            i;
  1241. X
  1242. X    stype = type;
  1243. X    while (--count >= 0)
  1244. X    {
  1245. X        sclass = cls();
  1246. X
  1247. X        /*
  1248. X         * We always move at least one character.
  1249. X         */
  1250. X        i = inc_cursor();
  1251. X        if (i == -1)
  1252. X            return TRUE;
  1253. X        if (i == 1 && eol && count == 0)    /* started at last char in line */
  1254. X            return FALSE;
  1255. X
  1256. X        if (sclass != 0)
  1257. X            while (cls() == sclass)
  1258. X            {
  1259. X                i = inc_cursor();
  1260. X                if (i == -1 || (i == 1 && eol && count == 0))
  1261. X                    return FALSE;
  1262. X            }
  1263. X
  1264. X        /*
  1265. X         * go to next non-white
  1266. X         */
  1267. X        while (cls() == 0)
  1268. X        {
  1269. X            /*
  1270. X             * We'll stop if we land on a blank line
  1271. X             */
  1272. X            if (curwin->w_cursor.col == 0 && *ml_get(curwin->w_cursor.lnum) == NUL)
  1273. X                break;
  1274. X
  1275. X            i = inc_cursor();
  1276. X            if (i == -1 || (i == 1 && eol && count == 0))
  1277. X                return FALSE;
  1278. X        }
  1279. X    }
  1280. X    return FALSE;
  1281. X}
  1282. X
  1283. X/*
  1284. X * bck_word(count, type) - move backward 'count' words
  1285. X *
  1286. X * Returns TRUE if top of the file was reached.
  1287. X */
  1288. X    int
  1289. Xbck_word(count, type)
  1290. X    long        count;
  1291. X    int         type;
  1292. X{
  1293. X    int         sclass;     /* starting class */
  1294. X
  1295. X    stype = type;
  1296. X    while (--count >= 0)
  1297. X    {
  1298. X        sclass = cls();
  1299. X
  1300. X        if (dec_cursor() == -1)        /* started at start of file */
  1301. X            return TRUE;
  1302. X
  1303. X        if (cls() != sclass || sclass == 0)
  1304. X        {
  1305. X            /*
  1306. X             * We were at the start of a word. Go back to the end of the prior
  1307. X             * word.
  1308. X             */
  1309. X            while (cls() == 0)  /* skip any white space */
  1310. X            {
  1311. X                /*
  1312. X                 * We'll stop if we land on a blank line
  1313. X                 */
  1314. X                if (curwin->w_cursor.col == 0 && *ml_get(curwin->w_cursor.lnum) == NUL)
  1315. X                    goto finished;
  1316. X
  1317. X                if (dec_cursor() == -1)        /* hit start of file, stop here */
  1318. X                    return FALSE;
  1319. X            }
  1320. X            sclass = cls();
  1321. X        }
  1322. X
  1323. X        /*
  1324. X         * Move backward to start of this word.
  1325. X         */
  1326. X        if (skip_chars(sclass, BACKWARD))
  1327. X                return FALSE;
  1328. X
  1329. X        inc_cursor();                    /* overshot - forward one */
  1330. Xfinished:
  1331. X        ;
  1332. X    }
  1333. X    return FALSE;
  1334. X}
  1335. X
  1336. X/*
  1337. X * end_word(count, type, stop) - move to the end of the word
  1338. X *
  1339. X * There is an apparent bug in the 'e' motion of the real vi. At least on the
  1340. X * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
  1341. X * motion crosses blank lines. When the real vi crosses a blank line in an
  1342. X * 'e' motion, the cursor is placed on the FIRST character of the next
  1343. X * non-blank line. The 'E' command, however, works correctly. Since this
  1344. X * appears to be a bug, I have not duplicated it here.
  1345. X *
  1346. X * Returns TRUE if end of the file was reached.
  1347. X *
  1348. X * If stop is TRUE and we are already on the end of a word, move one less.
  1349. X */
  1350. X    int
  1351. Xend_word(count, type, stop)
  1352. X    long        count;
  1353. X    int         type;
  1354. X    int            stop;
  1355. X{
  1356. X    int         sclass;     /* starting class */
  1357. X
  1358. X    stype = type;
  1359. X    while (--count >= 0)
  1360. X    {
  1361. X        sclass = cls();
  1362. X        if (inc_cursor() == -1)
  1363. X            return TRUE;
  1364. X
  1365. X        /*
  1366. X         * If we're in the middle of a word, we just have to move to the end of it.
  1367. X         */
  1368. X        if (cls() == sclass && sclass != 0)
  1369. X        {
  1370. X            /*
  1371. X             * Move forward to end of the current word
  1372. X             */
  1373. X            if (skip_chars(sclass, FORWARD))
  1374. X                    return TRUE;
  1375. X        }
  1376. X        else if (!stop || sclass == 0)
  1377. X        {
  1378. X            /*
  1379. X             * We were at the end of a word. Go to the end of the next word.
  1380. X             */
  1381. X
  1382. X            if (skip_chars(0, FORWARD))     /* skip any white space */
  1383. X                return TRUE;
  1384. X
  1385. X            /*
  1386. X             * Move forward to the end of this word.
  1387. X             */
  1388. X            if (skip_chars(cls(), FORWARD))
  1389. X                return TRUE;
  1390. X        }
  1391. X        dec_cursor();                    /* overshot - backward one */
  1392. X        stop = FALSE;                    /* we move only one word less */
  1393. X    }
  1394. X    return FALSE;
  1395. X}
  1396. X
  1397. X    int
  1398. Xskip_chars(class, dir)
  1399. X    int class;
  1400. X    int dir;
  1401. X{
  1402. X        while (cls() == class)
  1403. X            if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
  1404. X                return TRUE;
  1405. X        return FALSE;
  1406. X}
  1407. END_OF_FILE
  1408.   if test 30917 -ne `wc -c <'vim/src/search.c'`; then
  1409.     echo shar: \"'vim/src/search.c'\" unpacked with wrong size!
  1410.   fi
  1411.   # end of 'vim/src/search.c'
  1412. fi
  1413. if test -f 'vim/src/unix.c' -a "${1}" != "-c" ; then 
  1414.   echo shar: Will not clobber existing file \"'vim/src/unix.c'\"
  1415. else
  1416.   echo shar: Extracting \"'vim/src/unix.c'\" \(30140 characters\)
  1417.   sed "s/^X//" >'vim/src/unix.c' <<'END_OF_FILE'
  1418. X/* vi:ts=4:sw=4
  1419. X *
  1420. X * VIM - Vi IMproved        by Bram Moolenaar
  1421. X *
  1422. X * Read the file "credits.txt" for a list of people who contributed.
  1423. X * Read the file "uganda.txt" for copying and usage conditions.
  1424. X */
  1425. X
  1426. X/*
  1427. X * unix.c -- BSD and SYSV code
  1428. X *
  1429. X * A lot of this file was written by Juergen Weigert.
  1430. X */
  1431. X
  1432. X#include "vim.h"
  1433. X#include "globals.h"
  1434. X#include "param.h"
  1435. X#include "proto.h"
  1436. X
  1437. X#include <fcntl.h>
  1438. X#if !defined(pyr) && !defined(NOT_BOTH_TIME)
  1439. X# include <time.h>            /* on some systems time.h should not be
  1440. X                               included together with sys/time.h */
  1441. X#endif
  1442. X#include <sys/ioctl.h>
  1443. X#ifndef M_XENIX
  1444. X# include <sys/types.h>
  1445. X#endif
  1446. X#include <signal.h>
  1447. X
  1448. X#ifndef USE_SYSTEM        /* use fork/exec to start the shell */
  1449. X# include <sys/wait.h>
  1450. X# if !defined(SCO) && !defined(SOLARIS) && !defined(hpux) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(_SEQUENT_) && !defined(UNISYS)    /* SCO returns pid_t */
  1451. Xextern int fork();
  1452. X# endif
  1453. X# if !defined(linux) && !defined(SOLARIS) && !defined(USL) && !defined(sun) && !(defined(hpux) && defined(__STDC__)) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(USL) && !defined(UNISYS)
  1454. Xextern int execvp __ARGS((const char *, const char **));
  1455. X# endif
  1456. X#endif
  1457. X
  1458. X#if defined(SYSV_UNIX) || defined(USL)
  1459. X# if defined(__sgi) || defined(UTS2) || defined(UTS4) || defined(MIPS) || defined (MIPSEB) || defined(__osf__)
  1460. X#  include <sys/time.h>
  1461. X# endif
  1462. X# if defined(M_XENIX) || defined(SCO)
  1463. X#  include <stropts.h>
  1464. X# endif
  1465. X# if defined(M_XENIX) || defined(SCO) || defined(UNICOS)
  1466. X#  include <sys/select.h>
  1467. X#  define bzero(a, b)    memset((a), 0, (b))
  1468. X# endif
  1469. X# if !defined(M_XENIX) && !defined(UNICOS)
  1470. X#  include <poll.h>
  1471. X# endif
  1472. X# if defined(SCO) || defined(ISC)
  1473. X#  include <sys/stream.h>
  1474. X#  include <sys/ptem.h>
  1475. X# endif
  1476. X# if defined(M_UNIX) && !defined(SCO)
  1477. X#  include <sys/time.h>
  1478. X# endif       /* M_UNIX */
  1479. X# ifdef ISC
  1480. X#  include <termios.h>
  1481. X# endif
  1482. X# include <termio.h>
  1483. X#else    /* SYSV_UNIX */
  1484. X# include <sys/time.h>
  1485. X# if defined(hpux) || defined(linux)
  1486. X#  include <termio.h>
  1487. X#  if defined(hpux) && !defined(SIGWINCH)    /* hpux 9.01 has it */
  1488. X#   define SIGWINCH SIGWINDOW
  1489. X#  endif
  1490. X# else
  1491. X#  include <sgtty.h>
  1492. X# endif    /* hpux */
  1493. X#endif    /* !SYSV_UNIX */
  1494. X
  1495. X#if (defined(pyr) || defined(NO_FD_ZERO)) && defined(SYSV_UNIX) && defined(FD_ZERO)
  1496. X# undef FD_ZERO
  1497. X#endif
  1498. X
  1499. X#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
  1500. X# ifdef SIGWINCH
  1501. X#  undef SIGWINCH
  1502. X# endif
  1503. X# ifdef TIOCGWINSZ
  1504. X#  undef TIOCGWINSZ
  1505. X# endif
  1506. X#endif
  1507. X
  1508. X#ifdef USE_X11
  1509. X
  1510. X# include <X11/Xlib.h>
  1511. X# include <X11/Xutil.h>
  1512. X
  1513. XWindow        x11_window = 0;
  1514. XDisplay        *x11_display = NULL;
  1515. X
  1516. Xstatic int    get_x11_windis __ARGS((void));
  1517. X#ifdef BUGGY
  1518. Xstatic void set_x11_title __ARGS((char_u *));
  1519. Xstatic void set_x11_icon __ARGS((char_u *));
  1520. X#endif
  1521. X#endif
  1522. X
  1523. Xstatic void get_x11_title __ARGS((void));
  1524. Xstatic void get_x11_icon __ARGS((void));
  1525. X
  1526. Xstatic int    Read __ARGS((char_u *, long));
  1527. Xstatic int    WaitForChar __ARGS((int));
  1528. Xstatic int    RealWaitForChar __ARGS((int));
  1529. Xstatic void fill_inbuf __ARGS((void));
  1530. X#ifdef USL
  1531. Xstatic void sig_winch __ARGS((int));
  1532. X#else
  1533. X# if defined(SIGWINCH) && !defined(linux) && !defined(__alpha) && !defined(mips) && !defined(_SEQUENT_) && !defined(SCO) && !defined(SOLARIS) && !defined(ISC)
  1534. Xstatic void sig_winch __ARGS((int, int, struct sigcontext *));
  1535. X# endif
  1536. X#endif
  1537. X
  1538. Xstatic int do_resize = FALSE;
  1539. Xstatic char_u *oldtitle = NULL;
  1540. Xstatic char_u *oldicon = NULL;
  1541. Xstatic char_u *extra_shell_arg = NULL;
  1542. Xstatic int show_shell_mess = TRUE;
  1543. X
  1544. X/*
  1545. X * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
  1546. X */
  1547. X#undef TRUE
  1548. X#define TRUE 1
  1549. X#undef FALSE
  1550. X#define FALSE 0
  1551. X
  1552. X    void
  1553. Xmch_write(s, len)
  1554. X    char_u    *s;
  1555. X    int        len;
  1556. X{
  1557. X    write(1, (char *)s, len);
  1558. X}
  1559. X
  1560. X/*
  1561. X * GetChars(): low level input funcion.
  1562. X * Get a characters from the keyboard.
  1563. X * If wtime == 0 do not wait for characters.
  1564. X * If wtime == n wait a short time for characters.
  1565. X * If wtime == -1 wait forever for characters.
  1566. X */
  1567. X    int
  1568. XGetChars(buf, maxlen, wtime)
  1569. X    char_u    *buf;
  1570. X    int        maxlen;
  1571. X    int        wtime;            /* don't use "time", MIPS cannot handle it */
  1572. X{
  1573. X    int        len;
  1574. X
  1575. X    if (wtime >= 0)
  1576. X    {
  1577. X        while (WaitForChar(wtime) == 0)        /* no character available */
  1578. X        {
  1579. X            if (!do_resize)            /* return if not interrupted by resize */
  1580. X                return 0;
  1581. X            set_winsize(0, 0, FALSE);
  1582. X            do_resize = FALSE;
  1583. X        }
  1584. X    }
  1585. X    else        /* wtime == -1 */
  1586. X    {
  1587. X    /*
  1588. X     * If there is no character available within 'updatetime' seconds
  1589. X     * flush all the swap files to disk
  1590. X     * Also done when interrupted by SIGWINCH.
  1591. X     */
  1592. X        if (WaitForChar((int)p_ut) == 0)
  1593. X            updatescript(0);
  1594. X    }
  1595. X
  1596. X    for (;;)    /* repeat until we got a character */
  1597. X    {
  1598. X        if (do_resize)        /* window changed size */
  1599. X        {
  1600. X            set_winsize(0, 0, FALSE);
  1601. X            do_resize = FALSE;
  1602. X        }
  1603. X        /* 
  1604. X         * we want to be interrupted by the winch signal
  1605. X         */
  1606. X        WaitForChar(-1);
  1607. X        if (do_resize)        /* interrupted by SIGWINCHsignal */
  1608. X            continue;
  1609. X        len = Read(buf, (long)maxlen);
  1610. X        if (len > 0)
  1611. X            return len;
  1612. X    }
  1613. X}
  1614. X
  1615. X/*
  1616. X * return non-zero if a character is available
  1617. X */
  1618. X    int
  1619. Xmch_char_avail()
  1620. X{
  1621. X    return WaitForChar(0);
  1622. X}
  1623. X
  1624. X    long
  1625. Xmch_avail_mem(special)
  1626. X    int special;
  1627. X{
  1628. X    return 0x7fffffff;        /* virual memory eh */
  1629. X}
  1630. X
  1631. X#ifndef FD_ZERO
  1632. X    void
  1633. Xvim_delay()
  1634. X{
  1635. X    poll(0, 0, 500);
  1636. X}
  1637. X#else
  1638. X# if (defined(__STDC__) && !defined(hpux)) || defined(ultrix)
  1639. Xextern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  1640. X# endif
  1641. X
  1642. X    void
  1643. Xvim_delay()
  1644. X{
  1645. X    struct timeval tv;
  1646. X
  1647. X    tv.tv_sec = 25 / 50;
  1648. X    tv.tv_usec = (25 % 50) * (1000000/50);
  1649. X    select(0, 0, 0, 0, &tv);
  1650. X}
  1651. X#endif
  1652. X
  1653. X    static void
  1654. X#if defined(__alpha) || (defined(mips) && !defined(USL))
  1655. Xsig_winch()
  1656. X#else
  1657. X# if defined(_SEQUENT_) || defined(SCO) || defined(ISC)
  1658. Xsig_winch(sig, code)
  1659. X    int        sig;
  1660. X    int        code;
  1661. X# else
  1662. X#  if defined(USL)
  1663. Xsig_winch(sig)
  1664. X    int        sig;
  1665. X#  else
  1666. Xsig_winch(sig, code, scp)
  1667. X    int        sig;
  1668. X    int        code;
  1669. X    struct sigcontext *scp;
  1670. X#  endif
  1671. X# endif
  1672. X#endif
  1673. X{
  1674. X#if defined(SIGWINCH)
  1675. X        /* this is not required on all systems, but it doesn't hurt anybody */
  1676. X    signal(SIGWINCH, (void (*)())sig_winch);
  1677. X#endif
  1678. X    do_resize = TRUE;
  1679. X}
  1680. X
  1681. X/*
  1682. X * If the machine has job control, use it to suspend the program,
  1683. X * otherwise fake it by starting a new shell.
  1684. X */
  1685. X    void
  1686. Xmch_suspend()
  1687. X{
  1688. X#ifdef SIGTSTP
  1689. X    settmode(0);
  1690. X    kill(0, SIGTSTP);        /* send ourselves a STOP signal */
  1691. X    settmode(1);
  1692. X#else
  1693. X    OUTSTR("new shell started\n");
  1694. X    (void)call_shell(NULL, 0, TRUE);
  1695. X#endif
  1696. X}
  1697. X
  1698. X    void
  1699. Xmch_windinit()
  1700. X{
  1701. X    Columns = 80;
  1702. X    Rows = 24;
  1703. X
  1704. X    flushbuf();
  1705. X
  1706. X    (void)mch_get_winsize();
  1707. X#if defined(SIGWINCH)
  1708. X    signal(SIGWINCH, (void (*)())sig_winch);
  1709. X#endif
  1710. X}
  1711. X
  1712. X/*
  1713. X * Check_win checks whether we have an interactive window.
  1714. X * If not, a new window is opened with the newcli command.
  1715. X * If we would open a window ourselves, the :sh and :! commands would not
  1716. X * work properly (Why? probably because we are then running in a background CLI).
  1717. X * This also is the best way to assure proper working in a next Workbench release.
  1718. X *
  1719. X * For the -e option (quickfix mode) we open our own window and disable :sh.
  1720. X * Otherwise we would never know when editing is finished.
  1721. X */
  1722. X#define BUF2SIZE 320        /* lenght of buffer for argument with complete path */
  1723. X
  1724. X    void
  1725. Xcheck_win(argc, argv)
  1726. X    int        argc;
  1727. X    char    **argv;
  1728. X{
  1729. X    if (!isatty(0) || !isatty(1))
  1730. X    {
  1731. X        fprintf(stderr, "VIM: no controlling terminal\n");
  1732. X        exit(2);
  1733. X    }
  1734. X}
  1735. X
  1736. X/*
  1737. X * fname_case(): Set the case of the filename, if it already exists.
  1738. X *                 This will cause the filename to remain exactly the same.
  1739. X */
  1740. X    void
  1741. Xfname_case(name)
  1742. X    char_u *name;
  1743. X{
  1744. X}
  1745. X
  1746. X#ifdef USE_X11
  1747. X/*
  1748. X * try to get x11 window and display
  1749. X *
  1750. X * return FAIL for failure, OK otherwise
  1751. X */
  1752. X    static int
  1753. Xget_x11_windis()
  1754. X{
  1755. X    char        *winid;
  1756. X
  1757. X    /*
  1758. X     * If WINDOWID not set, should try another method to find out
  1759. X     * what the current window number is. The only code I know for
  1760. X     * this is very complicated.
  1761. X     * We assume that zero is invalid for WINDOWID.
  1762. X     */
  1763. X    if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL) 
  1764. X        x11_window = (Window)atol(winid);
  1765. X    if (x11_window != 0 && x11_display == NULL)
  1766. X        x11_display = XOpenDisplay(NULL);
  1767. X    if (x11_window == 0 || x11_display == NULL)
  1768. X        return FAIL;
  1769. X    return OK;
  1770. X}
  1771. X
  1772. X/*
  1773. X * Determine original x11 Window Title
  1774. X */
  1775. X    static void
  1776. Xget_x11_title()
  1777. X{
  1778. X    XTextProperty    text_prop;
  1779. X
  1780. X    if (get_x11_windis() == OK)
  1781. X    {
  1782. X            /* Get window name if any */
  1783. X        if (XGetWMName(x11_display, x11_window, &text_prop))
  1784. X        {
  1785. X            if (text_prop.value != NULL)
  1786. X                oldtitle = strsave((char_u *)text_prop.value);
  1787. X            XFree((void *)text_prop.value);
  1788. X        }
  1789. X    }
  1790. X    if (oldtitle == NULL)        /* could not get old title */
  1791. X        oldtitle = (char_u *)"Thanks for flying Vim";
  1792. X}
  1793. X
  1794. X/*
  1795. X * Determine original x11 Window icon
  1796. X */
  1797. X
  1798. X    static void
  1799. Xget_x11_icon()
  1800. X{
  1801. X    XTextProperty text_prop;
  1802. X
  1803. X    if (get_x11_windis() == OK)
  1804. X    {
  1805. X            /* Get icon name if any */
  1806. X        if (XGetWMIconName(x11_display, x11_window, &text_prop))
  1807. X        {
  1808. X            if (text_prop.value != NULL)
  1809. X                oldicon = strsave((char_u *)text_prop.value);
  1810. X            XFree((void *)text_prop.value);
  1811. X        }
  1812. X    }
  1813. X
  1814. X        /* could not get old icon, use terminal name */
  1815. X    if (oldicon == NULL)
  1816. X    {
  1817. X        if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
  1818. X            oldicon = term_strings.t_name + 8;
  1819. X        else
  1820. X            oldicon = term_strings.t_name;
  1821. X    }
  1822. X}
  1823. X
  1824. X#if BUGGY
  1825. X
  1826. XThis is not included, because it probably does not work at all.
  1827. XOn my FreeBSD/Xfree86 in a shelltool I get all kinds of error messages and
  1828. XVim is stopped in an uncontrolled way.
  1829. X
  1830. X/*
  1831. X * Set x11 Window Title
  1832. X *
  1833. X * get_x11_windis() must be called before this and have returned OK
  1834. X */
  1835. X    static void
  1836. Xset_x11_title(title)
  1837. X    char_u        *title;
  1838. X{
  1839. X    XTextProperty text_prop;
  1840. X
  1841. X        /* Get icon name if any */
  1842. X    text_prop.value = title;
  1843. X    text_prop.nitems = STRLEN(title);
  1844. X    XSetWMName(x11_display, x11_window, &text_prop);
  1845. X    if (XGetWMName(x11_display, x11_window, &text_prop))     /* required? */
  1846. X        XFree((void *)text_prop.value);
  1847. X}
  1848. X
  1849. X/*
  1850. X * Set x11 Window icon
  1851. X *
  1852. X * get_x11_windis() must be called before this and have returned OK
  1853. X */
  1854. X    static void
  1855. Xset_x11_icon(icon)
  1856. X    char_u        *icon;
  1857. X{
  1858. X    XTextProperty text_prop;
  1859. X
  1860. X        /* Get icon name if any */
  1861. X    text_prop.value = icon;
  1862. X    text_prop.nitems = STRLEN(icon);
  1863. X    XSetWMIconName(x11_display, x11_window, &text_prop);
  1864. X    if (XGetWMIconName(x11_display, x11_window, &text_prop)) /* required? */
  1865. X        XFree((void *)text_prop.value);
  1866. X}
  1867. X#endif
  1868. X
  1869. X#else    /* USE_X11 */
  1870. X
  1871. X    static void
  1872. Xget_x11_title()
  1873. X{
  1874. X    oldtitle = (char_u *)"Thanks for flying Vim";
  1875. X}
  1876. X
  1877. X    static void
  1878. Xget_x11_icon()
  1879. X{
  1880. X    if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
  1881. X        oldicon = term_strings.t_name + 8;
  1882. X    else
  1883. X        oldicon = term_strings.t_name;
  1884. X}
  1885. X
  1886. X#endif    /* USE_X11 */
  1887. X
  1888. X
  1889. X/*
  1890. X * set the window title and icon
  1891. X * Currently only works for x11.
  1892. X */
  1893. X    void
  1894. Xmch_settitle(title, icon)
  1895. X    char_u *title;
  1896. X    char_u *icon;
  1897. X{
  1898. X    int            type = 0;
  1899. X
  1900. X    if (term_strings.t_name == NULL)        /* no terminal name (yet) */
  1901. X        return;
  1902. X
  1903. X/*
  1904. X * if the window ID and the display is known, we may use X11 calls
  1905. X */
  1906. X#ifdef USE_X11
  1907. X    if (get_x11_windis() == OK)
  1908. X        type = 1;
  1909. X#endif
  1910. X
  1911. X    /*
  1912. X     * note: if terminal is xterm, title is set with escape sequence rather
  1913. X     *          than x11 calls, because the x11 calls don't always work
  1914. X     */
  1915. X    if (    STRCMP(term_strings.t_name, "xterm") == 0 ||
  1916. X            STRCMP(term_strings.t_name, "builtin_xterm") == 0)
  1917. X        type = 2;
  1918. X
  1919. X        /*
  1920. X         * Note: getting the old window title for iris-ansi will only
  1921. X         * currently work if you set WINDOWID by hand, it is not
  1922. X         * done automatically like an xterm.
  1923. X         */
  1924. X    if (STRCMP(term_strings.t_name, "iris-ansi") == 0 ||
  1925. X             STRCMP(term_strings.t_name, "iris-ansi-net") == 0)
  1926. X        type = 3;
  1927. X
  1928. X    if (type)
  1929. X    {
  1930. X        if (title != NULL)
  1931. X        {
  1932. X            if (oldtitle == NULL)                /* first call, save title */
  1933. X                get_x11_title();
  1934. X
  1935. X            switch(type)
  1936. X            {
  1937. X#ifdef USE_X11
  1938. X#ifdef BUGGY
  1939. X            case 1:    set_x11_title(title);                /* x11 */
  1940. X                    break;
  1941. X#endif
  1942. X#endif
  1943. X            case 2: outstrn((char_u *)"\033]2;");        /* xterm */
  1944. X                    outstrn(title);
  1945. X                    outchar(Ctrl('G'));
  1946. X                    flushbuf();
  1947. X                    break;
  1948. X
  1949. X            case 3: outstrn((char_u *)"\033P1.y");        /* iris-ansi */
  1950. X                    outstrn(title);
  1951. X                    outstrn((char_u *)"\234");
  1952. X                    flushbuf();
  1953. X                    break;
  1954. X            }
  1955. X        }
  1956. X
  1957. X        if (icon != NULL)
  1958. X        {
  1959. X            if (oldicon == NULL)                /* first call, save icon */
  1960. X                get_x11_icon();
  1961. X
  1962. X            switch(type)
  1963. X            {
  1964. X#ifdef USE_X11
  1965. X#ifdef BUGGY
  1966. X            case 1:    set_x11_icon(icon);                    /* x11 */
  1967. X                    break;
  1968. X#endif
  1969. X#endif
  1970. X            case 2: outstrn((char_u *)"\033]1;");        /* xterm */
  1971. X                    outstrn(icon);
  1972. X                    outchar(Ctrl('G'));
  1973. X                    flushbuf();
  1974. X                    break;
  1975. X
  1976. X            case 3: outstrn((char_u *)"\033P3.y");        /* iris-ansi */
  1977. X                    outstrn(icon);
  1978. X                    outstrn((char_u *)"\234");
  1979. X                    flushbuf();
  1980. X                    break;
  1981. X            }
  1982. X        }
  1983. X    }
  1984. X}
  1985. X
  1986. X/*
  1987. X * Restore the window/icon title.
  1988. X * which is one of:
  1989. X *    1  Just restore title
  1990. X *  2  Just restore icon
  1991. X *    3  Restore title and icon
  1992. X */
  1993. X    void
  1994. Xmch_restore_title(which)
  1995. X    int which;
  1996. X{
  1997. X    mch_settitle((which & 1) ? oldtitle : NULL, (which & 2) ? oldicon : NULL);
  1998. X}
  1999. X
  2000. X/*
  2001. X * Get name of current directory into buffer 'buf' of length 'len' bytes.
  2002. X * Return OK for success, FAIL for failure.
  2003. X */
  2004. X    int 
  2005. Xvim_dirname(buf, len)
  2006. X    char_u *buf;
  2007. X    int len;
  2008. X{
  2009. X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  2010. X    extern int        errno;
  2011. X    extern char        *sys_errlist[];
  2012. X
  2013. X    if (getcwd((char *)buf, len) == NULL)
  2014. X    {
  2015. X        STRCPY(buf, sys_errlist[errno]);
  2016. X        return FAIL;
  2017. X    }
  2018. X    return OK;
  2019. X#else
  2020. X    return (getwd((char *)buf) != NULL ? OK : FAIL);
  2021. X#endif
  2022. X}
  2023. X
  2024. X/*
  2025. X * get absolute filename into buffer 'buf' of length 'len' bytes
  2026. X *
  2027. X * return FAIL for failure, OK for success
  2028. X */
  2029. X    int 
  2030. XFullName(fname, buf, len)
  2031. X    char_u *fname, *buf;
  2032. X    int len;
  2033. X{
  2034. X    int        l;
  2035. X    char_u    olddir[MAXPATHL];
  2036. X    char_u    *p;
  2037. X    int        c;
  2038. X    int        retval = OK;
  2039. X
  2040. X    if (fname == NULL)    /* always fail */
  2041. X    {
  2042. X        *buf = NUL;
  2043. X        return FAIL;
  2044. X    }
  2045. X
  2046. X    *buf = 0;
  2047. X    if (!isFullName(fname))            /* if not an absolute path */
  2048. X    {
  2049. X        /*
  2050. X         * If the file name has a path, change to that directory for a moment,
  2051. X         * and then do the getwd() (and get back to where we were).
  2052. X         * This will get the correct path name with "../" things.
  2053. X         */
  2054. X        if ((p = STRRCHR(fname, '/')) != NULL)
  2055. X        {
  2056. X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  2057. X            if (getcwd((char *)olddir, MAXPATHL) == NULL)
  2058. X#else
  2059. X            if (getwd((char *)olddir) == NULL)
  2060. X#endif
  2061. X            {
  2062. X                p = NULL;        /* can't get current dir: don't chdir */
  2063. X                retval = FAIL;
  2064. X            }
  2065. X            else
  2066. X            {
  2067. X                c = *p;
  2068. X                *p = NUL;
  2069. X                if (chdir((char *)fname))
  2070. X                    retval = FAIL;
  2071. X                else
  2072. X                    fname = p + 1;
  2073. X                *p = c;
  2074. X            }
  2075. X        }
  2076. X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  2077. X        if (getcwd((char *)buf, len) == NULL)
  2078. X#else
  2079. X        if (getwd((char *)buf) == NULL)
  2080. X#endif
  2081. X        {
  2082. X            retval = FAIL;
  2083. X            *buf = NUL;
  2084. X        }
  2085. X        l = STRLEN(buf);
  2086. X        if (l && buf[l - 1] != '/')
  2087. X            STRCAT(buf, "/");
  2088. X        if (p)
  2089. X            chdir((char *)olddir);
  2090. X    }
  2091. X    STRCAT(buf, fname);
  2092. X    return retval;
  2093. X}
  2094. X
  2095. X/*
  2096. X * return TRUE is fname is an absolute path name
  2097. X */
  2098. X    int
  2099. XisFullName(fname)
  2100. X    char_u        *fname;
  2101. X{
  2102. X    return (*fname == '/');
  2103. X}
  2104. X
  2105. X/*
  2106. X * get file permissions for 'name'
  2107. X */
  2108. X    long 
  2109. Xgetperm(name)
  2110. X    char_u *name;
  2111. X{
  2112. X    struct stat statb;
  2113. X
  2114. X    if (stat((char *)name, &statb))
  2115. X        return -1;
  2116. X    return statb.st_mode;
  2117. X}
  2118. X
  2119. X/*
  2120. X * set file permission for 'name' to 'perm'
  2121. X *
  2122. X * return FAIL for failure, OK otherwise
  2123. X */
  2124. X    int
  2125. Xsetperm(name, perm)
  2126. X    char_u *name;
  2127. X    int perm;
  2128. X{
  2129. X#ifdef SCO
  2130. X    return (chmod((char *)name, (mode_t)perm) == 0 ? OK : FAIL);
  2131. X#else
  2132. X    return (chmod((char *)name, perm) == 0 ? OK : FAIL);
  2133. X#endif
  2134. X}
  2135. X
  2136. X/*
  2137. X * return TRUE if "name" is a directory
  2138. X * return FALSE if "name" is not a directory
  2139. X * return -1 for error
  2140. X */
  2141. X    int 
  2142. Xisdir(name)
  2143. X    char_u *name;
  2144. X{
  2145. X    struct stat statb;
  2146. X
  2147. X    if (stat((char *)name, &statb))
  2148. X        return -1;
  2149. X#ifdef _POSIX_SOURCE
  2150. X    return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
  2151. X#else
  2152. X    return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
  2153. X#endif
  2154. X}
  2155. X
  2156. X    void
  2157. Xmch_windexit(r)
  2158. X    int r;
  2159. X{
  2160. X    settmode(0);
  2161. X    exiting = TRUE;
  2162. X    mch_settitle(oldtitle, oldicon);    /* restore xterm title */
  2163. X    stoptermcap();
  2164. X    flushbuf();
  2165. X    ml_close_all();                 /* remove all memfiles */
  2166. X    exit(r);
  2167. X}
  2168. X
  2169. X    void
  2170. Xmch_settmode(raw)
  2171. X    int                raw;
  2172. X{
  2173. X#if defined(ECHOE) && defined(ICANON) && !defined(__NeXT__)
  2174. X    /* for "new" tty systems */
  2175. X# ifdef CONVEX
  2176. X    static struct termios told;
  2177. X           struct termios tnew;
  2178. X# else
  2179. X    static struct termio told;
  2180. X           struct termio tnew;
  2181. X# endif
  2182. X#ifdef TIOCLGET
  2183. X    static unsigned long tty_local;
  2184. X#endif
  2185. X
  2186. X    if (raw)
  2187. X    {
  2188. X#ifdef TIOCLGET
  2189. X        ioctl(0, TIOCLGET, &tty_local);
  2190. X#endif
  2191. X        ioctl(0, TCGETA, &told);
  2192. X        tnew = told;
  2193. X        /*
  2194. X         * ICRNL enables typing ^V^M
  2195. X         */
  2196. X        tnew.c_iflag &= ~ICRNL;
  2197. X        tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
  2198. X#ifdef IEXTEN
  2199. X                    | IEXTEN        /* IEXTEN enables typing ^V on SOLARIS */
  2200. X#endif
  2201. X                        );
  2202. X        tnew.c_cc[VMIN] = 1;            /* return after 1 char */
  2203. X        tnew.c_cc[VTIME] = 0;            /* don't wait */
  2204. X        ioctl(0, TCSETA, &tnew);
  2205. X    }
  2206. X    else
  2207. X    {
  2208. X        ioctl(0, TCSETA, &told);
  2209. X#ifdef TIOCLGET
  2210. X        ioctl(0, TIOCLSET, &tty_local);
  2211. X#endif
  2212. X    }
  2213. X#else
  2214. X# ifndef TIOCSETN
  2215. X#  define TIOCSETN TIOCSETP        /* for hpux 9.0 */
  2216. X# endif
  2217. X    /* for "old" tty systems */
  2218. X    static struct sgttyb ttybold;
  2219. X           struct sgttyb ttybnew;
  2220. X
  2221. X    if (raw)
  2222. X    {
  2223. X        ioctl(0, TIOCGETP, &ttybold);
  2224. X        ttybnew = ttybold;
  2225. X        ttybnew.sg_flags &= ~(CRMOD | ECHO);
  2226. X        ttybnew.sg_flags |= RAW;
  2227. X        ioctl(0, TIOCSETN, &ttybnew);
  2228. X    }
  2229. X    else
  2230. X        ioctl(0, TIOCSETN, &ttybold);
  2231. X#endif
  2232. X}
  2233. X
  2234. X/*
  2235. X * set screen mode, always fails.
  2236. X */
  2237. X    int
  2238. Xmch_screenmode(arg)
  2239. X    char_u     *arg;
  2240. X{
  2241. X    EMSG("Screen mode setting not supported");
  2242. X    return FAIL;
  2243. X}
  2244. X
  2245. X/*
  2246. X * Try to get the current window size:
  2247. X * 1. with an ioctl(), most accurate method
  2248. X * 2. from the environment variables LINES and COLUMNS
  2249. X * 3. from the termcap
  2250. X * 4. keep using the old values
  2251. X */
  2252. X    int
  2253. Xmch_get_winsize()
  2254. X{
  2255. X    int            old_Rows = Rows;
  2256. X    int            old_Columns = Columns;
  2257. X    char_u        *p;
  2258. X
  2259. X    Columns = 0;
  2260. X    Rows = 0;
  2261. X
  2262. X/*
  2263. X * 1. try using an ioctl. It is the most accurate method.
  2264. X */
  2265. X# ifdef TIOCGSIZE
  2266. X    {
  2267. X        struct ttysize    ts;
  2268. X
  2269. X        if (ioctl(0, TIOCGSIZE, &ts) == 0)
  2270. X        {
  2271. X            Columns = ts.ts_cols;
  2272. X            Rows = ts.ts_lines;
  2273. X        }
  2274. X    }
  2275. X# else /* TIOCGSIZE */
  2276. X#  ifdef TIOCGWINSZ
  2277. X    {
  2278. X        struct winsize    ws;
  2279. X
  2280. X        if (ioctl(0, TIOCGWINSZ, &ws) == 0)
  2281. X        {
  2282. X            Columns = ws.ws_col;
  2283. X            Rows = ws.ws_row;
  2284. X        }
  2285. X    }
  2286. X#  endif /* TIOCGWINSZ */
  2287. X# endif /* TIOCGSIZE */
  2288. X
  2289. X/*
  2290. X * 2. get size from environment
  2291. X */
  2292. X    if (Columns == 0 || Rows == 0)
  2293. X    {
  2294. X        if ((p = (char_u *)getenv("LINES")))
  2295. X            Rows = atoi((char *)p);
  2296. X        if ((p = (char_u *)getenv("COLUMNS")))
  2297. X            Columns = atoi((char *)p);
  2298. X    }
  2299. X
  2300. X#ifdef TERMCAP
  2301. X/*
  2302. X * 3. try reading the termcap
  2303. X */
  2304. X    if (Columns == 0 || Rows == 0)
  2305. X    {
  2306. X        extern void getlinecol();
  2307. X
  2308. X        getlinecol();    /* get "co" and "li" entries from termcap */
  2309. X    }
  2310. X#endif
  2311. X
  2312. X/*
  2313. X * 4. If everything fails, use the old values
  2314. X */
  2315. X    if (Columns <= 0 || Rows <= 0)
  2316. X    {
  2317. X        Columns = old_Columns;
  2318. X        Rows = old_Rows;
  2319. X        return FAIL;
  2320. X    }
  2321. X
  2322. X    check_winsize();
  2323. X
  2324. X/* if size changed: screenalloc will allocate new screen buffers */
  2325. X    return OK;
  2326. X}
  2327. X
  2328. X    void
  2329. Xmch_set_winsize()
  2330. X{
  2331. X    /* should try to set the window size to Rows and Columns */
  2332. X}
  2333. X
  2334. X    int 
  2335. Xcall_shell(cmd, dummy, cooked)
  2336. X    char_u    *cmd;
  2337. X    int        dummy;
  2338. X    int        cooked;
  2339. X{
  2340. X#ifdef USE_SYSTEM        /* use system() to start the shell: simple but slow */
  2341. X
  2342. X    int        x;
  2343. X    char_u    newcmd[1024];
  2344. X
  2345. X    flushbuf();
  2346. X
  2347. X    if (cooked)
  2348. X        settmode(0);                 /* set to cooked mode */
  2349. X
  2350. X    if (cmd == NULL)
  2351. X        x = system(p_sh);
  2352. X    else
  2353. X    {
  2354. X        sprintf(newcmd, "%s %s -c \"%s\"", p_sh,
  2355. X                        extra_shell_arg == NULL ? "" : extra_shell_arg, cmd);
  2356. X        x = system(newcmd);
  2357. X    }
  2358. X    if (x == 127)
  2359. X    {
  2360. X        outstrn((char_u *)"\nCannot execute shell sh\n");
  2361. X    }
  2362. X#ifdef WEBB_COMPLETE
  2363. X    else if (x && !expand_interactively)
  2364. X#else
  2365. X    else if (x)
  2366. X#endif
  2367. X    {
  2368. X        outchar('\n');
  2369. X        outnum((long)x);
  2370. X        outstrn((char_u *)" returned\n");
  2371. X    }
  2372. X
  2373. X    if (cooked)
  2374. X        settmode(1);                         /* set to raw mode */
  2375. X    resettitle();
  2376. X    return (x ? FAIL : OK);
  2377. X
  2378. X#else /* USE_SYSTEM */        /* first attempt at not using system() */
  2379. X
  2380. X    char_u    newcmd[1024];
  2381. X    int        pid;
  2382. X    int        status = -1;
  2383. X    char    **argv = NULL;
  2384. X    int        argc;
  2385. X    int        i;
  2386. X    char_u    *p;
  2387. X    int        inquote;
  2388. X
  2389. X    flushbuf();
  2390. X    signal(SIGINT, SIG_IGN);    /* we don't want to be killed here */
  2391. X    if (cooked)
  2392. X        settmode(0);            /* set to cooked mode */
  2393. X
  2394. X    /*
  2395. X     * 1: find number of arguments
  2396. X     * 2: separate them and built argv[]
  2397. X     */
  2398. X    STRCPY(newcmd, p_sh);
  2399. X    for (i = 0; i < 2; ++i)    
  2400. X    {
  2401. X        p = newcmd;
  2402. X        inquote = FALSE;
  2403. X        argc = 0;
  2404. X        for (;;)
  2405. X        {
  2406. X            if (i == 1)
  2407. X                argv[argc] = (char *)p;
  2408. X            ++argc;
  2409. X            while (*p && (inquote || (*p != ' ' && *p != TAB)))
  2410. X            {
  2411. X                if (*p == '"')
  2412. X                    inquote = !inquote;
  2413. X                ++p;
  2414. X            }
  2415. X            if (*p == NUL)
  2416. X                break;
  2417. X            if (i == 1)
  2418. X                *p++ = NUL;
  2419. X            skipspace(&p);
  2420. X        }
  2421. X        if (i == 0)
  2422. X        {
  2423. X            argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
  2424. X            if (argv == NULL)        /* out of memory */
  2425. X                goto error;
  2426. X        }
  2427. X    }
  2428. X    if (cmd != NULL)
  2429. X    {
  2430. X        if (extra_shell_arg != NULL)
  2431. X            argv[argc++] = (char *)extra_shell_arg;
  2432. X        argv[argc++] = "-c";
  2433. X        argv[argc++] = (char *)cmd;
  2434. X    }
  2435. X    argv[argc] = NULL;
  2436. X
  2437. X    if ((pid = fork()) == -1)        /* maybe we should use vfork() */
  2438. X    {
  2439. X        outstrn((char_u *)"\nCannot fork\n");
  2440. X    }
  2441. X    else if (pid == 0)        /* child */
  2442. X    {
  2443. X        signal(SIGINT, SIG_DFL);
  2444. X        if (!show_shell_mess)
  2445. X        {
  2446. X            fclose(stdout);
  2447. X            fclose(stderr);
  2448. X        }
  2449. X        execvp(argv[0], (char **)argv);
  2450. X        exit(127);            /* exec failed, return failure code */
  2451. X    }
  2452. X    else                    /* parent */
  2453. X    {
  2454. X        wait(&status);
  2455. X        status = (status >> 8) & 255;
  2456. X        if (status)
  2457. X        {
  2458. X#ifdef WEBB_COMPLETE
  2459. X            if (status == 127)
  2460. X            {
  2461. X                outstrn((char_u *)"\nCannot execute shell ");
  2462. X                outstrn(p_sh);
  2463. X                outchar('\n');
  2464. X            }
  2465. X            else if (!expand_interactively)
  2466. X            {
  2467. X                outchar('\n');
  2468. X                outnum((long)status);
  2469. X                outstrn((char_u *)" returned\n");
  2470. X            }
  2471. X#else
  2472. X            outchar('\n');
  2473. X            if (status == 127)
  2474. X            {
  2475. X                outstrn((char_u *)"Cannot execute shell ");
  2476. X                outstrn(p_sh);
  2477. X            }
  2478. X            else
  2479. X            {
  2480. X                outnum((long)status);
  2481. X                outstrn((char_u *)" returned");
  2482. X            }
  2483. X            outchar('\n');
  2484. X#endif /* WEBB_COMPLETE */
  2485. X        }
  2486. X    }
  2487. X    free(argv);
  2488. X
  2489. Xerror:
  2490. X    if (cooked)
  2491. X        settmode(1);                         /* set to raw mode */
  2492. X    resettitle();
  2493. X    signal(SIGINT, SIG_DFL);
  2494. X    return (status ? FAIL : OK);
  2495. X
  2496. X#endif /* USE_SYSTEM */
  2497. X}
  2498. X
  2499. X/*
  2500. X * The input characters are buffered to be able to check for a CTRL-C.
  2501. X * This should be done with signals, but I don't know how to do that in
  2502. X * a portable way for a tty in RAW mode.
  2503. X */
  2504. X
  2505. X#define INBUFLEN 250
  2506. Xstatic char_u        inbuf[INBUFLEN];    /* internal typeahead buffer */
  2507. Xstatic int        inbufcount = 0;        /* number of chars in inbuf[] */
  2508. X
  2509. X    static int
  2510. XRead(buf, maxlen)
  2511. X    char_u    *buf;
  2512. X    long    maxlen;
  2513. X{
  2514. X    if (inbufcount == 0)        /* if the buffer is empty, fill it */
  2515. X        fill_inbuf();
  2516. X    if (maxlen > inbufcount)
  2517. X        maxlen = inbufcount;
  2518. X    memmove((char *)buf, (char *)inbuf, maxlen);
  2519. X    inbufcount -= maxlen;
  2520. X    if (inbufcount)
  2521. X        memmove((char *)inbuf, (char *)inbuf + maxlen, inbufcount);
  2522. X    return (int)maxlen;
  2523. X}
  2524. X
  2525. X    void
  2526. Xbreakcheck()
  2527. X{
  2528. X/*
  2529. X * check for CTRL-C typed by reading all available characters
  2530. X */
  2531. X    if (RealWaitForChar(0))        /* if characters available */
  2532. X        fill_inbuf();
  2533. X}
  2534. X
  2535. X    static void
  2536. Xfill_inbuf()
  2537. X{
  2538. X    int        len;
  2539. X
  2540. X    if (inbufcount >= INBUFLEN)        /* buffer full */
  2541. X        return;
  2542. X    len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
  2543. X    if (len <= 0)    /* cannot read input??? */
  2544. X    {
  2545. X        fprintf(stderr, "Vim: Error reading input, exiting...\n");
  2546. X        exit(1);
  2547. X    }
  2548. X    while (len-- > 0)
  2549. X    {
  2550. X        /*
  2551. X         * if a CTRL-C was typed, remove it from the buffer and set got_int
  2552. X         */
  2553. X        if (inbuf[inbufcount] == 3)
  2554. X        {
  2555. X            /* remove everything typed before the CTRL-C */
  2556. X            memmove((char *)inbuf, (char *)inbuf + inbufcount, len + 1);
  2557. X            inbufcount = 0;
  2558. X            got_int = TRUE;
  2559. X        }
  2560. X        ++inbufcount;
  2561. X    }
  2562. X}
  2563. X
  2564. X/* 
  2565. X * Wait "ticks" until a character is available from the keyboard or from inbuf[]
  2566. X * ticks = -1 will block forever
  2567. X */
  2568. X
  2569. X    static int
  2570. XWaitForChar(ticks)
  2571. X    int ticks;
  2572. X{
  2573. X    if (inbufcount)        /* something in inbuf[] */
  2574. X        return 1;
  2575. X    return RealWaitForChar(ticks);
  2576. X}
  2577. X
  2578. X/* 
  2579. X * Wait "ticks" until a character is available from the keyboard
  2580. X * ticks = -1 will block forever
  2581. X */
  2582. X    static int
  2583. XRealWaitForChar(ticks)
  2584. X    int ticks;
  2585. X{
  2586. X#ifndef FD_ZERO
  2587. X    struct pollfd fds;
  2588. X
  2589. X    fds.fd = 0;
  2590. X    fds.events = POLLIN;
  2591. X    return (poll(&fds, 1, ticks));
  2592. X#else
  2593. X    struct timeval tv;
  2594. X    fd_set fdset;
  2595. X
  2596. X    if (ticks >= 0)
  2597. X    {
  2598. X           tv.tv_sec = ticks / 1000;
  2599. X        tv.tv_usec = (ticks % 1000) * (1000000/1000);
  2600. X    }
  2601. X
  2602. X    FD_ZERO(&fdset);
  2603. X    FD_SET(0, &fdset);
  2604. X    return (select(1, &fdset, NULL, NULL, (ticks >= 0) ? &tv : NULL));
  2605. X#endif
  2606. X}
  2607. X
  2608. X#if !defined(__alpha) && !defined(mips) && !defined(SCO) && !defined(remove) && !defined(CONVEX)
  2609. X    int 
  2610. Xremove(buf)
  2611. X# if defined(linux) || defined(__STDC__) || defined(__NeXT__) || defined(M_UNIX)
  2612. X    const
  2613. X# endif
  2614. X            char *buf;
  2615. X{
  2616. X    return unlink(buf);
  2617. X}
  2618. X#endif
  2619. X
  2620. X/*
  2621. X * ExpandWildCard() - this code does wild-card pattern matching using the shell
  2622. X *
  2623. X * Mool: return 0 for success, 1 for error (you may loose some memory) and
  2624. X *       put an error message in *file.
  2625. X *
  2626. X * num_pat is number of input patterns
  2627. X * pat is array of pointers to input patterns
  2628. X * num_file is pointer to number of matched file names
  2629. X * file is pointer to array of pointers to matched file names
  2630. X * On Unix we do not check for files only yet
  2631. X * list_notfound is ignored
  2632. X */
  2633. X
  2634. Xextern char *mktemp __ARGS((char *));
  2635. X#ifndef SEEK_SET
  2636. X# define SEEK_SET 0
  2637. X#endif
  2638. X#ifndef SEEK_END
  2639. X# define SEEK_END 2
  2640. X#endif
  2641. X
  2642. X    int
  2643. XExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  2644. X    int             num_pat;
  2645. X    char_u          **pat;
  2646. X    int            *num_file;
  2647. X    char_u         ***file;
  2648. X    int                files_only;
  2649. X    int                list_notfound;
  2650. X{
  2651. X    char_u    tmpname[TMPNAMELEN];
  2652. X    char_u    *command;
  2653. X    int        i;
  2654. X    int        dir;
  2655. X    size_t    len;
  2656. X    FILE    *fd;
  2657. X    char_u    *buffer;
  2658. X    char_u    *p;
  2659. X    int        use_glob = FALSE;
  2660. X
  2661. X    *num_file = 0;        /* default: no files found */
  2662. X    *file = (char_u **)"";
  2663. X
  2664. X    /*
  2665. X     * If there are no wildcards, just copy the names to allocated memory.
  2666. X     * Saves a lot of time, because we don't have to start a new shell.
  2667. X     */
  2668. X    if (!have_wildcard(num_pat, pat))
  2669. X    {
  2670. X        *file = (char_u **)alloc(num_pat * sizeof(char_u *));
  2671. X        if (*file == NULL)
  2672. X        {
  2673. X            *file = (char_u **)"";
  2674. X            return FAIL;
  2675. X        }
  2676. X        for (i = 0; i < num_pat; i++)
  2677. X            (*file)[i] = strsave(pat[i]);
  2678. X        *num_file = num_pat;
  2679. X        return OK;
  2680. X    }
  2681. X
  2682. X/*
  2683. X * get a name for the temp file
  2684. X */
  2685. X    STRCPY(tmpname, TMPNAME2);
  2686. X    if (*mktemp((char *)tmpname) == NUL)
  2687. X    {
  2688. X        emsg(e_notmp);
  2689. X        return FAIL;
  2690. X    }
  2691. X
  2692. X/*
  2693. X * let the shell expand the patterns and write the result into the temp file
  2694. X * If we use csh, glob will work better than echo.
  2695. X */
  2696. X    if ((len = STRLEN(p_sh)) >= 3 && STRCMP(p_sh + len - 3, "csh") == 0)
  2697. X        use_glob = TRUE;
  2698. X
  2699. X    len = TMPNAMELEN + 11;
  2700. X    for (i = 0; i < num_pat; ++i)        /* count the length of the patterns */
  2701. X        len += STRLEN(pat[i]) + 3;
  2702. X    command = alloc(len);
  2703. X    if (command == NULL)
  2704. X        return FAIL;
  2705. X    if (use_glob)
  2706. X        STRCPY(command, "glob >");        /* built the shell command */
  2707. X    else
  2708. X        STRCPY(command, "echo >");        /* built the shell command */
  2709. X    STRCAT(command, tmpname);
  2710. X    for (i = 0; i < num_pat; ++i)
  2711. X    {
  2712. X#ifdef USE_SYSTEM
  2713. X        STRCAT(command, " \"");                /* need extra quotes because we */
  2714. X        STRCAT(command, pat[i]);            /*   start the shell twice */
  2715. X        STRCAT(command, "\"");
  2716. X#else
  2717. X        STRCAT(command, " ");
  2718. X        STRCAT(command, pat[i]);
  2719. X#endif
  2720. X    }
  2721. X#ifdef WEBB_COMPLETE
  2722. X    if (expand_interactively)
  2723. X        show_shell_mess = FALSE;
  2724. X#endif /* WEBB_COMPLETE */
  2725. X    if (use_glob)                            /* Use csh fast option */
  2726. X        extra_shell_arg = (char_u *)"-f";
  2727. X    i = call_shell(command, 0, FALSE);        /* execute it */
  2728. X    extra_shell_arg = NULL;
  2729. X    show_shell_mess = TRUE;
  2730. X    free(command);
  2731. X    if (i == FAIL)                            /* call_shell failed */
  2732. X    {
  2733. X        remove((char *)tmpname);
  2734. X#ifdef WEBB_COMPLETE
  2735. X        /* With interactive completion, the error message is not printed */
  2736. X        if (!expand_interactively)
  2737. X#endif /* WEBB_COMPLETE */
  2738. X        {
  2739. X            must_redraw = CLEAR;            /* probably messed up screen */
  2740. X            msg_outchar('\n');                /* clear bottom line quickly */
  2741. X            cmdline_row = Rows - 1;            /* continue on last line */
  2742. X        }
  2743. X        return FAIL;
  2744. X    }
  2745. X
  2746. X/*
  2747. X * read the names from the file into memory
  2748. X */
  2749. X     fd = fopen((char *)tmpname, "r");
  2750. X    if (fd == NULL)
  2751. X    {
  2752. X        emsg2(e_notopen, tmpname);
  2753. X        return FAIL;
  2754. X    }
  2755. X    fseek(fd, 0L, SEEK_END);
  2756. X    len = ftell(fd);                /* get size of temp file */
  2757. X    fseek(fd, 0L, SEEK_SET);
  2758. X    buffer = alloc(len + 1);
  2759. X    if (buffer == NULL)
  2760. X    {
  2761. X        remove((char *)tmpname);
  2762. X        fclose(fd);
  2763. X        return FAIL;
  2764. X    }
  2765. X    i = fread((char *)buffer, 1, len, fd);
  2766. X    fclose(fd);
  2767. X    remove((char *)tmpname);
  2768. X    if (i != len)
  2769. X    {
  2770. X        emsg2(e_notread, tmpname);
  2771. X        free(buffer);
  2772. X        return FAIL;
  2773. X    }
  2774. X
  2775. X    if (use_glob)        /* file names are separated with NUL */
  2776. X    {
  2777. X        buffer[len] = NUL;                    /* make sure the buffers ends in NUL */
  2778. X        i = 0;
  2779. X        for (p = buffer; p < buffer + len; ++p)
  2780. X            if (*p == NUL)                    /* count entry */
  2781. X                ++i;
  2782. X        if (len)
  2783. X            ++i;                            /* count last entry */
  2784. X    }
  2785. X    else                /* file names are separated with SPACE */
  2786. X    {
  2787. X        buffer[len] = '\n';                    /* make sure the buffers ends in NL */
  2788. X        p = buffer;
  2789. X        for (i = 0; *p != '\n'; ++i)        /* count number of entries */
  2790. X        {
  2791. X            while (*p != ' ' && *p != '\n')    /* skip entry */
  2792. X                ++p;
  2793. X            skipspace(&p);                    /* skip to next entry */
  2794. X        }
  2795. X    }
  2796. X    *num_file = i;
  2797. X    *file = (char_u **)alloc(sizeof(char_u *) * i);
  2798. X    if (*file == NULL)
  2799. X    {
  2800. X        free(buffer);
  2801. X        *file = (char_u **)"";
  2802. X        return FAIL;
  2803. X    }
  2804. X    p = buffer;
  2805. X    for (i = 0; i < *num_file; ++i)
  2806. X    {
  2807. X        (*file)[i] = p;
  2808. X        if (use_glob)
  2809. X        {
  2810. X            while (*p && p < buffer + len)        /* skip entry */
  2811. X                ++p;
  2812. X            ++p;                                /* skip NUL */
  2813. X        }
  2814. X        else
  2815. X        {
  2816. X            while (*p != ' ' && *p != '\n')        /* skip entry */
  2817. X                ++p;
  2818. X            if (*p == '\n')                        /* last entry */
  2819. X                *p = NUL;
  2820. X            else
  2821. X            {
  2822. X                *p++ = NUL;
  2823. X                skipspace(&p);                    /* skip to next entry */
  2824. X            }
  2825. X        }
  2826. X    }
  2827. X    for (i = 0; i < *num_file; ++i)
  2828. X    {
  2829. X        dir = (isdir((*file)[i]) == TRUE);
  2830. X        if (dir < 0)            /* if file doesn't exist don't add '/' */
  2831. X            dir = 0;
  2832. X        p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
  2833. X        if (p)
  2834. X        {
  2835. X            STRCPY(p, (*file)[i]);
  2836. X            if (dir)
  2837. X                STRCAT(p, "/");
  2838. X        }
  2839. X        (*file)[i] = p;
  2840. X    }
  2841. X    free(buffer);
  2842. X    return OK;
  2843. X}
  2844. X
  2845. X    void
  2846. XFreeWild(num, file)
  2847. X    int        num;
  2848. X    char_u    **file;
  2849. X{
  2850. X    if (file == NULL || num == 0)
  2851. X        return;
  2852. X    while (num--)
  2853. X        free(file[num]);
  2854. X    free(file);
  2855. X}
  2856. X
  2857. X    int
  2858. Xhas_wildcard(p)
  2859. X    char_u *p;
  2860. X{
  2861. X#ifdef __STDC__
  2862. X    return strpbrk((char *)p, "*?[{`~$") != NULL;
  2863. X#else
  2864. X    for ( ; *p; ++p)
  2865. X        if (STRCHR("*?[{`~$", *p) != NULL)
  2866. X            return 1;
  2867. X    return 0;
  2868. X#endif
  2869. X}
  2870. X
  2871. X    int
  2872. Xhave_wildcard(num, file)
  2873. X    int        num;
  2874. X    char_u    **file;
  2875. X{
  2876. X    register int i;
  2877. X
  2878. X    for (i = 0; i < num; i++)
  2879. X        if (has_wildcard(file[i]))
  2880. X            return 1;
  2881. X    return 0;
  2882. X}
  2883. X
  2884. X#if defined(M_XENIX) || defined(UTS2)
  2885. X/*
  2886. X * Scaled-down version of rename, which is missing in Xenix.
  2887. X * This version can only move regular files and will fail if the
  2888. X * destination exists.
  2889. X */
  2890. X    int
  2891. Xrename(src, dest)
  2892. X    char_u *src, *dest;
  2893. X{
  2894. X    struct stat        st;
  2895. X
  2896. X    if (stat(dest, &st) >= 0)    /* fail if destination exists */
  2897. X        return -1;
  2898. X    if (link(src, dest) != 0)    /* link file to new name */
  2899. X        return -1;
  2900. X    if (unlink(src) == 0)        /* delete link to old name */
  2901. X        return 0;
  2902. X    return -1;
  2903. X}
  2904. X#endif /* M_XENIX || UTS2 */
  2905. END_OF_FILE
  2906.   if test 30140 -ne `wc -c <'vim/src/unix.c'`; then
  2907.     echo shar: \"'vim/src/unix.c'\" unpacked with wrong size!
  2908.   fi
  2909.   # end of 'vim/src/unix.c'
  2910. fi
  2911. if test -f 'vim/tools/readme' -a "${1}" != "-c" ; then 
  2912.   echo shar: Will not clobber existing file \"'vim/tools/readme'\"
  2913. else
  2914.   echo shar: Extracting \"'vim/tools/readme'\" \(153 characters\)
  2915.   sed "s/^X//" >'vim/tools/readme' <<'END_OF_FILE'
  2916. XSome tools that can be used with Vim:
  2917. X
  2918. Xvim132: shell script to edit in 132 column mode on vt100 compatible terminals
  2919. Xref:    shell script for the K command
  2920. END_OF_FILE
  2921.   if test 153 -ne `wc -c <'vim/tools/readme'`; then
  2922.     echo shar: \"'vim/tools/readme'\" unpacked with wrong size!
  2923.   fi
  2924.   # end of 'vim/tools/readme'
  2925. fi
  2926. if test -f 'vim/uganda.txt' -a "${1}" != "-c" ; then 
  2927.   echo shar: Will not clobber existing file \"'vim/uganda.txt'\"
  2928. else
  2929.   echo shar: Extracting \"'vim/uganda.txt'\" \(3139 characters\)
  2930.   sed "s/^X//" >'vim/uganda.txt' <<'END_OF_FILE'
  2931. XVim is public domain. If you are happy with Vim and want to express that,
  2932. Xdon't send me money. I don't need it. But I know a place where they do need
  2933. Xyour money. Please read on.
  2934. X
  2935. XSummer 1993 I spent one month in Uganda with a Dutch team. I was very
  2936. Ximpressed with what I experienced there. Together with local people we built a
  2937. Xnursery school in Kibaale. In only three weeks from nothing to a roofed
  2938. Xbuilding!
  2939. X
  2940. XKibaale is a small town in the south of Uganda. It is an area that is suffering
  2941. Xfrom AIDS very badly. About 30% of the adults are infected. Because parents
  2942. Xdie, there are many orphans. They need a lot of help. The Kibaale children
  2943. Xcentre is working hard to provide the needy with food, medical care and
  2944. Xeducation. Food and medical care to keep them healthy now, and education so
  2945. Xthat they can take care of themselves in the future. This is the best charity
  2946. Xprogram I have ever encountered.
  2947. X
  2948. XThe key to solving the problems in this area is education. This has been
  2949. Xneglected in the past years with president Idi Amin and the following civil
  2950. Xwars. Now that the governement is stable again the people have to learn how to
  2951. Xtake care of themselves and how to avoid infections. There is also help for
  2952. Xpeople who are ill and hungry, but the primary goal is to prevent people from
  2953. Xgetting ill and learn them how to grow their own crops.
  2954. X
  2955. XI was impressed by the progress that is being made there. The work is very
  2956. Xwell organized. Every dollar is spent on something useful. Our team brought
  2957. Xabout $2000. For that money we were able to built most of a two classroom
  2958. Xnursery school. They have further plans to build a primary school and houses
  2959. Xfor the teachers. They also need money for books and other teaching materials.
  2960. X
  2961. XIf you want to support the Kibaale children centre, please send a contribution.
  2962. X
  2963. XHow do you know that the money will be spent right? First of all you have my
  2964. Xpersonal guarantee as the author of Vim. Further the project is co-sponsored
  2965. Xand inspected by World Vision, Save the Children Fund and International Child
  2966. XCare Fund. I will work for the project as a volunteer from September 1994 to
  2967. XAugust 1995.
  2968. X
  2969. XIf you have any further questions, send me e-mail: mool@oce.nl.
  2970. X
  2971. XThe director of the project is:
  2972. XSekaran Vellasamy
  2973. Xp.o. box 1658
  2974. XMasaka, Uganda, East Africa
  2975. X
  2976. XTransfering money from Holland:
  2977. XUse one of my accounts:
  2978. XRabobank Venlo, nr. 3765.05.117
  2979. XPostbank, nr. 1644503
  2980. X
  2981. XTransfering money from Europe:
  2982. XTo avoid banking costs the best thing is to send me a Eurocheque, written out
  2983. Xto "Bram Moolenaar" in Dutch Guilders (fl). But any other method should work.
  2984. X
  2985. XTransfering money from USA:
  2986. XSend me a check that can be cashed in Holland. Any "standard" banking check
  2987. Xshould be OK. Please consider adding $10 for banking costs.
  2988. X
  2989. XMy address: Bram Moolenaar
  2990. X        Kibaale Donation
  2991. X            Molenstraat 2
  2992. X            2162 HP  Lisse
  2993. X            The Netherlands. 
  2994. X
  2995. XOr you can transfer the money directly to the director of the project:
  2996. X
  2997. XCitibank, N.A.
  2998. Xa/c no. 36059709
  2999. XGlobal Clearance Services
  3000. X111 Wall Street 16th floor
  3001. XNew York 10043
  3002. XU.S.A.
  3003. XBeneficiary Mr. Sekaran Vellasamy a/c no. 2100, Gold Trust Bank LTD - Kampala
  3004. END_OF_FILE
  3005.   if test 3139 -ne `wc -c <'vim/uganda.txt'`; then
  3006.     echo shar: \"'vim/uganda.txt'\" unpacked with wrong size!
  3007.   fi
  3008.   # end of 'vim/uganda.txt'
  3009. fi
  3010. echo shar: End of archive 18 \(of 26\).
  3011. cp /dev/null ark18isdone
  3012. MISSING=""
  3013. 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
  3014.     if test ! -f ark${I}isdone ; then
  3015.     MISSING="${MISSING} ${I}"
  3016.     fi
  3017. done
  3018. if test "${MISSING}" = "" ; then
  3019.     echo You have unpacked all 26 archives.
  3020.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3021. else
  3022.     echo You still must unpack the following archives:
  3023.     echo "        " ${MISSING}
  3024. fi
  3025. exit 0
  3026. exit 0 # Just in case...
  3027.