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

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v37i012:  vim - Vi IMitation editor v1.27, Part12/24
  4. Message-ID: <1993Apr25.013418.22285@sparky.imd.sterling.com>
  5. X-Md4-Signature: c9891e2c16a4e43afb1a2578a5604090
  6. Date: Sun, 25 Apr 1993 01:34:18 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mool@oce.nl (Bram Moolenaar)
  10. Posting-number: Volume 37, Issue 12
  11. Archive-name: vim/part12
  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 12 (of 23)."
  21. # Contents:  vim/src/ops.c vim/src/search.c
  22. # Wrapped by mool@oce-rd2 on Mon Apr 19 15:50:10 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'vim/src/ops.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'vim/src/ops.c'\"
  26. else
  27. echo shar: Extracting \"'vim/src/ops.c'\" \(28332 characters\)
  28. sed "s/^X//" >'vim/src/ops.c' <<'END_OF_FILE'
  29. X/* vi:ts=4:sw=4
  30. X *
  31. X * VIM - Vi IMitation
  32. X *
  33. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  34. X *                            Tim Thompson            twitch!tjt
  35. X *                            Tony Andrews            onecom!wldrdg!tony 
  36. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  37. X */
  38. X
  39. X/*
  40. X * ops.c: implementation of various operators: doshift, dodelete, dotilde,
  41. X *          dochange, doyank, doput, dojoin
  42. X */
  43. X
  44. X#include "vim.h"
  45. X#include "globals.h"
  46. X#include "proto.h"
  47. X#include "param.h"
  48. X#include "ops.h"
  49. X
  50. X/*
  51. X * We have one yank buffer for normal yanks and puts, nine yank buffers for
  52. X * deletes and 26 yank buffers for use by name.
  53. X * Each yank buffer is an array of pointers to lines.
  54. X */
  55. Xstatic struct yankbuf
  56. X{
  57. X    char        **y_array;        /* pointer to array of line pointers */
  58. X    linenr_t     y_size;         /* number of lines in y_array */
  59. X    char        y_type;         /* MLINE, MCHAR or MBLOCK */
  60. X} y_buf[36];                    /* 0..9 = number buffers, 10..35 = char buffers */
  61. X
  62. Xstatic struct    yankbuf *y_current;        /* ptr to current yank buffer */
  63. Xstatic int        yankappend;                /* TRUE when appending */
  64. Xstatic struct    yankbuf *y_previous = NULL; /* ptr to last written yank buffer */
  65. X
  66. Xstatic void        get_yank_buffer __ARGS((int));
  67. Xstatic int        stuff_yank __ARGS((int, char *));
  68. Xstatic void        free_yank __ARGS((long));
  69. Xstatic void        free_yank_all __ARGS((void));
  70. Xstatic void        block_prep __ARGS((linenr_t, int));
  71. X
  72. X/* variables use by block_prep, dodelete and doyank */
  73. Xstatic int        startspaces;
  74. Xstatic int        endspaces;
  75. Xstatic int        textlen;
  76. Xstatic char        *textstart;
  77. Xstatic colnr_t    textcol;
  78. X
  79. X/*
  80. X * doshift - handle a shift operation
  81. X */
  82. X    void
  83. Xdoshift(op)
  84. X    int             op;
  85. X{
  86. X    register int i;
  87. X
  88. X    if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + nlines)))
  89. X        return;
  90. X
  91. X    Curpos.lnum += nlines;        /* start with last line, leave cursor on first */
  92. X    for (i = nlines; --i >= 0; )
  93. X        if (lineempty(--Curpos.lnum))
  94. X            Curpos.col = 0;
  95. X        else
  96. X            shift_line(op == LSHIFT);
  97. X
  98. X    updateScreen(CURSUPD);
  99. X
  100. X    if (nlines > p_report)
  101. X        smsg("%ld line%s %ced", nlines, plural(nlines),
  102. X                                    (op == RSHIFT) ? '>' : '<');
  103. X}
  104. X
  105. X/*
  106. X * shift the current line one shiftwidth left (if left != 0) or right
  107. X * leaves cursor on first blank in the line
  108. X */
  109. X    void
  110. Xshift_line(left)
  111. X    int left;
  112. X{
  113. X    register int count;
  114. X    register int i, j;
  115. X
  116. X    count = get_indent();            /* get current indent */
  117. X
  118. X    if (p_sr)        /* round off indent */
  119. X    {
  120. X        i = count / p_sw;            /* compute new indent */
  121. X        j = count % p_sw;
  122. X        if (j)
  123. X        {
  124. X            if (!left)
  125. X                ++i;
  126. X        }
  127. X        else if (left)
  128. X        {
  129. X            if (i)
  130. X                --i;
  131. X        }
  132. X        else
  133. X            ++i;
  134. X        count = i * p_sw;
  135. X    }
  136. X    else                /* original vi indent */
  137. X    {
  138. X        if (left)
  139. X        {
  140. X            count -= p_sw;
  141. X            if (count < 0)
  142. X                count = 0;
  143. X        }
  144. X        else
  145. X            count += p_sw;
  146. X    }
  147. X    set_indent(count, TRUE);        /* set new indent */
  148. X}
  149. X
  150. X/*
  151. X * Set y_current and yankappend, according to the value of yankbuffer.
  152. X */
  153. X    static void
  154. Xget_yank_buffer(writing)
  155. X    int        writing;
  156. X{
  157. X    register int i;
  158. X
  159. X    yankappend = FALSE;
  160. X    if (yankbuffer == 0 && y_previous != NULL && !writing)
  161. X    {
  162. X        y_current = y_previous;
  163. X        return;
  164. X    }
  165. X    i = yankbuffer;
  166. X    if (isdigit(i))
  167. X        i -= '0';
  168. X    else if (islower(i))
  169. X        i -= 'a' - 10;
  170. X    else if (isupper(i))
  171. X    {
  172. X        i -= 'A' - 10;
  173. X        yankappend = TRUE;
  174. X    }
  175. X    else            /* not 0-9, a-z or A-Z: use buffer 0 */
  176. X        i = 0;
  177. X    y_current = &(y_buf[i]);
  178. X    if (writing)        /* remember the buffer we write into for doput() */
  179. X        y_previous = y_current;
  180. X}
  181. X
  182. X/*
  183. X * (stop) recording into a yank buffer
  184. X */
  185. X    int
  186. Xdorecord(c)
  187. X    int c;
  188. X{
  189. X    char *p, *lp;
  190. X    static int bufname;
  191. X
  192. X    if (Recording == FALSE)         /* start recording */
  193. X    {
  194. X        if (!isalpha(c))
  195. X            return FALSE;
  196. X        Recording = TRUE;
  197. X        showmode();
  198. X        bufname = c;
  199. X        return TRUE;
  200. X    }
  201. X    else                            /* stop recording */
  202. X    {
  203. X        Recording = FALSE;
  204. X        if (p_mo)
  205. X            msg("");
  206. X        p = (char *)get_recorded();
  207. X        if (p == NULL)
  208. X            return FALSE;
  209. X        lp = strrchr(p, 'v');    /* delete the trailing 'v' */
  210. X        if (lp != NULL)
  211. X            *lp = NUL;
  212. X        return (stuff_yank(bufname, p));
  213. X    }
  214. X}
  215. X
  216. X/*
  217. X * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
  218. X * 'p' is assumed to be alloced.
  219. X */
  220. X    static int
  221. Xstuff_yank(bufname, p)
  222. X    int bufname;
  223. X    char *p;
  224. X{
  225. X    char *lp;
  226. X    char **pp;
  227. X
  228. X    yankbuffer = bufname;
  229. X    if (yankbuffer == '.')        /* read-only buffer */
  230. X        return FALSE;
  231. X    get_yank_buffer(TRUE);
  232. X    if (yankappend && y_current->y_array != NULL)
  233. X    {
  234. X        pp = &(y_current->y_array[y_current->y_size - 1]);
  235. X        lp = alloc((unsigned)(strlen(*pp) + strlen(p) + 1));
  236. X        if (lp == NULL)
  237. X        {
  238. X            free(p);
  239. X            return FALSE;
  240. X        }
  241. X        strcpy(lp, *pp);
  242. X        strcat(lp, p);
  243. X        free(p);
  244. X        free(*pp);
  245. X        *pp = lp;
  246. X    }
  247. X    else
  248. X    {
  249. X        free_yank_all();
  250. X        if ((y_current->y_array = (char **)alloc((unsigned)sizeof(char *))) == NULL)
  251. X        {
  252. X            free(p);
  253. X            return FALSE;
  254. X        }
  255. X        y_current->y_array[0] = p;
  256. X        y_current->y_size = 1;
  257. X        y_current->y_type = MCHAR;    /* used to be MLINE, why? */
  258. X    }
  259. X    return TRUE;
  260. X}
  261. X
  262. X/*
  263. X * execute a yank buffer: copy it into the stuff buffer
  264. X */
  265. X    int
  266. Xdoexecbuf(c)
  267. X    int c;
  268. X{
  269. X    static int lastc = NUL;
  270. X    long i;
  271. X
  272. X    if (c == '@')            /* repeat previous one */
  273. X        c = lastc;
  274. X
  275. X    lastc = c;
  276. X    if (!isalnum(c))        /* registers 0-9 and a-z are allowed */
  277. X        return FALSE;
  278. X
  279. X    yankbuffer = c;
  280. X    get_yank_buffer(FALSE);
  281. X    if (y_current->y_array == NULL)
  282. X        return FALSE;
  283. X
  284. X    for (i = y_current->y_size; --i >= 0; )
  285. X    {
  286. X    /* insert newline between lines and after last line if type is MLINE */
  287. X        if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  288. X        {
  289. X            if (ins_mapbuf("\n") < 0)
  290. X                return FALSE;
  291. X        }
  292. X        if (ins_mapbuf(y_current->y_array[i]) < 0)
  293. X            return FALSE;
  294. X    }
  295. X
  296. X    return TRUE;
  297. X}
  298. X
  299. X/*
  300. X * insert a yank buffer: copy it into the Read buffer
  301. X */
  302. X    int
  303. Xinsertbuf(c)
  304. X    int c;
  305. X{
  306. X    long i;
  307. X
  308. X    if (!isalnum(c))        /* registers 0-9 and a-z are allowed */
  309. X        return FALSE;
  310. X
  311. X    yankbuffer = c;
  312. X    get_yank_buffer(FALSE);
  313. X    if (y_current->y_array == NULL)
  314. X        return FALSE;
  315. X
  316. X    for (i = 0; i < y_current->y_size; ++i)
  317. X    {
  318. X        stuffReadbuff(y_current->y_array[i]);
  319. X    /* insert newline between lines and after last line if type is MLINE */
  320. X        if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  321. X            stuffReadbuff("\n");
  322. X    }
  323. X    return TRUE;
  324. X}
  325. X
  326. X/*
  327. X * dodelete - handle a delete operation
  328. X */
  329. X    void
  330. Xdodelete()
  331. X{
  332. X    register int    n;
  333. X    linenr_t        lnum;
  334. X    char            *ptr;
  335. X
  336. X    /*
  337. X     * Do a yank of whatever we're about to delete. If there's too much stuff
  338. X     * to fit in the yank buffer, then get a confirmation before doing the
  339. X     * delete. This is crude, but simple. And it avoids doing a delete of
  340. X     * something we can't put back if we want.
  341. X     */
  342. X    if (yankbuffer == 0)                /* normal delete: shift number buffers */
  343. X    {
  344. X        y_current = &y_buf[9];
  345. X        free_yank_all();                /* free buffer nine */
  346. X        for (n = 9; n > 1; --n)
  347. X            y_buf[n] = y_buf[n - 1];
  348. X        y_previous = y_current = &y_buf[1];
  349. X        y_buf[1].y_array = NULL;        /* set buffer one to empty */
  350. X    }
  351. X    else if (yankbuffer == '.')            /* read-only buffer */
  352. X    {
  353. X        beep();
  354. X        return;
  355. X    }
  356. X    else                                /* yank into specified buffer */
  357. X        get_yank_buffer(TRUE);
  358. X
  359. X    if (!doyank(TRUE))
  360. X    {
  361. X        if (ask_yesno("cannot yank; delete anyway") != 'y')
  362. X        {
  363. X            emsg(e_abort);
  364. X            return;
  365. X        }
  366. X    }
  367. X
  368. X    if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  369. X        return;
  370. X
  371. X/*
  372. X * block mode
  373. X */
  374. X    if (Quote_block)
  375. X    {
  376. X        for (lnum = Curpos.lnum; Curpos.lnum <= endop.lnum; ++Curpos.lnum)
  377. X        {
  378. X            block_prep(Curpos.lnum, TRUE);
  379. X            if (textlen == 0)        /* nothing to delete */
  380. X                continue;
  381. X
  382. X        /*
  383. X         * If we delete a TAB, it may be replaced by several characters.
  384. X         * Thus the number of characters may increase!
  385. X         */
  386. X            n = textlen - startspaces - endspaces;
  387. X        /* number of characters increases - make room */
  388. X            if (n < 0 && !canincrease(-n))
  389. X                continue;
  390. X            ptr = nr2ptr(Curpos.lnum) + textcol;
  391. X        /* copy the part after the deleted part */
  392. X            memmove(ptr + startspaces + endspaces, ptr + textlen, strlen(ptr + textlen) + 1);
  393. X        /* insert spaces */
  394. X            copy_spaces(ptr, (size_t)(startspaces + endspaces));
  395. X            if (n > 0)
  396. X                canincrease(0);
  397. X        }
  398. X        Curpos.lnum = lnum;
  399. X        CHANGED;
  400. X        updateScreen(VALID_TO_CURSCHAR);
  401. X        nlines = 0;        /* no lines deleted */
  402. X    }
  403. X    else if (mtype == MLINE)
  404. X    {
  405. X        u_clearline();    /* "U" command should not be possible after "dd" */
  406. X        if (operator == CHANGE)
  407. X        {
  408. X            dellines((long)(nlines - 1), TRUE);
  409. X            Curpos.col = 0;
  410. X            while (delchar(TRUE));
  411. X        }
  412. X        else
  413. X        {
  414. X            dellines(nlines, TRUE);
  415. X        }
  416. X    }
  417. X    else if (nlines == 1)        /* del. within line */
  418. X    {
  419. X        n = endop.col - startop.col + 1 - oneless;
  420. X        while (n--)
  421. X            if (!delchar(TRUE))
  422. X                break;
  423. X    }
  424. X    else                        /* del. between lines */
  425. X    {
  426. X        n = Curpos.col;
  427. X        while (Curpos.col >= n)
  428. X            if (!delchar(TRUE))
  429. X                break;
  430. X
  431. X        startop = Curpos;        /* remember Curpos */
  432. X        ++Curpos.lnum;
  433. X        dellines((long)(nlines - 2), TRUE);
  434. X        n = endop.col - oneless;
  435. X
  436. X        while (n-- >= 0)
  437. X            if (!delchar(TRUE))
  438. X                break;
  439. X        Curpos = startop;        /* restore Curpos */
  440. X        dojoin(FALSE);
  441. X    }
  442. X
  443. X    if ((mtype == MCHAR && nlines <= 2 /* && p_nu == FALSE */) || operator == CHANGE)
  444. X    {
  445. X        cursupdate();
  446. X        updateline();
  447. X    }
  448. X    else
  449. X        updateScreen(CURSUPD);
  450. X
  451. X    if (mtype == MCHAR)
  452. X        --nlines;
  453. X    msgmore(-nlines);
  454. X
  455. X        /* correct endop for deleted text (for "']" command) */
  456. X    if (Quote_block)
  457. X        endop.col = startop.col;
  458. X    else
  459. X        endop = startop;
  460. X}
  461. X
  462. X/*
  463. X * dotilde - handle the (non-standard vi) tilde operator
  464. X */
  465. X    void
  466. Xdotilde()
  467. X{
  468. X    FPOS pos;
  469. X
  470. X    if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  471. X        return;
  472. X
  473. X    pos = startop;
  474. X    if (Quote_block)        /* block mode */
  475. X    {
  476. X        for (; pos.lnum <= endop.lnum; ++pos.lnum)
  477. X        {
  478. X            block_prep(pos.lnum, FALSE);
  479. X            pos.col = textcol;
  480. X            for (; --textlen >= 0; inc(&pos))
  481. X                swapchar(&pos);
  482. X        }
  483. X    }
  484. X    else            /* not block mode */
  485. X    {
  486. X        if (mtype == MLINE)
  487. X        {
  488. X                pos.col = 0;
  489. X                endop.col = strlen(nr2ptr(endop.lnum));
  490. X                if (endop.col)
  491. X                        --endop.col;
  492. X        }
  493. X        else if (oneless)
  494. X            dec(&endop);
  495. X
  496. X        for ( ; ltoreq(pos, endop); inc(&pos))
  497. X            swapchar(&pos);
  498. X    }
  499. X
  500. X    if (mtype == MCHAR && nlines == 1 && !Quote_block)
  501. X    {
  502. X        cursupdate();
  503. X        updateline();
  504. X    }
  505. X    else
  506. X        updateScreen(CURSUPD);
  507. X
  508. X    if (nlines > p_report)
  509. X            smsg("%ld line%s ~ed", nlines, plural(nlines));
  510. X}
  511. X
  512. X/*
  513. X * If operator == UPPER: make uppercase,
  514. X * if operator == LOWER: make lowercase,
  515. X * else swap case of character at 'pos'
  516. X */
  517. X    void
  518. Xswapchar(pos)
  519. X    FPOS    *pos;
  520. X{
  521. X    int        c;
  522. X
  523. X    c = gchar(pos);
  524. X    if (islower(c) && operator != LOWER)
  525. X    {
  526. X        pchar(*pos, toupper(c));
  527. X        CHANGED;
  528. X    }
  529. X    else if (isupper(c) && operator != UPPER)
  530. X    {
  531. X        pchar(*pos, tolower(c));
  532. X        CHANGED;
  533. X    }
  534. X}
  535. X
  536. X/*
  537. X * dochange - handle a change operation
  538. X */
  539. X    void
  540. Xdochange()
  541. X{
  542. X    register colnr_t            l;
  543. X
  544. X    l = startop.col;
  545. X
  546. X    dodelete();
  547. X
  548. X    if ((l > Curpos.col) && !lineempty(Curpos.lnum))
  549. X        incCurpos();
  550. X
  551. X    startinsert(NUL, FALSE, (linenr_t)1);
  552. X}
  553. X
  554. X/*
  555. X * set all the yank buffers to empty (called from main())
  556. X */
  557. X    void
  558. Xinit_yank()
  559. X{
  560. X        register int i;
  561. X
  562. X        for (i = 0; i < 36; ++i)
  563. X                y_buf[i].y_array = NULL;
  564. X}
  565. X
  566. X/*
  567. X * Free "n" lines from the current yank buffer.
  568. X * Called for normal freeing and in case of error.
  569. X */
  570. X    static void
  571. Xfree_yank(n)
  572. X    long n;
  573. X{
  574. X    if (y_current->y_array != NULL)
  575. X    {
  576. X        register long i;
  577. X
  578. X        for (i = n; --i >= 0; )
  579. X        {
  580. X            if (i % 1000 == 999)                    /* this may take a while */
  581. X                smsg("freeing %ld lines", i + 1);
  582. X            free(y_current->y_array[i]);
  583. X        }
  584. X        free((char *)y_current->y_array);
  585. X        y_current->y_array = NULL;
  586. X        if (n >= 1000)
  587. X            msg("");
  588. X    }
  589. X}
  590. X
  591. X    static void
  592. Xfree_yank_all()
  593. X{
  594. X        free_yank(y_current->y_size);
  595. X}
  596. X
  597. X/*
  598. X * Yank the text between Curpos and startpos into a yank buffer.
  599. X * If we are to append ("uppercase), we first yank into a new yank buffer and
  600. X * then concatenate the old and the new one (so we keep the old one in case
  601. X * of out-of-memory).
  602. X */
  603. X    int
  604. Xdoyank(deleting)
  605. X    int deleting;
  606. X{
  607. X    long                 i;                /* index in y_array[] */
  608. X    struct yankbuf        *curr;        /* copy of y_current */
  609. X    struct yankbuf        new;         /* new yank buffer when appending */
  610. X    char                **new_ptr;
  611. X    register linenr_t    lnum;            /* current line number */
  612. X    long                 j;
  613. X
  614. X    char                *pnew;
  615. X
  616. X    if (yankbuffer == '.')            /* read-only buffer */
  617. X    {
  618. X        beep();
  619. X        return FALSE;
  620. X    }
  621. X    if (!deleting)                    /* dodelete() already set y_current */
  622. X        get_yank_buffer(TRUE);
  623. X
  624. X    curr = y_current;
  625. X    if (yankappend && y_current->y_array != NULL) /* append to existing contents */
  626. X        y_current = &new;
  627. X    else
  628. X        free_yank_all();        /* free previously yanked lines */
  629. X
  630. X    y_current->y_size = nlines;
  631. X    y_current->y_type = mtype;    /* set the yank buffer type */
  632. X    y_current->y_array = (char **)alloc((unsigned)(sizeof(char *) * nlines));
  633. X
  634. X    if (y_current->y_array == NULL)
  635. X    {
  636. X        y_current = curr;
  637. X        return FALSE;
  638. X    }
  639. X
  640. X    i = 0;
  641. X    lnum = startop.lnum;
  642. X
  643. X    if (Quote_block)
  644. X    {
  645. X/*
  646. X * block mode
  647. X */
  648. X        y_current->y_type = MBLOCK;    /* set the yank buffer type */
  649. X        for ( ; lnum <= endop.lnum; ++lnum)
  650. X        {
  651. X            block_prep(lnum, FALSE);
  652. X            if ((pnew= alloc(startspaces + endspaces + textlen + 1)) == NULL)
  653. X                goto fail;
  654. X            y_current->y_array[i++] = pnew;
  655. X            copy_spaces(pnew, (size_t)startspaces);
  656. X            pnew += startspaces;
  657. X            strncpy(pnew, textstart, (size_t)textlen);
  658. X            pnew += textlen;
  659. X            copy_spaces(pnew, (size_t)endspaces);
  660. X            pnew += endspaces;
  661. X            *pnew = NUL;
  662. X        }
  663. X    }
  664. X    else
  665. X    {
  666. X/*
  667. X * there are three parts for non-block mode:
  668. X * 1. if mtype != MLINE yank last part of the top line
  669. X * 2. yank the lines between startop and endop, inclusive when mtype == MLINE
  670. X * 3. if mtype != MLINE yank first part of the bot line
  671. X */
  672. X        if (mtype != MLINE)
  673. X        {
  674. X            if (nlines == 1)        /* startop and endop on same line */
  675. X            {
  676. X                    j = endop.col - startop.col + 1 - oneless;
  677. X                    if ((y_current->y_array[0] = strnsave(nr2ptr(lnum) + startop.col, (int)j)) == NULL)
  678. X                    {
  679. X    fail:
  680. X                            free_yank(i);    /* free the lines that we allocated */
  681. X                            y_current = curr;
  682. X                            return FALSE;
  683. X                    }
  684. X                    goto success;
  685. X            }
  686. X            if ((y_current->y_array[0] = strsave(nr2ptr(lnum++) + startop.col)) == NULL)
  687. X                    goto fail;
  688. X            ++i;
  689. X        }
  690. X
  691. X        while (mtype == MLINE ? (lnum <= endop.lnum) : (lnum < endop.lnum))
  692. X        {
  693. X            if ((y_current->y_array[i] = strsave(nr2ptr(lnum++))) == NULL)
  694. X                    goto fail;
  695. X            ++i;
  696. X        }
  697. X        if (mtype != MLINE)
  698. X        {
  699. X            if ((y_current->y_array[i] = strnsave(nr2ptr(endop.lnum), endop.col + 1 - oneless)) == NULL)
  700. X                    goto fail;
  701. X        }
  702. X    }
  703. X
  704. Xsuccess:
  705. X    if (curr != y_current)        /* append the new block to the old block */
  706. X    {
  707. X        new_ptr = (char **)alloc((unsigned)(sizeof(char *) * (curr->y_size + y_current->y_size)));
  708. X        if (new_ptr == NULL)
  709. X                goto fail;
  710. X        for (j = 0; j < curr->y_size; ++j)
  711. X                new_ptr[j] = curr->y_array[j];
  712. X        free(curr->y_array);
  713. X        curr->y_array = new_ptr;
  714. X
  715. X        if (mtype == MLINE)     /* MLINE overrides MCHAR and MBLOCK */
  716. X                curr->y_type = MLINE;
  717. X        if (curr->y_type == MCHAR)        /* concatenate the last line of the old
  718. X                                        block with the first line of the new block */
  719. X        {
  720. X                new_ptr = (char **)alloc((unsigned)(strlen(curr->y_array[curr->y_size - 1]) + strlen(y_current->y_array[0]) + 1));
  721. X                if (new_ptr == NULL)
  722. X                {
  723. X                        i = y_current->y_size - 1;
  724. X                        goto fail;
  725. X                }
  726. X                strcpy((char *)new_ptr, curr->y_array[--j]);
  727. X                strcat((char *)new_ptr, y_current->y_array[0]);
  728. X                free(curr->y_array[j]);
  729. X                free(y_current->y_array[0]);
  730. X                curr->y_array[j++] = (char *)new_ptr;
  731. X                i = 1;
  732. X        }
  733. X        else
  734. X                i = 0;
  735. X        while (i < y_current->y_size)
  736. X                curr->y_array[j++] = y_current->y_array[i++];
  737. X        curr->y_size = j;
  738. X        free(y_current->y_array);
  739. X        y_current = curr;
  740. X    }
  741. X    if (operator == YANK)        /* don't do this when deleting */
  742. X    {
  743. X        if (mtype == MCHAR)
  744. X            --nlines;
  745. X        if (nlines > p_report)
  746. X        {
  747. X            cursupdate();        /* redisplay now, so message is not deleted */
  748. X            smsg("%ld line%s yanked", nlines, plural(nlines));
  749. X        }
  750. X    }
  751. X
  752. X    return TRUE;
  753. X}
  754. X
  755. X    void
  756. Xdoput(dir, count)
  757. X    int dir;
  758. X    long count;
  759. X{
  760. X    char        *ptr, *ep;
  761. X    int         newlen;
  762. X    int            totlen = 0;        /* init for gcc */
  763. X    linenr_t    lnum;
  764. X    int            col;
  765. X    long         i;        /* index in y_array[] */
  766. X    int         y_type;
  767. X    long         y_size;
  768. X    char        **y_array;
  769. X    long         nlines = 0;
  770. X    int            vcol;
  771. X    int            delchar;
  772. X    int            incr = 0;
  773. X    long        j;
  774. X    FPOS        newCurpos;
  775. X
  776. X    startop = Curpos;            /* default for "'[" command */
  777. X    if (dir == FORWARD)
  778. X        startop.col++;
  779. X    endop = Curpos;                /* default for "']" command */
  780. X    if (yankbuffer == '.')        /* use inserted text */
  781. X    {
  782. X        stuff_inserted(dir == FORWARD ? (count == -1 ? 'o' : 'a') : (count == -1 ? 'O' : 'i'), count, FALSE);
  783. X        return;
  784. X    }
  785. X    get_yank_buffer(FALSE);
  786. X
  787. X    y_type = y_current->y_type;
  788. X    y_size = y_current->y_size;
  789. X    y_array = y_current->y_array;
  790. X
  791. X    if (count == -1)        /* :put command */
  792. X    {
  793. X        y_type = MLINE;
  794. X        count = 1;
  795. X    }
  796. X
  797. X    if (y_size == 0 || y_array == NULL)
  798. X    {
  799. X        beep();
  800. X        return;
  801. X    }
  802. X
  803. X    if (y_type == MBLOCK)
  804. X    {
  805. X        lnum = Curpos.lnum + y_size + 1;
  806. X        if (lnum > line_count)
  807. X            lnum = line_count + 1;
  808. X        if (!u_save(Curpos.lnum - 1, lnum))
  809. X            return;
  810. X    }
  811. X    else if (!u_saveCurpos())
  812. X        return;
  813. X
  814. X    newlen = strlen(y_array[0]);
  815. X    CHANGED;
  816. X
  817. X    lnum = Curpos.lnum;
  818. X    col = Curpos.col;
  819. X
  820. X/*
  821. X * block mode
  822. X */
  823. X    if (y_type == MBLOCK)
  824. X    {
  825. X        if (dir == FORWARD && gcharCurpos() != NUL)
  826. X        {
  827. X            col = getvcol(&Curpos, 3) + 1;
  828. X            ++Curpos.col;
  829. X        }
  830. X        else
  831. X            col = getvcol(&Curpos, 2);
  832. X        for (i = 0; i < y_size; ++i)
  833. X        {
  834. X            startspaces = 0;
  835. X            endspaces = 0;
  836. X            textcol = 0;
  837. X            vcol = 0;
  838. X            delchar = 0;
  839. X
  840. X        /* add a new line */
  841. X            if (Curpos.lnum > line_count)
  842. X            {
  843. X                ep = alloc_line(0);
  844. X                if (ep == NULL)
  845. X                        goto error;
  846. X                appendline(line_count, ep);
  847. X                ++nlines;
  848. X            }
  849. X            ptr = nr2ptr(Curpos.lnum);
  850. X            while (vcol < col && *ptr)
  851. X            {
  852. X                /* Count a tab for what it's worth (if list mode not on) */
  853. X                incr = chartabsize(*ptr, vcol);
  854. X                vcol += incr;
  855. X                ++ptr;
  856. X                ++textcol;
  857. X            }
  858. X            if (vcol < col)    /* line too short, padd with spaces */
  859. X            {
  860. X                startspaces = col - vcol;
  861. X            }
  862. X            else if (vcol > col)
  863. X            {
  864. X                endspaces = vcol - col;
  865. X                startspaces = incr - endspaces;
  866. X                --textcol;
  867. X                delchar = 1;
  868. X            }
  869. X            newlen = strlen(y_array[i]);
  870. X            totlen = count * newlen + startspaces + endspaces;
  871. X            if (!canincrease(totlen))
  872. X                break;
  873. X            ptr = nr2ptr(Curpos.lnum) + textcol;
  874. X
  875. X        /* move the text after the cursor to the end of the line. */
  876. X            memmove(ptr + totlen - delchar, ptr, strlen(ptr) + 1);
  877. X        /* may insert some spaces before the new text */
  878. X            copy_spaces(ptr, (size_t)startspaces);
  879. X            ptr += startspaces;
  880. X        /* insert the new text */
  881. X            for (j = 0; j < count; ++j)
  882. X            {
  883. X                    strncpy(ptr, y_array[i], (size_t)newlen);
  884. X                    ptr += newlen;
  885. X            }
  886. X        /* may insert some spaces after the new text */
  887. X            copy_spaces(ptr, (size_t)endspaces);
  888. X
  889. X            ++Curpos.lnum;
  890. X            if (i == 0)
  891. X                Curpos.col += startspaces;
  892. X        }
  893. X        endop.lnum = Curpos.lnum - 1;        /* for "']" command */
  894. X        endop.col = textcol + totlen - 1;
  895. X        Curpos.lnum = lnum;
  896. X        cursupdate();
  897. X        updateScreen(VALID_TO_CURSCHAR);
  898. X    }
  899. X    else        /* not block mode */
  900. X    {
  901. X        if (y_type == MCHAR)
  902. X        {
  903. X    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next character */
  904. X            if (dir == FORWARD && gcharCurpos() != NUL)
  905. X            {
  906. X                ++col;
  907. X                if (newlen)
  908. X                {
  909. X                    ++Curpos.col;
  910. X                    ++endop.col;
  911. X                }
  912. X            }
  913. X            newCurpos = Curpos;
  914. X        }
  915. X        else if (dir == BACKWARD)
  916. X    /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
  917. X            --lnum;
  918. X        else    /* type == MLINE, dir == FORWARD */
  919. X        {
  920. X            startop.col = 0;
  921. X            startop.lnum++;
  922. X        }
  923. X
  924. X/*
  925. X * simple case: insert into current line
  926. X */
  927. X        if (y_type == MCHAR && y_size == 1)
  928. X        {
  929. X            i = count * newlen;
  930. X            if (!canincrease((int)i))
  931. X                    return;                 /* alloc() will give error message */
  932. X            ep = nr2ptr(lnum) + col;
  933. X            memmove(ep + i, ep, strlen(ep) + 1);
  934. X            Curpos.col += i - 1;        /* put cursor on last putted char */
  935. X            for (i = 0; i < count; ++i)
  936. X            {
  937. X                    strncpy(ep, y_array[0], (size_t)newlen);
  938. X                    ep += newlen;
  939. X            }
  940. X            endop = Curpos;
  941. X            updateline();
  942. X        }
  943. X        else
  944. X        {
  945. X            if (y_type == MCHAR)
  946. X                --y_size;
  947. X            while (--count >= 0)
  948. X            {
  949. X                i = 0;
  950. X                if (y_type == MCHAR)
  951. X                {
  952. X                    /*
  953. X                     * Split the current line in two at the insert position.
  954. X                     * Append y_array[0] to first line.
  955. X                     * Insert y_array[size - 1] in front of second line.
  956. X                     */
  957. X                    ptr = nr2ptr(lnum) + col;
  958. X                    col = strlen(y_array[y_size]);
  959. X                    ep = alloc_line((unsigned)(strlen(ptr) + col));
  960. X                    if (ep == NULL)
  961. X                        goto error;
  962. X                    strcpy(ep, y_array[y_size]);
  963. X                    strcat(ep, ptr);
  964. X                    appendline(lnum, ep);            /* insert in second line */
  965. X                    ++nlines;
  966. X                    *ptr = NUL;
  967. X                    Curpos.lnum = lnum;
  968. X                    if (!canincrease(newlen))        /* lnum == Curpos.lnum! */
  969. X                        goto error;
  970. X                    strcat(nr2ptr(lnum), y_array[0]);/* append to first line */
  971. X                    i = 1;
  972. X                }
  973. X
  974. X                while (i < y_size)
  975. X                {
  976. X                    ep = save_line(y_array[i++]);
  977. X                    if (ep == NULL)
  978. X                        goto error;
  979. X                    appendline(lnum++, ep);
  980. X                    ++nlines;
  981. X                }
  982. X                if (y_type == MCHAR)
  983. X                    ++lnum;     /* lnum is now number of line below inserted lines */
  984. X            }
  985. X
  986. X            endop.lnum = lnum;        /* for "']" command */
  987. X            if (y_type == MLINE)
  988. X            {
  989. X                Curpos.col = 0;
  990. X                endop.col = 0;
  991. X                if (dir == FORWARD)
  992. X                {
  993. X                    updateScreen(NOT_VALID);        /* recompute Botline */
  994. X                    ++Curpos.lnum;
  995. X                }
  996. X                    /* put cursor on first non-blank in last inserted line */
  997. X                beginline(TRUE);
  998. X            }
  999. X            else        /* put cursor on first inserted character */
  1000. X            {
  1001. X                if (col > 1)
  1002. X                    endop.col = col - 1;
  1003. X                else
  1004. X                    endop.col = 0;
  1005. X                Curpos = newCurpos;
  1006. X            }
  1007. X
  1008. Xerror:
  1009. X            updateScreen(CURSUPD);
  1010. X        }
  1011. X    }
  1012. X
  1013. X    msgmore(nlines);
  1014. X    set_want_col = TRUE;
  1015. X}
  1016. X
  1017. X/*
  1018. X * display the contents of the yank buffers
  1019. X */
  1020. X    void
  1021. Xdodis()
  1022. X{
  1023. X    register int i, n;
  1024. X    register long j;
  1025. X    register char *p;
  1026. X    register struct yankbuf *yb;
  1027. X
  1028. X#ifdef AMIGA
  1029. X    settmode(0);            /* set cooked mode so output can be halted */
  1030. X#endif
  1031. X    for (i = -1; i < 36; ++i)
  1032. X    {
  1033. X        if (i == -1)
  1034. X        {
  1035. X            if (y_previous != NULL)
  1036. X                yb = y_previous;
  1037. X            else
  1038. X                yb = &(y_buf[0]);
  1039. X        }
  1040. X        else
  1041. X            yb = &(y_buf[i]);
  1042. X        if (yb->y_array != NULL)
  1043. X        {
  1044. X            if (i == -1)
  1045. X                outstrn("pP");
  1046. X            else
  1047. X            {
  1048. X                outchar('"');
  1049. X                if (i < 10)
  1050. X                    outchar(i + '0');
  1051. X                else
  1052. X                    outchar(i + 'a' - 10);
  1053. X            }
  1054. X            outchar(' ');
  1055. X
  1056. X            n = Columns - 4;
  1057. X            for (j = 0; j < yb->y_size && n > 0; ++j)
  1058. X            {
  1059. X                if (j)
  1060. X                {
  1061. X                    outstrn("^J");
  1062. X                    n -= 2;
  1063. X                }
  1064. X                for (p = yb->y_array[j]; *p && n > 0; ++p)
  1065. X                {
  1066. X                    outstrn(transchar(*p));
  1067. X                    n -= charsize(*p);
  1068. X                }
  1069. X            }
  1070. X            outchar('\n');
  1071. X            flushbuf();
  1072. X        }
  1073. X    }
  1074. X#ifdef AMIGA
  1075. X    settmode(1);
  1076. X#endif
  1077. X    wait_return(TRUE);
  1078. X}
  1079. X
  1080. X/*
  1081. X * join 'count' lines (minimal 2), including u_save()
  1082. X */
  1083. X    void
  1084. Xdodojoin(count, flag, redraw)
  1085. X    long    count;
  1086. X    int        flag;
  1087. X    int        redraw;
  1088. X{
  1089. X    if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + count)))
  1090. X        return;
  1091. X
  1092. X    while (--count > 0)
  1093. X        if (!dojoin(flag))
  1094. X        {
  1095. X                beep();
  1096. X                break;
  1097. X        }
  1098. X
  1099. X    if (redraw)
  1100. X        updateScreen(VALID_TO_CURSCHAR);
  1101. X}
  1102. X
  1103. X    int
  1104. Xdojoin(insert_space)
  1105. X    int            insert_space;
  1106. X{
  1107. X    char        *curr;
  1108. X    char        *next;
  1109. X    char        *endcurr;
  1110. X    int         currsize;        /* size of the current line */
  1111. X    int         nextsize;        /* size of the next line */
  1112. X    int            spaces;            /* number of spaces to insert */
  1113. X    int            rows_to_del;    /* number of rows on screen to delete */
  1114. X    linenr_t    t;
  1115. X
  1116. X    if (Curpos.lnum == line_count)        /* on last line */
  1117. X        return FALSE;
  1118. X
  1119. X    rows_to_del = plines_m(Curpos.lnum, Curpos.lnum + 1);
  1120. X    curr = nr2ptr(Curpos.lnum);
  1121. X    currsize = strlen(curr);
  1122. X    next = nr2ptr((linenr_t)(Curpos.lnum + 1));
  1123. X    spaces = 0;
  1124. X    if (insert_space)
  1125. X    {
  1126. X        skipspace(&next);
  1127. X        spaces = 1;
  1128. X        if (*next == ')' || currsize == 0)
  1129. X            spaces = 0;
  1130. X        else
  1131. X        {
  1132. X            endcurr = curr + currsize - 1;
  1133. X            if (*endcurr == ' ' || *endcurr == TAB)
  1134. X            {
  1135. X                spaces = 0;
  1136. X                if (currsize > 1)
  1137. X                    --endcurr;
  1138. X            }
  1139. X            if (p_js && strchr(".!?", *endcurr) != NULL)
  1140. X                ++spaces;
  1141. X        }
  1142. X    }
  1143. X    nextsize = strlen(next);
  1144. X    if (!canincrease(nextsize + spaces))
  1145. X        return FALSE;
  1146. X
  1147. X    curr = nr2ptr(Curpos.lnum); /* canincrease() will have changed the pointer */
  1148. X
  1149. X    while (spaces)
  1150. X    {
  1151. X        *(curr + currsize++) = ' ';
  1152. X        --spaces;
  1153. X    }
  1154. X    strcpy(curr + currsize, next);
  1155. X
  1156. X    /*
  1157. X     * Delete the following line. To do this we move the cursor there
  1158. X     * briefly, and then move it back.
  1159. X     */
  1160. X    t = Curpos.lnum;
  1161. X    ++Curpos.lnum;
  1162. X    dellines(1L, FALSE);
  1163. X    Curpos.lnum = t;
  1164. X
  1165. X    /*
  1166. X     * the number of rows on the screen is reduced by the difference
  1167. X     * in number of rows of the two old lines and the one new line
  1168. X     */
  1169. X    rows_to_del -= plines(Curpos.lnum);
  1170. X    if (rows_to_del > 0)
  1171. X        s_del(Cursrow, rows_to_del, TRUE);
  1172. X
  1173. X    if (currsize == 0)
  1174. X        Curpos.col = 0;
  1175. X    else
  1176. X    {
  1177. X        Curpos.col = currsize - 1;
  1178. X        oneright();     /* go to first char. of joined line */
  1179. X    }
  1180. X    CHANGED;
  1181. X
  1182. X    return TRUE;
  1183. X}
  1184. X
  1185. X/*
  1186. X * implementation of the format operator 'V'
  1187. X */
  1188. X    void
  1189. Xdoformat()
  1190. X{
  1191. X        /* prepare undo and join the lines */
  1192. X    dodojoin((long)endop.lnum - (long)startop.lnum + 1, TRUE, FALSE);
  1193. X
  1194. X        /* put cursor on last non-space */
  1195. X    coladvance(29999);
  1196. X    while (Curpos.col && isspace(gcharCurpos()))
  1197. X        decCurpos();
  1198. X    curs_columns();            /* update Cursvcol */
  1199. X
  1200. X        /* do the formatting */
  1201. X    State = INSERT;        /* for Opencmd() */
  1202. X    insertchar(NUL);
  1203. X    State = NORMAL;
  1204. X    updateScreen(NOT_VALID);
  1205. X}
  1206. X
  1207. X    void
  1208. Xstartinsert(initstr, startln, count)
  1209. X    int            initstr;
  1210. X    int         startln;        /* if set, insert at start of line */
  1211. X    long         count;
  1212. X{
  1213. X    Insstart = Curpos;
  1214. X    if (startln)
  1215. X        Insstart.col = 0;
  1216. X
  1217. X    if (initstr != NUL)
  1218. X    {
  1219. X            ResetBuffers();
  1220. X            AppendNumberToRedobuff(count);
  1221. X            AppendToRedobuff(mkstr(initstr));
  1222. X    }
  1223. X
  1224. X    if (initstr == 'R')
  1225. X        State = REPLACE;
  1226. X    else
  1227. X        State = INSERT;
  1228. X
  1229. X    if (p_mo)
  1230. X        showmode();
  1231. X
  1232. X    edit(count);
  1233. X}
  1234. X
  1235. X/*
  1236. X * prepare a few things for block mode yank/delete/tilde
  1237. X *
  1238. X * for delete:
  1239. X * - textlen includes the first/last char to be (partly) deleted
  1240. X * - start/endspaces is the number of columns that are taken by the
  1241. X *     first/last deleted char minus the number of columns that have to be deleted.
  1242. X * for yank and tilde:
  1243. X * - textlen includes the first/last char to be wholly yanked
  1244. X * - start/endspaces is the number of columns of the first/last yanked char
  1245. X *   that are to be yanked.
  1246. X */
  1247. X    static void
  1248. Xblock_prep(lnum, delete)
  1249. X    linenr_t    lnum;
  1250. X    int            delete;
  1251. X{
  1252. X    int            vcol;
  1253. X    int            incr = 0;
  1254. X    char        *pend;
  1255. X
  1256. X    startspaces = 0;
  1257. X    endspaces = 0;
  1258. X    textlen = 0;
  1259. X    textcol = 0;
  1260. X    vcol = 0;
  1261. X    textstart = nr2ptr(lnum);
  1262. X    while (vcol < startvcol && *textstart)
  1263. X    {
  1264. X        /* Count a tab for what it's worth (if list mode not on) */
  1265. X        incr = chartabsize(*textstart, vcol);
  1266. X        vcol += incr;
  1267. X        ++textstart;
  1268. X        ++textcol;
  1269. X    }
  1270. X    if (vcol < startvcol)    /* line too short */
  1271. X    {
  1272. X        if (!delete)
  1273. X            endspaces = endvcol - startvcol + 1;
  1274. X    }
  1275. X    else /* vcol >= startvcol */
  1276. X    {
  1277. X        startspaces = vcol - startvcol;
  1278. X        if (delete && vcol > startvcol)
  1279. X            startspaces = incr - startspaces;
  1280. X        pend = textstart;
  1281. X        while (vcol <= endvcol && *pend)
  1282. X        {
  1283. X            /* Count a tab for what it's worth (if list mode not on) */
  1284. X            incr = chartabsize(*pend, vcol);
  1285. X            vcol += incr;
  1286. X            ++pend;
  1287. X        }
  1288. X        if (vcol < endvcol && !delete)    /* line too short */
  1289. X        {
  1290. X            endspaces = endvcol - vcol;
  1291. X        }
  1292. X        else if (vcol > endvcol)
  1293. X        {
  1294. X            if (delete)
  1295. X                endspaces = vcol - endvcol - 1;
  1296. X            else if (pend != textstart)
  1297. X            {
  1298. X                endspaces = incr - (vcol - endvcol);
  1299. X                if (endspaces)
  1300. X                    --pend;
  1301. X            }
  1302. X        }
  1303. X        if (delete && startspaces)
  1304. X        {
  1305. X            --textstart;
  1306. X            --textcol;
  1307. X        }
  1308. X        textlen = pend - textstart;
  1309. X    }
  1310. X}
  1311. X
  1312. X    int
  1313. Xdoaddsub(c, Prenum1)
  1314. X    int            c;
  1315. X    linenr_t    Prenum1;
  1316. X{
  1317. X    register int     col;
  1318. X    char            buf[30];
  1319. X    int                hex;        /* 'x' or 'X': hexadecimal; '0': octal */
  1320. X    static int        hexupper = FALSE;    /* 0xABC */
  1321. X    long            n;
  1322. X    char            *ptr;
  1323. X
  1324. X    ptr = nr2ptr(Curpos.lnum);
  1325. X    col = Curpos.col;
  1326. X
  1327. X        /* first check if we are on a hexadecimal number */
  1328. X    while (col > 0 && isxdigit(ptr[col]))
  1329. X        --col;
  1330. X    if (col > 0 && toupper(ptr[col]) == 'X' && ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
  1331. X        --col;        /* found hexadecimal number */
  1332. X    else
  1333. X    {
  1334. X        /* first search forward and then backward for start of number */
  1335. X        col = Curpos.col;
  1336. X
  1337. X        while (ptr[col] != NUL && !isdigit(ptr[col]))
  1338. X            ++col;
  1339. X
  1340. X        while (col > 0 && isdigit(ptr[col - 1]))
  1341. X            --col;
  1342. X    }
  1343. X
  1344. X    if (isdigit(ptr[col]) && u_saveCurpos())
  1345. X    {
  1346. X        set_want_col = TRUE;
  1347. X
  1348. X        if (ptr[col] != '0')
  1349. X            hex = 0;                /* decimal */
  1350. X        else
  1351. X        {
  1352. X            hex = toupper(ptr[col + 1]);        /* assume hexadecimal */
  1353. X            if (hex != 'X' || !isxdigit(ptr[col + 2]))
  1354. X            {
  1355. X                if (isdigit(hex))
  1356. X                    hex = '0';        /* octal */
  1357. X                else
  1358. X                    hex = 0;        /* 0 by itself is decimal */
  1359. X            }
  1360. X        }
  1361. X
  1362. X        if (!hex && col > 0 && ptr[col - 1] == '-')
  1363. X            --col;
  1364. X
  1365. X        ptr += col;
  1366. X        if (hex == '0')
  1367. X            sscanf(ptr, "%lo", &n);
  1368. X        else if (hex)
  1369. X            sscanf(ptr, "%lx", &n);    /* "%X" doesn't work! */
  1370. X        else
  1371. X            n = atol(ptr);
  1372. X
  1373. X        if (c == Ctrl('A'))
  1374. X            n += Prenum1;
  1375. X        else
  1376. X            n -= Prenum1;
  1377. X
  1378. X        if (hex == 'X')                    /* skip the '0x' */
  1379. X            col += 2;
  1380. X        Curpos.col = col;
  1381. X        do                                /* delete the old number */
  1382. X        {
  1383. X            if (isalpha(c))
  1384. X            {
  1385. X                if (isupper(c))
  1386. X                    hexupper = TRUE;
  1387. X                else
  1388. X                    hexupper = FALSE;
  1389. X            }
  1390. X            delchar(FALSE);
  1391. X            c = gcharCurpos();
  1392. X        }
  1393. X        while (hex ? (hex == '0' ? c >= '0' && c <= '7' : isxdigit(c)) : isdigit(c));
  1394. X
  1395. X        if (hex == '0')
  1396. X            sprintf(buf, "0%lo", n);
  1397. X        else if (hexupper)
  1398. X            sprintf(buf, "%lX", n);
  1399. X        else if (hex)
  1400. X            sprintf(buf, "%lx", n);
  1401. X        else
  1402. X            sprintf(buf, "%ld", n);
  1403. X        insstr(buf);                    /* insert the new number */
  1404. X        --Curpos.col;
  1405. X        updateline();
  1406. X        return TRUE;
  1407. X    }
  1408. X    else
  1409. X    {
  1410. X        beep();
  1411. X        return FALSE;
  1412. X    }
  1413. X}
  1414. END_OF_FILE
  1415. if test 28332 -ne `wc -c <'vim/src/ops.c'`; then
  1416.     echo shar: \"'vim/src/ops.c'\" unpacked with wrong size!
  1417. fi
  1418. # end of 'vim/src/ops.c'
  1419. fi
  1420. if test -f 'vim/src/search.c' -a "${1}" != "-c" ; then 
  1421.   echo shar: Will not clobber existing file \"'vim/src/search.c'\"
  1422. else
  1423. echo shar: Extracting \"'vim/src/search.c'\" \(21652 characters\)
  1424. sed "s/^X//" >'vim/src/search.c' <<'END_OF_FILE'
  1425. X/* vi:ts=4:sw=4
  1426. X *
  1427. X * VIM - Vi IMitation
  1428. X *
  1429. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  1430. X *                            Tim Thompson            twitch!tjt
  1431. X *                            Tony Andrews            onecom!wldrdg!tony
  1432. X *                            G. R. (Fred) Walter     watmath!watcgl!grwalter
  1433. X */
  1434. X/*
  1435. X * search.c: code for normal mode searching commands
  1436. X */
  1437. X
  1438. X#include "vim.h"
  1439. X#include "globals.h"
  1440. X#include "proto.h"
  1441. X#include "param.h"
  1442. X
  1443. X/* modified Henry Spencer's regular expression routines */
  1444. X#include "regexp.h"
  1445. X
  1446. Xstatic int inmacro __ARGS((char *, char *));
  1447. Xstatic int cls __ARGS((void));
  1448. X
  1449. X/*
  1450. X * This file contains various searching-related routines. These fall into
  1451. X * three groups:
  1452. X * 1. string searches (for /, ?, n, and N)
  1453. X * 2. character searches within a single line (for f, F, t, T, etc)
  1454. X * 3. "other" kinds of searches like the '%' command, and 'word' searches.
  1455. X */
  1456. X
  1457. X/*
  1458. X * String searches
  1459. X *
  1460. X * The string search functions are divided into two levels:
  1461. X * lowest:    searchit(); called by dosearch() and docmdline().
  1462. X * Highest: dosearch(); changes Curpos, called by normal().
  1463. X *
  1464. X * The last search pattern is remembered for repeating the same search.
  1465. X * This pattern is shared between the :g, :s, ? and / commands.
  1466. X * This is in myregcomp().
  1467. X *
  1468. X * The actual string matching is done using a heavily modified version of
  1469. X * Henry Spencer's regular expression library.
  1470. X */
  1471. X
  1472. Xstatic char     *search_pattern = NULL;  /* previous search pattern */
  1473. Xstatic int        want_start;              /* looking for start of line? */
  1474. X
  1475. X/*
  1476. X * translate search pattern for regcomp()
  1477. X */
  1478. X    regexp *
  1479. Xmyregcomp(pat)
  1480. X    char *pat;
  1481. X{
  1482. X    regexp *retval;
  1483. X
  1484. X    if (pat == NULL || *pat == NUL)     /* use previous search pattern */
  1485. X    {
  1486. X        if (search_pattern == NULL)
  1487. X        {
  1488. X            emsg(e_noprevre);
  1489. X            return (regexp *) NULL;
  1490. X        }
  1491. X        pat = search_pattern;
  1492. X    }
  1493. X    else
  1494. X    {
  1495. X        if (search_pattern != NULL)
  1496. X            free(search_pattern);
  1497. X        search_pattern = strsave(pat);
  1498. X        reg_magic = p_magic;        /* Magic sticks with the r.e. */
  1499. X    }
  1500. X    want_start = (*pat == '^');        /* looking for start of line? */
  1501. X    reg_ic = p_ic;                /* tell the regexec routine how to search */
  1502. X    retval = regcomp(pat);
  1503. X    return retval;
  1504. X}
  1505. X
  1506. X/*
  1507. X * lowest level search function.
  1508. X * Search for 'count'th occurrence of 'str' in direction 'dir'.
  1509. X * Start at position 'pos' and return the found position in 'pos'.
  1510. X * Return 1 for success, 0 for failure.
  1511. X */
  1512. X    int
  1513. Xsearchit(pos, dir, str, count, end)
  1514. X    FPOS    *pos;
  1515. X    int     dir;
  1516. X    char    *str;
  1517. X    long    count;
  1518. X    int        end;
  1519. X{
  1520. X    int             found;
  1521. X    linenr_t        lnum;
  1522. X    linenr_t        startlnum;
  1523. X    regexp           *prog;
  1524. X    register char  *s;
  1525. X    char           *ptr;
  1526. X    register int    i;
  1527. X    register char  *match, *matchend;
  1528. X    int             loop;
  1529. X
  1530. X    if ((prog = myregcomp(str)) == NULL)
  1531. X    {
  1532. X        emsg(e_invstring);
  1533. X        return 0;
  1534. X    }
  1535. X/*
  1536. X * find the string
  1537. X */
  1538. X    found = 1;
  1539. X    while (count-- && found)    /* stop after count matches, or no more matches */
  1540. X    {
  1541. X        startlnum = pos->lnum;    /* remember start of search for detecting no match */
  1542. X        found = 0;                /* default: not found */
  1543. X
  1544. X        i = pos->col + dir;     /* search starts one postition away */
  1545. X        lnum = pos->lnum;
  1546. X
  1547. X        if (dir == BACKWARD)
  1548. X        {
  1549. X            if (i < 0)
  1550. X                --lnum;
  1551. X        }
  1552. X
  1553. X        for (loop = 0; loop != 2; ++loop)   /* do this twice if 'wrapscan' is set */
  1554. X        {
  1555. X            for ( ; lnum > 0 && lnum <= line_count; lnum += dir, i = -1)
  1556. X            {
  1557. X                s = ptr = nr2ptr(lnum);
  1558. X                if (dir == FORWARD && i > 0)    /* first line for forward search */
  1559. X                {
  1560. X                    if (want_start || strlen(s) <= (size_t)i)   /* match not possible */
  1561. X                        continue;
  1562. X                    s += i;
  1563. X                }
  1564. X
  1565. X                if (regexec(prog, s, dir == BACKWARD || i <= 0))
  1566. X                {                            /* match somewhere on line */
  1567. X                    match = prog->startp[0];
  1568. X                    matchend = prog->endp[0];
  1569. X                    if (dir == BACKWARD && !want_start)
  1570. X                    {
  1571. X                        /*
  1572. X                         * Now, if there are multiple matches on this line, we have to
  1573. X                         * get the last one. Or the last one before the cursor, if we're
  1574. X                         * on that line.
  1575. X                         */
  1576. X                        while (regexec(prog, prog->startp[0] + 1, (int)FALSE))
  1577. X                        {
  1578. X                            if ((i >= 0) && ((prog->startp[0] - s) > i))
  1579. X                                break;
  1580. X                            match = prog->startp[0];
  1581. X                            matchend = prog->endp[0];
  1582. X                        }
  1583. X
  1584. X                        if ((i >= 0) && ((match - s) > i))
  1585. X                            continue;
  1586. X                    }
  1587. X
  1588. X                    pos->lnum = lnum;
  1589. X                    if (end)
  1590. X                        pos->col = (int) (matchend - ptr - 1);
  1591. X                    else
  1592. X                        pos->col = (int) (match - ptr);
  1593. X                    found = 1;
  1594. X                    break;
  1595. X                }
  1596. X                /* breakcheck is slow, do it only once in 16 lines */
  1597. X                if ((lnum & 15) == 0)
  1598. X                    breakcheck();       /* stop if ctrl-C typed */
  1599. X                if (got_int)
  1600. X                    break;
  1601. X
  1602. X                if (loop && lnum == startlnum)  /* if second loop stop where started */
  1603. X                    break;
  1604. X            }
  1605. X    /* stop the search if wrapscan isn't set, after an interrupt and after a match */
  1606. X            if (!p_ws || got_int || found)
  1607. X                break;
  1608. X
  1609. X            if (dir == BACKWARD)    /* start second loop at the other end */
  1610. X                lnum = line_count;
  1611. X            else
  1612. X                lnum = 1;
  1613. X        }
  1614. X        if (got_int)
  1615. X            break;
  1616. X    }
  1617. X
  1618. X    free((char *) prog);
  1619. X
  1620. X    if (!found)             /* did not find it */
  1621. X    {
  1622. X        if (got_int)
  1623. X                emsg(e_interr);
  1624. X        else
  1625. X                emsg(e_patnotf);
  1626. X        return 0;
  1627. X    }
  1628. X
  1629. X    return 1;
  1630. X}
  1631. X
  1632. X/*
  1633. X * Highest level string search function.
  1634. X * Search for the 'count'th occurence of string 'str' in direction 'dir'
  1635. X *                     If 'dir' is 0: use previous dir.
  1636. X * If 'str' is 0 or 'str' is empty: use previous string.
  1637. X *              If 'reverse' is TRUE: go in reverse of previous dir.
  1638. X *                 If 'echo' is TRUE: echo the search command
  1639. X */
  1640. X    int
  1641. Xdosearch(dir, str, reverse, count, echo)
  1642. X    int                dir;
  1643. X    char           *str;
  1644. X    int                reverse;
  1645. X    long            count;
  1646. X    int                echo;
  1647. X{
  1648. X    FPOS            pos;        /* position of the last match */
  1649. X    int                dirc;
  1650. X    static int        lastsdir = FORWARD;    /* previous search direction */
  1651. X    static int        lastoffline;/* previous/current search has line offset */
  1652. X    static int        lastend;    /* previous/current search set cursor at end */
  1653. X    static long     lastoff;    /* previous/current line or char offset */
  1654. X    static int        nosetpm;    /* do not call setpcmark() */
  1655. X    register char    *p;
  1656. X    register long    c;
  1657. X    char            *dircp = NULL;
  1658. X
  1659. X    if (dir == 0)
  1660. X        dir = lastsdir;
  1661. X    else
  1662. X        lastsdir = dir;
  1663. X    if (reverse)
  1664. X        dir = -dir;
  1665. X
  1666. X    dirc = (dir == FORWARD ? '/' : '?');
  1667. X    if (str == NULL || *str == NUL)     /* use previous string and options */
  1668. X    {
  1669. X        if (search_pattern == NULL)
  1670. X        {
  1671. X            emsg(e_noprevre);
  1672. X            return 0;
  1673. X        }
  1674. X        str = "";
  1675. X    }
  1676. X    else
  1677. X    {
  1678. X        /* If there is a matching '/' or '?', toss it */
  1679. X        for (p = str; *p; ++p)
  1680. X        {
  1681. X            if (*p == dirc)
  1682. X            {
  1683. X                dircp = p;        /* remember where we put the NUL */
  1684. X                *p++ = NUL;
  1685. X                break;
  1686. X            }
  1687. X            if (*p == '\\' && p[1] != NUL)
  1688. X                ++p;    /* skip next character */
  1689. X        }
  1690. X
  1691. X        lastoffline = FALSE;
  1692. X        lastend = FALSE;
  1693. X        nosetpm = FALSE;
  1694. X        lastoff = 0;
  1695. X        switch (*p)
  1696. X        {
  1697. X            case 'n':   nosetpm = TRUE; /* do not call setpcmark() */
  1698. X                        ++p;
  1699. X                        break;
  1700. X            case '+':
  1701. X            case '-':                   /* got a line offset */
  1702. X                        lastoffline = TRUE;
  1703. X                        break;
  1704. X            case 'e':                   /* position cursor at end */
  1705. X                        lastend = TRUE;
  1706. X            case 's':                   /* got a character offset from start */
  1707. X                        ++p;
  1708. X        }
  1709. X        if (*p == '+' || *p == '-')     /* got an offset */
  1710. X        {
  1711. X            lastoff = atol(p);
  1712. X            ++p;                        /* skip number */
  1713. X            while (isdigit(*p))
  1714. X                ++p;
  1715. X        }
  1716. X        searchcmdlen = p - str;            /* compute lenght of search command
  1717. X                                                        for get_address() */
  1718. X    }
  1719. X
  1720. X    if (echo)
  1721. X    {
  1722. X        smsg("%c%s", dirc, *str == NUL ? search_pattern : str);
  1723. X        if (lastoffline || lastend || lastoff || nosetpm)
  1724. X        {
  1725. X            outchar(dirc);
  1726. X            if (nosetpm)
  1727. X                outchar('n');
  1728. X            else if (lastend)
  1729. X                outchar('e');
  1730. X            else if (!lastoffline)
  1731. X                outchar('s');
  1732. X            if (lastoff < 0)
  1733. X            {
  1734. X                outchar('-');
  1735. X                outnum((long)-lastoff);
  1736. X            }
  1737. X            else if (lastoff > 0 || lastoffline)
  1738. X            {
  1739. X                outchar('+');
  1740. X                outnum((long)lastoff);
  1741. X            }
  1742. X        }
  1743. X
  1744. X        gotocmdline(FALSE, NUL);
  1745. X        flushbuf();
  1746. X    }
  1747. X
  1748. X    pos = Curpos;
  1749. X
  1750. X    c = searchit(&pos, dir, str, count, lastend);
  1751. X    if (dircp)
  1752. X        *dircp = dirc;        /* put second '/' or '?' back for normal() */
  1753. X    if (!c)
  1754. X        return 0;
  1755. X
  1756. X    if (!lastoffline)           /* add the character offset to the column */
  1757. X    {
  1758. X        if (lastoff > 0)        /* offset to the right, check for end of line */
  1759. X        {
  1760. X            p = pos2ptr(&pos) + 1;
  1761. X            c = lastoff;
  1762. X            while (c-- && *p++ != NUL)
  1763. X                ++pos.col;
  1764. X        }
  1765. X        else                    /* offset to the left, check for start of line */
  1766. X        {
  1767. X            if ((c = pos.col + lastoff) < 0)
  1768. X                c = 0;
  1769. X            pos.col = c;
  1770. X        }
  1771. X    }
  1772. X
  1773. X    if (!nosetpm)
  1774. X        setpcmark();
  1775. X    Curpos = pos;
  1776. X    set_want_col = TRUE;
  1777. X
  1778. X    if (!lastoffline)
  1779. X        return 1;
  1780. X
  1781. X/*
  1782. X * add the offset to the line number.
  1783. X */
  1784. X    c = Curpos.lnum + lastoff;
  1785. X    if (c < 1)
  1786. X        Curpos.lnum = 1;
  1787. X    else if (c > line_count)
  1788. X        Curpos.lnum = line_count;
  1789. X    else
  1790. X        Curpos.lnum = c;
  1791. X    Curpos.col = 0;
  1792. X
  1793. X    return 2;
  1794. X}
  1795. X
  1796. X
  1797. X/*
  1798. X * Character Searches
  1799. X */
  1800. X
  1801. X/*
  1802. X * searchc(c, dir, type, count)
  1803. X *
  1804. X * Search for character 'c', in direction 'dir'. If 'type' is 0, move to the
  1805. X * position of the character, otherwise move to just before the char.
  1806. X * Repeat this 'count' times.
  1807. X */
  1808. X    int
  1809. Xsearchc(c, dir, type, count)
  1810. X    int             c;
  1811. X    register int    dir;
  1812. X    int             type;
  1813. X    long            count;
  1814. X{
  1815. X    static char     lastc = NUL;    /* last character searched for */
  1816. X    static int        lastcdir;        /* last direction of character search */
  1817. X    static int        lastctype;        /* last type of search ("find" or "to") */
  1818. X    register int    col;
  1819. X    char            *p;
  1820. X    int             len;
  1821. X
  1822. X    if (c != NUL)       /* normal search: remember args for repeat */
  1823. X    {
  1824. X        lastc = c;
  1825. X        lastcdir = dir;
  1826. X        lastctype = type;
  1827. X    }
  1828. X    else                /* repeat previous search */
  1829. X    {
  1830. X        if (lastc == NUL)
  1831. X            return FALSE;
  1832. X        if (dir)        /* repeat in opposite direction */
  1833. X            dir = -lastcdir;
  1834. X        else
  1835. X            dir = lastcdir;
  1836. X    }
  1837. X
  1838. X    p = nr2ptr(Curpos.lnum);
  1839. X    col = Curpos.col;
  1840. X    len = strlen(p);
  1841. X
  1842. X    /*
  1843. X     * On 'to' searches, skip one to start with so we can repeat searches in
  1844. X     * the same direction and have it work right.
  1845. X     * REMOVED to get vi compatibility
  1846. X     * if (lastctype)
  1847. X     *    col += dir;
  1848. X     */
  1849. X
  1850. X    while (count--)
  1851. X    {
  1852. X            for (;;)
  1853. X            {
  1854. X                if ((col += dir) < 0 || col >= len)
  1855. X                    return FALSE;
  1856. X                if (p[col] == lastc)
  1857. X                        break;
  1858. X            }
  1859. X    }
  1860. X    if (lastctype)
  1861. X        col -= dir;
  1862. X    Curpos.col = col;
  1863. X    return TRUE;
  1864. X}
  1865. X
  1866. X/*
  1867. X * "Other" Searches
  1868. X */
  1869. X
  1870. X/*
  1871. X * showmatch - move the cursor to the matching paren or brace
  1872. X */
  1873. X    FPOS           *
  1874. Xshowmatch()
  1875. X{
  1876. X    static FPOS pos;
  1877. X    char        initc;        /* char under cursor */
  1878. X    char        findc;        /* matching char */
  1879. X    char        c;
  1880. X    int         count = 0;
  1881. X    int         i;
  1882. X    static char table[6] = {'(', ')', '[', ']', '{', '}'};
  1883. X    int         inquote = 0;
  1884. X    register char        *p;
  1885. X
  1886. X    pos = Curpos;
  1887. X
  1888. X    for (p = nr2ptr(pos.lnum); ;++pos.col)
  1889. X    {
  1890. X        if ((initc = p[pos.col]) == NUL)
  1891. X            return (FPOS *) NULL;
  1892. X        for (i = 0; i < 6; ++i)
  1893. X            if (table[i] == initc)
  1894. X                goto foundit;
  1895. X    }
  1896. X
  1897. Xfoundit:
  1898. X    if (i & 1)                  /* backward search */
  1899. X        findc = table[i - 1];
  1900. X    else                        /* forward search */
  1901. X        findc = table[i + 1];
  1902. X    i &= 1;
  1903. X
  1904. X    /* we only do a breakcheck() once for every 16 lines */
  1905. X    while (!got_int)
  1906. X    {
  1907. X            /* we could use inc() and dec() here, but that is much slower */
  1908. X        if (i)              /* backward search */
  1909. X        {
  1910. X            if (pos.col == 0)   /* at start of line, go to previous one */
  1911. X            {
  1912. X                if (pos.lnum == 1)      /* start of file */
  1913. X                    break;
  1914. X                --pos.lnum;
  1915. X                p = nr2ptr(pos.lnum);
  1916. X                pos.col = strlen(p);
  1917. X                if ((pos.lnum & 15) == 0)
  1918. X                    breakcheck();
  1919. X            }
  1920. X            else
  1921. X                --pos.col;
  1922. X        }
  1923. X        else                    /* forward search */
  1924. X        {
  1925. X            if (p[pos.col] == NUL)  /* at end of line, go to next one */
  1926. X            {
  1927. X                if (pos.lnum == line_count) /* end of file */
  1928. X                    break;
  1929. X                ++pos.lnum;
  1930. X                pos.col = 0;
  1931. X                p = nr2ptr(pos.lnum);
  1932. X                if ((pos.lnum & 15) == 0)
  1933. X                    breakcheck();
  1934. X            }
  1935. X            else
  1936. X                ++pos.col;
  1937. X        }
  1938. X
  1939. X        /*
  1940. X         * anything that is preceded with a backslash is ignored
  1941. X         */
  1942. X        if (pos.col == 0 || p[pos.col - 1] != '\\')
  1943. X        {
  1944. X        /*
  1945. X         * Things inside quotes are ignored by setting 'inquote'.
  1946. X         * If we find a quote without a preceding '\' invert 'inquote'.
  1947. X         * At the end of a line not ending in '\' we reset 'inquote'.
  1948. X         */
  1949. X            switch (c = p[pos.col])
  1950. X            {
  1951. X            case NUL:
  1952. X                inquote = FALSE;
  1953. X                break;
  1954. X
  1955. X            case '"':
  1956. X                inquote = !inquote;
  1957. X                break;
  1958. X
  1959. X            /*
  1960. X             * Skip things in single quotes: 'x' or '\x'.
  1961. X             * Be careful for single single quotes, eg jon's.
  1962. X             * Things like '\233' or '\x3f' are ok, there is no brace in it.
  1963. X             */
  1964. X            case '\'':
  1965. X                if (i)                        /* backward search */
  1966. X                {
  1967. X                    if (pos.col > 1)
  1968. X                    {
  1969. X                        if (p[pos.col - 2] == '\'')
  1970. X                            pos.col -= 2;
  1971. X                        else if (p[pos.col - 2] == '\\' && pos.col > 2 && p[pos.col - 3] == '\'')
  1972. X                            pos.col -= 3;
  1973. X                    }
  1974. X                }
  1975. X                else if (p[pos.col + 1])    /* forward search */
  1976. X                {
  1977. X                    if (p[pos.col + 1] == '\\' && p[pos.col + 2] && p[pos.col + 3] == '\'')
  1978. X                        pos.col += 3;
  1979. X                    else if (p[pos.col + 2] == '\'')
  1980. X                        pos.col += 2;
  1981. X                }
  1982. X                break;
  1983. X
  1984. X            default:
  1985. X                if (!inquote)      /* only check for match outside of quotes */
  1986. X                {
  1987. X                    if (c == initc)
  1988. X                        count++;
  1989. X                    else if (c == findc)
  1990. X                    {
  1991. X                        if (count == 0)
  1992. X                            return &pos;
  1993. X                        count--;
  1994. X                    }
  1995. X                }
  1996. X            }
  1997. X        }
  1998. X    }
  1999. X    return (FPOS *) NULL;       /* never found it */
  2000. X}
  2001. X
  2002. X/*
  2003. X * findfunc(dir, what) - Find the next line starting with 'what' in direction 'dir'
  2004. X *
  2005. X * Return TRUE if a line was found.
  2006. X */
  2007. X    int
  2008. Xfindfunc(dir, what, count)
  2009. X    int         dir;
  2010. X    int            what;
  2011. X    long        count;
  2012. X{
  2013. X    linenr_t    curr;
  2014. X
  2015. X    curr = Curpos.lnum;
  2016. X
  2017. X    for (;;)
  2018. X    {
  2019. X        if (dir == FORWARD)
  2020. X        {
  2021. X                if (curr++ == line_count)
  2022. X                        break;
  2023. X        }
  2024. X        else
  2025. X        {
  2026. X                if (curr-- == 1)
  2027. X                        break;
  2028. X        }
  2029. X
  2030. X        if (*nr2ptr(curr) == what)
  2031. X        {
  2032. X            if (--count > 0)
  2033. X                continue;
  2034. X            setpcmark();
  2035. X            Curpos.lnum = curr;
  2036. X            Curpos.col = 0;
  2037. X            return TRUE;
  2038. X        }
  2039. X    }
  2040. X
  2041. X    return FALSE;
  2042. X}
  2043. X
  2044. X/*
  2045. X * findsent(dir, count) - Find the start of the next sentence in direction 'dir'
  2046. X * Sentences are supposed to end in ".", "!" or "?" followed by white space,
  2047. X * or at an empty line.
  2048. X * Return TRUE if the next sentence was found.
  2049. X */
  2050. X    int
  2051. Xfindsent(dir, count)
  2052. X        int     dir;
  2053. X        long    count;
  2054. X{
  2055. X        FPOS            pos, tpos;
  2056. X        register int    c;
  2057. X        int             (*func) __PARMS((FPOS *));
  2058. X        int             startlnum;
  2059. X
  2060. X        pos = Curpos;
  2061. X        if (dir == FORWARD)
  2062. X                func = incl;
  2063. X        else
  2064. X                func = decl;
  2065. X
  2066. X        while (count--)
  2067. X        {
  2068. X                /* if on an empty line, skip upto a non-empty line */
  2069. X                if (gchar(&pos) == NUL)
  2070. X                {
  2071. X                        do
  2072. X                                if ((*func)(&pos) == -1)
  2073. X                                        break;
  2074. X                        while (gchar(&pos) == NUL);
  2075. X                        if (dir == FORWARD)
  2076. X                                goto found;
  2077. X                }
  2078. X                /* if on the start of a paragraph or a section and searching
  2079. X                 * forward, go to the next line */
  2080. X                else if (dir == FORWARD && pos.col == 0 && startPS(pos.lnum, NUL))
  2081. X                {
  2082. X                        if (pos.lnum == line_count)
  2083. X                            return FALSE;
  2084. X                        ++pos.lnum;
  2085. X                        goto found;
  2086. X                }
  2087. X                else if (dir == BACKWARD)
  2088. X                        decl(&pos);
  2089. X
  2090. X                /* go back to the previous non-blank char */
  2091. X                while ((c = gchar(&pos)) == ' ' || c == '\t' ||
  2092. X                        (dir == BACKWARD && strchr(".!?)]\"'", c) != NULL))
  2093. X                        if (decl(&pos) == -1)
  2094. X                                break;
  2095. X
  2096. X                /* remember the line where the search started */
  2097. X                startlnum = pos.lnum;
  2098. X
  2099. X                for (;;)                /* find end of sentence */
  2100. X                {
  2101. X                        if ((c = gchar(&pos)) == NUL ||
  2102. X                                (pos.col == 0 && startPS(pos.lnum, NUL)))
  2103. X                        {
  2104. X                            if (dir == BACKWARD && pos.lnum != startlnum)
  2105. X                                ++pos.lnum;
  2106. X                            break;
  2107. X                        }
  2108. X                        if (c == '.' || c == '!' || c == '?')
  2109. X                        {
  2110. X                                tpos = pos;
  2111. X                                do
  2112. X                                    if ((c = inc(&tpos)) == -1)
  2113. X                                        break;
  2114. X                                while (strchr(")}\"'", c = gchar(&tpos)) != NULL);
  2115. X                                if (c == -1  || c == ' ' || c == '\t' || c == NUL)
  2116. X                                {
  2117. X                                        pos = tpos;
  2118. X                                        if (gchar(&pos) == NUL) /* skip NUL at EOL */
  2119. X                                                inc(&pos);
  2120. X                                        break;
  2121. X                                }
  2122. X                        }
  2123. X                        if ((*func)(&pos) == -1)
  2124. X                        {
  2125. X                                if (count)
  2126. X                                        return FALSE;
  2127. X                                break;
  2128. X                        }
  2129. X                }
  2130. Xfound:
  2131. X                /* skip white space */
  2132. X                while ((c = gchar(&pos)) == ' ' || c == '\t')
  2133. X                        if (incl(&pos) == -1)
  2134. X                                break;
  2135. X        }
  2136. X
  2137. X        Curpos = pos;
  2138. X        setpcmark();
  2139. X        return TRUE;
  2140. X}
  2141. X
  2142. X/*
  2143. X * findpar(dir, count, what) - Find the next paragraph in direction 'dir'
  2144. X * Paragraphs are currently supposed to be separated by empty lines.
  2145. X * Return TRUE if the next paragraph was found.
  2146. X * If 'what' is '{' or '}' we go to the next section.
  2147. X */
  2148. X    int
  2149. Xfindpar(dir, count, what)
  2150. X    register int    dir;
  2151. X    long            count;
  2152. X    int             what;
  2153. X{
  2154. X    register linenr_t    curr;
  2155. X    int                    did_skip;        /* TRUE after separating lines have
  2156. X                                                been skipped */
  2157. X    int                    first;            /* TRUE on first line */
  2158. X
  2159. X    curr = Curpos.lnum;
  2160. X
  2161. X    while (count--)
  2162. X    {
  2163. X        did_skip = FALSE;
  2164. X        for (first = TRUE; ; first = FALSE)
  2165. X        {
  2166. X                if (*nr2ptr(curr) != NUL)
  2167. X                    did_skip = TRUE;
  2168. X
  2169. X                if (!first && did_skip && startPS(curr, what))
  2170. X                    break;
  2171. X
  2172. X                if ((curr += dir) < 1 || curr > line_count)
  2173. X                {
  2174. X                        if (count)
  2175. X                                return FALSE;
  2176. X                        curr -= dir;
  2177. X                        break;
  2178. X                }
  2179. X        }
  2180. X    }
  2181. X    setpcmark();
  2182. X    Curpos.lnum = curr;
  2183. X    if (curr == line_count)
  2184. X    {
  2185. X        if ((Curpos.col = strlen(nr2ptr(curr))) != 0)
  2186. X                --Curpos.col;
  2187. X    }
  2188. X    else
  2189. X        Curpos.col = 0;
  2190. X    return TRUE;
  2191. X}
  2192. X
  2193. X/*
  2194. X * check if the string 's' is a nroff macro that is in option 'opt'
  2195. X */
  2196. X    static int
  2197. Xinmacro(opt, s)
  2198. X        char *opt;
  2199. X        register char *s;
  2200. X{
  2201. X        register char *macro;
  2202. X
  2203. X        for (macro = opt; macro[0]; ++macro)
  2204. X        {
  2205. X                if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ')
  2206. X                        && (macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
  2207. X                        break;
  2208. X                ++macro;
  2209. X                if (macro[0] == NUL)
  2210. X                        break;
  2211. X        }
  2212. X        return (macro[0] != NUL);
  2213. X}
  2214. X
  2215. X/*
  2216. X * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
  2217. X * If 'para' is '{' or '}' only check for sections.
  2218. X */
  2219. X    int
  2220. XstartPS(lnum, para)
  2221. X    linenr_t    lnum;
  2222. X    int         para;
  2223. X{
  2224. X    register char *s;
  2225. X
  2226. X    s = nr2ptr(lnum);
  2227. X    if ((para == NUL && *s == '{') || *s == para || *s == '\f')
  2228. X        return TRUE;
  2229. X    if (*s++ != '.')
  2230. X        return FALSE;
  2231. X    if (inmacro(p_sections, s) || (!para && inmacro(p_para, s)))
  2232. X        return TRUE;
  2233. X    else
  2234. X        return FALSE;
  2235. X}
  2236. X
  2237. X/*
  2238. X * The following routines do the word searches performed by the 'w', 'W',
  2239. X * 'b', 'B', 'e', and 'E' commands.
  2240. X */
  2241. X
  2242. X/*
  2243. X * To perform these searches, characters are placed into one of three
  2244. X * classes, and transitions between classes determine word boundaries.
  2245. X *
  2246. X * The classes are:
  2247. X *
  2248. X * 0 - white space
  2249. X * 1 - letters, digits and underscore
  2250. X * 2 - everything else
  2251. X */
  2252. X
  2253. Xstatic int        stype;            /* type of the word motion being performed */
  2254. X
  2255. X/*
  2256. X * cls() - returns the class of character at Curpos
  2257. X *
  2258. X * The 'type' of the current search modifies the classes of characters if a 'W',
  2259. X * 'B', or 'E' motion is being done. In this case, chars. from class 2 are
  2260. X * reported as class 1 since only white space boundaries are of interest.
  2261. X */
  2262. X    static int
  2263. Xcls()
  2264. X{
  2265. X    register int c;
  2266. X
  2267. X    c = gcharCurpos();
  2268. X    if (c == ' ' || c == '\t' || c == NUL)
  2269. X        return 0;
  2270. X
  2271. X    if (isidchar(c))
  2272. X        return 1;
  2273. X
  2274. X    /*
  2275. X     * If stype is non-zero, report these as class 1.
  2276. X     */
  2277. X    return (stype == 0) ? 2 : 1;
  2278. X}
  2279. X
  2280. X
  2281. X/*
  2282. X * fwd_word(count, type) - move forward one word
  2283. X *
  2284. X * Returns TRUE if end of the file was reached.
  2285. X */
  2286. X    int
  2287. Xfwd_word(count, type)
  2288. X    long        count;
  2289. X    int         type;
  2290. X{
  2291. X    int         sclass;     /* starting class */
  2292. X
  2293. X    stype = type;
  2294. X    while (--count >= 0)
  2295. X    {
  2296. X        sclass = cls();
  2297. X
  2298. X        /*
  2299. X         * We always move at least one character.
  2300. X         */
  2301. X        if (incCurpos() == -1)
  2302. X            return TRUE;
  2303. X
  2304. X        if (sclass != 0)
  2305. X            if (skip_chars(sclass, FORWARD))
  2306. X                return TRUE;
  2307. X
  2308. X        /*
  2309. X         * go to next non-white
  2310. X         */
  2311. X        while (cls() == 0)
  2312. X        {
  2313. X            /*
  2314. X             * We'll stop if we land on a blank line
  2315. X             */
  2316. X            if (Curpos.col == 0 && *nr2ptr(Curpos.lnum) == NUL)
  2317. X                break;
  2318. X
  2319. X            if (incCurpos() == -1)
  2320. X                return TRUE;
  2321. X        }
  2322. X    }
  2323. X    return FALSE;
  2324. X}
  2325. X
  2326. X/*
  2327. X * bck_word(count, type) - move backward 'count' words
  2328. X *
  2329. X * Returns TRUE if top of the file was reached.
  2330. X */
  2331. X    int
  2332. Xbck_word(count, type)
  2333. X    long        count;
  2334. X    int         type;
  2335. X{
  2336. X    int         sclass;     /* starting class */
  2337. X
  2338. X    stype = type;
  2339. X    while (--count >= 0)
  2340. X    {
  2341. X        sclass = cls();
  2342. X
  2343. X        if (decCurpos() == -1)
  2344. X            return TRUE;
  2345. X
  2346. X        if (cls() != sclass || sclass == 0)
  2347. X        {
  2348. X            /*
  2349. X             * We were at the start of a word. Go back to the end of the prior
  2350. X             * word.
  2351. X             */
  2352. X            while (cls() == 0)  /* skip any white space */
  2353. X            {
  2354. X                /*
  2355. X                 * We'll stop if we land on a blank line
  2356. X                 */
  2357. X                if (Curpos.col == 0 && *nr2ptr(Curpos.lnum) == NUL)
  2358. X                    goto finished;
  2359. X
  2360. X                if (decCurpos() == -1)
  2361. X                    return TRUE;
  2362. X            }
  2363. X            sclass = cls();
  2364. X        }
  2365. X
  2366. X        /*
  2367. X         * Move backward to start of this word.
  2368. X         */
  2369. X        if (skip_chars(sclass, BACKWARD))
  2370. X                return TRUE;
  2371. X
  2372. X        incCurpos();                    /* overshot - forward one */
  2373. Xfinished:
  2374. X        ;
  2375. X    }
  2376. X    return FALSE;
  2377. X}
  2378. X
  2379. X/*
  2380. X * end_word(count, type, stop) - move to the end of the word
  2381. X *
  2382. X * There is an apparent bug in the 'e' motion of the real vi. At least on the
  2383. X * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
  2384. X * motion crosses blank lines. When the real vi crosses a blank line in an
  2385. X * 'e' motion, the cursor is placed on the FIRST character of the next
  2386. X * non-blank line. The 'E' command, however, works correctly. Since this
  2387. X * appears to be a bug, I have not duplicated it here.
  2388. X *
  2389. X * Returns TRUE if end of the file was reached.
  2390. X *
  2391. X * If stop is TRUE and we are already on the end of a word, move one less.
  2392. X */
  2393. X    int
  2394. Xend_word(count, type, stop)
  2395. X    long        count;
  2396. X    int         type;
  2397. X    int            stop;
  2398. X{
  2399. X    int         sclass;     /* starting class */
  2400. X
  2401. X    stype = type;
  2402. X    while (--count >= 0)
  2403. X    {
  2404. X        sclass = cls();
  2405. X        if (incCurpos() == -1)
  2406. X            return TRUE;
  2407. X
  2408. X        /*
  2409. X         * If we're in the middle of a word, we just have to move to the end of it.
  2410. X         */
  2411. X        if (cls() == sclass && sclass != 0)
  2412. X        {
  2413. X            /*
  2414. X             * Move forward to end of the current word
  2415. X             */
  2416. X            if (skip_chars(sclass, FORWARD))
  2417. X                    return TRUE;
  2418. X        }
  2419. X        else if (!stop || sclass == 0)
  2420. X        {
  2421. X            /*
  2422. X             * We were at the end of a word. Go to the end of the next word.
  2423. X             */
  2424. X
  2425. X            if (skip_chars(0, FORWARD))     /* skip any white space */
  2426. X                return TRUE;
  2427. X
  2428. X            /*
  2429. X             * Move forward to the end of this word.
  2430. X             */
  2431. X            if (skip_chars(cls(), FORWARD))
  2432. X                return TRUE;
  2433. X        }
  2434. X        decCurpos();                    /* overshot - backward one */
  2435. X        stop = FALSE;                    /* we move only one word less */
  2436. X    }
  2437. X    return FALSE;
  2438. X}
  2439. X
  2440. X    int
  2441. Xskip_chars(class, dir)
  2442. X    int class;
  2443. X    int dir;
  2444. X{
  2445. X        while (cls() == class)
  2446. X            if ((dir == FORWARD ? incCurpos() : decCurpos()) == -1)
  2447. X                return 1;
  2448. X        return 0;
  2449. X}
  2450. END_OF_FILE
  2451. if test 21652 -ne `wc -c <'vim/src/search.c'`; then
  2452.     echo shar: \"'vim/src/search.c'\" unpacked with wrong size!
  2453. fi
  2454. # end of 'vim/src/search.c'
  2455. fi
  2456. echo shar: End of archive 12 \(of 23\).
  2457. cp /dev/null ark12isdone
  2458. MISSING=""
  2459. 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
  2460.     if test ! -f ark${I}isdone ; then
  2461.     MISSING="${MISSING} ${I}"
  2462.     fi
  2463. done
  2464. if test "${MISSING}" = "" ; then
  2465.     echo You have unpacked all 23 archives.
  2466.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2467. else
  2468.     echo You still need to unpack the following archives:
  2469.     echo "        " ${MISSING}
  2470. fi
  2471. ##  End of shell archive.
  2472. exit 0
  2473. -------------8<----------------8<----------------8<---------------8<--------
  2474. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  2475. Oce Nederland B.V., Research & Development | necessarily represent the position
  2476. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  2477. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  2478. UUCP: mool@oce.nl        fax +31 77 595450 | whatever will be accepted.
  2479.  
  2480. exit 0 # Just in case...
  2481.