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

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v37i005:  vim - Vi IMitation editor v1.27, Part05/24
  4. Message-ID: <1993Apr23.172958.16246@sparky.imd.sterling.com>
  5. X-Md4-Signature: 29aa58ecfce17becb2bc0bc68a07ef7a
  6. Date: Fri, 23 Apr 1993 17:29:58 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mool@oce.nl (Bram Moolenaar)
  10. Posting-number: Volume 37, Issue 5
  11. Archive-name: vim/part05
  12. Environment: UNIX, AMIGA, MS-DOS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 5 (of 23)."
  21. # Contents:  vim/src/csearch.c vim/src/main.c vim/src/mark.c
  22. #   vim/src/script.c vim/src/tag.c
  23. # Wrapped by mool@oce-rd2 on Mon Apr 19 15:50:07 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'vim/src/csearch.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'vim/src/csearch.c'\"
  27. else
  28. echo shar: Extracting \"'vim/src/csearch.c'\" \(9336 characters\)
  29. sed "s/^X//" >'vim/src/csearch.c' <<'END_OF_FILE'
  30. X/* vi:ts=4:sw=4
  31. X *
  32. X * VIM - Vi IMitation
  33. X *
  34. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  35. X *                            Tim Thompson            twitch!tjt
  36. X *                            Tony Andrews            onecom!wldrdg!tony
  37. X *                            G. R. (Fred) Walter     watmath!watcgl!grwalter
  38. X */
  39. X
  40. X/*
  41. X *
  42. X * csearch.c: command line searching commands
  43. X */
  44. X
  45. X#include "vim.h"
  46. X#include "globals.h"
  47. X#include "proto.h"
  48. X#include "param.h"
  49. X
  50. X/* we use modified Henry Spencer's regular expression routines */
  51. X#include "regexp.h"
  52. X
  53. Xint global_busy = 0;            /* set to 1 if global busy, 2 if global has
  54. X                                    been called during a global command */
  55. Xint global_wait;                /* set to 1 if wait_return has to be called
  56. X                                    after global command */
  57. Xextern regexp *myregcomp __ARGS((char *));
  58. X
  59. X/* dosub(lp, up, cmd)
  60. X *
  61. X * Perform a substitution from line 'lp' to line 'up' using the
  62. X * command pointed to by 'cmd' which should be of the form:
  63. X *
  64. X * /pattern/substitution/gc
  65. X *
  66. X * The trailing 'g' is optional and, if present, indicates that multiple
  67. X * substitutions should be performed on each line, if applicable.
  68. X * The trailing 'c' is optional and, if present, indicates that a confirmation
  69. X * will be asked for each replacement.
  70. X * The usual escapes are supported as described in the regexp docs.
  71. X */
  72. X
  73. Xextern char *reg_prev_sub;        /* this is in regexp.c */
  74. X
  75. X    void
  76. Xdosub(lp, up, cmd, nextcommand)
  77. X    linenr_t    lp;
  78. X    linenr_t    up;
  79. X    char        *cmd;
  80. X    u_char        **nextcommand;
  81. X{
  82. X    linenr_t        lnum;
  83. X    long            i;
  84. X    char           *ptr;
  85. X    regexp           *prog;
  86. X    long            nsubs = 0;
  87. X    linenr_t        nlines = 0;
  88. X    int                do_all;         /* do multiple substitutions per line */
  89. X    int                do_ask;         /* ask for confirmation */
  90. X    char           *pat, *sub = NULL;
  91. X    static char    *old_sub = NULL;
  92. X    int             delimiter;
  93. X    int             sublen;
  94. X
  95. X    if (strchr("0123456789gc|\"#", *cmd) == NULL)       /* new pattern and substitution */
  96. X    {
  97. X        delimiter = *cmd++;            /* remember delimiter character */
  98. X        pat = cmd;                    /* remember the start of the regexp */
  99. X
  100. X        /*
  101. X         * do the next loop twice:
  102. X         *  i == 0: find the end of the regexp
  103. X         *  i == 1: find the end of the substitution
  104. X         */
  105. X        for (i = 0; ; ++i)
  106. X        {
  107. X            while (cmd[0])
  108. X            {
  109. X                if (cmd[0] == delimiter)            /* end delimiter found */
  110. X                {
  111. X                    *cmd++ = NUL;                    /* replace it by a NUL */
  112. X                    break;
  113. X                }
  114. X                if (cmd[0] == '\\' && cmd[1] != 0)    /* skip escaped characters */
  115. X                    ++cmd;
  116. X                ++cmd;
  117. X            }
  118. X            if (i == 1)
  119. X                break;
  120. X            sub = cmd;                /* remember the start of the substitution */
  121. X        }
  122. X        free(old_sub);
  123. X        old_sub = strsave(sub);
  124. X    }
  125. X    else                                /* use previous pattern and substitution */
  126. X    {
  127. X        if (old_sub == NULL)    /* there is no previous command */
  128. X        {
  129. X            beep();
  130. X            return;
  131. X        }
  132. X        pat = NULL;             /* myregcomp() will use previous pattern */
  133. X        sub = old_sub;
  134. X    }
  135. X
  136. X    /*
  137. X     * find trailing options
  138. X     */
  139. X    do_all = FALSE;
  140. X    do_ask = FALSE;
  141. X    while (*cmd)
  142. X    {
  143. X        if (*cmd == 'g')
  144. X            do_all = TRUE;
  145. X        else if (*cmd == 'c')
  146. X            do_ask = TRUE;
  147. X        else
  148. X            break;
  149. X        ++cmd;
  150. X    }
  151. X
  152. X    /*
  153. X     * check for a trailing count
  154. X     */
  155. X    skipspace(&cmd);
  156. X    if (isdigit(*cmd))
  157. X    {
  158. X        i = getdigits(&cmd);
  159. X        if (i <= 0)
  160. X        {
  161. X            emsg(e_zerocount);
  162. X            return;
  163. X        }
  164. X        lp = up;
  165. X        up += i - 1;
  166. X    }
  167. X
  168. X    /*
  169. X     * check for trailing '|', '"' or '#'
  170. X     */
  171. X    skipspace(&cmd);
  172. X    if (*cmd)
  173. X    {
  174. X        if (strchr("|\"#", *cmd) != NULL)
  175. X        {
  176. X            *nextcommand = (u_char *)cmd;
  177. X        }
  178. X        else
  179. X        {
  180. X            emsg(e_trailing);
  181. X            return;
  182. X        }
  183. X    }
  184. X
  185. X    if ((prog = myregcomp(pat)) == NULL)
  186. X    {
  187. X        emsg(e_invcmd);
  188. X        return;
  189. X    }
  190. X
  191. X    for (lnum = lp; lnum <= up && !got_int; ++lnum)
  192. X    {
  193. X        ptr = nr2ptr(lnum);
  194. X        if (regexec(prog, ptr, (int)TRUE))  /* a match on this line */
  195. X        {
  196. X            char       *ns, *sns = NULL, *p, *prevp, *oldp = NULL;
  197. X            int            did_sub = FALSE;
  198. X
  199. X            if (nsubs == 0)
  200. X                    setpcmark();
  201. X            /*
  202. X             * Save the line that was last changed for the final cursor
  203. X             * position (just like the real vi).
  204. X             */
  205. X            Curpos.lnum = lnum;
  206. X
  207. X            prevp = p = ptr;
  208. X            do
  209. X            {
  210. X                Curpos.col = prog->startp[0] - ptr;
  211. X                /*
  212. X                 * First match empty string does not count, except for first match.
  213. X                 * This reproduces the strange vi behaviour.
  214. X                 * This also catches endless loops.
  215. X                 */
  216. X                if (did_sub && p == oldp && p == prog->endp[0])
  217. X                {
  218. X                    ++p;
  219. X                    goto skip2;
  220. X                }
  221. X                if (do_ask)
  222. X                {
  223. X                        updateScreen(CURSUPD);
  224. X                        smsg("replace by %s (y/n/q)? ", sub);
  225. X                        setcursor();
  226. X                        if ((i = vgetc()) == 'q')
  227. X                        {
  228. X                            got_int = TRUE;
  229. X                            break;
  230. X                        }
  231. X                        else if (i != 'y')
  232. X                            goto skip;
  233. X                }
  234. X
  235. X                        /* get length of substitution part */
  236. X                sublen = regsub(prog, sub, ptr, 0, (int)p_magic);
  237. X                if (did_sub == FALSE)
  238. X                {
  239. X                    /*
  240. X                     * Get some space for a temporary buffer to do the substitution
  241. X                     * into.
  242. X                     */
  243. X                    if ((sns = alloc((unsigned)(strlen(ptr) + sublen + 5))) == NULL)
  244. X                        goto outofmem;
  245. X                    *sns = NUL;
  246. X                    did_sub = TRUE;
  247. X                }
  248. X                else
  249. X                {
  250. X                    /*
  251. X                     * extend the temporary buffer to do the substitution into.
  252. X                     */
  253. X                    if ((ns = alloc((unsigned)(strlen(sns) + strlen(prevp) + sublen + 1))) == NULL)
  254. X                        goto outofmem;
  255. X                    strcpy(ns, sns);
  256. X                    free(sns);
  257. X                    sns = ns;
  258. X                }
  259. X
  260. X                for (ns = sns; *ns; ns++)
  261. X                    ;
  262. X                /*
  263. X                 * copy up to the part that matched
  264. X                 */
  265. X                while (prevp < prog->startp[0])
  266. X                    *ns++ = *prevp++;
  267. X
  268. X                regsub(prog, sub, ns, 1, (int)p_magic);
  269. X                nsubs++;
  270. X                /*
  271. X                 * Regsub may have replaced a ~ by the old sub.
  272. X                 * We have to use the result, otherwise the ~ is replaced
  273. X                 * over and over again.
  274. X                 */
  275. X                sub = reg_prev_sub;
  276. X
  277. X                prevp = prog->endp[0];    /* remember last copied character */
  278. X                /*
  279. X                 * continue searching after the match
  280. X                 * prevent endless loop with patterns that match empty strings,
  281. X                 * e.g. :s/$/pat/g or :s/[a-z]* /(&)/g
  282. X                 */
  283. Xskip:
  284. X                p = prog->endp[0];
  285. X                oldp = p;
  286. X                if (*p == NUL)      /* end of line: quit here */
  287. X                    break;
  288. X
  289. Xskip2:
  290. X                    /* breakcheck is slow, don't call it too often */
  291. X                if ((nsubs & 15) == 0)
  292. X                    breakcheck();
  293. X
  294. X            } while (!got_int && do_all && regexec(prog, p, (int)FALSE));
  295. X
  296. X            if (did_sub)
  297. X            {
  298. X                    /*
  299. X                     * copy the rest of the line, that didn't match
  300. X                     */
  301. X                    strcat(sns, prevp);
  302. X
  303. X                    if ((ptr = save_line(sns)) != NULL)
  304. X                            u_savesub(lnum, replaceline(lnum, ptr));
  305. X
  306. X                    free(sns);          /* free the temp buffer */
  307. X                    ++nlines;
  308. X            }
  309. X        }
  310. X            /* breakcheck is slow, don't call it too often */
  311. X        if ((lnum & 15) == 0)
  312. X            breakcheck();
  313. X    }
  314. X
  315. Xoutofmem:
  316. X    if (nsubs)
  317. X    {
  318. X        CHANGED;
  319. X        updateScreen(CURSUPD); /* need this to update LineSizes */
  320. X        beginline(TRUE);
  321. X        if (nsubs > p_report)
  322. X            smsg("%s%ld substitution%s on %ld line%s",
  323. X                                got_int ? "(Interrupted) " : "",
  324. X                                nsubs, plural(nsubs),
  325. X                                (long)nlines, plural((long)nlines));
  326. X        else if (got_int)
  327. X                msg(e_interr);
  328. X        else if (do_ask)
  329. X                msg("");
  330. X    }
  331. X    else if (got_int)
  332. X        msg(e_interr);
  333. X    else
  334. X        msg("No match");
  335. X
  336. X    free((char *) prog);
  337. X}
  338. X
  339. X/*
  340. X * doglob(cmd)
  341. X *
  342. X * Execute a global command of the form:
  343. X *
  344. X * g/pattern/X : execute X on all lines where pattern matches
  345. X * v/pattern/X : execute X on all lines where pattern does not match
  346. X *
  347. X * where 'X' is an EX command
  348. X *
  349. X * The command character (as well as the trailing slash) is optional, and
  350. X * is assumed to be 'p' if missing.
  351. X *
  352. X * This is implemented in two passes: first we scan the file for the pattern and
  353. X * set a mark for each line that (not) matches. secondly we execute the command
  354. X * for each line that has a mark. This is required because after deleting
  355. X * lines we do not know where to search for the next match.
  356. X */
  357. X
  358. X    void
  359. Xdoglob(type, lp, up, cmd)
  360. X    int         type;
  361. X    linenr_t    lp, up;
  362. X    char        *cmd;
  363. X{
  364. X    linenr_t        lnum;        /* line number according to old situation */
  365. X    linenr_t        old_lcount; /* line_count before the command */
  366. X    int             ndone;
  367. X
  368. X    char            delim;        /* delimiter, normally '/' */
  369. X    char           *pat;
  370. X    regexp           *prog;
  371. X    int                match;
  372. X
  373. X    if (global_busy)
  374. X    {
  375. X        emsg("Cannot do :global recursive");
  376. X        ++global_busy;
  377. X        return;
  378. X    }
  379. X
  380. X    delim = *cmd++;             /* skip the delimiter */
  381. X    pat = cmd;
  382. X
  383. X    while (cmd[0])
  384. X    {
  385. X        if (cmd[0] == delim)                /* end delimiter found */
  386. X        {
  387. X            *cmd++ = NUL;                    /* replace it by a NUL */
  388. X            break;
  389. X        }
  390. X        if (cmd[0] == '\\' && cmd[1] != 0)    /* skip escaped characters */
  391. X            ++cmd;
  392. X        ++cmd;
  393. X    }
  394. X
  395. X    reg_ic = p_ic;           /* set "ignore case" flag appropriately */
  396. X
  397. X    if ((prog = myregcomp(pat)) == NULL)
  398. X    {
  399. X        emsg(e_invcmd);
  400. X        return;
  401. X    }
  402. X    msg("");
  403. X
  404. X/*
  405. X * pass 1: set marks for each (not) matching line
  406. X */
  407. X    ndone = 0;
  408. X    for (lnum = lp; lnum <= up && !got_int; ++lnum)
  409. X    {
  410. X        match = regexec(prog, nr2ptr(lnum), (int)TRUE);     /* a match on this line? */
  411. X        if ((type == 'g' && match) || (type == 'v' && !match))
  412. X        {
  413. X            setmarked(lnum);
  414. X            ndone++;
  415. X        }
  416. X            /* breakcheck is slow, don't call it too often */
  417. X        if ((lnum & 15) == 0)
  418. X            breakcheck();
  419. X    }
  420. X
  421. X/*
  422. X * pass 2: execute the command for each line that has been marked
  423. X */
  424. X    if (got_int)
  425. X        msg("Interrupted");
  426. X    else if (ndone == 0)
  427. X        msg("No match");
  428. X    else
  429. X    {
  430. X        global_busy = 1;
  431. X        global_wait = 0;
  432. X        RedrawingDisabled = TRUE;
  433. X        old_lcount = line_count;
  434. X        while (!got_int && (lnum = firstmarked()) != 0 && global_busy == 1)
  435. X        {
  436. X            Curpos.lnum = lnum;
  437. X            Curpos.col = 0;
  438. X            if (*cmd == NUL)
  439. X                docmdline((u_char *)"p");
  440. X            else
  441. X                docmdline((u_char *)cmd);
  442. X            breakcheck();
  443. X        }
  444. X
  445. X        RedrawingDisabled = FALSE;
  446. X        if (global_wait)                /* wait for return */
  447. X            wait_return(FALSE);
  448. X        updateScreen(CLEAR);
  449. X        msgmore(line_count - old_lcount);
  450. X    }
  451. X
  452. X    clearmarked();      /* clear rest of the marks */
  453. X    global_busy = 0;
  454. X    free((char *) prog);
  455. X}
  456. END_OF_FILE
  457. if test 9336 -ne `wc -c <'vim/src/csearch.c'`; then
  458.     echo shar: \"'vim/src/csearch.c'\" unpacked with wrong size!
  459. fi
  460. # end of 'vim/src/csearch.c'
  461. fi
  462. if test -f 'vim/src/main.c' -a "${1}" != "-c" ; then 
  463.   echo shar: Will not clobber existing file \"'vim/src/main.c'\"
  464. else
  465. echo shar: Extracting \"'vim/src/main.c'\" \(9338 characters\)
  466. sed "s/^X//" >'vim/src/main.c' <<'END_OF_FILE'
  467. X/* vi:ts=4:sw=4
  468. X *
  469. X * VIM - Vi IMitation
  470. X *
  471. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  472. X *                            Tim Thompson            twitch!tjt
  473. X *                            Tony Andrews            onecom!wldrdg!tony 
  474. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  475. X */
  476. X
  477. X#define EXTERN
  478. X#include "vim.h"
  479. X#include "globals.h"
  480. X#include "proto.h"
  481. X#include "param.h"
  482. X
  483. Xstatic void usage __PARMS((int));
  484. X
  485. X    static void
  486. Xusage(n)
  487. X    int n;
  488. X{
  489. X    register int i;
  490. X    static char *(use[]) = {"[file ..]\n",
  491. X                            "-t tag\n",
  492. X                            "+[command] file ..\n",
  493. X                            "-c {command} file ..\n",
  494. X                            "-e\n"};
  495. X    static char *(errors[]) =  {"Unknown option\n",            /* 0 */
  496. X                                "Too many arguments\n",        /* 1 */
  497. X                                "Argument missing\n",        /* 2 */
  498. X                                };
  499. X
  500. X    fprintf(stderr, errors[n]);
  501. X    fprintf(stderr, "usage:");
  502. X    for (i = 0; ; ++i)
  503. X    {
  504. X        fprintf(stderr, " vim [options] ");
  505. X        fprintf(stderr, use[i]);
  506. X        if (i == (sizeof(use) / sizeof(char *)) - 1)
  507. X            break;
  508. X        fprintf(stderr, "   or:");
  509. X    }
  510. X#ifdef AMIGA
  511. X    fprintf(stderr, "\noptions: -v -n -r -d device -s scriptin -w scriptout -T terminal\n");
  512. X#else
  513. X    fprintf(stderr, "\noptions: -v -n -r -s scriptin -w scriptout -T terminal\n");
  514. X#endif
  515. X    mch_windexit(1);
  516. X}
  517. X
  518. X    void
  519. Xmain(argc, argv)
  520. X    int                argc;
  521. X    char          **argv;
  522. X{
  523. X    char           *initstr;        /* init string from the environment */
  524. X    char           *term = NULL;    /* specified terminal name */
  525. X    char           *fname = NULL;    /* file name from command line */
  526. X    char           *command = NULL;    /* command from + option */
  527. X    char           *tagname = NULL;    /* tag from -t option */
  528. X    int             c;
  529. X    int                doqf = 0;
  530. X    int                i;
  531. X
  532. X#ifdef DEBUG
  533. X# ifdef MSDOS
  534. X    OPENDEBUG("#debug#");
  535. X# else
  536. X    OPENDEBUG("/tmp/debug/vim");
  537. X# endif
  538. X#endif
  539. X
  540. X/*
  541. X * Check if we have an interactive window.
  542. X * If not, open one with a newcli command (needed for :! to work).
  543. X * check_win will also handle the -d argument (for the Amiga).
  544. X */
  545. X    check_win(argc, argv);
  546. X
  547. X    ++argv;
  548. X    /*
  549. X     * Process the command line arguments
  550. X     *         '-s scriptin'
  551. X     *        '-w scriptout'
  552. X     *        '-v'
  553. X     *        '-n'
  554. X     *        '-r'
  555. X     *        '-T terminal'
  556. X     */
  557. X    while (argc > 1 && argv[0][0] == '-' &&
  558. X            strchr("swvnrTd", c = argv[0][1]) != NULL && c)
  559. X    {
  560. X        --argc;
  561. X        switch (c)
  562. X        {
  563. X        case 'v':
  564. X            readonlymode = TRUE;
  565. X            p_ro = TRUE;
  566. X            /*FALLTHROUGH*/
  567. X
  568. X        case 'n':
  569. X            p_uc = 0;
  570. X            break;
  571. X
  572. X        case 'r':
  573. X            recoverymode = 1;
  574. X            break;
  575. X        
  576. X        default:    /* options with argument */
  577. X            ++argv;
  578. X            --argc;
  579. X            if (argc < 1)
  580. X                usage(2);
  581. X
  582. X            switch (c)
  583. X            {
  584. X            case 's':
  585. X                if ((scriptin[0] = fopen(argv[0], READBIN)) == NULL)
  586. X                {
  587. X                        fprintf(stderr, "cannot open %s for reading\n", argv[0]);
  588. X                        mch_windexit(2);
  589. X                }
  590. X                break;
  591. X            
  592. X            case 'w':
  593. X                if ((scriptout = fopen(argv[0],
  594. X#ifdef MSDOS
  595. X                                                    "ab"
  596. X#else
  597. X                                                    "a"
  598. X#endif
  599. X                                                        )) == NULL)
  600. X                {
  601. X                        fprintf(stderr, "cannot open %s for output\n", argv[0]);
  602. X                        mch_windexit(2);
  603. X                }
  604. X                break;
  605. X
  606. X/*
  607. X * The -T term option is always available and when TERMCAP is supported it
  608. X * overrides the environment variable TERM.
  609. X */
  610. X            case 'T':
  611. X                term = *argv;
  612. X                break;
  613. X            
  614. X        /*    case 'd':        This is ignored as it is handled in check_win() */
  615. X            }
  616. X        }
  617. X        ++argv;
  618. X    }
  619. X
  620. X    /*
  621. X     * Allocate space for the generic buffer
  622. X     */
  623. X    if ((IObuff = alloc(IOSIZE)) == NULL)
  624. X        mch_windexit(0);
  625. X
  626. X    /* note that we may use mch_windexit() before mch_windinit()! */
  627. X    mch_windinit();
  628. X    set_init();            /* after mch_windinit because Rows is used */
  629. X
  630. X    /*
  631. X     * Process the other command line arguments.
  632. X     */
  633. X    if (argc > 1)
  634. X    {
  635. X        c = argv[0][1];
  636. X        switch (argv[0][0])
  637. X        {
  638. X          case '-':
  639. X            switch (c)
  640. X            {
  641. X              case 'e':            /* -e QuickFix mode */
  642. X                if (argc != 2)
  643. X                    usage(1);
  644. X                doqf = 1;
  645. X                break;
  646. X
  647. X            case 'c':            /* -c {command} file .. */
  648. X                if (argc <= 3)
  649. X                    usage(2);
  650. X                ++argv;
  651. X                --argc;
  652. X                command = &(argv[0][0]);
  653. X                goto getfiles;
  654. X
  655. X            case 't':            /* -t tag */
  656. X                if (argc < 3)
  657. X                    usage(2);
  658. X                if (argc > 3)
  659. X                    usage(1);
  660. X                ++argv;
  661. X                tagname = argv[0];
  662. X                break;
  663. X
  664. X            default:
  665. X                usage(0);
  666. X            }
  667. X            break;
  668. X
  669. X          case '+':             /* + or +{number} or +/{pat} or +{command} */
  670. X            if (argc < 3)        /* no filename */
  671. X                    usage(2);
  672. X            if (c == NUL)
  673. X                command = "$";
  674. X            else
  675. X                command = &(argv[0][1]);
  676. X
  677. Xgetfiles:
  678. X            ++argv;
  679. X            --argc;
  680. X            /*FALLTHROUGH*/
  681. X
  682. X          default:                /* must be a file name */
  683. X#if defined(WILD_CARDS) && !defined(UNIX)
  684. X            ExpandWildCards(argc - 1, argv, &numfiles, &files, TRUE, TRUE);
  685. X            if (numfiles != 0)
  686. X                fname = files[0];
  687. X
  688. X#else
  689. X            files = argv;
  690. X            numfiles = argc - 1;
  691. X            fname = argv[0];
  692. X#endif
  693. X            if (numfiles > 1)
  694. X                printf("%d files to edit\n", numfiles);
  695. X            break;
  696. X        }
  697. X    }
  698. X
  699. X    if (numfiles == 0)
  700. X        numfiles = 1;
  701. X
  702. X    RedrawingDisabled = TRUE;
  703. X    filealloc();                /* Initialize storage structure */
  704. X    init_yank();                /* init yank buffers */
  705. X    termcapinit(term);            /* get terminal capabilities */
  706. X
  707. X#ifdef USE_LOCALE
  708. X#include <locale.h>
  709. X    setlocale(LC_ALL, "");        /* for ctype() and the like */
  710. X#endif
  711. X
  712. X#ifdef MSDOS /* default mapping for some often used keys */
  713. X    domap(0, "#1 :help\r", 0);                /* F1 is help key */
  714. X    domap(0, "\236R i", 0);                    /* INSERT is 'i' */
  715. X    domap(0, "\236S x", 0);                    /* DELETE is 'x' */
  716. X    domap(0, "\236G 0", 0);                    /* HOME is '0' */
  717. X    domap(0, "\236w H", 0);                    /* CTRL-HOME is 'H' */
  718. X    domap(0, "\236O $", 0);                    /* END is '$' */
  719. X    domap(0, "\236u L", 0);                    /* CTRL-END is 'L' */
  720. X    domap(0, "\236I \002", 0);                /* PageUp is '^B' */
  721. X    domap(0, "\236\204 1G", 0);                /* CTRL-PageUp is '1G' */
  722. X    domap(0, "\236Q \006", 0);                /* PageDown is '^F' */
  723. X    domap(0, "\236v G", 0);                    /* CTRL-PageDown is 'G' */
  724. X            /* insert mode */
  725. X    domap(0, "\236S \017x", INSERT);            /* DELETE is '^Ox' */
  726. X    domap(0, "\236G \017""0", INSERT);        /* HOME is '^O0' */
  727. X    domap(0, "\236w \017H", INSERT);        /* CTRL-HOME is '^OH' */
  728. X    domap(0, "\236O \017$", INSERT);        /* END is '^O$' */
  729. X    domap(0, "\236u \017L", INSERT);        /* CTRL-END is '^OL' */
  730. X    domap(0, "\236I \017\002", INSERT);        /* PageUp is '^O^B' */
  731. X    domap(0, "\236\204 \017\061G", INSERT);    /* CTRL-PageUp is '^O1G' */
  732. X    domap(0, "\236Q \017\006", INSERT);        /* PageDown is '^O^F' */
  733. X    domap(0, "\236v \017G", INSERT);        /* CTRL-PageDown is '^OG' */
  734. X#endif
  735. X
  736. X/*
  737. X * get system wide defaults (for unix)
  738. X */
  739. X#ifdef DEFVIMRC_FILE
  740. X    dosource(DEFVIMRC_FILE);
  741. X#endif
  742. X
  743. X/*
  744. X * Try to read initialization commands from the following places:
  745. X * - environment variable VIMINIT
  746. X * - file s:.vimrc ($HOME/.vimrc for Unix)
  747. X * - environment variable EXINIT
  748. X * - file s:.exrc ($HOME/.exrc for Unix)
  749. X * The first that exists is used, the rest is ignored.
  750. X */
  751. X    if ((initstr = (char *)vimgetenv("VIMINIT")) != NULL)
  752. X        docmdline((u_char *)initstr);
  753. X    else if (dosource(SYSVIMRC_FILE))
  754. X    {
  755. X        if ((initstr = (char *)vimgetenv("EXINIT")) != NULL)
  756. X            docmdline((u_char *)initstr);
  757. X        else
  758. X            dosource(SYSEXRC_FILE);
  759. X    }
  760. X
  761. X/*
  762. X * Read initialization commands from ".vimrc" or ".exrc" in current directory.
  763. X * Because of security reasons we disallow shell and write commands now,
  764. X * except for unix if the file is owned by the user.
  765. X * Only do this if VIMRC_FILE is not the same as SYSVIMRC_FILE or DEFVIMRC_FILE.
  766. X */
  767. X#ifdef UNIX
  768. X    {
  769. X        struct stat s;
  770. X
  771. X        stat(VIMRC_FILE, &s);
  772. X        if (s.st_uid != getuid())    /* ".vimrc" file is not owned by user */
  773. X            secure = 1;
  774. X    }
  775. X#else
  776. X    secure = 1;
  777. X#endif
  778. X
  779. X    i = 1;
  780. X    if (fullpathcmp(SYSVIMRC_FILE, VIMRC_FILE)
  781. X#ifdef DEFVIMRC_FILE
  782. X            && fullpathcmp(DEFVIMRC_FILE, VIMRC_FILE)
  783. X#endif
  784. X            )
  785. X        i = dosource(VIMRC_FILE);
  786. X#ifdef UNIX
  787. X    if (i)
  788. X    {
  789. X        struct stat s;
  790. X
  791. X        stat(EXRC_FILE, &s);
  792. X        if (s.st_uid != getuid())    /* ".exrc" file is not owned by user */
  793. X            secure = 1;
  794. X        else
  795. X            secure = 0;
  796. X    }
  797. X#endif
  798. X    if (i && fullpathcmp(SYSEXRC_FILE, EXRC_FILE))
  799. X        dosource(EXRC_FILE);
  800. X
  801. X/*
  802. X * Call settmode and starttermcap here, so the T_KS and T_TS may be defined
  803. X * by termcapinit and redifined in .exrc.
  804. X */
  805. X    settmode(1);
  806. X    starttermcap();
  807. X
  808. X    if (secure == 2)        /* done something that is not allowed */
  809. X        wait_return(TRUE);        /* must be called after settmode(1) */
  810. X    secure = 0;
  811. X
  812. X#ifdef AMIGA
  813. X    fname_case(fname);        /* set correct case for file name */
  814. X#endif
  815. X    setfname(fname);
  816. X    maketitle();
  817. X
  818. X/*
  819. X * start putting things on the screen
  820. X */
  821. X    starting = FALSE;
  822. X    screenalloc();
  823. X    screenclear();
  824. X    if (Filename != NULL)
  825. X        readfile(Filename, (linenr_t)0, TRUE);
  826. X    else
  827. X        msg("Empty Buffer");
  828. X
  829. X    setpcmark();
  830. X    if (!tagname)
  831. X        startscript();                /* start writing to auto script file */
  832. X
  833. X    if (recoverymode && !scriptin[curscript])    /* first do script file, then recover */
  834. X        openrecover();
  835. X
  836. X    /* position the display and the cursor at the top of the file. */
  837. X    Topline = 1;
  838. X    Curpos.lnum = 1;
  839. X    Curpos.col = 0;
  840. X    Cursrow = Curscol = 0;
  841. X
  842. X    if (doqf)
  843. X    {
  844. X        if (qf_init(p_ef))
  845. X            mch_windexit(3);
  846. X        qf_jump(0);
  847. X    }
  848. X
  849. X    if (command)
  850. X        docmdline((u_char *)command);
  851. X    /*
  852. X     * put the :ta command in the stuff buffer here, so that it will not
  853. X     * be erased by an emsg().
  854. X     */
  855. X    if (tagname)
  856. X    {
  857. X        stuffReadbuff(":ta ");
  858. X        stuffReadbuff(tagname);
  859. X        stuffReadbuff("\n");
  860. X    }
  861. X
  862. X    RedrawingDisabled = FALSE;
  863. X    updateScreen(NOT_VALID);
  864. X
  865. X        /* start in insert mode (already taken care of for :ta command) */
  866. X    if (p_im && stuff_empty())
  867. X        stuffReadbuff("i");
  868. X/*
  869. X * main command loop
  870. X */
  871. X    for (;;)
  872. X    {
  873. X        adjustCurpos();
  874. X        cursupdate();    /* Figure out where the cursor is based on Curpos. */
  875. X
  876. X        if (Quote.lnum)
  877. X            updateScreen(INVERTED);        /* update inverted part */
  878. X        setcursor();
  879. X
  880. X        normal();                        /* get and execute a command */
  881. X    }
  882. X    /*NOTREACHED*/
  883. X}
  884. X
  885. X    void
  886. Xgetout(r)
  887. X    int             r;
  888. X{
  889. X    windgoto((int)Rows - 1, 0);
  890. X    outchar('\r');
  891. X    outchar('\n');
  892. X    mch_windexit(r);
  893. X}
  894. END_OF_FILE
  895. if test 9338 -ne `wc -c <'vim/src/main.c'`; then
  896.     echo shar: \"'vim/src/main.c'\" unpacked with wrong size!
  897. fi
  898. # end of 'vim/src/main.c'
  899. fi
  900. if test -f 'vim/src/mark.c' -a "${1}" != "-c" ; then 
  901.   echo shar: Will not clobber existing file \"'vim/src/mark.c'\"
  902. else
  903. echo shar: Extracting \"'vim/src/mark.c'\" \(8995 characters\)
  904. sed "s/^X//" >'vim/src/mark.c' <<'END_OF_FILE'
  905. X/* vi:ts=4:sw=4
  906. X *
  907. X * VIM - Vi IMitation
  908. X *
  909. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  910. X *                            Tim Thompson            twitch!tjt
  911. X *                            Tony Andrews            onecom!wldrdg!tony 
  912. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  913. X */
  914. X
  915. X/*
  916. X * mark.c: functions for setting marks and jumping to them
  917. X */
  918. X
  919. X#include "vim.h"
  920. X#include "globals.h"
  921. X#include "proto.h"
  922. X#include "mark.h"
  923. X#include "ops.h"        /* for endop and startop */
  924. X
  925. X/*
  926. X * This file contains routines to maintain and manipulate marks.
  927. X */
  928. X
  929. X#define NMARKS            26            /* max. # of named marks */
  930. X#define JUMPLISTSIZE    50            /* max. # of marks in jump list */
  931. X
  932. Xstatic struct mark pcmark;                    /* previous context mark */
  933. Xstatic struct mark namedm[NMARKS];            /* original vi marks */
  934. Xstatic struct filemark namedfm[NMARKS];        /* new marks with file nr */
  935. Xstatic struct filemark jumplist[JUMPLISTSIZE];    /* list of old pcmarks */
  936. X
  937. Xstatic int jumplistlen = 0;
  938. Xstatic int jumplistidx = 0;
  939. X
  940. Xstatic FPOS *mark2pos __ARGS((struct mark *));
  941. X
  942. X/*
  943. X * setmark(c) - set named mark 'c' at current cursor position
  944. X *
  945. X * Returns TRUE on success, FALSE if no room for mark or bad name given.
  946. X */
  947. X    int
  948. Xsetmark(c)
  949. X    int            c;
  950. X{
  951. X    int             i;
  952. X
  953. X    if (islower(c))
  954. X    {
  955. X        i = c - 'a';
  956. X        namedm[i].ptr = nr2ptr(Curpos.lnum);
  957. X        namedm[i].col = Curpos.col;
  958. X        return TRUE;
  959. X    }
  960. X    if (isupper(c))
  961. X    {
  962. X        i = c - 'A';
  963. X        namedfm[i].mark.ptr = nr2ptr(Curpos.lnum);
  964. X        namedfm[i].mark.col = Curpos.col;
  965. X        namedfm[i].lnum = Curpos.lnum;
  966. X        namedfm[i].fnum = 0;
  967. X        return TRUE;
  968. X    }
  969. X    return FALSE;
  970. X}
  971. X
  972. X/*
  973. X * setpcmark() - set the previous context mark to the current position
  974. X *                 and insert it into the jump list
  975. X */
  976. X    void
  977. Xsetpcmark()
  978. X{
  979. X    int i;
  980. X#ifdef ROTATE
  981. X    struct filemark tempmark;
  982. X#endif
  983. X
  984. X    pcmark.ptr = nr2ptr(Curpos.lnum);
  985. X    pcmark.col = Curpos.col;
  986. X
  987. X#ifndef ROTATE
  988. X    /*
  989. X     * simply add the new entry at the end of the list
  990. X     */
  991. X    jumplistidx = jumplistlen;
  992. X#else
  993. X    /*
  994. X     * If last used entry is not at the top, put it at the top by rotating
  995. X     * the stack until it is (the newer entries will be at the bottom).
  996. X     * Keep one entry (the last used one) at the top.
  997. X     */
  998. X    if (jumplistidx < jumplistlen)
  999. X        ++jumplistidx;
  1000. X    while (jumplistidx < jumplistlen)
  1001. X    {
  1002. X        tempmark = jumplist[jumplistlen - 1];
  1003. X        for (i = jumplistlen - 1; i > 0; --i)
  1004. X            jumplist[i] = jumplist[i - 1];
  1005. X        jumplist[0] = tempmark;
  1006. X        ++jumplistidx;
  1007. X    }
  1008. X#endif
  1009. X
  1010. X        /* only add new entry if it differs from the last one */
  1011. X    if (jumplistlen == 0 || jumplist[jumplistidx - 1].mark.ptr != pcmark.ptr)
  1012. X    {
  1013. X            /* if jumplist is full: remove oldest entry */
  1014. X        if (++jumplistlen > JUMPLISTSIZE)
  1015. X        {
  1016. X            jumplistlen = JUMPLISTSIZE;
  1017. X            for (i = 1; i < jumplistlen; ++i)
  1018. X                jumplist[i - 1] = jumplist[i];
  1019. X            --jumplistidx;
  1020. X        }
  1021. X
  1022. X        jumplist[jumplistidx].mark = pcmark;
  1023. X        jumplist[jumplistidx].lnum = Curpos.lnum;
  1024. X        jumplist[jumplistidx].fnum = 0;
  1025. X        ++jumplistidx;
  1026. X    }
  1027. X}
  1028. X
  1029. X/*
  1030. X * move "count" positions in the jump list (count may be negative)
  1031. X */
  1032. X    FPOS *
  1033. Xmovemark(count)
  1034. X    int count;
  1035. X{
  1036. X    FPOS        *pos;
  1037. X
  1038. X    if (jumplistlen == 0)            /* nothing to jump to */
  1039. X        return (FPOS *)NULL;
  1040. X
  1041. X    if (jumplistidx + count < 0 || jumplistidx + count >= jumplistlen)
  1042. X        return (FPOS *)NULL;
  1043. X
  1044. X    /*
  1045. X     * if first CTRL-O or CTRL-I command after a jump, add cursor position to list
  1046. X     */
  1047. X    if (jumplistidx == jumplistlen)
  1048. X    {
  1049. X        setpcmark();
  1050. X        --jumplistidx;        /* skip the new entry */
  1051. X    }
  1052. X
  1053. X    jumplistidx += count;
  1054. X    if (jumplist[jumplistidx].mark.ptr == NULL)    /* jump to other file */
  1055. X    {
  1056. X        if (getaltfile(jumplist[jumplistidx].fnum - 1, jumplist[jumplistidx].lnum, FALSE))
  1057. X            return (FPOS *)NULL;
  1058. X        Curpos.col = jumplist[jumplistidx].mark.col;
  1059. X        jumplist[jumplistidx].fnum = 0;
  1060. X        jumplist[jumplistidx].mark.ptr = nr2ptr(Curpos.lnum);
  1061. X        pos = (FPOS *)-1;
  1062. X    }
  1063. X    else
  1064. X        pos = mark2pos(&jumplist[jumplistidx].mark);
  1065. X    return pos;
  1066. X}
  1067. X
  1068. X/*
  1069. X * getmark(c) - find mark for char 'c'
  1070. X *
  1071. X * Return pointer to FPOS if found
  1072. X *        NULL if no such mark.
  1073. X *        -1 if mark is in other file (only if changefile is TRUE)
  1074. X */
  1075. X    FPOS *
  1076. Xgetmark(c, changefile)
  1077. X    int            c;
  1078. X    int            changefile;
  1079. X{
  1080. X    FPOS    *posp;
  1081. X
  1082. X    posp = NULL;
  1083. X    if (c == '\'' || c == '`')            /* previous context mark */
  1084. X        posp = mark2pos(&pcmark);
  1085. X    else if (c == '[')                    /* to start of previous operator */
  1086. X    {
  1087. X        if (startop.lnum > 0 && startop.lnum <= line_count)
  1088. X            posp = &startop;
  1089. X    }
  1090. X    else if (c == ']')                    /* to end of previous operator */
  1091. X    {
  1092. X        if (endop.lnum > 0 && endop.lnum <= line_count)
  1093. X            posp = &endop;
  1094. X    }
  1095. X    else if (islower(c))                /* normal named mark */
  1096. X        posp = mark2pos(&(namedm[c - 'a']));
  1097. X    else if (isupper(c))                /* named file mark */
  1098. X    {
  1099. X        c -= 'A';
  1100. X        posp = mark2pos(&(namedfm[c].mark));
  1101. X        if (posp == NULL && namedfm[c].lnum != 0 && (changefile || samealtfile(namedfm[c].fnum - 1)))
  1102. X        {
  1103. X            if (!getaltfile(namedfm[c].fnum - 1, namedfm[c].lnum, TRUE))
  1104. X            {
  1105. X                Curpos.col = namedfm[c].mark.col;
  1106. X                namedfm[c].fnum = 0;
  1107. X                namedfm[c].mark.ptr = nr2ptr(Curpos.lnum);
  1108. X                posp = (FPOS *)-1;
  1109. X            }
  1110. X        }
  1111. X    }
  1112. X    return posp;
  1113. X}
  1114. X
  1115. X    static FPOS *
  1116. Xmark2pos(markp)
  1117. X    struct mark *markp;
  1118. X{
  1119. X    static FPOS pos;
  1120. X
  1121. X    if (markp->ptr != NULL && (pos.lnum = ptr2nr(markp->ptr, (linenr_t)1)) != 0)
  1122. X    {
  1123. X        pos.col = markp->col;
  1124. X        return (&pos);
  1125. X    }
  1126. X    return (FPOS *)NULL;
  1127. X}
  1128. X
  1129. X/*
  1130. X * clrallmarks() - clear all marks
  1131. X *
  1132. X * Used mainly when trashing the entire buffer during ":e" type commands
  1133. X */
  1134. X    void
  1135. Xclrallmarks()
  1136. X{
  1137. X    static int             i = -1;
  1138. X
  1139. X    if (i == -1)        /* first call ever: initialize */
  1140. X        for (i = 0; i < NMARKS; i++)
  1141. X            namedfm[i].lnum = 0;
  1142. X
  1143. X    for (i = 0; i < NMARKS; i++)
  1144. X    {
  1145. X        namedm[i].ptr = NULL;
  1146. X        namedfm[i].mark.ptr = NULL;
  1147. X    }
  1148. X    pcmark.ptr = NULL;
  1149. X    qf_clrallmarks();
  1150. X    for (i = 0; i < jumplistlen; ++i)
  1151. X        jumplist[i].mark.ptr = NULL;
  1152. X}
  1153. X
  1154. X/*
  1155. X * increment the file number for all filemarks
  1156. X * called when adding a file to the file stack
  1157. X */
  1158. X    void
  1159. Xincrmarks()
  1160. X{
  1161. X    int            i;
  1162. X
  1163. X    for (i = 0; i < NMARKS; i++)
  1164. X        ++namedfm[i].fnum;
  1165. X
  1166. X    for (i = 0; i < jumplistlen; ++i)
  1167. X    {
  1168. X#if 0        /* this would take too much time */
  1169. X        if (jumplist[i].fnum == 0)    /* current file */
  1170. X            jumplist[i].lnum = ptr2nr(jumplist[i].mark.ptr, 1);
  1171. X#endif
  1172. X        ++jumplist[i].fnum;
  1173. X    }
  1174. X}
  1175. X
  1176. X/*
  1177. X * decrement the file number for the filemarks of the current file
  1178. X * called when not adding the current file name to the file stack
  1179. X */
  1180. X    void
  1181. Xdecrmarks()
  1182. X{
  1183. X    int            i;
  1184. X
  1185. X    for (i = 0; i < NMARKS; i++)
  1186. X        if (namedfm[i].fnum == 1)
  1187. X            namedfm[i].fnum = 0;
  1188. X
  1189. X    for (i = 0; i < jumplistlen; ++i)
  1190. X        if (jumplist[i].fnum == 1)
  1191. X            jumplist[i].fnum = 0;
  1192. X}
  1193. X
  1194. X/*
  1195. X * adjustmark: set new ptr for a mark
  1196. X * if new == NULL the mark is effectively deleted
  1197. X */
  1198. X   void
  1199. Xadjustmark(old, new)
  1200. X        char *old, *new;
  1201. X{
  1202. X        register int i;
  1203. X
  1204. X        for (i = 0; i < NMARKS; ++i)
  1205. X        {
  1206. X            if (namedm[i].ptr == old)
  1207. X                namedm[i].ptr = new;
  1208. X            if (namedfm[i].mark.ptr == old)
  1209. X            {
  1210. X                namedfm[i].mark.ptr = new;
  1211. X                if (new == NULL)
  1212. X                    namedfm[i].lnum = 0;        /* delete this mark */
  1213. X            }
  1214. X        }
  1215. X        if (pcmark.ptr == old)
  1216. X                pcmark.ptr = new;
  1217. X        for (i = 0; i < jumplistlen; ++i)
  1218. X                if (jumplist[i].mark.ptr == old)
  1219. X                        jumplist[i].mark.ptr = new;
  1220. X        qf_adjustmark(old, new);
  1221. X}
  1222. X
  1223. X/*
  1224. X * get name of file from a filemark (use the occasion to update the lnum)
  1225. X */
  1226. X    char *
  1227. Xfm_getname(fmark)
  1228. X    struct filemark *fmark;
  1229. X{
  1230. X    linenr_t    nr;
  1231. X    char        *name;
  1232. X
  1233. X    if (fmark->fnum != 0)                        /* maybe not current file */
  1234. X    {
  1235. X        name = getaltfname(fmark->fnum - 1);
  1236. X        if (name == NULL)
  1237. X            return "-none-";
  1238. X        if (Filename == NULL || fnamecmp(name, Filename) != 0)    /* not current file */
  1239. X            return name;
  1240. X        fmark->fnum = 0;
  1241. X    }
  1242. X    if (fmark->mark.ptr == NULL)
  1243. X        fmark->mark.ptr = nr2ptr(fmark->lnum);    /* update ptr */
  1244. X    else
  1245. X    {
  1246. X        nr = ptr2nr(fmark->mark.ptr, (linenr_t)1);
  1247. X        if (nr != 0)
  1248. X            fmark->lnum = nr;                    /* update lnum */
  1249. X    }
  1250. X    return "-current-";
  1251. X}
  1252. X
  1253. X/*
  1254. X * print the marks (use the occasion to update the line numbers)
  1255. X */
  1256. X    void
  1257. Xdomarks()
  1258. X{
  1259. X    int            i;
  1260. X    char        *name;
  1261. X
  1262. X#ifdef AMIGA
  1263. X    settmode(0);        /* set cooked mode, so output can be halted */
  1264. X#endif
  1265. X    outstrn("\nmark line  file\n");
  1266. X    for (i = 0; i < NMARKS; ++i)
  1267. X    {
  1268. X        if (namedm[i].ptr != NULL)
  1269. X        {
  1270. X            sprintf(IObuff, " %c %5ld\n",
  1271. X                i + 'a',
  1272. X                ptr2nr(namedm[i].ptr, (linenr_t)1));
  1273. X            outstrn(IObuff);
  1274. X        }
  1275. X        flushbuf();
  1276. X    }
  1277. X    for (i = 0; i < NMARKS; ++i)
  1278. X    {
  1279. X        if (namedfm[i].lnum != 0)
  1280. X        {
  1281. X            name = fm_getname(&namedfm[i]);
  1282. X            if (name == NULL)        /* file name not available */
  1283. X                continue;
  1284. X
  1285. X            sprintf(IObuff, " %c %5ld  %s\n",
  1286. X                i + 'A',
  1287. X                namedfm[i].lnum,
  1288. X                name);
  1289. X            outstrn(IObuff);
  1290. X        }
  1291. X        flushbuf();
  1292. X    }
  1293. X#ifdef AMIGA
  1294. X    settmode(1);
  1295. X#endif
  1296. X    wait_return(TRUE);
  1297. X}
  1298. X
  1299. X/*
  1300. X * print the jumplist (use the occasion to update the line numbers)
  1301. X */
  1302. X    void
  1303. Xdojumps()
  1304. X{
  1305. X    int            i;
  1306. X    char        *name;
  1307. X
  1308. X#ifdef AMIGA
  1309. X    settmode(0);        /* set cooked mode, so output can be halted */
  1310. X#endif
  1311. X    outstrn("\n jump line  file\n");
  1312. X    for (i = 0; i < jumplistlen; ++i)
  1313. X    {
  1314. X        if (jumplist[i].lnum != 0)
  1315. X        {
  1316. X            name = fm_getname(&jumplist[i]);
  1317. X            if (name == NULL)        /* file name not available */
  1318. X                continue;
  1319. X
  1320. X            sprintf(IObuff, "%c %2d %5ld  %s\n",
  1321. X                i == jumplistidx ? '>' : ' ',
  1322. X                i + 1,
  1323. X                jumplist[i].lnum,
  1324. X                name);
  1325. X            outstrn(IObuff);
  1326. X        }
  1327. X        flushbuf();
  1328. X    }
  1329. X    if (jumplistidx == jumplistlen)
  1330. X        outstrn(">\n");
  1331. X#ifdef AMIGA
  1332. X    settmode(1);
  1333. X#endif
  1334. X    wait_return(TRUE);
  1335. X}
  1336. END_OF_FILE
  1337. if test 8995 -ne `wc -c <'vim/src/mark.c'`; then
  1338.     echo shar: \"'vim/src/mark.c'\" unpacked with wrong size!
  1339. fi
  1340. # end of 'vim/src/mark.c'
  1341. fi
  1342. if test -f 'vim/src/script.c' -a "${1}" != "-c" ; then 
  1343.   echo shar: Will not clobber existing file \"'vim/src/script.c'\"
  1344. else
  1345. echo shar: Extracting \"'vim/src/script.c'\" \(11660 characters\)
  1346. sed "s/^X//" >'vim/src/script.c' <<'END_OF_FILE'
  1347. X/* vi:ts=4:sw=4
  1348. X *
  1349. X * VIM - Vi IMitation
  1350. X *
  1351. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  1352. X *                            Tim Thompson            twitch!tjt
  1353. X *                            Tony Andrews            onecom!wldrdg!tony 
  1354. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  1355. X */
  1356. X
  1357. X/*
  1358. X * script.c: functions for handling script files
  1359. X */
  1360. X
  1361. X#include "vim.h"
  1362. X#include "globals.h"
  1363. X#include "proto.h"
  1364. X#include "param.h"
  1365. X
  1366. Xstatic char *scriptname;            /* name of the script in use */
  1367. Xstatic FILE *autoscriptfd = NULL;
  1368. Xstatic char *makescriptname __ARGS((void));
  1369. Xstatic void Supdatescript __ARGS((char *));
  1370. X
  1371. Xextern int global_busy;            /* this is in csearch.c */
  1372. X
  1373. X/*
  1374. X * for Amiga Dos 2.0x we use Open/Close/Flush instead of fopen/fclose
  1375. X */
  1376. X#ifdef AMIGA
  1377. X# ifndef NO_ARP
  1378. Xextern int dos2;                    /* this is in amiga.c */
  1379. X# endif
  1380. X# ifdef SASC
  1381. X#  include <proto/dos.h>
  1382. X# endif
  1383. X#endif
  1384. X
  1385. X/*
  1386. X * We use this flag to avoid writing :win to commands to the script file
  1387. X * during startup.
  1388. X */
  1389. Xstatic int script_started = FALSE;
  1390. X
  1391. X/*
  1392. X * startscript(): open automatic script file
  1393. X */
  1394. X    void
  1395. Xstartscript()
  1396. X{
  1397. X    int        n;
  1398. X    char    buf[25];
  1399. X#ifdef AMIGA
  1400. X    int        r;
  1401. X    FILE    *dummyfd = NULL;
  1402. X#endif
  1403. X
  1404. X    script_started = TRUE;
  1405. X
  1406. X#ifdef AMIGA
  1407. X/*
  1408. X * With Amiga DOS 2.0 the system may lockup with the sequence: write to .vim
  1409. X * file, close it, delete it, create a new .vim file and write to it.
  1410. X * This is a problem in the filesystem hash chains (solved in version 39.xx).
  1411. X * The Delay seems to solve this problem, maybe because DOS gets a chance to
  1412. X * finish closing and deleting the old .vim file. Also do this for DOS 1.3,
  1413. X * just in case.
  1414. X */
  1415. X    if (stopscript())
  1416. X        Delay(10L);        /* This should fix the lockup bug */
  1417. X#else
  1418. X    stopscript();        /* stop any old script */
  1419. X#endif
  1420. X
  1421. X    if (p_uc == 0 || exiting)    /* no auto script wanted/needed */
  1422. X        return;
  1423. X    if (Changed)
  1424. X        emsg("Warning: buffer already changed, auto script file will be incomplete");
  1425. X
  1426. X#ifdef AMIGA
  1427. X/*
  1428. X * If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
  1429. X * compatible filesystem, it is possible that the file "test.doc.vim" which we
  1430. X * create will be exactly the same file. To avoid this problem we temporarily
  1431. X * create "test.doc".
  1432. X */
  1433. X    if (!(p_sn || thisfile_sn) && Filename && getperm(Filename) < 0)
  1434. X        dummyfd = fopen(Filename, "w");
  1435. X#endif
  1436. X
  1437. X/*
  1438. X * we try different names until we find one that does not exist yet
  1439. X */
  1440. X    scriptname = makescriptname();
  1441. X    for (;;)
  1442. X    {
  1443. X        if (scriptname == NULL)        /* must be out of memory */
  1444. X            break;
  1445. X        if ((n = strlen(scriptname)) == 0)    /* safety check */
  1446. X        {
  1447. X            free(scriptname);
  1448. X            break;
  1449. X        }
  1450. X        
  1451. X        /*
  1452. X         * check if the scriptfile already exists
  1453. X         */
  1454. X        if (getperm(scriptname) < 0)        /* it does not exist */
  1455. X        {
  1456. X                /*
  1457. X                 * Create the autoscript file.
  1458. X                 */
  1459. X#ifdef AMIGA
  1460. X# ifndef NO_ARP
  1461. X            if (dos2)
  1462. X# endif
  1463. X                autoscriptfd = (FILE *)Open((UBYTE *)scriptname, (long)MODE_NEWFILE);
  1464. X# ifndef NO_ARP
  1465. X            else
  1466. X                autoscriptfd = fopen(scriptname, "w");
  1467. X# endif
  1468. X#else    /* !AMIGA */
  1469. X                autoscriptfd = fopen(scriptname, WRITEBIN);
  1470. X#endif    /* AMIGA */
  1471. X
  1472. X#ifdef AMIGA
  1473. X            /*
  1474. X             * on the Amiga getperm() will return -1 when the file exists but
  1475. X             * is being used by another program. This happens if you edit
  1476. X             * a file twice.
  1477. X             */
  1478. X            if (autoscriptfd != NULL || (IoErr() != ERROR_OBJECT_IN_USE && IoErr() != ERROR_OBJECT_EXISTS))
  1479. X#endif
  1480. X                break;
  1481. X        }
  1482. X    /*
  1483. X     * get here when file already exists
  1484. X     */
  1485. X        if (scriptname[n - 1] == 'm')        /* first try */
  1486. X        {
  1487. X#ifdef AMIGA
  1488. X        /*
  1489. X         * on MS-DOS compatible filesystems (e.g. messydos) file.doc.vim
  1490. X         * and file.doc are the same file. To guess if this problem is
  1491. X         * present try if file.doc.vix exists. If it does, we set thisfile_sn
  1492. X         * and try file_doc.vim (dots replaced by underscores for this file),
  1493. X         * and try again. If it doesn't we assume that "file.doc.vim" already
  1494. X         * exists.
  1495. X         */
  1496. X            if (!(p_sn || thisfile_sn))        /* not tried yet */
  1497. X            {
  1498. X                scriptname[n - 1] = 'x';
  1499. X                r = getperm(scriptname);    /* try "file.vix" */
  1500. X                scriptname[n - 1] = 'm';
  1501. X                if (r >= 0)                    /* it seems to exist */
  1502. X                {
  1503. X                    thisfile_sn = TRUE;
  1504. X                    free(scriptname);
  1505. X                    scriptname = makescriptname();    /* '.' replaced by '_' */
  1506. X                    continue;                        /* try again */
  1507. X                }
  1508. X            }
  1509. X#endif
  1510. X            /* if we get here ".vim" file really exists */
  1511. X            emsg(".vim file exists: an edit of this file has not been finished");
  1512. X        }
  1513. X
  1514. X        if (scriptname[n - 1] == 'a')    /* tried enough names, give up */
  1515. X        {
  1516. X            free(scriptname);
  1517. X            break;
  1518. X        }
  1519. X        --scriptname[n - 1];                /* change last char of the name */
  1520. X    }
  1521. X    if (autoscriptfd != NULL)        /* ".vim" file has been created */
  1522. X    {
  1523. X        script_winsize();            /* always start with a :win command */
  1524. X                                    /* output cursor position if neccessary */
  1525. X        if (Curpos.lnum > 1 || Curpos.col > 0)
  1526. X        {
  1527. X            sprintf(buf, "%ldG0%dl", (long)Curpos.lnum, (int)Curpos.col);
  1528. X            Supdatescript(buf);
  1529. X        }
  1530. X    }
  1531. X
  1532. X#ifdef AMIGA
  1533. X    if (dummyfd)        /* file has been created temporarily */
  1534. X    {
  1535. X        fclose(dummyfd);
  1536. X        remove(Filename);
  1537. X    }
  1538. X#endif
  1539. X}
  1540. X
  1541. X    int
  1542. Xstopscript()
  1543. X{
  1544. X    if (!autoscriptfd)
  1545. X        return FALSE;        /* nothing to stop */
  1546. X
  1547. X#ifdef AMIGA
  1548. X# ifndef NO_ARP
  1549. X    if (dos2)
  1550. X# endif
  1551. X        Close((BPTR)autoscriptfd);
  1552. X# ifndef NO_ARP
  1553. X    else
  1554. X        fclose(autoscriptfd);
  1555. X# endif
  1556. X#else
  1557. X    fclose(autoscriptfd);
  1558. X#endif
  1559. X    remove(scriptname);        /* delete the file */
  1560. X    autoscriptfd = NULL;
  1561. X    free(scriptname);
  1562. X    return TRUE;
  1563. X}
  1564. X
  1565. X/*
  1566. X * open new script file
  1567. X * return 0 on success, 1 on error
  1568. X */
  1569. X    int
  1570. Xopenscript(name)
  1571. X    char *name;
  1572. X{
  1573. X    int oldcurscript;
  1574. X
  1575. X    if (curscript + 1 == NSCRIPT)
  1576. X    {
  1577. X        emsg(e_nesting);
  1578. X        return 1;
  1579. X    }
  1580. X    else
  1581. X    {
  1582. X        if (scriptin[curscript] != NULL)    /* already reading script */
  1583. X            ++curscript;
  1584. X        if ((scriptin[curscript] = fopen((char *)name, READBIN)) == NULL)
  1585. X        {
  1586. X            emsg(e_notopen);
  1587. X            if (curscript)
  1588. X                --curscript;
  1589. X            return 1;
  1590. X        }
  1591. X        /*
  1592. X         * With command ":g/pat/so! file" we have to execute the
  1593. X         * commands from the file now.
  1594. X         */
  1595. X        if (global_busy)
  1596. X        {
  1597. X            State = NORMAL;
  1598. X            oldcurscript = curscript;
  1599. X            do
  1600. X            {
  1601. X                normal();
  1602. X                vpeekc();            /* check for end of file */
  1603. X            }
  1604. X            while (scriptin[oldcurscript]);
  1605. X            State = CMDLINE;
  1606. X        }
  1607. X    }
  1608. X    return 0;
  1609. X}
  1610. X
  1611. X/*
  1612. X * updatescipt() is called when a character has to be written into the script file
  1613. X * or when we have waited some time for a character (c == 0)
  1614. X */
  1615. X    void
  1616. Xupdatescript(c)
  1617. X    int c;
  1618. X{
  1619. X    static int count = 0;
  1620. X
  1621. X    if (c && scriptout)
  1622. X        putc(c, scriptout);
  1623. X    if (autoscriptfd == NULL || (c == 0 && count == 0))        /* nothing to do */
  1624. X        return;
  1625. X    if (c)
  1626. X    {
  1627. X#ifdef AMIGA
  1628. X# ifndef NO_ARP
  1629. X        if (dos2)
  1630. X# endif
  1631. X            FPutC((BPTR)autoscriptfd, (unsigned long)c);
  1632. X# ifndef NO_ARP
  1633. X        else
  1634. X            putc(c, autoscriptfd);
  1635. X# endif
  1636. X#else
  1637. X        putc(c, autoscriptfd);
  1638. X#endif
  1639. X        ++count;
  1640. X    }
  1641. X    if ((c == 0 || count >= p_uc) && Updated)
  1642. X    {
  1643. X        /*
  1644. X         * Before DOS 2.0x we have to close and open the file in order to really
  1645. X         * get the characters in the file to disk!
  1646. X         * With DOS 2.0x Flush() can be used for that
  1647. X         */
  1648. X#ifdef AMIGA
  1649. X# ifndef NO_ARP
  1650. X        if (dos2)
  1651. X# endif
  1652. X            Flush((BPTR)autoscriptfd);
  1653. X# ifndef NO_ARP
  1654. X        else
  1655. X        {
  1656. X            fclose(autoscriptfd);
  1657. X            autoscriptfd = fopen(scriptname, "a");
  1658. X        }
  1659. X# endif
  1660. X#else     /* !AMIGA */
  1661. X        fclose(autoscriptfd);
  1662. X# ifdef MSDOS
  1663. X        autoscriptfd = fopen(scriptname, "ab");
  1664. X# else
  1665. X        autoscriptfd = fopen(scriptname, "a");
  1666. X# endif
  1667. X#endif
  1668. X        count = 0;
  1669. X        Updated = 0;
  1670. X    }
  1671. X}
  1672. X
  1673. X    static void
  1674. XSupdatescript(str)
  1675. X    char *str;
  1676. X{
  1677. X    while (*str)
  1678. X        updatescript(*str++);
  1679. X}
  1680. X
  1681. X/*
  1682. X * try to open the ".vim" file for recovery
  1683. X * if recoverymode is 1: start recovery, set recoverymode to 2
  1684. X * if recoverymode is 2: stop recovery mode
  1685. X */
  1686. X    void
  1687. Xopenrecover()
  1688. X{
  1689. X    char *fname;
  1690. X    struct stat efile, rfile;
  1691. X
  1692. X    if (recoverymode == 2)        /* end of recovery */
  1693. X    {
  1694. X        if (got_int)
  1695. X        {
  1696. X            emsg("Recovery Interrupted");
  1697. X                /* somehow the cursor ends up in the wrong place (why?) */
  1698. X            setcursor();
  1699. X            flushbuf();
  1700. X        }
  1701. X        else
  1702. X            msg("Recovery completed");
  1703. X        recoverymode = 0;
  1704. X    }
  1705. X    else
  1706. X    {
  1707. X        fname = makescriptname();
  1708. X        if (fname)
  1709. X        {
  1710. X            recoverymode = 2;
  1711. X            if (Filename != NULL &&
  1712. X                    stat(Filename, &efile) != -1 &&
  1713. X                    stat(fname, &rfile) != -1 &&
  1714. X                    efile.st_mtime > rfile.st_mtime)
  1715. X                emsg(".vim file is older; file not recovered");
  1716. X            else
  1717. X            {
  1718. X                if (openscript(fname))
  1719. X                    emsg("Cannot open .vim file; file not recovered");
  1720. X            }
  1721. X            free(fname);
  1722. X        }
  1723. X    }
  1724. X}
  1725. X
  1726. X/*
  1727. X * make script name out of the filename
  1728. X */
  1729. X    static char *
  1730. Xmakescriptname()
  1731. X{
  1732. X    char *r, *s, *fname;
  1733. X
  1734. X    r = modname(Filename, ".vim");
  1735. X    if (*p_dir == 0 || r == NULL)
  1736. X        return r;
  1737. X
  1738. X    for (fname = s = r; *s; ++s)        /* skip path */
  1739. X    {
  1740. X#ifdef UNIX
  1741. X        if (*s == '/')        /* UNIX has ':' inside file names */
  1742. X#else
  1743. X        if (*s == ':' || *s == PATHSEP)
  1744. X#endif
  1745. X            fname = s + 1;
  1746. X    }
  1747. X
  1748. X    s = alloc((unsigned)(strlen(p_dir) + strlen(fname) + 1));
  1749. X    if (s != NULL)
  1750. X    {
  1751. X        strcpy(s, p_dir);
  1752. X        strcat(s, fname);
  1753. X    }
  1754. X    free(r);
  1755. X    return s;
  1756. X}
  1757. X
  1758. X/*
  1759. X * add extention to filename - change path/fo.o.h to path/fo.o.h.ext or
  1760. X * fo_o_h.ext for MSDOS or when dotfname option reset.
  1761. X *
  1762. X * Assumed that fname is a valid name found in the filesystem we assure that
  1763. X * the return value is a different name and ends in ".ext".
  1764. X * "ext" MUST start with a "." and MUST be at most 4 characters long.
  1765. X * Space for the returned name is allocated, must be freed later.
  1766. X */
  1767. X
  1768. X    char *
  1769. Xmodname(fname, ext)
  1770. X    char *fname, *ext;
  1771. X{
  1772. X    char            *retval;
  1773. X    register char   *s;
  1774. X    register char   *ptr;
  1775. X    register int    fnamelen, extlen;
  1776. X    char            currentdir[512];
  1777. X
  1778. X    extlen = strlen(ext);
  1779. X
  1780. X    /*
  1781. X     * if there is no filename we must get the name of the current directory
  1782. X     * (we need the full path in case :cd is used)
  1783. X     */
  1784. X    if (fname == NULL || *fname == NUL)
  1785. X    {
  1786. X        (void)dirname(currentdir, 511);
  1787. X        strcat(currentdir, PATHSEPSTR);
  1788. X        fnamelen = strlen(currentdir);
  1789. X    }
  1790. X    else
  1791. X        fnamelen = strlen(fname);
  1792. X    retval = alloc((unsigned) (fnamelen + extlen + 1));
  1793. X    if (retval != NULL)
  1794. X    {
  1795. X        if (fname == NULL || *fname == NUL)
  1796. X            strcpy(retval, currentdir);
  1797. X        else
  1798. X            strcpy(retval, fname);
  1799. X        /*
  1800. X         * search backwards until we hit a '\' or ':' replacing all '.' by '_'
  1801. X         * for MSDOS or when dotfname option reset.
  1802. X         * Then truncate what is after the '\' or ':' to 8 characters for MSDOS
  1803. X         * and 26 characters for AMIGA and UNIX.
  1804. X         */
  1805. X        for (ptr = retval + fnamelen; ptr >= retval; ptr--)
  1806. X        {
  1807. X#ifndef MSDOS
  1808. X            if (p_sn || thisfile_sn)
  1809. X#endif
  1810. X                if (*ptr == '.')    /* replace '.' by '_' */
  1811. X                    *ptr = '_';
  1812. X#ifdef UNIX
  1813. X            if (*ptr == '/')        /* UNIX has ':' inside file names */
  1814. X#else
  1815. X            if (*ptr == ':' || *ptr == PATHSEP)
  1816. X#endif
  1817. X                break;
  1818. X        }
  1819. X        ptr++;
  1820. X
  1821. X        /* the filename has at most BASENAMELEN characters. */
  1822. X        if (strlen(ptr) > BASENAMELEN)
  1823. X            ptr[BASENAMELEN] = '\0';
  1824. X#ifndef MSDOS
  1825. X        if ((p_sn || thisfile_sn) && strlen(ptr) > 8)
  1826. X            ptr[8] = '\0';
  1827. X#endif
  1828. X        s = ptr + strlen(ptr);
  1829. X
  1830. X        /*
  1831. X         * Append the extention.
  1832. X         * ext must start with '.' and cannot exceed 3 more characters.
  1833. X         */
  1834. X        strcpy(s, ext);
  1835. X        if (fname != NULL && strcmp(fname, retval) == 0)
  1836. X        {
  1837. X            /* after modification still the same name? */
  1838. X            /* we search for a character that can be replaced by '_' */
  1839. X            while (--s >= ptr)
  1840. X            {
  1841. X                if (*s != '_')
  1842. X                {
  1843. X                    *s = '_';
  1844. X                    break;
  1845. X                }
  1846. X            }
  1847. X            if (s < ptr)
  1848. X            {
  1849. X                /* fname was "________.<ext>" how tricky! */
  1850. X                *ptr = 'v';
  1851. X            }
  1852. X        }
  1853. X    }
  1854. X    return retval;
  1855. X}
  1856. X
  1857. X/*
  1858. X * the new window size must be used in scripts;
  1859. X * write a ":winsize width height" command to the (auto)script
  1860. X * Postpone this action if not in NORMAL State, otherwise we may insert the
  1861. X * command halfway another command.
  1862. X */
  1863. Xint script_winsize_postponed = FALSE;
  1864. X
  1865. X    void
  1866. Xscript_winsize()
  1867. X{
  1868. X    char            buf[25];
  1869. X
  1870. X    if (!script_started || State != NORMAL)        /* postpone action */
  1871. X    {
  1872. X        script_winsize_postponed = TRUE;
  1873. X        return;
  1874. X    }
  1875. X
  1876. X    sprintf(buf, ":win %d %d\r", (int)Columns, (int)Rows);
  1877. X    Supdatescript(buf);
  1878. X    script_winsize_postponed = FALSE;
  1879. X}
  1880. X
  1881. X/*
  1882. X * This function is called after each "State = NORMAL"
  1883. X */
  1884. X    void
  1885. Xscript_winsize_pp()
  1886. X{
  1887. X    if (script_winsize_postponed)
  1888. X        script_winsize();
  1889. X}
  1890. END_OF_FILE
  1891. if test 11660 -ne `wc -c <'vim/src/script.c'`; then
  1892.     echo shar: \"'vim/src/script.c'\" unpacked with wrong size!
  1893. fi
  1894. # end of 'vim/src/script.c'
  1895. fi
  1896. if test -f 'vim/src/tag.c' -a "${1}" != "-c" ; then 
  1897.   echo shar: Will not clobber existing file \"'vim/src/tag.c'\"
  1898. else
  1899. echo shar: Extracting \"'vim/src/tag.c'\" \(9119 characters\)
  1900. sed "s/^X//" >'vim/src/tag.c' <<'END_OF_FILE'
  1901. X/* vi:ts=4:sw=4
  1902. X *
  1903. X * VIM - Vi IMitation
  1904. X *
  1905. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  1906. X *                            Tim Thompson            twitch!tjt
  1907. X *                            Tony Andrews            onecom!wldrdg!tony 
  1908. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  1909. X */
  1910. X
  1911. X/*
  1912. X * Code to handle tags and the tag stack
  1913. X */
  1914. X
  1915. X#include "vim.h"
  1916. X#include "globals.h"
  1917. X#include "proto.h"
  1918. X#include "param.h"
  1919. X#include "mark.h"
  1920. X
  1921. X#define TAGSTACKSIZE 20
  1922. X
  1923. X/*
  1924. X * the taggy struct is used to store the information about a :tag command:
  1925. X *    the tag name and the cursor position BEFORE the :tag command
  1926. X */
  1927. Xstruct taggy
  1928. X{
  1929. X    char            *tagname;            /* tag name */
  1930. X    struct filemark fmark;                /* cursor position */
  1931. X};
  1932. X
  1933. X/*
  1934. X * the tagstack grows from 0 upwards:
  1935. X * entry 0: older
  1936. X * entry 1: newer
  1937. X * entry 2: newest
  1938. X */
  1939. Xstatic struct taggy tagstack[TAGSTACKSIZE];    /* the tag stack */
  1940. Xstatic int tagstackidx = 0;                /* index just below active entry */
  1941. Xstatic int tagstacklen = 0;                /* number of tags on the stack */
  1942. X
  1943. Xstatic int findtag __ARGS((char *));
  1944. Xstatic char *firsttaborspace __ARGS((char *));
  1945. X
  1946. Xstatic char bottommsg[] = "at bottom of tag stack";
  1947. Xstatic char topmsg[] = "at top of tag stack";
  1948. X
  1949. X/*
  1950. X * Jump to tag; handling of tag stack
  1951. X *
  1952. X * *tag != NUL (:tag): jump to new tag, add to tag stack
  1953. X * type == 1 (:pop) || type == 2 (CTRL-T): jump to old position
  1954. X * type == 0 (:tag): jump to old tag
  1955. X */
  1956. X    void
  1957. Xdotag(tag, type, count)
  1958. X    char    *tag;
  1959. X    int        type;
  1960. X    int        count;
  1961. X{
  1962. X    int             i;
  1963. X    struct taggy    temptag;
  1964. X
  1965. X    if (*tag != NUL)                        /* new pattern, add to the stack */
  1966. X    {
  1967. X        /*
  1968. X         * if last used entry is not at the top, put it at the top by rotating
  1969. X         * the stack until it is (the newer entries will be at the bottom)
  1970. X         */
  1971. X        while (tagstackidx < tagstacklen)
  1972. X        {
  1973. X            temptag = tagstack[tagstacklen - 1];
  1974. X            for (i = tagstacklen - 1; i > 0; --i)
  1975. X                tagstack[i] = tagstack[i - 1];
  1976. X            tagstack[0] = temptag;
  1977. X            ++tagstackidx;
  1978. X        }
  1979. X                /* if tagstack is full: remove oldest entry */
  1980. X        if (++tagstacklen > TAGSTACKSIZE)
  1981. X        {
  1982. X            tagstacklen = TAGSTACKSIZE;
  1983. X            free(tagstack[0].tagname);
  1984. X            for (i = 1; i < tagstacklen; ++i)
  1985. X                tagstack[i - 1] = tagstack[i];
  1986. X            --tagstackidx;
  1987. X        }
  1988. X    /*
  1989. X     * remember the tag and the position before the jump
  1990. X     */
  1991. X        tagstack[tagstackidx].tagname = strsave(tag);
  1992. X        tagstack[tagstackidx].fmark.lnum = Curpos.lnum;
  1993. X        tagstack[tagstackidx].fmark.mark.col = Curpos.col;
  1994. X        tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
  1995. X        tagstack[tagstackidx].fmark.fnum = 0;
  1996. X    }
  1997. X    else if (tagstacklen == 0)                    /* empty stack */
  1998. X    {
  1999. X        emsg("tag stack empty");
  2000. X        return;
  2001. X    }
  2002. X    else if (type)                                /* go to older position */
  2003. X    {
  2004. X        if ((tagstackidx -= count) < 0)
  2005. X        {
  2006. X            tagstackidx = 0;
  2007. X            emsg(bottommsg);
  2008. X        }
  2009. X        else if (tagstackidx >= tagstacklen)    /* must have been count == 0 */
  2010. X        {
  2011. X            emsg(topmsg);
  2012. X            return;
  2013. X        }
  2014. X        if (tagstack[tagstackidx].fmark.mark.ptr == NULL)    /* jump to other file */
  2015. X        {
  2016. X            if (getaltfile(tagstack[tagstackidx].fmark.fnum - 1, tagstack[tagstackidx].fmark.lnum, TRUE))
  2017. X            {
  2018. X                emsg(e_notopen);
  2019. X                return;
  2020. X            }
  2021. X            /* "refresh" this position, so we will not fall off the altfile array */
  2022. X            tagstack[tagstackidx].fmark.fnum = 0;
  2023. X            tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
  2024. X        }
  2025. X        else
  2026. X            Curpos.lnum = ptr2nr(tagstack[tagstackidx].fmark.mark.ptr, (linenr_t)1);
  2027. X        Curpos.col = tagstack[tagstackidx].fmark.mark.col;
  2028. X        return;
  2029. X    }
  2030. X    else                                    /* go to newer pattern */
  2031. X    {
  2032. X        if ((tagstackidx += count - 1) >= tagstacklen)
  2033. X        {
  2034. X            tagstackidx = tagstacklen - 1;
  2035. X            emsg(topmsg);
  2036. X        }
  2037. X        else if (tagstackidx < 0)            /* must have been count == 0 */
  2038. X        {
  2039. X            emsg(bottommsg);
  2040. X            tagstackidx = 0;
  2041. X            return;
  2042. X        }
  2043. X    }
  2044. X    if (findtag(tagstack[tagstackidx].tagname) > 0)
  2045. X        ++tagstackidx;
  2046. X    else if (bufempty())        /* "vim -t tag" failed, start script now */
  2047. X        startscript();
  2048. X}
  2049. X
  2050. X/*
  2051. X * invalidate the line pointer for all tags
  2052. X * called when abandoning the current file
  2053. X */
  2054. X    void
  2055. Xclrtags()
  2056. X{
  2057. X    int            i;
  2058. X
  2059. X    for (i = 0; i < tagstacklen; ++i)
  2060. X        tagstack[i].fmark.mark.ptr = NULL;
  2061. X}
  2062. X
  2063. X/*
  2064. X * increment the file number for all tags
  2065. X * called when adding a file to the file stack
  2066. X */
  2067. X    void
  2068. Xincrtags()
  2069. X{
  2070. X    int            i;
  2071. X
  2072. X    for (i = 0; i < tagstacklen; ++i)
  2073. X    {
  2074. X#if 0        /* this would take too much time */
  2075. X        if (tagstack[i].fmark.fnum == 0)    /* current file */
  2076. X            tagstack[i].fmark.lnum = ptr2nr(tagstack[i].fmark.mark.ptr, 1);
  2077. X#endif
  2078. X        ++tagstack[i].fmark.fnum;
  2079. X    }
  2080. X}
  2081. X
  2082. X/*
  2083. X * decrement the file number for the tags of the current file
  2084. X * called when not adding the current file name to the file stack
  2085. X */
  2086. X    void
  2087. Xdecrtags()
  2088. X{
  2089. X    int            i;
  2090. X
  2091. X    for (i = 0; i < tagstacklen; ++i)
  2092. X        if (tagstack[i].fmark.fnum == 1)
  2093. X            tagstack[i].fmark.fnum = 0;
  2094. X}
  2095. X
  2096. X/*
  2097. X * Print the tag stack (use the occasion to update the line numbers)
  2098. X */
  2099. X    void
  2100. Xdotags()
  2101. X{
  2102. X    int            i;
  2103. X    char        *name;
  2104. X
  2105. X#ifdef AMIGA
  2106. X    settmode(0);        /* set cooked mode so output can be halted */
  2107. X#endif
  2108. X    outstrn("\n  # TO tag      FROM line in file\n");
  2109. X    for (i = 0; i < tagstacklen; ++i)
  2110. X    {
  2111. X        if (tagstack[i].tagname != NULL)
  2112. X        {
  2113. X            name = fm_getname(&(tagstack[i].fmark));
  2114. X            if (name == NULL)        /* file name not available */
  2115. X                continue;
  2116. X
  2117. X            sprintf(IObuff, "%c%2d %-15s %4ld  %s\n",
  2118. X                i == tagstackidx ? '>' : ' ',
  2119. X                i + 1,
  2120. X                tagstack[i].tagname,
  2121. X                tagstack[i].fmark.lnum,
  2122. X                name);
  2123. X            outstrn(IObuff);
  2124. X        }
  2125. X        flushbuf();
  2126. X    }
  2127. X    if (tagstackidx == tagstacklen)        /* idx at top of stack */
  2128. X        outstrn(">\n");
  2129. X#ifdef AMIGA
  2130. X    settmode(1);
  2131. X#endif
  2132. X    wait_return(TRUE);
  2133. X}
  2134. X
  2135. X/*
  2136. X * findtag(tag) - goto tag
  2137. X *   return 0 for failure, 1 for success
  2138. X */
  2139. X    static int
  2140. Xfindtag(tag)
  2141. X    char           *tag;
  2142. X{
  2143. X    FILE       *tp, *fopen();
  2144. X    char        lbuf[LSIZE];
  2145. X    char        pbuf[LSIZE];            /* search pattern buffer */
  2146. X    char       *fname, *str;
  2147. X    int            cmplen;
  2148. X    char        *m = NULL;
  2149. X    register char    *p;
  2150. X    char        *np;                    /* pointer into file name string */
  2151. X    char        sbuf[CMDBUFFSIZE + 1];    /* tag file name */
  2152. X    int            i;
  2153. X    int            save_secure;
  2154. X
  2155. X    if (tag == NULL)        /* out of memory condition */
  2156. X        return 0;
  2157. X
  2158. X    if ((cmplen = p_tl) == 0)
  2159. X        cmplen = 999;
  2160. X
  2161. X    /* get stack of tag file names from tags option */
  2162. X    for (np = p_tags; *np; )
  2163. X    {
  2164. X        for (i = 0; i < CMDBUFFSIZE && *np; ++i)    /* copy next file name into lbuf */
  2165. X        {
  2166. X            if (*np == ' ')
  2167. X            {
  2168. X                ++np;
  2169. X                break;
  2170. X            }
  2171. X            sbuf[i] = *np++;
  2172. X        }
  2173. X        sbuf[i] = 0;
  2174. X        if ((tp = fopen(sbuf, "r")) == NULL)
  2175. X        {
  2176. X            m = "Can't open tags file %s";
  2177. X            goto erret2;
  2178. X        }
  2179. X        while (fgets(lbuf, LSIZE, tp) != NULL)
  2180. X        {
  2181. X            m = "Format error in tags file %s";    /* default error message */
  2182. X
  2183. X        /* find start of file name, after first TAB or space */
  2184. X            fname = firsttaborspace(lbuf);
  2185. X            if (fname == NULL)
  2186. X                goto erret;
  2187. X            *fname++ = '\0';
  2188. X
  2189. X        /* find start of search command, after second TAB or space */
  2190. X            str = firsttaborspace(fname);
  2191. X            if (str == NULL)
  2192. X                goto erret;
  2193. X            *str++ = '\0';
  2194. X
  2195. X            if (strncmp(lbuf, tag, (size_t)cmplen) == 0)
  2196. X            {
  2197. X                fclose(tp);
  2198. X                /*
  2199. X                 * Tag found!
  2200. X                 * If the command is a string like "/^function fname"
  2201. X                 * scan through the search string. If we see a magic
  2202. X                 * char, we have to quote it. This lets us use "real"
  2203. X                 * implementations of ctags.
  2204. X                 */
  2205. X                if (*str == '/' || *str == '?')
  2206. X                {
  2207. X                    p = pbuf;
  2208. X                    *p++ = *str++;            /* copy the '/' or '?' */
  2209. X                    if (*str == '^')
  2210. X                        *p++ = *str++;            /* copy the '^' */
  2211. X
  2212. X                    while (*str)
  2213. X                    {
  2214. X                        switch (*str)
  2215. X                        {
  2216. X                        case '\\':    if (str[1] == '(')    /* remove '\' before '(' */
  2217. X                                        ++str;
  2218. X                                    else
  2219. X                                        *p++ = *str++;
  2220. X                                    break;
  2221. X
  2222. X                        case '\n':    *p++ = pbuf[0];    /* copy '/' or '?' */
  2223. X                                    *str = 'n';        /* no setpcmark() for search */
  2224. X                                    break;
  2225. X
  2226. X                                    /*
  2227. X                                     * if string ends in search character: skip it
  2228. X                                     * else escape it with '\'
  2229. X                                     */
  2230. X                        case '/':
  2231. X                        case '?':    if (*str != pbuf[0])    /* not a search char */
  2232. X                                        break;
  2233. X                                    if (str[1] == '\n')        /* last char */
  2234. X                                    {
  2235. X                                        ++str;
  2236. X                                        continue;
  2237. X                                    }
  2238. X                        case '[':
  2239. X                                    if (!p_magic)
  2240. X                                        break;
  2241. X                        case '^':
  2242. X                        case '*':
  2243. X                        case '.':    *p++ = '\\';
  2244. X                                    break;
  2245. X                        }
  2246. X                        *p++ = *str++;
  2247. X                    }
  2248. X                }
  2249. X                else        /* not a search command, just copy it */
  2250. X                    for (p = pbuf; *str && *str != '\n'; )
  2251. X                        *p++ = *str++;
  2252. X                *p = NUL;
  2253. X
  2254. X                RedrawingDisabled = TRUE;
  2255. X                if ((i = getfile(fname, TRUE)) <= 0)
  2256. X                {
  2257. X                    set_want_col = TRUE;
  2258. X
  2259. X                    RedrawingDisabled = FALSE;
  2260. X                    /* dosearch(pbuf[0] == '/' ? FORWARD : BACKWARD, pbuf + 1, FALSE, 1L); */
  2261. X                    save_secure = secure;
  2262. X                    secure = 1;
  2263. X                    docmdline((u_char *)pbuf);
  2264. X                    if (secure == 2)        /* done something that is not allowed */
  2265. X                        wait_return(TRUE);
  2266. X                    secure = save_secure;
  2267. X
  2268. X                    if (p_im && i == -1)
  2269. X                        stuffReadbuff("\033\007i");    /* ESC CTRL-G i */
  2270. X                    else
  2271. X                        stuffReadbuff("\007");        /* CTRL-G */
  2272. X                    return 1;
  2273. X                }
  2274. X                RedrawingDisabled = FALSE;
  2275. X                return 0;
  2276. X            }
  2277. X        }
  2278. X        m = NULL;
  2279. X
  2280. Xerret:
  2281. X        fclose(tp);
  2282. Xerret2:
  2283. X        if (m)
  2284. X        {
  2285. X            smsg(m, sbuf);
  2286. X            sleep(1);
  2287. X        }
  2288. X    }
  2289. X    if (m == NULL)
  2290. X        emsg("tag not found");
  2291. X    return 0;
  2292. X}
  2293. X
  2294. X/*
  2295. X * find first TAB or space
  2296. X */
  2297. X    static char *
  2298. Xfirsttaborspace(str)
  2299. X    char *str;
  2300. X{
  2301. X    char *p1, *p2;
  2302. X
  2303. X    p1 = strchr(str, TAB);            /* find first TAB */
  2304. X    p2 = strchr(str, ' ');            /* find first space */
  2305. X    if (p1 == NULL || (p2 != NULL && p2 < p1))
  2306. X        return p2;                    /* space comes first */
  2307. X    return p1;
  2308. X}
  2309. END_OF_FILE
  2310. if test 9119 -ne `wc -c <'vim/src/tag.c'`; then
  2311.     echo shar: \"'vim/src/tag.c'\" unpacked with wrong size!
  2312. fi
  2313. # end of 'vim/src/tag.c'
  2314. fi
  2315. echo shar: End of archive 5 \(of 23\).
  2316. cp /dev/null ark5isdone
  2317. MISSING=""
  2318. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  2319.     if test ! -f ark${I}isdone ; then
  2320.     MISSING="${MISSING} ${I}"
  2321.     fi
  2322. done
  2323. if test "${MISSING}" = "" ; then
  2324.     echo You have unpacked all 23 archives.
  2325.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2326. else
  2327.     echo You still need to unpack the following archives:
  2328.     echo "        " ${MISSING}
  2329. fi
  2330. ##  End of shell archive.
  2331. exit 0
  2332. -------------8<----------------8<----------------8<---------------8<--------
  2333. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  2334. Oce Nederland B.V., Research & Development | necessarily represent the position
  2335. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  2336. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  2337. UUCP: mool@oce.nl        fax +31 77 595450 | whatever will be accepted.
  2338.  
  2339. exit 0 # Just in case...
  2340.