home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2197 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  76.2 KB

  1. From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
  2. Newsgroups: alt.sources
  3. Subject: ELvis 1.4, part 6 of 8
  4. Message-ID: <830@pdxgate.UUCP>
  5. Date: 3 Dec 90 21:33:56 GMT
  6.  
  7. # --------------------------- cut here ----------------------------
  8. # This is a shar archive.  To unpack it, save it to a file, and delete
  9. # anything above the "cut here" line.  Then run sh on the file.
  10. #
  11. # -rw-r--r--  1 kirkenda     9893 Dec  2 17:57 modify.c
  12. # -rw-r--r--  1 kirkenda    10230 Dec  2 17:57 move1.c
  13. # -rw-r--r--  1 kirkenda     4445 Dec  2 17:57 move2.c
  14. # -rw-r--r--  1 kirkenda     2697 Dec  2 17:57 move3.c
  15. # -rw-r--r--  1 kirkenda     3699 Dec  2 17:57 move4.c
  16. # -rw-r--r--  1 kirkenda     3940 Dec  2 17:57 move5.c
  17. # -rw-r--r--  1 kirkenda    14362 Dec  2 17:57 opts.c
  18. # -rw-r--r--  1 kirkenda     2306 Dec  2 17:57 recycle.c
  19. # -rw-r--r--  1 kirkenda    19816 Dec  2 17:57 redraw.c
  20. #
  21.  
  22. if test -f modify.c -a "$1" != -f
  23. then
  24. echo Will not overwrite modify.c
  25. else
  26. echo Extracting modify.c
  27. sed 's/^X//' >modify.c <<\eof
  28. X/* modify.c */
  29. X
  30. X/* This file contains the low-level file modification functions:
  31. X *    delete(frommark, tomark)    - removes line or portions of lines
  32. X *    add(frommark, text)        - inserts new text
  33. X *    change(frommark, tomark, text)    - delete, then add
  34. X */
  35. X
  36. X#include "config.h"
  37. X#include "vi.h"
  38. X
  39. X#ifdef DEBUG
  40. X# include <stdio.h>
  41. Xstatic FILE *dbg;
  42. X
  43. X/*VARARGS1*/
  44. Xdebout(msg, arg1, arg2, arg3, arg4, arg5)
  45. X    char    *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
  46. X{
  47. X    if (!dbg)
  48. X    {
  49. X        dbg = fopen("debug.out", "w");
  50. X        setbuf(dbg, (FILE *)0);
  51. X    }
  52. X    fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
  53. X}
  54. X#endif /* DEBUG */
  55. X
  56. X/* delete a range of text from the file */
  57. Xvoid delete(frommark, tomark)
  58. X    MARK        frommark;    /* first char to be deleted */
  59. X    MARK        tomark;        /* AFTER last char to be deleted */
  60. X{
  61. X    int        i;        /* used to move thru logical blocks */
  62. X    REG char    *scan;        /* used to scan thru text of the blk */
  63. X    REG char    *cpy;        /* used when copying chars */
  64. X    BLK        *blk;        /* a text block */
  65. X    long        l;        /* a line number */
  66. X    MARK        m;        /* a traveling version of frommark */
  67. X
  68. X#ifdef DEBUG
  69. X    debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
  70. X#endif
  71. X
  72. X    /* if not deleting anything, quit now */
  73. X    if (frommark == tomark)
  74. X    {
  75. X        return;
  76. X    }
  77. X
  78. X    /* This is a change */
  79. X    changes++;
  80. X    significant = TRUE;
  81. X
  82. X    /* if this is a multi-line change, then we'll have to redraw */
  83. X    if (markline(frommark) != markline(tomark))
  84. X    {
  85. X        mustredraw = TRUE;
  86. X        redrawrange(markline(frommark), markline(tomark), markline(frommark));
  87. X    }
  88. X
  89. X    /* adjust marks 'a through 'z and '' as needed */
  90. X    l = markline(tomark);
  91. X    for (i = 0; i < NMARKS; i++)
  92. X    {
  93. X        if (mark[i] < frommark)
  94. X        {
  95. X            continue;
  96. X        }
  97. X        else if (mark[i] < tomark)
  98. X        {
  99. X            mark[i] = MARK_UNSET;
  100. X        }
  101. X        else if (markline(mark[i]) == l)
  102. X        {
  103. X            if (markline(frommark) == l)
  104. X            {
  105. X                mark[i] -= markidx(tomark) - markidx(frommark);
  106. X            }
  107. X            else
  108. X            {
  109. X                mark[i] -= markidx(tomark);
  110. X            }
  111. X        }
  112. X        else
  113. X        {
  114. X            mark[i] -= MARK_AT_LINE(l - markline(frommark));
  115. X        }
  116. X    }
  117. X
  118. X    /* Reporting... */
  119. X    if (markidx(frommark) == 0 && markidx(tomark) == 0)
  120. X    {
  121. X        rptlines = markline(tomark) - markline(frommark);
  122. X        rptlabel = "deleted";
  123. X    }
  124. X
  125. X    /* find the block containing frommark */
  126. X    l = markline(frommark);
  127. X    for (i = 1; lnum[i] < l; i++)
  128. X    {
  129. X    }
  130. X
  131. X    /* process each affected block... */
  132. X    for (m = frommark;
  133. X         m < tomark && lnum[i] < INFINITY;
  134. X         m = MARK_AT_LINE(lnum[i - 1] + 1))
  135. X    {
  136. X        /* fetch the block */
  137. X        blk = blkget(i);
  138. X
  139. X        /* find the mark in the block */
  140. X        scan = blk->c;
  141. X        for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
  142. X        {
  143. X            while (*scan++ != '\n')
  144. X            {
  145. X            }
  146. X        }
  147. X        scan += markidx(m);
  148. X
  149. X        /* figure out where the changes to this block end */
  150. X        if (markline(tomark) > lnum[i])
  151. X        {
  152. X            cpy = blk->c + BLKSIZE;
  153. X        }
  154. X        else if (markline(tomark) == markline(m))
  155. X        {
  156. X            cpy = scan - markidx(m) + markidx(tomark);
  157. X        }
  158. X        else
  159. X        {
  160. X            cpy = scan;
  161. X            for (l = markline(tomark) - markline(m);
  162. X                 l > 0;
  163. X                 l--)
  164. X            {
  165. X                while (*cpy++ != '\n')
  166. X                {
  167. X                }
  168. X            }
  169. X            cpy += markidx(tomark);
  170. X        }
  171. X
  172. X        /* delete the stuff by moving chars within this block */
  173. X        while (cpy < blk->c + BLKSIZE)
  174. X        {
  175. X            *scan++ = *cpy++;
  176. X        }
  177. X        while (scan < blk->c + BLKSIZE)
  178. X        {
  179. X            *scan++ = '\0';
  180. X        }
  181. X
  182. X        /* adjust tomark to allow for lines deleted from this block */
  183. X        tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
  184. X
  185. X        /* if this block isn't empty now, then advance i */
  186. X        if (*blk->c)
  187. X        {
  188. X            i++;
  189. X        }
  190. X
  191. X        /* the buffer has changed.  Update hdr and lnum. */
  192. X        blkdirty(blk);
  193. X    }
  194. X
  195. X    /* must have at least 1 line */
  196. X    if (nlines == 0)
  197. X    {
  198. X        blk = blkadd(1);
  199. X        blk->c[0] = '\n';
  200. X        blkdirty(blk);
  201. X        cursor = MARK_FIRST;
  202. X    }
  203. X}
  204. X
  205. X
  206. X/* add some text at a specific place in the file */
  207. Xvoid add(atmark, newtext)
  208. X    MARK        atmark;        /* where to insert the new text */
  209. X    char        *newtext;    /* NUL-terminated string to insert */
  210. X{
  211. X    REG char    *scan;        /* used to move through string */
  212. X    REG char    *build;        /* used while copying chars */
  213. X    int        addlines;    /* number of lines we're adding */
  214. X    int        lastpart;    /* size of last partial line */
  215. X    BLK        *blk;        /* the block to be modified */
  216. X    int        blkno;        /* the logical block# of (*blk) */
  217. X    REG char    *newptr;    /* where new text starts in blk */
  218. X    BLK        buf;        /* holds chars from orig blk */
  219. X    BLK        linebuf;    /* holds part of line that didn't fit */
  220. X    BLK        *following;    /* the BLK following the last BLK */
  221. X    int        i;
  222. X    long        l;
  223. X
  224. X#ifdef DEBUG
  225. X    debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext);
  226. X#endif
  227. X#ifdef lint
  228. X    buf.c[0] = 0;
  229. X#endif
  230. X    /* if not adding anything, return now */
  231. X    if (!*newtext)
  232. X    {
  233. X        return;
  234. X    }
  235. X
  236. X    /* This is a change */
  237. X    changes++;
  238. X    significant = TRUE;
  239. X
  240. X    /* count the number of lines in the new text */
  241. X    for (scan = newtext, lastpart = addlines = 0; *scan; )
  242. X    {
  243. X        if (*scan++ == '\n')
  244. X        {
  245. X            addlines++;
  246. X            lastpart = 0;
  247. X        }
  248. X        else
  249. X        {
  250. X            lastpart++;
  251. X        }
  252. X    }
  253. X
  254. X    /* Reporting... */
  255. X    if (lastpart == 0 && markidx(atmark) == 0)
  256. X    {
  257. X        rptlines = addlines;
  258. X        rptlabel = "added";
  259. X    }
  260. X
  261. X    /* extract the line# from atmark */
  262. X    l = markline(atmark);
  263. X
  264. X    /* if more than 0 lines, then we'll have to redraw the screen */
  265. X    if (addlines > 0)
  266. X    {
  267. X        mustredraw = TRUE;
  268. X        if (markidx(atmark) == 0 && lastpart == 0)
  269. X        {
  270. X            redrawrange(l, l, l + addlines);
  271. X        }
  272. X        else
  273. X        {
  274. X            /* make sure the last line gets redrawn -- it was
  275. X             * split, so its appearance has changed
  276. X             */
  277. X            redrawrange(l, l + 1L, l + addlines + 1L);
  278. X        }
  279. X    }
  280. X
  281. X    /* adjust marks 'a through 'z and '' as needed */
  282. X    for (i = 0; i < NMARKS; i++)
  283. X    {
  284. X        if (mark[i] < atmark)
  285. X        {
  286. X            /* earlier line, or earlier in same line: no change */
  287. X            continue;
  288. X        }
  289. X        else if (markline(mark[i]) > l)
  290. X        {
  291. X            /* later line: move down a whole number of lines */
  292. X            mark[i] += MARK_AT_LINE(addlines);
  293. X        }
  294. X        else
  295. X        {
  296. X            /* later in same line */
  297. X            if (addlines > 0)
  298. X            {
  299. X                /* multi-line add, which split this line:
  300. X                 * move down, and possibly left or right,
  301. X                 * depending on where the split was and how
  302. X                 * much text was inserted after the last \n
  303. X                 */
  304. X                mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
  305. X            }
  306. X            else
  307. X            {
  308. X                /* totally within this line: move right */
  309. X                mark[i] += lastpart;
  310. X            }
  311. X        }
  312. X    }
  313. X
  314. X    /* get the block to be modified */
  315. X    for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
  316. X    {
  317. X    }
  318. X    blk = blkget(blkno);
  319. X    buf = *blk;
  320. X
  321. X    /* figure out where the new text starts */
  322. X    for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
  323. X         l > 0;
  324. X         l--)
  325. X    {
  326. X        while (*newptr++ != '\n')
  327. X        {
  328. X        }
  329. X    }
  330. X    newptr += markidx(atmark);
  331. X
  332. X    /* keep start of old block */
  333. X    build = blk->c + (newptr - buf.c);
  334. X
  335. X    /* fill this block (or blocks) from the newtext string */
  336. X    while (*newtext)
  337. X    {
  338. X        while (*newtext && build < blk->c + BLKSIZE - 1)
  339. X        {
  340. X            *build++ = *newtext++;
  341. X        }
  342. X        if (*newtext)
  343. X        {
  344. X            /* save the excess */
  345. X            for (scan = linebuf.c + BLKSIZE;
  346. X                 build > blk->c && build[-1] != '\n';
  347. X                 )
  348. X            {
  349. X                *--scan = *--build;
  350. X            }
  351. X
  352. X            /* write the block */
  353. X            while (build < blk->c + BLKSIZE)
  354. X            {
  355. X                *build++ = '\0';
  356. X            }
  357. X            blkdirty(blk);
  358. X
  359. X            /* add another block */
  360. X            blkno++;
  361. X            blk = blkadd(blkno);
  362. X
  363. X            /* copy in the excess from last time */
  364. X            for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  365. X            {
  366. X                *build++ = *scan++;
  367. X            }
  368. X        }
  369. X    }
  370. X
  371. X    /* fill this block(s) from remainder of orig block */
  372. X    while (newptr < buf.c + BLKSIZE && *newptr)
  373. X    {
  374. X        while (newptr < buf.c + BLKSIZE
  375. X            && *newptr
  376. X            && build < blk->c + BLKSIZE - 1)
  377. X        {
  378. X            *build++ = *newptr++;
  379. X        }
  380. X        if (newptr < buf.c + BLKSIZE && *newptr)
  381. X        {
  382. X            /* save the excess */
  383. X            for (scan = linebuf.c + BLKSIZE;
  384. X                 build > blk->c && build[-1] != '\n';
  385. X                 )
  386. X            {
  387. X                *--scan = *--build;
  388. X            }
  389. X
  390. X            /* write the block */
  391. X            while (build < blk->c + BLKSIZE)
  392. X            {
  393. X                *build++ = '\0';
  394. X            }
  395. X            blkdirty(blk);
  396. X
  397. X            /* add another block */
  398. X            blkno++;
  399. X            blk = blkadd(blkno);
  400. X
  401. X            /* copy in the excess from last time */
  402. X            for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  403. X            {
  404. X                *build++ = *scan++;
  405. X            }
  406. X        }
  407. X    }
  408. X
  409. X    /* see if we can combine our last block with the following block */
  410. X    if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
  411. X    {
  412. X        /* hey, we probably can!  Get the following block & see... */
  413. X        following = blkget(blkno + 1);
  414. X        if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
  415. X        {
  416. X            /* we can!  Copy text from following to blk */
  417. X            for (scan = following->c; *scan; )
  418. X            {
  419. X                *build++ = *scan++;
  420. X            }
  421. X            while (build < blk->c + BLKSIZE)
  422. X            {
  423. X                *build++ = '\0';
  424. X            }
  425. X            blkdirty(blk);
  426. X
  427. X            /* pretend the following was the last blk */
  428. X            blk = following;
  429. X            build = blk->c;
  430. X        }
  431. X    }
  432. X
  433. X    /* that last block is dirty by now */
  434. X    while (build < blk->c + BLKSIZE)
  435. X    {
  436. X        *build++ = '\0';
  437. X    }
  438. X    blkdirty(blk);
  439. X}
  440. X
  441. X
  442. X/* change the text of a file */
  443. Xvoid change(frommark, tomark, newtext)
  444. X    MARK    frommark, tomark;
  445. X    char    *newtext;
  446. X{
  447. X    int    i;
  448. X    long    l;
  449. X    char    *text;
  450. X    BLK    *blk;
  451. X
  452. X#ifdef DEBUG
  453. X    debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
  454. X#endif
  455. X
  456. X    /* optimize for single-character replacement */
  457. X    if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
  458. X    {
  459. X        /* find the block containing frommark */
  460. X        l = markline(frommark);
  461. X        for (i = 1; lnum[i] < l; i++)
  462. X        {
  463. X        }
  464. X
  465. X        /* get the block */
  466. X        blk = blkget(i);
  467. X
  468. X        /* find the line within the block */
  469. X        for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
  470. X        {
  471. X            if (*text == '\n')
  472. X            {
  473. X                i--;
  474. X            }
  475. X        }
  476. X
  477. X        /* replace the char */
  478. X        text += markidx(frommark);
  479. X        if (*text == newtext[0])
  480. X        {
  481. X            /* no change was needed - same char */
  482. X            return;
  483. X        }
  484. X        else if (*text != '\n')
  485. X        {
  486. X            /* This is a change */
  487. X            changes++;
  488. X            significant = TRUE;
  489. X            ChangeText
  490. X            {
  491. X                *text = newtext[0];
  492. X                blkdirty(blk);
  493. X            }
  494. X            return;
  495. X        }
  496. X        /* else it is a complex change involving newline... */
  497. X    }
  498. X
  499. X    /* couldn't optimize, so do delete & add */
  500. X    ChangeText
  501. X    {
  502. X        delete(frommark, tomark);
  503. X        add(frommark, newtext);
  504. X        rptlabel = "changed";
  505. X    }
  506. X}
  507. eof
  508. if test `wc -c <modify.c` -ne 9893
  509. then
  510. echo modify.c damaged!
  511. fi
  512. fi
  513.  
  514. if test -f move1.c -a "$1" != -f
  515. then
  516. echo Will not overwrite move1.c
  517. else
  518. echo Extracting move1.c
  519. sed 's/^X//' >move1.c <<\eof
  520. X/* move1.c */
  521. X
  522. X/* Author:
  523. X *    Steve Kirkendall
  524. X *    14407 SW Teal Blvd. #C
  525. X *    Beaverton, OR 97005
  526. X *    kirkenda@cs.pdx.edu
  527. X */
  528. X
  529. X
  530. X/* This file contains most movement functions */
  531. X
  532. X#include "config.h"
  533. X#include <ctype.h>
  534. X#include "vi.h"
  535. X
  536. X#ifndef isascii
  537. X# define isascii(c)    !((c) & ~0x7f)
  538. X#endif
  539. X
  540. XMARK    m_updnto(m, cnt, cmd)
  541. X    MARK    m;    /* movement is relative to this mark */
  542. X    long    cnt;    /* a numeric argument */
  543. X{
  544. X    DEFAULT(cmd == 'G' ? nlines : 1L);
  545. X
  546. X    /* move up or down 'cnt' lines */
  547. X    switch (cmd)
  548. X    {
  549. X      case ('P'&0x1f):
  550. X      case '-':
  551. X      case 'k':
  552. X        m -= MARK_AT_LINE(cnt);
  553. X        break;
  554. X
  555. X      case 'G':
  556. X        if (cnt < 1L || cnt > nlines)
  557. X        {
  558. X            msg("Only %ld lines", nlines);
  559. X            return MARK_UNSET;
  560. X        }
  561. X        m = MARK_AT_LINE(cnt);
  562. X        break;
  563. X
  564. X      default:
  565. X        m += MARK_AT_LINE(cnt);
  566. X    }
  567. X
  568. X    /* if that left us screwed up, then fail */
  569. X    if (m < MARK_FIRST || markline(m) > nlines)
  570. X    {
  571. X        return MARK_UNSET;
  572. X    }
  573. X
  574. X    return m;
  575. X}
  576. X
  577. X/*ARGSUSED*/
  578. XMARK    m_right(m, cnt)
  579. X    MARK    m;    /* movement is relative to this mark */
  580. X    long    cnt;    /* a numeric argument */
  581. X{
  582. X    int        idx;    /* index of the new cursor position */
  583. X
  584. X    DEFAULT(1);
  585. X
  586. X    /* move to right, if that's OK */
  587. X    pfetch(markline(m));
  588. X    idx = markidx(m) + cnt;
  589. X    if (idx < plen)
  590. X    {
  591. X        m += cnt;
  592. X    }
  593. X    else
  594. X    {
  595. X        return MARK_UNSET;
  596. X    }
  597. X
  598. X    return m;
  599. X}
  600. X
  601. X/*ARGSUSED*/
  602. XMARK    m_left(m, cnt)
  603. X    MARK    m;    /* movement is relative to this mark */
  604. X    long    cnt;    /* a numeric argument */
  605. X{
  606. X    DEFAULT(1);
  607. X
  608. X    /* move to the left, if that's OK */
  609. X    if (markidx(m) >= cnt)
  610. X    {
  611. X        m -= cnt;
  612. X    }
  613. X    else
  614. X    {
  615. X        return MARK_UNSET;
  616. X    }
  617. X
  618. X    return m;
  619. X}
  620. X
  621. X/*ARGSUSED*/
  622. XMARK    m_tocol(m, cnt)
  623. X    MARK    m;    /* movement is relative to this mark */
  624. X    long    cnt;    /* a numeric argument */
  625. X{
  626. X    char    *text;    /* text of the line */
  627. X    int    col;    /* column number */
  628. X    int    idx;    /* index into the line */
  629. X
  630. X    DEFAULT(1);
  631. X
  632. X    /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  633. X    cnt--;
  634. X
  635. X    /* if 0, that's easy */
  636. X    if (cnt == 0)
  637. X    {
  638. X        m &= ~(BLKSIZE - 1);
  639. X        return m;
  640. X    }
  641. X
  642. X    /* find that column within the line */
  643. X    pfetch(markline(m));
  644. X    text = ptext;
  645. X    for (col = idx = 0; col < cnt && *text; text++, idx++)
  646. X    {
  647. X        if (*text == '\t' && !*o_list)
  648. X        {
  649. X            col += *o_tabstop;
  650. X            col -= col % *o_tabstop;
  651. X        }
  652. X        else if (UCHAR(*text) < ' ' || *text == '\177')
  653. X        {
  654. X            col += 2;
  655. X        }
  656. X#ifndef NO_CHARATTR
  657. X        else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  658. X        {
  659. X            text += 2; /* plus one more as part of for loop */
  660. X        }
  661. X#endif
  662. X        else
  663. X        {
  664. X            col++;
  665. X        }
  666. X    }
  667. X    if (!*text)
  668. X    {
  669. X        return MARK_UNSET;
  670. X    }
  671. X    else
  672. X    {
  673. X        m = (m & ~(BLKSIZE - 1)) + idx;
  674. X    }
  675. X    return m;
  676. X}
  677. X
  678. X/*ARGSUSED*/
  679. XMARK    m_front(m, cnt)
  680. X    MARK    m;    /* movement is relative to this mark */
  681. X    long    cnt;    /* a numeric argument (ignored) */
  682. X{
  683. X    char    *scan;
  684. X
  685. X    /* move to the first non-whitespace character */
  686. X    pfetch(markline(m));
  687. X    scan = ptext;
  688. X    m &= ~(BLKSIZE - 1);
  689. X    while (*scan == ' ' || *scan == '\t')
  690. X    {
  691. X        scan++;
  692. X        m++;
  693. X    }
  694. X
  695. X    return m;
  696. X}
  697. X
  698. X/*ARGSUSED*/
  699. XMARK    m_rear(m, cnt)
  700. X    MARK    m;    /* movement is relative to this mark */
  701. X    long    cnt;    /* a numeric argument (ignored) */
  702. X{
  703. X    /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  704. X     * that other code will convert this to a more reasonable MARK before
  705. X     * anything tries to actually use it.  (See adjmove() in vi.c)
  706. X     */
  707. X    return m | (BLKSIZE - 1);
  708. X}
  709. X
  710. X#ifndef NO_SENTENCE
  711. X/*ARGSUSED*/
  712. XMARK    m_fsentence(m, cnt)
  713. X    MARK    m;    /* movement is relative to this mark */
  714. X    long    cnt;    /* a numeric argument */
  715. X{
  716. X    REG char    *text;
  717. X    REG long    l;
  718. X
  719. X    DEFAULT(1);
  720. X
  721. X    /* get the current line */
  722. X    l = markline(m);
  723. X    pfetch(l);
  724. X    text = ptext + markidx(m);
  725. X
  726. X    /* for each requested sentence... */
  727. X    while (cnt-- > 0)
  728. X    {
  729. X        /* search forward for one of [.?!] followed by spaces or EOL */
  730. X        do
  731. X        {
  732. X            /* wrap at end of line */
  733. X            if (!text[0])
  734. X            {
  735. X                if (l >= nlines)
  736. X                {
  737. X                    return MARK_UNSET;
  738. X                }
  739. X                l++;
  740. X                pfetch(l);
  741. X                text = ptext;
  742. X            }
  743. X            else
  744. X            {
  745. X                text++;
  746. X            }
  747. X        } while (text[0] != '.' && text[0] != '?' && text[0] != '!'
  748. X            || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
  749. X    }
  750. X
  751. X    /* construct a mark for this location */
  752. X    m = buildmark(text);
  753. X
  754. X    /* move forward to the first word of the next sentence */
  755. X    m = m_fword(m, 1L);
  756. X
  757. X    return m;
  758. X}
  759. X
  760. X/*ARGSUSED*/
  761. XMARK    m_bsentence(m, cnt)
  762. X    MARK    m;    /* movement is relative to this mark */
  763. X    long    cnt;    /* a numeric argument */
  764. X{
  765. X    REG char    *text;    /* used to scan thru text */
  766. X    REG long    l;    /* current line number */
  767. X    int        flag;    /* have we passed at least one word? */
  768. X
  769. X    DEFAULT(1);
  770. X
  771. X    /* get the current line */
  772. X    l = markline(m);
  773. X    pfetch(l);
  774. X    text = ptext + markidx(m);
  775. X
  776. X    /* for each requested sentence... */
  777. X    flag = TRUE;
  778. X    while (cnt-- > 0)
  779. X    {
  780. X        /* search backward for one of [.?!] followed by spaces or EOL */
  781. X        do
  782. X        {
  783. X            /* wrap at beginning of line */
  784. X            if (text == ptext)
  785. X            {
  786. X                do
  787. X                {
  788. X                    if (l <= 1)
  789. X                    {
  790. X                        return MARK_UNSET;
  791. X                    }
  792. X                    l--;
  793. X                    pfetch(l);
  794. X                } while (!*ptext);
  795. X                text = ptext + plen - 1;
  796. X            }
  797. X            else
  798. X            {
  799. X                text--;
  800. X            }
  801. X
  802. X            /* are we moving past a "word"? */
  803. X            if (text[0] >= '0')
  804. X            {
  805. X                flag = FALSE;
  806. X            }
  807. X        } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!'
  808. X            || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
  809. X    }
  810. X
  811. X    /* construct a mark for this location */
  812. X    m = buildmark(text);
  813. X
  814. X    /* move to the front of the following sentence */
  815. X    m = m_fword(m, 1L);
  816. X
  817. X    return m;
  818. X}
  819. X#endif
  820. X
  821. X/*ARGSUSED*/
  822. XMARK    m_fparagraph(m, cnt)
  823. X    MARK    m;    /* movement is relative to this mark */
  824. X    long    cnt;    /* a numeric argument */
  825. X{
  826. X    char    *text;
  827. X    char    *pscn;    /* used to scan thru value of "paragraphs" option */
  828. X    long    l;
  829. X
  830. X    DEFAULT(1);
  831. X
  832. X    for (l = markline(m); cnt > 0 && l++ < nlines; )
  833. X    {
  834. X        text = fetchline(l);
  835. X        if (!*text)
  836. X        {
  837. X            cnt--;
  838. X        }
  839. X#ifndef NO_SENTENCE
  840. X        else if (*text == '.')
  841. X        {
  842. X            for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
  843. X            {
  844. X                if (pscn[0] == text[1] && pscn[1] == text[2])
  845. X                {
  846. X                    cnt--;
  847. X                    break;
  848. X                }
  849. X            }
  850. X        }
  851. X#endif
  852. X    }
  853. X    if (l <= nlines)
  854. X    {
  855. X        m = MARK_AT_LINE(l);
  856. X    }
  857. X    else
  858. X    {
  859. X        m = MARK_LAST;
  860. X    }
  861. X    return m;
  862. X}
  863. X
  864. X/*ARGSUSED*/
  865. XMARK    m_bparagraph(m, cnt)
  866. X    MARK    m;    /* movement is relative to this mark */
  867. X    long    cnt;    /* a numeric argument */
  868. X{
  869. X    char    *text;
  870. X    char    *pscn;    /* used to scan thru value of "paragraph" option */
  871. X    long    l;
  872. X
  873. X    DEFAULT(1);
  874. X
  875. X    for (l = markline(m); cnt > 0 && l-- > 1; )
  876. X    {
  877. X        text = fetchline(l);
  878. X        if (!*text)
  879. X        {
  880. X            cnt--;
  881. X        }
  882. X#ifndef NO_SENTENCE
  883. X        else if (*text == '.')
  884. X        {
  885. X            for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
  886. X            {
  887. X                if (pscn[0] == text[1] && pscn[1] == text[2])
  888. X                {
  889. X                    cnt--;
  890. X                    break;
  891. X                }
  892. X            }
  893. X        }
  894. X#endif
  895. X    }
  896. X    if (l >= 1)
  897. X    {
  898. X        m = MARK_AT_LINE(l);
  899. X    }
  900. X    else
  901. X    {
  902. X        m = MARK_FIRST;
  903. X    }
  904. X    return m;
  905. X}
  906. X
  907. X/*ARGSUSED*/
  908. XMARK    m_fsection(m, cnt, key)
  909. X    MARK    m;    /* movement is relative to this mark */
  910. X    long    cnt;    /* (ignored) */
  911. X    int    key;    /* second key stroke - must be ']' */
  912. X{
  913. X    char    *text;
  914. X    char    *sscn;    /* used to scan thru value of "sections" option */
  915. X    long    l;
  916. X
  917. X    /* make sure second key was ']' */
  918. X    if (key != ']')
  919. X    {
  920. X        return MARK_UNSET;
  921. X    }
  922. X
  923. X    for (l = markline(m); l++ < nlines; )
  924. X    {
  925. X        text = fetchline(l);
  926. X        if (*text == '{')
  927. X        {
  928. X            break;
  929. X        }
  930. X#ifndef NO_SENTENCE
  931. X        else if (*text == '.')
  932. X        {
  933. X            for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
  934. X            {
  935. X                if (sscn[0] == text[1] && sscn[1] == text[2])
  936. X                {
  937. X                    goto BreakBreak;
  938. X                }
  939. X            }
  940. X        }
  941. X#endif
  942. X    }
  943. XBreakBreak:
  944. X    if (l <= nlines)
  945. X    {
  946. X        m = MARK_AT_LINE(l);
  947. X    }
  948. X    else
  949. X    {
  950. X        m = MARK_LAST;
  951. X    }
  952. X    return m;
  953. X}
  954. X
  955. X/*ARGSUSED*/
  956. XMARK    m_bsection(m, cnt, key)
  957. X    MARK    m;    /* movement is relative to this mark */
  958. X    long    cnt;    /* (ignored) */
  959. X    int    key;    /* second key stroke - must be '[' */
  960. X{
  961. X    char    *text;
  962. X    char    *sscn;    /* used to scan thru value of "sections" option */
  963. X    long    l;
  964. X
  965. X    /* make sure second key was '[' */
  966. X    if (key != '[')
  967. X    {
  968. X        return MARK_UNSET;
  969. X    }
  970. X
  971. X    for (l = markline(m); l-- > 1; )
  972. X    {
  973. X        text = fetchline(l);
  974. X        if (*text == '{')
  975. X        {
  976. X            break;
  977. X        }
  978. X#ifndef NO_SENTENCE
  979. X        else if (*text == '.')
  980. X        {
  981. X            for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
  982. X            {
  983. X                if (sscn[0] == text[1] && sscn[1] == text[2])
  984. X                {
  985. X                    goto BreakBreak;
  986. X                }
  987. X            }
  988. X        }
  989. X#endif
  990. X    }
  991. XBreakBreak:
  992. X    if (l >= 1)
  993. X    {
  994. X        m = MARK_AT_LINE(l);
  995. X    }
  996. X    else
  997. X    {
  998. X        m = MARK_FIRST;
  999. X    }
  1000. X    return m;
  1001. X}
  1002. X
  1003. X
  1004. X/*ARGSUSED*/
  1005. XMARK    m_match(m, cnt)
  1006. X    MARK    m;    /* movement is relative to this mark */
  1007. X    long    cnt;    /* a numeric argument (ignored) */
  1008. X{
  1009. X    long    l;
  1010. X    REG char    *text;
  1011. X    REG char    match;
  1012. X    REG char    nest;
  1013. X    REG int        count;
  1014. X
  1015. X    /* get the current line */
  1016. X    l = markline(m);
  1017. X    pfetch(l);
  1018. X    text = ptext + markidx(m);
  1019. X
  1020. X    /* search forward within line for one of "[](){}" */
  1021. X    for (match = '\0'; !match && *text; text++)
  1022. X    {
  1023. X        /* tricky way to recognize 'em in ASCII */
  1024. X        nest = *text;
  1025. X        if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
  1026. X        {
  1027. X            match = nest ^ ('[' ^ ']');
  1028. X        }
  1029. X        else if ((nest & 0xfe) == '(')
  1030. X        {
  1031. X            match = nest ^ ('(' ^ ')');
  1032. X        }
  1033. X        else
  1034. X        {
  1035. X            match = 0;
  1036. X        }
  1037. X    }
  1038. X    if (!match)
  1039. X    {
  1040. X        return MARK_UNSET;
  1041. X    }
  1042. X    text--;
  1043. X
  1044. X    /* search forward or backward for match */
  1045. X    if (match == '(' || match == '[' || match == '{')
  1046. X    {
  1047. X        /* search backward */
  1048. X        for (count = 1; count > 0; )
  1049. X        {
  1050. X            /* wrap at beginning of line */
  1051. X            if (text == ptext)
  1052. X            {
  1053. X                do
  1054. X                {
  1055. X                    if (l <= 1L)
  1056. X                    {
  1057. X                        return MARK_UNSET;
  1058. X                    }
  1059. X                    l--;
  1060. X                    pfetch(l);
  1061. X                } while (!*ptext);
  1062. X                text = ptext + plen - 1;
  1063. X            }
  1064. X            else
  1065. X            {
  1066. X                text--;
  1067. X            }
  1068. X
  1069. X            /* check the char */
  1070. X            if (*text == match)
  1071. X                count--;
  1072. X            else if (*text == nest)
  1073. X                count++;
  1074. X        }
  1075. X    }
  1076. X    else
  1077. X    {
  1078. X        /* search forward */
  1079. X        for (count = 1; count > 0; )
  1080. X        {
  1081. X            /* wrap at end of line */
  1082. X            if (!*text)
  1083. X            {
  1084. X                if (l >= nlines)
  1085. X                {
  1086. X                    return MARK_UNSET;
  1087. X                }
  1088. X                l++;
  1089. X                pfetch(l);
  1090. X                text = ptext;
  1091. X            }
  1092. X            else
  1093. X            {
  1094. X                text++;
  1095. X            }
  1096. X
  1097. X            /* check the char */
  1098. X            if (*text == match)
  1099. X                count--;
  1100. X            else if (*text == nest)
  1101. X                count++;
  1102. X        }
  1103. X    }
  1104. X
  1105. X    /* construct a mark for this place */
  1106. X    m = buildmark(text);
  1107. X    return m;
  1108. X}
  1109. X
  1110. X/*ARGSUSED*/
  1111. XMARK    m_tomark(m, cnt, key)
  1112. X    MARK    m;    /* movement is relative to this mark */
  1113. X    long    cnt;    /* (ignored) */
  1114. X    int    key;    /* keystroke - the mark to move to */
  1115. X{
  1116. X    /* mark '' is a special case */
  1117. X    if (key == '\'' || key == '`')
  1118. X    {
  1119. X        if (mark[26] == MARK_UNSET)
  1120. X        {
  1121. X            return MARK_FIRST;
  1122. X        }
  1123. X        else
  1124. X        {
  1125. X            return mark[26];
  1126. X        }
  1127. X    }
  1128. X
  1129. X    /* if not a valid mark number, don't move */
  1130. X    if (key < 'a' || key > 'z')
  1131. X    {
  1132. X        return MARK_UNSET;
  1133. X    }
  1134. X
  1135. X    /* return the selected mark -- may be MARK_UNSET */
  1136. X    if (!mark[key - 'a'])
  1137. X    {
  1138. X        msg("mark '%c is unset", key);
  1139. X    }
  1140. X    return mark[key - 'a'];
  1141. X}
  1142. X
  1143. eof
  1144. if test `wc -c <move1.c` -ne 10230
  1145. then
  1146. echo move1.c damaged!
  1147. fi
  1148. fi
  1149.  
  1150. if test -f move2.c -a "$1" != -f
  1151. then
  1152. echo Will not overwrite move2.c
  1153. else
  1154. echo Extracting move2.c
  1155. sed 's/^X//' >move2.c <<\eof
  1156. X/* move2.c */
  1157. X
  1158. X/* Author:
  1159. X *    Steve Kirkendall
  1160. X *    14407 SW Teal Blvd. #C
  1161. X *    Beaverton, OR 97005
  1162. X *    kirkenda@cs.pdx.edu
  1163. X */
  1164. X
  1165. X
  1166. X/* This function contains the movement functions that perform RE searching */
  1167. X
  1168. X#include "config.h"
  1169. X#include "vi.h"
  1170. X#include "regexp.h"
  1171. X
  1172. Xextern long    atol();
  1173. X
  1174. Xstatic regexp    *re;    /* compiled version of the pattern to search for */
  1175. Xstatic        prevsf;    /* boolean: previous search direction was forward? */
  1176. X
  1177. XMARK    m_nsrch(m)
  1178. X    MARK    m;    /* where to start searching */
  1179. X{
  1180. X    if (prevsf)
  1181. X    {
  1182. X        m = m_fsrch(m, (char *)0);
  1183. X        prevsf = TRUE;
  1184. X    }
  1185. X    else
  1186. X    {
  1187. X        m = m_bsrch(m, (char *)0);
  1188. X        prevsf = FALSE;
  1189. X    }
  1190. X    return m;
  1191. X}
  1192. X
  1193. XMARK    m_Nsrch(m)
  1194. X    MARK    m;    /* where to start searching */
  1195. X{
  1196. X    if (prevsf)
  1197. X    {
  1198. X        m = m_bsrch(m, (char *)0);
  1199. X        prevsf = TRUE;
  1200. X    }
  1201. X    else
  1202. X    {
  1203. X        m = m_fsrch(m, (char *)0);
  1204. X        prevsf = FALSE;
  1205. X    }
  1206. X    return m;
  1207. X}
  1208. X
  1209. XMARK    m_fsrch(m, ptrn)
  1210. X    MARK    m;    /* where to start searching */
  1211. X    char    *ptrn;    /* pattern to search for */
  1212. X{
  1213. X    long    l;    /* line# of line to be searched */
  1214. X    char    *line;    /* text of line to be searched */
  1215. X    int    wrapped;/* boolean: has our search wrapped yet? */
  1216. X    int    pos;    /* where we are in the line */
  1217. X    long    delta;    /* line offset, for things like "/foo/+1" */
  1218. X
  1219. X    /* remember: "previous search was forward" */
  1220. X    prevsf = TRUE;
  1221. X
  1222. X    delta = 0L;
  1223. X    if (ptrn && *ptrn)
  1224. X    {
  1225. X        /* locate the closing '/', if any */
  1226. X        line = parseptrn(ptrn);
  1227. X        if (*line)
  1228. X        {
  1229. X            delta = atol(line);
  1230. X        }
  1231. X        ptrn++;
  1232. X
  1233. X        /* free the previous pattern */
  1234. X        if (re) free(re);
  1235. X
  1236. X        /* compile the pattern */
  1237. X        re = regcomp(ptrn);
  1238. X        if (!re)
  1239. X        {
  1240. X            return MARK_UNSET;
  1241. X        }
  1242. X    }
  1243. X    else if (!re)
  1244. X    {
  1245. X        msg("No previous expression");
  1246. X        return MARK_UNSET;
  1247. X    }
  1248. X
  1249. X    /* search forward for the pattern */
  1250. X    pos = markidx(m) + 1;
  1251. X    pfetch(markline(m));
  1252. X    if (pos >= plen)
  1253. X    {
  1254. X        pos = 0;
  1255. X        m = (m | (BLKSIZE - 1)) + 1;
  1256. X    }
  1257. X    wrapped = FALSE;
  1258. X    for (l = markline(m); l != markline(m) + 1 || !wrapped; l++)
  1259. X    {
  1260. X        /* wrap search */
  1261. X        if (l > nlines)
  1262. X        {
  1263. X            /* if we wrapped once already, then the search failed */
  1264. X            if (wrapped)
  1265. X            {
  1266. X                break;
  1267. X            }
  1268. X
  1269. X            /* else maybe we should wrap now? */
  1270. X            if (*o_wrapscan)
  1271. X            {
  1272. X                l = 0;
  1273. X                wrapped = TRUE;
  1274. X                continue;
  1275. X            }
  1276. X            else
  1277. X            {
  1278. X                break;
  1279. X            }
  1280. X        }
  1281. X
  1282. X        /* get this line */
  1283. X        line = fetchline(l);
  1284. X
  1285. X        /* check this line */
  1286. X        if (regexec(re, &line[pos], (pos == 0)))
  1287. X        {
  1288. X            /* match! */
  1289. X            if (wrapped && *o_warn)
  1290. X                msg("(wrapped)");
  1291. X            if (delta != 0L)
  1292. X            {
  1293. X                l += delta;
  1294. X                if (l < 1 || l > nlines)
  1295. X                {
  1296. X                    msg("search offset too big");
  1297. X                    return MARK_UNSET;
  1298. X                }
  1299. X                return m_front(MARK_AT_LINE(l), 0L);
  1300. X            }
  1301. X            return MARK_AT_LINE(l) + (int)(re->startp[0] - line);
  1302. X        }
  1303. X        pos = 0;
  1304. X    }
  1305. X
  1306. X    /* not found */
  1307. X    msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE");
  1308. X    return MARK_UNSET;
  1309. X}
  1310. X
  1311. XMARK    m_bsrch(m, ptrn)
  1312. X    MARK    m;    /* where to start searching */
  1313. X    char    *ptrn;    /* pattern to search for */
  1314. X{
  1315. X    long    l;    /* line# of line to be searched */
  1316. X    char    *line;    /* text of line to be searched */
  1317. X    int    wrapped;/* boolean: has our search wrapped yet? */
  1318. X    int    pos;    /* last acceptable idx for a match on this line */
  1319. X    int    last;    /* remembered idx of the last acceptable match on this line */
  1320. X    int    try;    /* an idx at which we strat searching for another match */
  1321. X
  1322. X    /* remember: "previous search was not forward" */
  1323. X    prevsf = FALSE;
  1324. X
  1325. X    if (ptrn && *ptrn)
  1326. X    {
  1327. X        /* locate the closing '?', if any */
  1328. X        line = parseptrn(ptrn);
  1329. X        ptrn++;
  1330. X
  1331. X        /* free the previous pattern, if any */
  1332. X        if (re) free(re);
  1333. X
  1334. X        /* compile the pattern */
  1335. X        re = regcomp(ptrn);
  1336. X        if (!re)
  1337. X        {
  1338. X            return MARK_UNSET;
  1339. X        }
  1340. X    }
  1341. X    else if (!re)
  1342. X    {
  1343. X        msg("No previous expression");
  1344. X        return MARK_UNSET;
  1345. X    }
  1346. X
  1347. X    /* search backward for the pattern */
  1348. X    pos = markidx(m);
  1349. X    wrapped = FALSE;
  1350. X    for (l = markline(m); l != markline(m) - 1 || !wrapped; l--)
  1351. X    {
  1352. X        /* wrap search */
  1353. X        if (l < 1)
  1354. X        {
  1355. X            if (*o_wrapscan)
  1356. X            {
  1357. X                l = nlines + 1;
  1358. X                wrapped = TRUE;
  1359. X                continue;
  1360. X            }
  1361. X            else
  1362. X            {
  1363. X                break;
  1364. X            }
  1365. X        }
  1366. X
  1367. X        /* get this line */
  1368. X        line = fetchline(l);
  1369. X
  1370. X        /* check this line */
  1371. X        if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos)
  1372. X        {
  1373. X            /* match!  now find the last acceptable one in this line */
  1374. X            do
  1375. X            {
  1376. X                last = (int)(re->startp[0] - line);
  1377. X                try = (int)(re->endp[0] - line);
  1378. X            } while (try > 0
  1379. X                 && regexec(re, &line[try], FALSE)
  1380. X                 && (int)(re->startp[0] - line) < pos);
  1381. X
  1382. X            if (wrapped && *o_warn)
  1383. X                msg("(wrapped)");
  1384. X            return MARK_AT_LINE(l) + last;
  1385. X        }
  1386. X        pos = BLKSIZE;
  1387. X    }
  1388. X
  1389. X    /* not found */
  1390. X    msg(*o_wrapscan ? "Not found" : "Hit top without finding RE");
  1391. X    return MARK_UNSET;
  1392. X}
  1393. X
  1394. eof
  1395. if test `wc -c <move2.c` -ne 4445
  1396. then
  1397. echo move2.c damaged!
  1398. fi
  1399. fi
  1400.  
  1401. if test -f move3.c -a "$1" != -f
  1402. then
  1403. echo Will not overwrite move3.c
  1404. else
  1405. echo Extracting move3.c
  1406. sed 's/^X//' >move3.c <<\eof
  1407. X/* move3.c */
  1408. X
  1409. X/* Author:
  1410. X *    Steve Kirkendall
  1411. X *    14407 SW Teal Blvd. #C
  1412. X *    Beaverton, OR 97005
  1413. X *    kirkenda@cs.pdx.edu
  1414. X */
  1415. X
  1416. X
  1417. X/* This file contains movement functions that perform character searches */
  1418. X
  1419. X#include "config.h"
  1420. X#include "vi.h"
  1421. X
  1422. X#ifndef NO_CHARSEARCH
  1423. Xstatic MARK    (*prevfwdfn)();    /* function to search in same direction */
  1424. Xstatic MARK    (*prevrevfn)();    /* function to search in opposite direction */
  1425. Xstatic char    prev_key;    /* sought cvhar from previous [fFtT] */
  1426. X
  1427. XMARK    m__ch(m, cnt, cmd)
  1428. X    MARK    m;    /* current position */
  1429. X    long    cnt;
  1430. X    char    cmd;    /* command: either ',' or ';' */
  1431. X{
  1432. X    MARK    (*tmp)();
  1433. X
  1434. X    if (!prevfwdfn)
  1435. X    {
  1436. X        msg("No previous f, F, t, or T command");
  1437. X        return MARK_UNSET;
  1438. X    }
  1439. X
  1440. X    if (cmd == ',')
  1441. X    {
  1442. X        m =  (*prevrevfn)(m, cnt, prev_key);
  1443. X
  1444. X        /* Oops! we didn't want to change the prev*fn vars! */
  1445. X        tmp = prevfwdfn;
  1446. X        prevfwdfn = prevrevfn;
  1447. X        prevrevfn = tmp;
  1448. X
  1449. X        return m;
  1450. X    }
  1451. X    else
  1452. X    {
  1453. X        return (*prevfwdfn)(m, cnt, prev_key);
  1454. X    }
  1455. X}
  1456. X
  1457. X/* move forward within this line to next occurrence of key */
  1458. XMARK    m_fch(m, cnt, key)
  1459. X    MARK    m;    /* where to search from */
  1460. X    long    cnt;
  1461. X    char    key;    /* what to search for */
  1462. X{
  1463. X    REG char    *text;
  1464. X
  1465. X    DEFAULT(1);
  1466. X
  1467. X    prevfwdfn = m_fch;
  1468. X    prevrevfn = m_Fch;
  1469. X    prev_key = key;
  1470. X
  1471. X    pfetch(markline(m));
  1472. X    text = ptext + markidx(m);
  1473. X    while (cnt-- > 0)
  1474. X    {
  1475. X        do
  1476. X        {
  1477. X            m++;
  1478. X            text++;
  1479. X        } while (*text && *text != key);
  1480. X    }
  1481. X    if (!*text)
  1482. X    {
  1483. X        return MARK_UNSET;
  1484. X    }
  1485. X    return m;
  1486. X}
  1487. X
  1488. X/* move backward within this line to previous occurrence of key */
  1489. XMARK    m_Fch(m, cnt, key)
  1490. X    MARK    m;    /* where to search from */
  1491. X    long    cnt;
  1492. X    char    key;    /* what to search for */
  1493. X{
  1494. X    REG char    *text;
  1495. X
  1496. X    DEFAULT(1);
  1497. X
  1498. X    prevfwdfn = m_Fch;
  1499. X    prevrevfn = m_fch;
  1500. X    prev_key = key;
  1501. X
  1502. X    pfetch(markline(m));
  1503. X    text = ptext + markidx(m);
  1504. X    while (cnt-- > 0)
  1505. X    {
  1506. X        do
  1507. X        {
  1508. X            m--;
  1509. X            text--;
  1510. X        } while (text >= ptext && *text != key);
  1511. X    }
  1512. X    if (text < ptext)
  1513. X    {
  1514. X        return MARK_UNSET;
  1515. X    }
  1516. X    return m;
  1517. X}
  1518. X
  1519. X/* move forward within this line almost to next occurrence of key */
  1520. XMARK    m_tch(m, cnt, key)
  1521. X    MARK    m;    /* where to search from */
  1522. X    long    cnt;
  1523. X    char    key;    /* what to search for */
  1524. X{
  1525. X    /* skip the adjacent char */
  1526. X    pfetch(markline(m));
  1527. X    if (plen <= markidx(m))
  1528. X    {
  1529. X        return MARK_UNSET;
  1530. X    }
  1531. X    m++;
  1532. X
  1533. X    m = m_fch(m, cnt, key);
  1534. X    if (m == MARK_UNSET)
  1535. X    {
  1536. X        return MARK_UNSET;
  1537. X    }
  1538. X
  1539. X    prevfwdfn = m_tch;
  1540. X    prevrevfn = m_Tch;
  1541. X
  1542. X    return m - 1;
  1543. X}
  1544. X
  1545. X/* move backward within this line almost to previous occurrence of key */
  1546. XMARK    m_Tch(m, cnt, key)
  1547. X    MARK    m;    /* where to search from */
  1548. X    long    cnt;
  1549. X    char    key;    /* what to search for */
  1550. X{
  1551. X    /* skip the adjacent char */
  1552. X    if (markidx(m) == 0)
  1553. X    {
  1554. X        return MARK_UNSET;
  1555. X    }
  1556. X    m--;
  1557. X
  1558. X    m = m_Fch(m, cnt, key);
  1559. X    if (m == MARK_UNSET)
  1560. X    {
  1561. X        return MARK_UNSET;
  1562. X    }
  1563. X
  1564. X    prevfwdfn = m_Tch;
  1565. X    prevrevfn = m_tch;
  1566. X
  1567. X    return m + 1;
  1568. X}
  1569. X#endif
  1570. eof
  1571. if test `wc -c <move3.c` -ne 2697
  1572. then
  1573. echo move3.c damaged!
  1574. fi
  1575. fi
  1576.  
  1577. if test -f move4.c -a "$1" != -f
  1578. then
  1579. echo Will not overwrite move4.c
  1580. else
  1581. echo Extracting move4.c
  1582. sed 's/^X//' >move4.c <<\eof
  1583. X/* move4.c */
  1584. X
  1585. X/* Author:
  1586. X *    Steve Kirkendall
  1587. X *    14407 SW Teal Blvd. #C
  1588. X *    Beaverton, OR 97005
  1589. X *    kirkenda@cs.pdx.edu
  1590. X */
  1591. X
  1592. X
  1593. X/* This file contains movement functions which are screen-relative */
  1594. X
  1595. X#include "config.h"
  1596. X#include "vi.h"
  1597. X
  1598. X/* This moves the cursor to a particular row on the screen */
  1599. X/*ARGSUSED*/
  1600. XMARK m_row(m, cnt, key)
  1601. X    MARK    m;    /* the cursor position */
  1602. X    long    cnt;    /* the row we'll move to */
  1603. X    int    key;    /* the keystroke of this move - H/L/M */
  1604. X{
  1605. X    DEFAULT(1);
  1606. X
  1607. X    /* calculate destination line based on key */
  1608. X    cnt--;
  1609. X    switch (key)
  1610. X    {
  1611. X      case 'H':
  1612. X        cnt = topline + cnt;
  1613. X        break;
  1614. X
  1615. X      case 'M':
  1616. X        cnt = topline + (LINES - 1) / 2;
  1617. X        break;
  1618. X
  1619. X      case 'L':
  1620. X        cnt = botline - cnt;
  1621. X        break;
  1622. X    }
  1623. X
  1624. X    /* return the mark of the destination line */
  1625. X    return MARK_AT_LINE(cnt);
  1626. X}
  1627. X
  1628. X
  1629. X/* This function repositions the current line to show on a given row */
  1630. X/*ARGSUSED*/
  1631. XMARK m_z(m, cnt, key)
  1632. X    MARK    m;    /* the cursor */
  1633. X    long    cnt;    /* the line number we're repositioning */
  1634. X    int    key;    /* key struck after the z */
  1635. X{
  1636. X    long    newtop;
  1637. X
  1638. X    /* Which line are we talking about? */
  1639. X    if (cnt < 0 || cnt > nlines)
  1640. X    {
  1641. X        return MARK_UNSET;
  1642. X    }
  1643. X    if (cnt)
  1644. X    {
  1645. X        m = MARK_AT_LINE(cnt);
  1646. X        newtop = cnt;
  1647. X    }
  1648. X    else
  1649. X    {
  1650. X        newtop = markline(m);
  1651. X    }
  1652. X
  1653. X    /* allow a "window size" number to be entered, but ignore it */
  1654. X    while (key >= '0' && key <= '9')
  1655. X    {
  1656. X        key = getkey(0);
  1657. X    }
  1658. X
  1659. X    /* figure out which line will have to be at the top of the screen */
  1660. X    switch (key)
  1661. X    {
  1662. X      case '\n':
  1663. X#if OSK
  1664. X      case '\l':
  1665. X#else
  1666. X      case '\r':
  1667. X#endif
  1668. X      case '+':
  1669. X        break;
  1670. X
  1671. X      case '.':
  1672. X      case 'z':
  1673. X        newtop -= LINES / 2;
  1674. X        break;
  1675. X
  1676. X      case '-':
  1677. X        newtop -= LINES - 1;
  1678. X        break;
  1679. X
  1680. X      default:
  1681. X        return MARK_UNSET;
  1682. X    }
  1683. X
  1684. X    /* make the new topline take effect */
  1685. X    if (newtop >= 1)
  1686. X    {
  1687. X        topline = newtop;
  1688. X    }
  1689. X    else
  1690. X    {
  1691. X        topline = 1L;
  1692. X    }
  1693. X    mustredraw = TRUE;
  1694. X
  1695. X    /* The cursor doesn't move */
  1696. X    return m;
  1697. X}
  1698. X
  1699. X
  1700. X/* This function scrolls the screen.  It does this by calling redraw() with
  1701. X * an off-screen line as the argument.  It will move the cursor if necessary
  1702. X * so that the cursor is on the new screen.
  1703. X */
  1704. X/*ARGSUSED*/
  1705. XMARK m_scroll(m, cnt, key)
  1706. X    MARK    m;    /* the cursor position */
  1707. X    long    cnt;    /* for some keys: the number of lines to scroll */
  1708. X    int    key;    /* keystroke that causes this movement */
  1709. X{
  1710. X    MARK    tmp;    /* a temporary mark, used as arg to redraw() */
  1711. X
  1712. X    /* adjust cnt, and maybe *o_scroll, depending of key */
  1713. X    switch (key)
  1714. X    {
  1715. X      case ctrl('F'):
  1716. X      case ctrl('B'):
  1717. X        DEFAULT(1);
  1718. X        mustredraw = TRUE;
  1719. X        cnt = cnt * (LINES - 1) - 1; /* keeps one old line on screen */
  1720. X        break;
  1721. X
  1722. X      case ctrl('E'):
  1723. X      case ctrl('Y'):
  1724. X        DEFAULT(1);
  1725. X        break;
  1726. X
  1727. X      case ctrl('U'):
  1728. X      case ctrl('D'):
  1729. X        if (cnt == 0) /* default */
  1730. X        {
  1731. X            cnt = *o_scroll;
  1732. X        }
  1733. X        else
  1734. X        {
  1735. X            if (cnt > LINES - 1)
  1736. X            {
  1737. X                cnt = LINES - 1;
  1738. X            }
  1739. X            *o_scroll = cnt;
  1740. X        }
  1741. X        break;
  1742. X    }
  1743. X
  1744. X    /* scroll up or down, depending on key */
  1745. X    switch (key)
  1746. X    {
  1747. X      case ctrl('B'):
  1748. X      case ctrl('Y'):
  1749. X      case ctrl('U'):
  1750. X        cnt = topline - cnt;
  1751. X        if (cnt < 1L)
  1752. X        {
  1753. X            cnt = 1L;
  1754. X            m = MARK_FIRST;
  1755. X        }
  1756. X        tmp = MARK_AT_LINE(cnt) + markidx(m);
  1757. X        redraw(tmp, FALSE);
  1758. X        if (markline(m) > botline)
  1759. X        {
  1760. X            m = MARK_AT_LINE(botline);
  1761. X        }
  1762. X        break;
  1763. X
  1764. X      case ctrl('F'):
  1765. X      case ctrl('E'):
  1766. X      case ctrl('D'):
  1767. X        cnt = botline + cnt;
  1768. X        if (cnt > nlines)
  1769. X        {
  1770. X            cnt = nlines;
  1771. X            m = MARK_LAST;
  1772. X        }
  1773. X        tmp = MARK_AT_LINE(cnt) + markidx(m);
  1774. X        redraw(tmp, FALSE);
  1775. X        if (markline(m) < topline)
  1776. X        {
  1777. X            m = MARK_AT_LINE(topline);
  1778. X        }
  1779. X        break;
  1780. X    }
  1781. X
  1782. X    /* arrange for ctrl-B and ctrl-F to redraw the smart line */
  1783. X    if (key == ctrl('B') || key == ctrl('F'))
  1784. X    {
  1785. X        changes++;
  1786. X
  1787. X        /* also, erase the statusline.  This happens naturally for
  1788. X         * the scrolling commands, but the paging commands need to
  1789. X         * explicitly clear the statusline.
  1790. X         */
  1791. X        msg("");
  1792. X    }
  1793. X
  1794. X    return m;
  1795. X}
  1796. eof
  1797. if test `wc -c <move4.c` -ne 3699
  1798. then
  1799. echo move4.c damaged!
  1800. fi
  1801. fi
  1802.  
  1803. if test -f move5.c -a "$1" != -f
  1804. then
  1805. echo Will not overwrite move5.c
  1806. else
  1807. echo Extracting move5.c
  1808. sed 's/^X//' >move5.c <<\eof
  1809. X/* move5.c */
  1810. X
  1811. X/* Author:
  1812. X *    Steve Kirkendall
  1813. X *    14407 SW Teal Blvd. #C
  1814. X *    Beaverton, OR 97005
  1815. X *    kirkenda@cs.pdx.edu
  1816. X */
  1817. X
  1818. X
  1819. X/* This file contains the word-oriented movement functions */
  1820. X
  1821. X#include <ctype.h>
  1822. X#include "config.h"
  1823. X#include "vi.h"
  1824. X
  1825. X#ifndef isascii
  1826. X# define isascii(c)    !((c) & ~0x7f)
  1827. X#endif
  1828. X
  1829. X
  1830. XMARK    m_fword(m, cnt, cmd)
  1831. X    MARK    m;    /* movement is relative to this mark */
  1832. X    long    cnt;    /* a numeric argument */
  1833. X    int    cmd;    /* either 'w' or 'W' */
  1834. X{
  1835. X    REG long    l;
  1836. X    REG char    *text;
  1837. X    REG int        i;
  1838. X
  1839. X    DEFAULT(1);
  1840. X
  1841. X    l = markline(m);
  1842. X    pfetch(l);
  1843. X    text = ptext + markidx(m);
  1844. X    while (cnt-- > 0) /* yes, ASSIGNMENT! */
  1845. X    {
  1846. X        i = *text++;
  1847. X
  1848. X        if (cmd == 'W')
  1849. X        {
  1850. X            /* include any non-whitespace */
  1851. X            while (i && (!isascii(i) || !isspace(i)))
  1852. X            {
  1853. X                i = *text++;
  1854. X            }
  1855. X        }
  1856. X        else if (!isascii(i) || isalnum(i) || i == '_')
  1857. X        {
  1858. X            /* include an alphanumeric word */
  1859. X            while (i && (!isascii(i) || isalnum(i) || i == '_'))
  1860. X            {
  1861. X                i = *text++;
  1862. X            }
  1863. X        }
  1864. X        else
  1865. X        {
  1866. X            /* include contiguous punctuation */
  1867. X            while (i && isascii(i) && !isalnum(i) && !isspace(i))
  1868. X            {
  1869. X                i = *text++;
  1870. X            }
  1871. X        }
  1872. X
  1873. X        /* include trailing whitespace */
  1874. X        while (!i || isascii(i) && isspace(i))
  1875. X        {
  1876. X            /* did we hit the end of this line? */
  1877. X            if (!i)
  1878. X            {
  1879. X                /* move to next line, if there is one */
  1880. X                l++;
  1881. X                if (l > nlines)
  1882. X                {
  1883. X                    return MARK_UNSET;
  1884. X                }
  1885. X                pfetch(l);
  1886. X                text = ptext;
  1887. X            }
  1888. X
  1889. X            i = *text++;
  1890. X        }
  1891. X        text--;
  1892. X    }
  1893. X
  1894. X    /* construct a MARK for this place */
  1895. X    m = buildmark(text);
  1896. X    return m;
  1897. X}
  1898. X
  1899. X
  1900. XMARK    m_bword(m, cnt, cmd)
  1901. X    MARK    m;    /* movement is relative to this mark */
  1902. X    long    cnt;    /* a numeric argument */
  1903. X    int    cmd;    /* either 'b' or 'B' */
  1904. X{
  1905. X    REG long    l;
  1906. X    REG char    *text;
  1907. X
  1908. X    DEFAULT(1);
  1909. X
  1910. X    l = markline(m);
  1911. X    pfetch(l);
  1912. X    text = ptext + markidx(m);
  1913. X    while (cnt-- > 0) /* yes, ASSIGNMENT! */
  1914. X    {
  1915. X        text--;
  1916. X
  1917. X        /* include preceding whitespace */
  1918. X        while (text < ptext || isascii(*text) && isspace(*text))
  1919. X        {
  1920. X            /* did we hit the end of this line? */
  1921. X            if (text < ptext)
  1922. X            {
  1923. X                /* move to preceding line, if there is one */
  1924. X                l--;
  1925. X                if (l <= 0)
  1926. X                {
  1927. X                    return MARK_UNSET;
  1928. X                }
  1929. X                pfetch(l);
  1930. X                text = ptext + plen - 1;
  1931. X            }
  1932. X            else
  1933. X            {
  1934. X                text--;
  1935. X            }
  1936. X        }
  1937. X
  1938. X        if (cmd == 'B')
  1939. X        {
  1940. X            /* include any non-whitespace */
  1941. X            while (text >= ptext && (!isascii(*text) || !isspace(*text)))
  1942. X            {
  1943. X                text--;
  1944. X            }
  1945. X        }
  1946. X        else if (!isascii(*text) || isalnum(*text) || *text == '_')
  1947. X        {
  1948. X            /* include an alphanumeric word */
  1949. X            while (text >= ptext && (!isascii(*text) || isalnum(*text) || *text == '_'))
  1950. X            {
  1951. X                text--;
  1952. X            }
  1953. X        }
  1954. X        else
  1955. X        {
  1956. X            /* include contiguous punctuation */
  1957. X            while (text >= ptext && isascii(*text) && !isalnum(*text) && !isspace(*text))
  1958. X            {
  1959. X                text--;
  1960. X            }
  1961. X        }
  1962. X        text++;
  1963. X    }
  1964. X
  1965. X    /* construct a MARK for this place */
  1966. X    m = buildmark(text);
  1967. X    return m;
  1968. X}
  1969. X
  1970. XMARK    m_eword(m, cnt, cmd)
  1971. X    MARK    m;    /* movement is relative to this mark */
  1972. X    long    cnt;    /* a numeric argument */
  1973. X    int    cmd;    /* either 'e' or 'E' */
  1974. X{
  1975. X    REG long    l;
  1976. X    REG char    *text;
  1977. X    REG int        i;
  1978. X
  1979. X    DEFAULT(1);
  1980. X
  1981. X    l = markline(m);
  1982. X    pfetch(l);
  1983. X    text = ptext + markidx(m);
  1984. X    while (cnt-- > 0) /* yes, ASSIGNMENT! */
  1985. X    {
  1986. X        text++;
  1987. X        i = *text++;
  1988. X
  1989. X        /* include preceding whitespace */
  1990. X        while (!i || isascii(i) && isspace(i))
  1991. X        {
  1992. X            /* did we hit the end of this line? */
  1993. X            if (!i)
  1994. X            {
  1995. X                /* move to next line, if there is one */
  1996. X                l++;
  1997. X                if (l > nlines)
  1998. X                {
  1999. X                    return MARK_UNSET;
  2000. X                }
  2001. X                pfetch(l);
  2002. X                text = ptext;
  2003. X            }
  2004. X
  2005. X            i = *text++;
  2006. X        }
  2007. X
  2008. X        if (cmd == 'E')
  2009. X        {
  2010. X            /* include any non-whitespace */
  2011. X            while (i && (!isascii(i) || !isspace(i)))
  2012. X            {
  2013. X                i = *text++;
  2014. X            }
  2015. X        }
  2016. X        else if (!isascii(i) || isalnum(i) || i == '_')
  2017. X        {
  2018. X            /* include an alphanumeric word */
  2019. X            while (i && (!isascii(i) || isalnum(i) || i == '_'))
  2020. X            {
  2021. X                i = *text++;
  2022. X            }
  2023. X        }
  2024. X        else
  2025. X        {
  2026. X            /* include contiguous punctuation */
  2027. X            while (i && isascii(i) && !isalnum(i) && !isspace(i))
  2028. X            {
  2029. X                i = *text++;
  2030. X            }
  2031. X        }
  2032. X        text -= 2;
  2033. X    }
  2034. X
  2035. X    /* construct a MARK for this place */
  2036. X    m = buildmark(text);
  2037. X    return m;
  2038. X}
  2039. eof
  2040. if test `wc -c <move5.c` -ne 3940
  2041. then
  2042. echo move5.c damaged!
  2043. fi
  2044. fi
  2045.  
  2046. if test -f opts.c -a "$1" != -f
  2047. then
  2048. echo Will not overwrite opts.c
  2049. else
  2050. echo Extracting opts.c
  2051. sed 's/^X//' >opts.c <<\eof
  2052. X/* opts.c */
  2053. X
  2054. X/* Author:
  2055. X *    Steve Kirkendall
  2056. X *    14407 SW Teal Blvd. #C
  2057. X *    Beaverton, OR 97005
  2058. X *    kirkenda@cs.pdx.edu
  2059. X */
  2060. X
  2061. X
  2062. X/* This file contains the code that manages the run-time options -- The 
  2063. X * values that can be modified via the "set" command.
  2064. X */
  2065. X
  2066. X#include "config.h"
  2067. X#include "vi.h"
  2068. X#ifndef NULL
  2069. X#define NULL (char *)0
  2070. X#endif
  2071. Xextern char    *getenv();
  2072. X
  2073. X/* maximum width to permit for strings, including ="" */
  2074. X#define MAXWIDTH 20
  2075. X
  2076. X/* These are the default values of all options */
  2077. Xchar    o_autoindent[1] =    {FALSE};
  2078. Xchar    o_autoprint[1] =    {TRUE};
  2079. Xchar    o_autowrite[1] =     {FALSE};
  2080. X#ifndef NO_ERRLIST
  2081. Xchar    o_cc[30] =        {CC_COMMAND};
  2082. X#endif
  2083. X#ifndef NO_CHARATTR
  2084. Xchar    o_charattr[1] =        {FALSE};
  2085. X#endif
  2086. Xchar    o_columns[3] =        {80, 32, 255};
  2087. X#ifndef NO_DIGRAPH
  2088. Xchar    o_digraph[1] =        {FALSE};
  2089. X#endif
  2090. Xchar    o_directory[30] =    TMPDIR;
  2091. Xchar    o_edcompatible[1] =    {FALSE};
  2092. Xchar    o_errorbells[1] =    {TRUE};
  2093. Xchar    o_exrefresh[1] =    {TRUE};
  2094. X#ifndef NO_DIGRAPH
  2095. Xchar    o_flipcase[80]
  2096. X# if CS_IBMPC
  2097. X    = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
  2098. X# endif
  2099. X# if CS_LATIN1
  2100. X    /* initialized by initopts() */
  2101. X# endif
  2102. X    ;
  2103. X#endif
  2104. X#ifndef NO_SENTENCE
  2105. Xchar    o_hideformat[1] =    {FALSE};
  2106. X#endif
  2107. Xchar    o_ignorecase[1] =    {FALSE};
  2108. X#ifndef NO_EXTENSIONS
  2109. Xchar    o_inputmode[1] =    {FALSE};
  2110. X#endif
  2111. Xchar    o_keytime[3] =        {2, 0, 5};
  2112. Xchar    o_keywordprg[80] =    {KEYWORDPRG};
  2113. Xchar    o_lines[3] =        {25, 2, 50};    /* More lines? Enlarge kbuf */
  2114. Xchar    o_list[1] =        {FALSE};
  2115. X#ifndef NO_MAGIC
  2116. Xchar    o_magic[1] =        {TRUE};
  2117. X#endif
  2118. X#ifndef NO_ERRLIST
  2119. Xchar    o_make[30] =        {MAKE_COMMAND};
  2120. X#endif
  2121. X#ifndef NO_MODELINE
  2122. Xchar    o_modeline[1] =        {FALSE};
  2123. X#endif
  2124. X#ifndef NO_SENTENCE
  2125. Xchar    o_paragraphs[30] =    "PPppIPLPQP";
  2126. X#endif
  2127. X#if MSDOS
  2128. Xchar    o_pcbios[1] =        {TRUE};
  2129. X#endif
  2130. Xchar    o_readonly[1] =        {FALSE};
  2131. Xchar    o_report[3] =        {5, 1, 127};
  2132. Xchar    o_scroll[3] =        {12, 1, 127};
  2133. X#ifndef NO_SENTENCE
  2134. Xchar    o_sections[30] =    "NHSHSSSEse";
  2135. X#endif
  2136. Xchar    o_shell[60] =        SHELL;
  2137. Xchar    o_shiftwidth[3] =    {8, 1, 255};
  2138. X#ifndef NO_SHOWMATCH
  2139. Xchar    o_showmatch[1] =    {FALSE};
  2140. X#endif
  2141. X#ifndef    NO_SHOWMODE
  2142. Xchar    o_smd[1] =        {FALSE};
  2143. X#endif
  2144. Xchar    o_sidescroll[3] =    {8, 1, 40};
  2145. Xchar    o_sync[1] =        {NEEDSYNC};
  2146. Xchar    o_tabstop[3] =        {8, 1, 40};
  2147. Xchar    o_term[30] =        "?";
  2148. Xchar    o_vbell[1] =        {TRUE};
  2149. Xchar    o_warn[1] =        {TRUE};
  2150. Xchar    o_wrapmargin[3] =    {0, 0, 255};
  2151. Xchar    o_wrapscan[1] =        {TRUE};
  2152. X
  2153. X
  2154. X/* The following describes the names & types of all options */
  2155. X#define BOOL    0
  2156. X#define    NUM    1
  2157. X#define    STR    2
  2158. X#define SET    0x01    /* this option has had its value altered */
  2159. X#define CANSET    0x02    /* this option can be set at any time */
  2160. X#define RCSET    0x06    /* this option can be set in a .exrc file only */
  2161. X#define MR    0x40    /* does this option affect the way text is displayed? */
  2162. Xstruct
  2163. X{
  2164. X    char    *name;    /* name of an option */
  2165. X    char    *nm;    /* short name of an option */
  2166. X    char    type;    /* type of an option */
  2167. X    char    flags;    /* boolean: has this option been set? */
  2168. X    char    *value;    /* value */
  2169. X}
  2170. X    opts[] =
  2171. X{
  2172. X    /* name            type    flags    redraw    value */
  2173. X    { "autoindent",    "ai",    BOOL,    CANSET    ,    o_autoindent    },
  2174. X    { "autoprint",    "ap",    BOOL,    CANSET    ,    o_autoprint    },
  2175. X    { "autowrite",    "aw",    BOOL,    CANSET    ,    o_autowrite    },
  2176. X#ifndef NO_ERRLIST
  2177. X    { "cc",        "cc",    STR,    CANSET    ,    o_cc        },
  2178. X#endif
  2179. X#ifndef NO_CHARATTR
  2180. X    { "charattr",    "ca",    BOOL,    CANSET    | MR,    o_charattr    },
  2181. X#endif
  2182. X    { "columns",    "co",    NUM,    SET    ,    o_columns    },
  2183. X#ifndef NO_DIGRAPH
  2184. X    { "digraph",    "dig",    BOOL,    CANSET    ,    o_digraph    },
  2185. X#endif
  2186. X    { "directory",    "dir",    STR,    RCSET    ,    o_directory    },
  2187. X    { "edcompatible","ed",    BOOL,    CANSET    ,    o_edcompatible    },
  2188. X    { "errorbells",    "eb",    BOOL,    CANSET    ,    o_errorbells    },
  2189. X    { "exrefresh",    "er",    BOOL,    CANSET    ,    o_exrefresh    },
  2190. X#ifndef NO_DIGRAPH
  2191. X    { "flipcase",    "fc",    STR,    CANSET    ,    o_flipcase    },
  2192. X#endif
  2193. X#ifndef NO_SENTENCE
  2194. X    { "hideformat",    "hf",    BOOL,    CANSET    | MR,    o_hideformat    },
  2195. X#endif
  2196. X    { "ignorecase",    "ic",    BOOL,    CANSET    ,    o_ignorecase    },
  2197. X#ifndef NO_EXTENSIONS
  2198. X    { "inputmode",    "im",    BOOL,    CANSET    ,    o_inputmode    },
  2199. X#endif
  2200. X    { "keytime",    "kt",    NUM,    CANSET    ,    o_keytime    },
  2201. X    { "keywordprg",    "kp",    STR,    CANSET    ,    o_keywordprg    },
  2202. X    { "lines",    "ls",    NUM,    SET    ,    o_lines        },
  2203. X    { "list",    "li",    BOOL,    CANSET    | MR,    o_list        },
  2204. X#ifndef NO_MAGIC
  2205. X    { "magic",    "ma",    BOOL,    CANSET    ,    o_magic        },
  2206. X#endif
  2207. X#ifndef NO_ERRLIST
  2208. X    { "make",    "mk",    STR,    CANSET    ,    o_make        },
  2209. X#endif
  2210. X#ifndef NO_MODELINE
  2211. X    { "modeline",    "ml",    BOOL,    CANSET    ,    o_modeline    },
  2212. X#endif
  2213. X#ifndef NO_SENTENCE
  2214. X    { "paragraphs",    "pa",    STR,    CANSET    ,    o_paragraphs    },
  2215. X#endif
  2216. X#if MSDOS
  2217. X    { "pcbios",    "pc",    BOOL,    SET    ,    o_pcbios    },
  2218. X#endif
  2219. X    { "readonly",    "ro",    BOOL,    CANSET    ,    o_readonly    },
  2220. X    { "report",    "re",    NUM,    CANSET    ,    o_report    },
  2221. X    { "scroll",    "sc",    NUM,    CANSET    ,    o_scroll    },
  2222. X#ifndef NO_SENTENCE
  2223. X    { "sections",    "se",    STR,    CANSET    ,    o_sections    },
  2224. X#endif
  2225. X    { "shell",    "sh",    STR,    CANSET    ,    o_shell        },
  2226. X#ifndef NO_SHOWMATCH
  2227. X    { "showmatch",    "sm",    BOOL,    CANSET    ,    o_showmatch    },
  2228. X#endif
  2229. X#ifndef    NO_SHOWMODE
  2230. X    { "showmode",    "smd",    BOOL,    CANSET    ,    o_smd        },
  2231. X#endif
  2232. X    { "shiftwidth",    "sw",    NUM,    CANSET    ,    o_shiftwidth    },
  2233. X    { "sidescroll",    "ss",    NUM,    CANSET    ,    o_sidescroll    },
  2234. X    { "sync",    "sy",    BOOL,    CANSET    ,    o_sync        },
  2235. X    { "tabstop",    "ts",    NUM,    CANSET    | MR,    o_tabstop    },
  2236. X    { "term",    "te",    STR,    SET    ,    o_term        },
  2237. X    { "vbell",    "vb",    BOOL,    CANSET    ,    o_vbell        },
  2238. X    { "warn",    "wa",    BOOL,    CANSET    ,    o_warn        },
  2239. X    { "wrapmargin",    "wm",    NUM,    CANSET    ,    o_wrapmargin    },
  2240. X    { "wrapscan",    "ws",    BOOL,    CANSET    ,    o_wrapscan    },
  2241. X    { NULL, NULL, 0, CANSET, NULL }
  2242. X};
  2243. X
  2244. X
  2245. X/* This function initializes certain options from environment variables, etc. */
  2246. Xvoid initopts()
  2247. X{
  2248. X    char    *val;
  2249. X    int    i;
  2250. X
  2251. X    /* set some stuff from environment variables */
  2252. X#if MSDOS
  2253. X    if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
  2254. X#else
  2255. X    if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
  2256. X#endif
  2257. X    {
  2258. X        strcpy(o_shell, val);
  2259. X    }
  2260. X
  2261. X#if ANY_UNIX
  2262. X    if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
  2263. X    {
  2264. X        strcpy(o_term, val);
  2265. X    }
  2266. X#endif
  2267. X#if TOS
  2268. X    val = "vt52";
  2269. X    strcpy(o_term, val);
  2270. X#endif
  2271. X#if MSDOS
  2272. X    if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
  2273. X        && strcmp(val, "pcbios"))
  2274. X    {
  2275. X        strcpy(o_term, val);
  2276. X        o_pcbios[0] = 0;
  2277. X    }
  2278. X    else
  2279. X    {
  2280. X        strcpy(o_term, "pcbios");
  2281. X        o_pcbios[0] = 1;
  2282. X    }
  2283. X#endif
  2284. X#if MSDOS || TOS
  2285. X    if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
  2286. X    ||  (val = getenv("TEMP")))
  2287. X        strcpy(o_directory, val);
  2288. X#endif
  2289. X
  2290. X    *o_scroll = LINES / 2 - 1;
  2291. X
  2292. X    /* disable the vbell option if we don't know how to do a vbell */
  2293. X    if (!has_VB)
  2294. X    {
  2295. X        for (i = 0; opts[i].value != o_vbell; i++)
  2296. X        {
  2297. X        }
  2298. X        opts[i].flags &= ~CANSET;
  2299. X        *o_vbell = FALSE;
  2300. X    }
  2301. X
  2302. X#ifndef NO_DIGRAPH
  2303. X# ifdef CS_LATIN1
  2304. X    for (i = 0, val = o_flipcase; i < 32; i++)
  2305. X    {
  2306. X        /* leave out the multiply/divide symbols */
  2307. X        if (i == 23)
  2308. X            continue;
  2309. X
  2310. X        /* add upper/lowercase pair */
  2311. X        *val++ = i + 0xc0;
  2312. X        *val++ = i + 0xe0;
  2313. X    }
  2314. X    *val = '\0';
  2315. X# endif /* CS_LATIN1 */
  2316. X#endif /* not NO_DIGRAPH */
  2317. X}
  2318. X
  2319. X/* This function lists the current values of all options */
  2320. Xvoid dumpopts(all)
  2321. X    int    all;    /* boolean: dump all options, or just set ones? */
  2322. X{
  2323. X#ifndef NO_OPTCOLS
  2324. X    int    i, j, k;
  2325. X    char    nbuf[4];    /* used for converting numbers to ASCII */
  2326. X    int    widths[5];    /* width of each column, including gap */
  2327. X    int    ncols;        /* number of columns */
  2328. X    int    nrows;        /* number of options per column */
  2329. X    int    nset;        /* number of options to be output */
  2330. X    int    width;        /* width of a particular option */
  2331. X    int    todump[50];    /* indicies of options to be dumped */
  2332. X
  2333. X    /* step 1: count the number of set options */
  2334. X    for (nset = i = 0; opts[i].name; i++)
  2335. X    {
  2336. X        if (all || (opts[i].flags & SET))
  2337. X        {
  2338. X            todump[nset++] = i;
  2339. X        }
  2340. X    }
  2341. X
  2342. X    /* step two: try to use as many columns as possible */
  2343. X    for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
  2344. X    {
  2345. X        /* how many would go in this column? */
  2346. X        nrows = (nset + ncols - 1) / ncols;
  2347. X
  2348. X        /* figure out the width of each column */
  2349. X        for (i = 0; i < ncols; i++)
  2350. X        {
  2351. X            widths[i] = 0;
  2352. X            for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
  2353. X            {
  2354. X                /* figure out the width of a particular option */
  2355. X                switch (opts[todump[k]].type)
  2356. X                {
  2357. X                  case BOOL:
  2358. X                    if (!*opts[todump[k]].value)
  2359. X                        width = 2;
  2360. X                    else
  2361. X                        width = 0;
  2362. X                    break;
  2363. X
  2364. X                  case STR:
  2365. X                    width = 3 + strlen(opts[todump[k]].value);
  2366. X                    if (width > MAXWIDTH)
  2367. X                        width = MAXWIDTH;
  2368. X                    break;
  2369. X
  2370. X                  case NUM:
  2371. X                    width = 4;
  2372. X                    break;
  2373. X                }
  2374. X                width += strlen(opts[todump[k]].name);
  2375. X
  2376. X                /* if this is the widest so far, widen col */
  2377. X                if (width > widths[i])
  2378. X                {
  2379. X                    widths[i] = width;
  2380. X                }
  2381. X            }
  2382. X
  2383. X        }
  2384. X
  2385. X        /* if the total width is narrow enough, then use it */
  2386. X        for (width = -2, i = 0; i < ncols; i++)
  2387. X        {
  2388. X            width += widths[i] + 2;
  2389. X        }
  2390. X        if (width < COLS - 1)
  2391. X        {
  2392. X            break;
  2393. X        }
  2394. X    }
  2395. X
  2396. X    /* step 3: output the columns */
  2397. X    nrows = (nset + ncols - 1) / ncols;
  2398. X    for (i = 0; i < nrows; i++)
  2399. X    {
  2400. X        for (j = 0; j < ncols; j++)
  2401. X        {
  2402. X            /* if we hit the end of the options, quit */
  2403. X            k = i + j * nrows;
  2404. X            if (k >= nset)
  2405. X            {
  2406. X                break;
  2407. X            }
  2408. X
  2409. X            /* output this option's value */
  2410. X            width = 0;
  2411. X            switch (opts[todump[k]].type)
  2412. X            {
  2413. X              case BOOL:
  2414. X                if (!*opts[todump[k]].value)
  2415. X                {
  2416. X                    qaddch('n');
  2417. X                    qaddch('o');
  2418. X                    width = 2;
  2419. X                }
  2420. X                qaddstr(opts[todump[k]].name);
  2421. X                width += strlen(opts[todump[k]].name);
  2422. X                break;
  2423. X
  2424. X              case NUM:
  2425. X                sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
  2426. X                qaddstr(opts[todump[k]].name);
  2427. X                qaddch('=');
  2428. X                qaddstr(nbuf);
  2429. X                width = 4 + strlen(opts[todump[k]].name);
  2430. X                break;
  2431. X
  2432. X              case STR:
  2433. X                qaddstr(opts[todump[k]].name);
  2434. X                qaddch('=');
  2435. X                qaddch('"');
  2436. X                strcpy(tmpblk.c, opts[todump[k]].value);
  2437. X                width = 3 + strlen(tmpblk.c);
  2438. X                if (width > MAXWIDTH)
  2439. X                {
  2440. X                    width = MAXWIDTH;
  2441. X                    strcpy(tmpblk.c + MAXWIDTH - 6, "...");
  2442. X                }
  2443. X                qaddstr(tmpblk.c);
  2444. X                qaddch('"');
  2445. X                width += strlen(opts[todump[k]].name);
  2446. X                break;
  2447. X            }
  2448. X
  2449. X            /* pad the field to the correct size */
  2450. X            if (k + nrows <= nset)
  2451. X            {
  2452. X                while (width < widths[j] + 2)
  2453. X                {
  2454. X                    qaddch(' ');
  2455. X                    width++;
  2456. X                }
  2457. X            }
  2458. X        }
  2459. X        addch('\n');
  2460. X        exrefresh();
  2461. X    }
  2462. X#else
  2463. X    int    i;
  2464. X    int    col;
  2465. X    char    nbuf[4];
  2466. X
  2467. X    for (i = col = 0; opts[i].name; i++)
  2468. X    {
  2469. X        /* if not set and not all, ignore this option */
  2470. X        if (!all && !(opts[i].flags & SET))
  2471. X        {
  2472. X            continue;
  2473. X        }
  2474. X
  2475. X        /* align this option in one of the columns */
  2476. X        if (col > 52)
  2477. X        {
  2478. X            addch('\n');
  2479. X            col = 0;
  2480. X        }
  2481. X        else if (col > 26)
  2482. X        {
  2483. X            while (col < 52)
  2484. X            {
  2485. X                qaddch(' ');
  2486. X                col++;
  2487. X            }
  2488. X        }
  2489. X        else if (col > 0)
  2490. X        {
  2491. X            while (col < 26)
  2492. X            {
  2493. X                qaddch(' ');
  2494. X                col++;
  2495. X            }
  2496. X        }
  2497. X
  2498. X        switch (opts[i].type)
  2499. X        {
  2500. X          case BOOL:
  2501. X            if (!*opts[i].value)
  2502. X            {
  2503. X                qaddch('n');
  2504. X                qaddch('o');
  2505. X                col += 2;
  2506. X            }
  2507. X            qaddstr(opts[i].name);
  2508. X            col += strlen(opts[i].name);
  2509. X            break;
  2510. X
  2511. X          case NUM:
  2512. X            sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
  2513. X            qaddstr(opts[i].name);
  2514. X            qaddch('=');
  2515. X            qaddstr(nbuf);
  2516. X            col += 4 + strlen(opts[i].name);
  2517. X            break;
  2518. X
  2519. X          case STR:
  2520. X            qaddstr(opts[i].name);
  2521. X            qaddch('=');
  2522. X            qaddch('"');
  2523. X            qaddstr(opts[i].value);
  2524. X            qaddch('"');
  2525. X            col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
  2526. X            break;
  2527. X        }
  2528. X        exrefresh();
  2529. X    }
  2530. X    if (col > 0)
  2531. X    {
  2532. X        addch('\n');
  2533. X        exrefresh();
  2534. X    }
  2535. X#endif
  2536. X}
  2537. X
  2538. X#ifndef NO_MKEXRC
  2539. X/* This function saves the current configuarion of options to a file */
  2540. Xvoid saveopts(fd)
  2541. X    int    fd;    /* file descriptor to write to */
  2542. X{
  2543. X    int    i;
  2544. X    char    buf[256], *pos;
  2545. X
  2546. X    /* write each set options */
  2547. X    for (i = 0; opts[i].name; i++)
  2548. X    {
  2549. X        /* if unset or unsettable, ignore this option */
  2550. X        if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
  2551. X        {
  2552. X            continue;
  2553. X        }
  2554. X
  2555. X        strcpy(buf, "set ");
  2556. X        pos = &buf[4];
  2557. X        switch (opts[i].type)
  2558. X        {
  2559. X          case BOOL:
  2560. X            if (!*opts[i].value)
  2561. X            {
  2562. X                *pos++='n';
  2563. X                *pos++='o';
  2564. X            }
  2565. X            strcpy(pos, opts[i].name);
  2566. X            strcat(pos, "\n");
  2567. X            break;
  2568. X
  2569. X          case NUM:
  2570. X            sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
  2571. X            break;
  2572. X
  2573. X          case STR:
  2574. X            sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
  2575. X            break;
  2576. X        }
  2577. X        twrite(fd, buf, strlen(buf));
  2578. X    }
  2579. X}
  2580. X#endif
  2581. X
  2582. X
  2583. X/* This function changes the values of one or more options. */
  2584. Xvoid setopts(assignments)
  2585. X    char    *assignments;    /* a string containing option assignments */
  2586. X{
  2587. X    char    *name;        /* name of variable in assignments */
  2588. X    char    *value;        /* value of the variable */
  2589. X    char    *scan;        /* used for moving through strings */
  2590. X    int    i, j;
  2591. X
  2592. X    /* for each assignment... */
  2593. X    for (name = assignments; *name; )
  2594. X    {
  2595. X        /* skip whitespace */
  2596. X        if (*name == ' ' || *name == '\t')
  2597. X        {
  2598. X            name++;
  2599. X            continue;
  2600. X        }
  2601. X
  2602. X        /* find the value, if any */
  2603. X        for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
  2604. X        {
  2605. X        }
  2606. X        if (*scan == '=')
  2607. X        {
  2608. X            *scan++ = '\0';
  2609. X            if (*scan == '"')
  2610. X            {
  2611. X                value = ++scan;
  2612. X                while (*scan && *scan != '"')
  2613. X                {
  2614. X                    scan++;
  2615. X                }
  2616. X                if (*scan)
  2617. X                {
  2618. X                    *scan++ = '\0';
  2619. X                }
  2620. X            }
  2621. X            else
  2622. X            {
  2623. X                value = scan;
  2624. X                while (*scan && *scan != ' ' && *scan != '\t')
  2625. X                {
  2626. X                    scan++;
  2627. X                }
  2628. X                if (*scan)
  2629. X                {
  2630. X                    *scan++ = '\0';
  2631. X                }
  2632. X            }
  2633. X        }
  2634. X        else
  2635. X        {
  2636. X            if (*scan)
  2637. X            {
  2638. X                *scan++ = '\0';
  2639. X            }
  2640. X            value = NULL;
  2641. X            if (name[0] == 'n' && name[1] == 'o')
  2642. X            {
  2643. X                name += 2;
  2644. X            }
  2645. X        }
  2646. X
  2647. X        /* find the variable */
  2648. X        for (i = 0;
  2649. X             opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
  2650. X             i++)
  2651. X        {
  2652. X        }
  2653. X
  2654. X        /* change the variable */
  2655. X        if (!opts[i].name)
  2656. X        {
  2657. X            msg("invalid option name \"%s\"", name);
  2658. X        }
  2659. X        else if ((opts[i].flags & CANSET) != CANSET)
  2660. X        {
  2661. X            msg("option \"%s\" can't be altered", name);
  2662. X        }
  2663. X        else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
  2664. X        {
  2665. X            msg("option \"%s\" can only be set in a %s file", name, EXRC);
  2666. X        }
  2667. X        else if (value)
  2668. X        {
  2669. X            switch (opts[i].type)
  2670. X            {
  2671. X              case BOOL:
  2672. X                msg("option \"[no]%s\" is boolean", name);
  2673. X                break;
  2674. X
  2675. X              case NUM:
  2676. X                j = atoi(value);
  2677. X                if (j == 0 && *value != '0')
  2678. X                {
  2679. X                    msg("option \"%s\" must have a numeric value", name);
  2680. X                }
  2681. X                else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
  2682. X                {
  2683. X                    msg("option \"%s\" must have a value between %d and %d",
  2684. X                        name, opts[i].value[1], opts[i].value[2] & 0xff);
  2685. X                }
  2686. X                else
  2687. X                {
  2688. X                    *opts[i].value = atoi(value);
  2689. X                    opts[i].flags |= SET;
  2690. X                }
  2691. X                break;
  2692. X
  2693. X              case STR:
  2694. X                strcpy(opts[i].value, value);
  2695. X                opts[i].flags |= SET;
  2696. X                break;
  2697. X            }
  2698. X            if (opts[i].flags & MR)
  2699. X            {
  2700. X                mustredraw = TRUE;
  2701. X            }
  2702. X        }
  2703. X        else /* valid option, no value */
  2704. X        {
  2705. X            if (opts[i].type == BOOL)
  2706. X            {
  2707. X                *opts[i].value = (name[-1] != 'o');
  2708. X                opts[i].flags |= SET;
  2709. X                if (opts[i].flags & MR)
  2710. X                {
  2711. X                    mustredraw = TRUE;
  2712. X                }
  2713. X            }
  2714. X            else
  2715. X            {
  2716. X                msg("option \"%s\" must be given a value", name);
  2717. X            }
  2718. X        }
  2719. X
  2720. X        /* move on to the next option */
  2721. X        name = scan;
  2722. X    }
  2723. X
  2724. X    /* special processing ... */
  2725. X
  2726. X    /* if "readonly" then set the READONLY flag for this file */
  2727. X    if (*o_readonly)
  2728. X    {
  2729. X        setflag(file, READONLY);
  2730. X    }
  2731. X}
  2732. eof
  2733. if test `wc -c <opts.c` -ne 14362
  2734. then
  2735. echo opts.c damaged!
  2736. fi
  2737. fi
  2738.  
  2739. if test -f recycle.c -a "$1" != -f
  2740. then
  2741. echo Will not overwrite recycle.c
  2742. else
  2743. echo Extracting recycle.c
  2744. sed 's/^X//' >recycle.c <<\eof
  2745. X/* recycle.c */
  2746. X
  2747. X/* Author:
  2748. X *    Steve Kirkendall
  2749. X *    14407 SW Teal Blvd. #C
  2750. X *    Beaverton, OR 97005
  2751. X *    kirkenda@cs.pdx.edu
  2752. X */
  2753. X
  2754. X
  2755. X/* This file contains the functions perform garbage collection and allocate
  2756. X * reusable blocks.
  2757. X */
  2758. X
  2759. X#include "config.h"
  2760. X#include "vi.h"
  2761. X
  2762. X#ifndef NO_RECYCLE
  2763. X/* this whole file would have be skipped if NO_RECYCLE is defined */
  2764. X
  2765. Xextern long    lseek();
  2766. X
  2767. X#define BTST(bitno, byte)    ((byte) & (1 << (bitno)))
  2768. X#define BSET(bitno, byte)    ((byte) |= (1 << (bitno)))
  2769. X#define BCLR(bitno, byte)    ((byte) &= ~(1 << (bitno)))
  2770. X
  2771. X#define TST(blkno)        ((blkno) < MAXBIT ? BTST((blkno) & 7, bitmap[(blkno) >> 3]) : 1)
  2772. X#define SET(blkno)        if ((blkno) < MAXBIT) BSET((blkno) & 7, bitmap[(blkno) >> 3])
  2773. X#define CLR(blkno)        if ((blkno) < MAXBIT) BCLR((blkno) & 7, bitmap[(blkno) >> 3])
  2774. X
  2775. X/* bitmap of free blocks in first 4096k of tmp file */
  2776. Xstatic unsigned char bitmap[512];
  2777. X#define MAXBIT    (sizeof bitmap << 3)
  2778. X
  2779. X/* this function locates all free blocks in the current tmp file */
  2780. Xvoid garbage()
  2781. X{
  2782. X    int    i;
  2783. X    BLK    oldhdr;
  2784. X
  2785. X    /* start by assuming every block is free */
  2786. X    for (i = 0; i < sizeof bitmap; i++)
  2787. X    {
  2788. X        bitmap[i] = 255;
  2789. X    }
  2790. X
  2791. X    /* header block isn't free */
  2792. X#ifndef lint
  2793. X    CLR(0);
  2794. X#endif
  2795. X
  2796. X    /* blocks needed for current hdr aren't free */
  2797. X    for (i = 1; i < MAXBLKS; i++)
  2798. X    {
  2799. X        CLR(hdr.n[i]);
  2800. X    }
  2801. X
  2802. X    /* blocks needed for undo version aren't free */
  2803. X    lseek(tmpfd, 0L, 0);
  2804. X    if (read(tmpfd, &oldhdr, (unsigned)sizeof oldhdr) != sizeof oldhdr)
  2805. X    {
  2806. X        msg("garbage() failed to read oldhdr??");
  2807. X        for (i = 0; i < sizeof bitmap; i++)
  2808. X        {
  2809. X            bitmap[i] = 0;
  2810. X        }
  2811. X        return;
  2812. X    }
  2813. X    for (i = 1; i < MAXBLKS; i++)
  2814. X    {
  2815. X        CLR(oldhdr.n[i]);
  2816. X    }
  2817. X
  2818. X    /* blocks needed for cut buffers aren't free */
  2819. X    for (i = cutneeds(&oldhdr) - 1; i >= 0; i--)
  2820. X    {
  2821. X        CLR(oldhdr.n[i]);
  2822. X    }
  2823. X}
  2824. X
  2825. X/* This function allocates the first available block in the tmp file */
  2826. Xlong allocate()
  2827. X{
  2828. X    int    i;
  2829. X    long    offset;
  2830. X
  2831. X    /* search for the first byte with a free bit set */
  2832. X    for (i = 0; i < sizeof bitmap && bitmap[i] == 0; i++)
  2833. X    {
  2834. X    }
  2835. X
  2836. X    /* if we hit the end of the bitmap, return the end of the file */
  2837. X    if (i == sizeof bitmap)
  2838. X    {
  2839. X        offset = lseek(tmpfd, 0L, 2);
  2840. X    }
  2841. X    else /* compute the offset for the free block */
  2842. X    {
  2843. X        for (i <<= 3; TST(i) == 0; i++)
  2844. X        {
  2845. X        }
  2846. X        offset = (long)i * (long)BLKSIZE;
  2847. X
  2848. X        /* mark the block as "allocated" */
  2849. X        CLR(i);
  2850. X    }
  2851. X
  2852. X    return offset;
  2853. X}
  2854. X
  2855. X#endif
  2856. eof
  2857. if test `wc -c <recycle.c` -ne 2306
  2858. then
  2859. echo recycle.c damaged!
  2860. fi
  2861. fi
  2862.  
  2863. if test -f redraw.c -a "$1" != -f
  2864. then
  2865. echo Will not overwrite redraw.c
  2866. else
  2867. echo Extracting redraw.c
  2868. sed 's/^X//' >redraw.c <<\eof
  2869. X/* redraw.c */
  2870. X
  2871. X/* Author:
  2872. X *    Steve Kirkendall
  2873. X *    14407 SW Teal Blvd. #C
  2874. X *    Beaverton, OR 97005
  2875. X *    kirkenda@cs.pdx.edu
  2876. X */
  2877. X
  2878. X
  2879. X/* This file contains functions that draw text on the screen.  The major entry
  2880. X * points are:
  2881. X *    redrawrange()    - called from modify.c to give hints about what parts
  2882. X *              of the screen need to be redrawn.
  2883. X *    redraw()    - redraws the screen (or part of it) and positions
  2884. X *              the cursor where it belongs.
  2885. X *    idx2col()    - converts a markidx() value to a logical column number.
  2886. X */
  2887. X
  2888. X#include "config.h"
  2889. X#include "vi.h"
  2890. X
  2891. X/* This variable contains the line number that smartdrawtext() knows best */
  2892. Xstatic long smartlno;
  2893. X
  2894. X/* This function remebers where changes were made, so that the screen can be
  2895. X * redraw in a more efficient manner.
  2896. X */
  2897. Xstatic long    redrawafter;    /* line# of first line that must be redrawn */
  2898. Xstatic long    preredraw;    /* line# of last line changed, before change */
  2899. Xstatic long    postredraw;    /* line# of last line changed, after change */
  2900. Xvoid redrawrange(after, pre, post)
  2901. X    long    after;    /* lower bound of redrawafter */
  2902. X    long    pre;    /* upper bound of preredraw */
  2903. X    long    post;    /* upper bound of postredraw */
  2904. X{
  2905. X    if (after == redrawafter)
  2906. X    {
  2907. X        /* multiple insertions/deletions at the same place -- combine
  2908. X         * them
  2909. X         */
  2910. X        preredraw -= (post - pre);
  2911. X        if (postredraw < post)
  2912. X        {
  2913. X            preredraw += (post - postredraw);
  2914. X            postredraw = post;
  2915. X        }
  2916. X        if (redrawafter > preredraw)
  2917. X        {
  2918. X            redrawafter = preredraw;
  2919. X        }
  2920. X        if (redrawafter < 1L)
  2921. X        {
  2922. X            redrawafter = 0L;
  2923. X            preredraw = postredraw = INFINITY;
  2924. X        }
  2925. X    }
  2926. X    else if (postredraw > 0L)
  2927. X    {
  2928. X        /* multiple changes in different places -- redraw everything
  2929. X         * after "after".
  2930. X         */
  2931. X        postredraw = preredraw = INFINITY;
  2932. X        if (after < redrawafter)
  2933. X            redrawafter = after;
  2934. X    }
  2935. X    else
  2936. X    {
  2937. X        /* first change */
  2938. X        redrawafter = after;
  2939. X        preredraw = pre;
  2940. X        postredraw = post;
  2941. X    }
  2942. X}
  2943. X
  2944. X
  2945. X#ifndef NO_CHARATTR
  2946. X/* see if a given line uses character attribute strings */
  2947. Xstatic int hasattr(lno, text)
  2948. X    long        lno;    /* the line# of the cursor */
  2949. X    REG char    *text;    /* the text of the line, from fetchline */
  2950. X{
  2951. X    static long    plno;    /* previous line number */
  2952. X    static long    chgs;    /* previous value of changes counter */
  2953. X    static int    panswer;/* previous answer */
  2954. X    char        *scan;
  2955. X
  2956. X    /* if charattr is off, then the answer is "no, it doesn't" */
  2957. X    if (!*o_charattr)
  2958. X    {
  2959. X        chgs = 0; /* <- forces us to check if charattr is later set */
  2960. X        return FALSE;
  2961. X    }
  2962. X
  2963. X    /* if we already know the answer, return it... */
  2964. X    if (lno == plno && chgs == changes)
  2965. X    {
  2966. X        return panswer;
  2967. X    }
  2968. X
  2969. X    /* get the line & look for "\fX" */
  2970. X    if (!text[0] || !text[1] || !text[2])
  2971. X    {
  2972. X        panswer = FALSE;
  2973. X    }
  2974. X    else
  2975. X    {
  2976. X        for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
  2977. X        {
  2978. X        }
  2979. X        panswer = (scan[2] != '\0');
  2980. X    }
  2981. X
  2982. X    /* save the results */
  2983. X    plno = lno;
  2984. X    chgs = changes;
  2985. X
  2986. X    /* return the results */
  2987. X    return panswer;
  2988. X}
  2989. X#endif
  2990. X
  2991. X
  2992. X
  2993. X/* This function converts a MARK to a column number.  It doesn't automatically
  2994. X * adjust for leftcol; that must be done by the calling function
  2995. X */
  2996. Xint idx2col(curs, text, inputting)
  2997. X    MARK        curs;    /* the line# & index# of the cursor */
  2998. X    REG char    *text;    /* the text of the line, from fetchline */
  2999. X    int        inputting;    /* boolean: called from input() ? */
  3000. X{
  3001. X    static MARK    pcursor;/* previous cursor, for possible shortcut */
  3002. X    static MARK    pcol;    /* column number for pcol */
  3003. X    static long    chgs;    /* previous value of changes counter */
  3004. X    REG int        col;    /* used to count column numbers */
  3005. X    REG int        idx;    /* used to count down the index */
  3006. X    REG int        i;
  3007. X
  3008. X    /* for now, assume we have to start counting at the left edge */
  3009. X    col = 0;
  3010. X    idx = markidx(curs);
  3011. X
  3012. X    /* if the file hasn't changed & line number is the same & it has no
  3013. X     * embedded character attribute strings, can we do shortcuts?
  3014. X     */
  3015. X    if (chgs == changes
  3016. X     && !((curs ^ pcursor) & ~(BLKSIZE - 1))
  3017. X#ifndef NO_CHARATTR
  3018. X     && !hasattr(markline(curs), text)
  3019. X#endif
  3020. X    )
  3021. X    {
  3022. X        /* no movement? */
  3023. X        if (curs == pcursor)
  3024. X        {
  3025. X            /* return the column of the char; for tabs, return its last column */
  3026. X            if (text[idx] == '\t' && !inputting && !*o_list)
  3027. X            {
  3028. X                return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
  3029. X            }
  3030. X            else
  3031. X            {
  3032. X                return pcol;
  3033. X            }
  3034. X        }
  3035. X
  3036. X        /* movement to right? */
  3037. X        if (curs > pcursor)
  3038. X        {
  3039. X            /* start counting from previous place */
  3040. X            col = pcol;
  3041. X            idx = markidx(curs) - markidx(pcursor);
  3042. X            text += markidx(pcursor);
  3043. X        }
  3044. X    }
  3045. X
  3046. X    /* count over to the char after the idx position */
  3047. X    while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
  3048. X    {
  3049. X        if (i == '\t' && !*o_list)
  3050. X        {
  3051. X            col += *o_tabstop;
  3052. X            col -= col % *o_tabstop;
  3053. X        }
  3054. X        else if (i >= '\0' && i < ' ' || i == '\177')
  3055. X        {
  3056. X            col += 2;
  3057. X        }
  3058. X#ifndef NO_CHARATTR
  3059. X        else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  3060. X        {
  3061. X            text += 2; /* plus one more at bottom of loop */
  3062. X            idx -= 2;
  3063. X        }            
  3064. X#endif
  3065. X        else
  3066. X        {
  3067. X            col++;
  3068. X        }
  3069. X        text++;
  3070. X        idx--;
  3071. X    }
  3072. X
  3073. X    /* save stuff to speed next call */
  3074. X    pcursor = curs;
  3075. X    pcol = col;
  3076. X    chgs = changes;
  3077. X
  3078. X    /* return the column of the char; for tabs, return its last column */
  3079. X    if (*text == '\t' && !inputting && !*o_list)
  3080. X    {
  3081. X        return col + *o_tabstop - (col % *o_tabstop) - 1;
  3082. X    }
  3083. X    else
  3084. X    {
  3085. X        return col;
  3086. X    }
  3087. X}
  3088. X
  3089. X
  3090. X/* This function is similar to idx2col except that it takes care of sideways
  3091. X * scrolling - for the given line, at least.
  3092. X */
  3093. Xint mark2phys(m, text, inputting)
  3094. X    MARK    m;        /* a mark to convert */
  3095. X    char    *text;        /* the line that m refers to */
  3096. X    int    inputting;    /* boolean: caled from input() ? */
  3097. X{
  3098. X    int    i;
  3099. X
  3100. X    i = idx2col(m, text, inputting);
  3101. X    while (i < leftcol)
  3102. X    {
  3103. X        leftcol -= *o_sidescroll;
  3104. X        mustredraw = TRUE;
  3105. X        redrawrange(1L, INFINITY, INFINITY);
  3106. X        qaddch('\r');
  3107. X        /* drawtext(text); */
  3108. X    }
  3109. X    while (i > rightcol)
  3110. X    {
  3111. X        leftcol += *o_sidescroll;
  3112. X        mustredraw = TRUE;
  3113. X        redrawrange(1L, INFINITY, INFINITY);
  3114. X        qaddch('\r');
  3115. X        /* drawtext(text); */
  3116. X    }
  3117. X    physcol = i - leftcol;
  3118. X    physrow = markline(m) - topline;
  3119. X
  3120. X    return physcol;
  3121. X}
  3122. X
  3123. X/* This function draws a single line of text on the screen.  The screen's
  3124. X * cursor is assumed to be located at the leftmost column of the appropriate
  3125. X * row.
  3126. X */
  3127. Xstatic void drawtext(text, clr)
  3128. X    REG char    *text;    /* the text to draw */
  3129. X    int        clr;    /* boolean: do a clrtoeol? */
  3130. X{
  3131. X    REG int        col;    /* column number */
  3132. X    REG int        i;
  3133. X    REG int        tabstop;    /* *o_tabstop */
  3134. X    REG int        limitcol;    /* leftcol or leftcol + COLS */
  3135. X    int        abnormal;    /* boolean: charattr != A_NORMAL? */
  3136. X
  3137. X#ifndef NO_SENTENCE
  3138. X    /* if we're hiding format lines, and this is one of them, then hide it */
  3139. X    if (*o_hideformat && *text == '.')
  3140. X    {
  3141. X        clrtoeol();
  3142. X#if OSK
  3143. X        qaddch('\l');
  3144. X#else
  3145. X        qaddch('\n');
  3146. X#endif
  3147. X        return;
  3148. X    }
  3149. X#endif
  3150. X
  3151. X    /* move some things into registers... */
  3152. X    limitcol = leftcol;
  3153. X    tabstop = *o_tabstop;
  3154. X    abnormal = FALSE;
  3155. X
  3156. X#ifndef CRUNCH
  3157. X    if (clr)
  3158. X        clrtoeol();
  3159. X#endif
  3160. X    /* skip stuff that was scrolled off left edge */
  3161. X    for (col = 0;
  3162. X         (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  3163. X         text++)
  3164. X    {
  3165. X        if (i == '\t' && !*o_list)
  3166. X        {
  3167. X            col = col + tabstop - (col % tabstop);
  3168. X        }
  3169. X        else if (i >= 0 && i < ' ' || i == '\177')
  3170. X        {
  3171. X            col += 2;
  3172. X        }
  3173. X#ifndef NO_CHARATTR
  3174. X        else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  3175. X        {
  3176. X            text += 2; /* plus one more as part of "for" loop */
  3177. X
  3178. X            /* since this attribute might carry over, we need it */
  3179. X            switch (*text)
  3180. X            {
  3181. X              case 'R':
  3182. X              case 'P':
  3183. X                attrset(A_NORMAL);
  3184. X                abnormal = FALSE;
  3185. X                break;
  3186. X
  3187. X              case 'B':
  3188. X                attrset(A_BOLD);
  3189. X                abnormal = TRUE;
  3190. X                break;
  3191. X
  3192. X              case 'U':
  3193. X                attrset(A_UNDERLINE);
  3194. X                abnormal = TRUE;
  3195. X                break;
  3196. X
  3197. X              case 'I':
  3198. X                attrset(A_ALTCHARSET);
  3199. X                abnormal = TRUE;
  3200. X                break;
  3201. X            }
  3202. X        }
  3203. X#endif
  3204. X        else
  3205. X        {
  3206. X            col++;
  3207. X        }
  3208. X    }
  3209. X
  3210. X    /* adjust for control char that was partially visible */
  3211. X    while (col > limitcol)
  3212. X    {
  3213. X        qaddch(' ');
  3214. X        limitcol++;
  3215. X    }
  3216. X
  3217. X    /* now for the visible characters */
  3218. X    for (limitcol = leftcol + COLS;
  3219. X         (i = *text) && col < limitcol;
  3220. X         text++)
  3221. X    {
  3222. X        if (i == '\t' && !*o_list)
  3223. X        {
  3224. X            i = col + tabstop - (col % tabstop);
  3225. X            if (i < limitcol)
  3226. X            {
  3227. X#ifdef CRUNCH
  3228. X                if (!clr && has_PT && !((i - leftcol) & 7))
  3229. X#else
  3230. X                if (has_PT && !((i - leftcol) & 7))
  3231. X#endif
  3232. X                {
  3233. X                    do
  3234. X                    {
  3235. X                        qaddch('\t');
  3236. X                        col += 8; /* not exact! */
  3237. X                    } while (col < i);
  3238. X                    col = i; /* NOW it is exact */
  3239. X                }
  3240. X                else
  3241. X                {
  3242. X                    do
  3243. X                    {
  3244. X                        qaddch(' ');
  3245. X                        col++;
  3246. X                    } while (col < i);
  3247. X                }
  3248. X            }
  3249. X            else /* tab ending after screen? next line! */
  3250. X            {
  3251. X                col = limitcol;
  3252. X                if (has_AM)
  3253. X                {
  3254. X                    addch('\n');    /* GB */
  3255. X                }
  3256. X            }
  3257. X        }
  3258. X        else if (i >= 0 && i < ' ' || i == '\177')
  3259. X        {
  3260. X            col += 2;
  3261. X            qaddch('^');
  3262. X            if (col <= limitcol)
  3263. X            {
  3264. X                qaddch(i ^ '@');
  3265. X            }
  3266. X        }
  3267. X#ifndef NO_CHARATTR
  3268. X        else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  3269. X        {
  3270. X            text += 2; /* plus one more as part of "for" loop */
  3271. X            switch (*text)
  3272. X            {
  3273. X              case 'R':
  3274. X              case 'P':
  3275. X                attrset(A_NORMAL);
  3276. X                abnormal = FALSE;
  3277. X                break;
  3278. X
  3279. X              case 'B':
  3280. X                attrset(A_BOLD);
  3281. X                abnormal = TRUE;
  3282. X                break;
  3283. X
  3284. X              case 'U':
  3285. X                attrset(A_UNDERLINE);
  3286. X                abnormal = TRUE;
  3287. X                break;
  3288. X
  3289. X              case 'I':
  3290. X                attrset(A_ALTCHARSET);
  3291. X                abnormal = TRUE;
  3292. X                break;
  3293. X            }
  3294. X        }
  3295. X#endif
  3296. X        else
  3297. X        {
  3298. X            col++;
  3299. X            qaddch(i);
  3300. X        }
  3301. X    }
  3302. X
  3303. X    /* get ready for the next line */
  3304. X#ifndef NO_CHARATTR
  3305. X    if (abnormal)
  3306. X    {
  3307. X        attrset(A_NORMAL);
  3308. X    }
  3309. X#endif
  3310. X    if (*o_list && col < limitcol)
  3311. X    {
  3312. X        qaddch('$');
  3313. X        col++;
  3314. X    }
  3315. X#ifdef CRUNCH
  3316. X    if (clr && col < limitcol)
  3317. X    {
  3318. X        clrtoeol();
  3319. X    }
  3320. X#endif
  3321. X    if (!has_AM || col < limitcol)
  3322. X    {
  3323. X        addch('\n');
  3324. X    }
  3325. X}
  3326. X
  3327. X
  3328. X#ifndef CRUNCH
  3329. Xstatic void nudgecursor(same, scan, new, lno)
  3330. X    int    same;    /* number of chars to be skipped over */
  3331. X    char    *scan;    /* where the same chars end */
  3332. X    char    *new;    /* where the visible part of the line starts */
  3333. X    long    lno;    /* line number of this line */
  3334. X{
  3335. X    if (same > 0)
  3336. X    {
  3337. X        if (same < 5)
  3338. X        {
  3339. X            /* move the cursor by overwriting */
  3340. X            while (same > 0)
  3341. X            {
  3342. X                qaddch(scan[-same]);
  3343. X                same--;
  3344. X            }
  3345. X        }
  3346. X        else
  3347. X        {
  3348. X            /* move the cursor by calling move() */
  3349. X            move((int)(lno - topline), (int)(scan - new));
  3350. X        }
  3351. X    }
  3352. X}
  3353. X#endif /* not CRUNCH */
  3354. X
  3355. X/* This function draws a single line of text on the screen, possibly with
  3356. X * some cursor optimization.  The cursor is repositioned before drawing
  3357. X * begins, so its position before doesn't really matter.
  3358. X */
  3359. Xstatic void smartdrawtext(text, lno)
  3360. X    REG char    *text;    /* the text to draw */
  3361. X    long        lno;    /* line number of the text */
  3362. X{
  3363. X#ifdef CRUNCH
  3364. X    move((int)(lno - topline), 0);
  3365. X    drawtext(text, TRUE);
  3366. X#else /* not CRUNCH */
  3367. X    static char    old[256];    /* how the line looked last time */
  3368. X    char        new[256];    /* how it looks now */
  3369. X    char        *build;        /* used to put chars into new[] */
  3370. X    char        *scan;        /* used for moving thru new[] or old[] */
  3371. X    char        *end;        /* last non-blank changed char */
  3372. X    char        *shift;        /* used to insert/delete chars */
  3373. X    int        same;        /* length of a run of unchanged chars */
  3374. X    int        limitcol;
  3375. X    int        col;
  3376. X    int        i;
  3377. X
  3378. X# ifndef NO_CHARATTR
  3379. X    /* if this line has attributes, do it the dumb way instead */
  3380. X    if (hasattr(lno, text))
  3381. X    {
  3382. X        move((int)(lno - topline), 0);
  3383. X        drawtext(text, TRUE);
  3384. X        return;
  3385. X    }
  3386. X# endif
  3387. X# ifndef NO_SENTENCE
  3388. X    /* if this line is a format line, & we're hiding format lines, then
  3389. X     * let the dumb drawtext() function handle it
  3390. X     */
  3391. X    if (*o_hideformat && *text == '.')
  3392. X    {
  3393. X        move((int)(lno - topline), 0);
  3394. X        drawtext(text, TRUE);
  3395. X        return;
  3396. X    }
  3397. X# endif
  3398. X
  3399. X    /* skip stuff that was scrolled off left edge */
  3400. X    limitcol = leftcol;
  3401. X    for (col = 0;
  3402. X         (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  3403. X         text++)
  3404. X    {
  3405. X        if (i == '\t' && !*o_list)
  3406. X        {
  3407. X            col = col + *o_tabstop - (col % *o_tabstop);
  3408. X        }
  3409. X        else if (i >= 0 && i < ' ' || i == '\177')
  3410. X        {
  3411. X            col += 2;
  3412. X        }
  3413. X        else
  3414. X        {
  3415. X            col++;
  3416. X        }
  3417. X    }
  3418. X
  3419. X    /* adjust for control char that was partially visible */
  3420. X    build = new;
  3421. X    while (col > limitcol)
  3422. X    {
  3423. X        *build++ = ' ';
  3424. X        limitcol++;
  3425. X    }
  3426. X
  3427. X    /* now for the visible characters */
  3428. X    for (limitcol = leftcol + COLS;
  3429. X         (i = *text) && col < limitcol;
  3430. X         text++)
  3431. X    {
  3432. X        if (i == '\t' && !*o_list)
  3433. X        {
  3434. X            i = col + *o_tabstop - (col % *o_tabstop);
  3435. X            while (col < i && col < limitcol)
  3436. X            {
  3437. X                *build++ = ' ';
  3438. X                col++;
  3439. X            }
  3440. X        }
  3441. X        else if (i >= 0 && i < ' ' || i == '\177')
  3442. X        {
  3443. X            col += 2;
  3444. X            *build++ = '^';
  3445. X            if (col <= limitcol)
  3446. X            {
  3447. X                *build++ = (i ^ '@');
  3448. X            }
  3449. X        }
  3450. X        else
  3451. X        {
  3452. X            col++;
  3453. X            *build++ = i;
  3454. X        }
  3455. X    }
  3456. X    if (col < limitcol && *o_list)
  3457. X    {
  3458. X        *build++ = '$';
  3459. X        col++;
  3460. X    }
  3461. X    end = build;
  3462. X    while (col < limitcol)
  3463. X    {
  3464. X        *build++ = ' ';
  3465. X        col++;
  3466. X    }
  3467. X
  3468. X    /* locate the last non-blank character */
  3469. X    while (end > new && end[-1] == ' ')
  3470. X    {
  3471. X        end--;
  3472. X    }
  3473. X
  3474. X    /* can we optimize the displaying of this line? */
  3475. X    if (lno != smartlno)
  3476. X    {
  3477. X        /* nope, can't optimize - different line */
  3478. X        move((int)(lno - topline), 0);
  3479. X        for (scan = new, build = old; scan < end; )
  3480. X        {
  3481. X            qaddch(*scan);
  3482. X            *build++ = *scan++;
  3483. X        }
  3484. X        if (end < new + COLS)
  3485. X        {
  3486. X            clrtoeol();
  3487. X            while (build < old + COLS)
  3488. X            {
  3489. X                *build++ = ' ';
  3490. X            }
  3491. X        }
  3492. X        smartlno = lno;
  3493. X        return;
  3494. X    }
  3495. X
  3496. X    /* skip any initial unchanged characters */
  3497. X    for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
  3498. X    {
  3499. X    }
  3500. X    move((int)(lno - topline), (int)(scan - new));
  3501. X
  3502. X    /* The in-between characters must be changed */
  3503. X    same = 0;
  3504. X    while (scan < end)
  3505. X    {
  3506. X        /* is this character a match? */
  3507. X        if (scan[0] == build[0])
  3508. X        {
  3509. X            same++;
  3510. X        }
  3511. X        else /* do we want to insert? */
  3512. X        if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
  3513. X        {
  3514. X            nudgecursor(same, scan, new, lno);
  3515. X            same = 0;
  3516. X
  3517. X            insch(*scan);
  3518. X            for (shift = old + COLS; --shift > build; )
  3519. X            {
  3520. X                shift[0] = shift[-1];
  3521. X            }
  3522. X            *build = *scan;
  3523. X        }
  3524. X        else /* do we want to delete? */
  3525. X        if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
  3526. X        {
  3527. X            nudgecursor(same, scan, new, lno);
  3528. X            same = 0;
  3529. X
  3530. X            delch();
  3531. X            same++;
  3532. X            for (shift = build; shift < old + COLS - 1; shift++)
  3533. X            {
  3534. X                shift[0] = shift[1];
  3535. X            }
  3536. X            *shift = ' ';
  3537. X        }
  3538. X        else /* we must overwrite */
  3539. X        {
  3540. X            nudgecursor(same, scan, new, lno);
  3541. X            same = 0;
  3542. X
  3543. X            addch(*scan);
  3544. X            *build = *scan;
  3545. X        }
  3546. X
  3547. X        build++;
  3548. X        scan++;
  3549. X    }
  3550. X
  3551. X    /* maybe clear to EOL */
  3552. X    while (build < old + COLS && *build == ' ')
  3553. X    {
  3554. X        build++;
  3555. X    }
  3556. X    if (build < old + COLS)
  3557. X    {
  3558. X        nudgecursor(same, scan, new, lno);
  3559. X        same = 0;
  3560. X
  3561. X        clrtoeol();
  3562. X        while (build < old + COLS)
  3563. X        {
  3564. X            *build++ = ' ';
  3565. X        }
  3566. X    }
  3567. X#endif /* not CRUNCH */
  3568. X}
  3569. X
  3570. X
  3571. X/* This function is used in visual mode for drawing the screen (or just parts
  3572. X * of the screen, if that's all thats needed).  It also takes care of
  3573. X * scrolling.
  3574. X */
  3575. Xvoid redraw(curs, inputting)
  3576. X    MARK    curs;        /* where to leave the screen's cursor */
  3577. X    int    inputting;    /* boolean: being called from input() ? */
  3578. X{
  3579. X    char        *text;        /* a line of text to display */
  3580. X    static long    chgs;        /* previous changes level */
  3581. X    long        l;
  3582. X    int        i;
  3583. X
  3584. X    /* if curs == MARK_UNSET, then we should reset internal vars */
  3585. X    if (curs == MARK_UNSET)
  3586. X    {
  3587. X        if (topline < 1 || topline > nlines)
  3588. X        {
  3589. X            topline = 1L;
  3590. X        }
  3591. X        else
  3592. X        {
  3593. X            move(LINES - 1, 0);
  3594. X            clrtoeol();
  3595. X        }
  3596. X        leftcol = 0;
  3597. X        mustredraw = TRUE;
  3598. X        redrawafter = INFINITY;
  3599. X        preredraw = 0L;
  3600. X        postredraw = 0L;
  3601. X        chgs = 0;
  3602. X        smartlno = 0L;
  3603. X        return;
  3604. X    }
  3605. X
  3606. X    /* figure out which column the cursor will be in */
  3607. X    l = markline(curs);
  3608. X    text = fetchline(l);
  3609. X    mark2phys(curs, text, inputting);
  3610. X
  3611. X    /* adjust topline, if necessary, to get the cursor on the screen */
  3612. X    if (l >= topline && l <= botline)
  3613. X    {
  3614. X        /* it is on the screen already */
  3615. X
  3616. X        /* if the file was changed but !mustredraw, then redraw line */
  3617. X        if (chgs != changes && !mustredraw)
  3618. X        {
  3619. X            smartdrawtext(text, l);
  3620. X        }
  3621. X    }
  3622. X    else if (l < topline && l > topline - LINES && (has_SR || has_AL))
  3623. X    {
  3624. X        /* near top - scroll down */
  3625. X        if (!mustredraw)
  3626. X        {
  3627. X            move(0,0);
  3628. X            while (l < topline)
  3629. X            {
  3630. X                topline--;
  3631. X                if (has_SR)
  3632. X                {
  3633. X                    do_SR();
  3634. X                }
  3635. X                else
  3636. X                {
  3637. X                    insertln();
  3638. X                }
  3639. X                text = fetchline(topline);
  3640. X                drawtext(text, FALSE);
  3641. X                do_UP();
  3642. X            }
  3643. X
  3644. X            /* blank out the last line */
  3645. X            move(LINES - 1, 0);
  3646. X            clrtoeol();
  3647. X        }
  3648. X        else
  3649. X        {
  3650. X            topline = l;
  3651. X            redrawafter = INFINITY;
  3652. X            preredraw = 0L;
  3653. X            postredraw = 0L;
  3654. X        }
  3655. X    }
  3656. X    else if (l > topline && l < botline + LINES)
  3657. X    {
  3658. X        /* near bottom -- scroll up */
  3659. X        if (!mustredraw
  3660. X#if 1
  3661. X         || redrawafter == preredraw && preredraw == botline && postredraw == l
  3662. X#endif
  3663. X        )
  3664. X        {
  3665. X            move(LINES - 1,0);
  3666. X            clrtoeol();
  3667. X            while (l > botline)
  3668. X            {
  3669. X                topline++; /* <-- also adjusts botline */
  3670. X                text = fetchline(botline);
  3671. X                drawtext(text, FALSE);
  3672. X            }
  3673. X            mustredraw = FALSE;
  3674. X        }
  3675. X        else
  3676. X        {
  3677. X            topline = l - (LINES - 2);
  3678. X            redrawafter = INFINITY;
  3679. X            preredraw = 0L;
  3680. X            postredraw = 0L;
  3681. X        }
  3682. X    }
  3683. X    else
  3684. X    {
  3685. X        /* distant line - center it & force a redraw */
  3686. X        topline = l - (LINES / 2) - 1;
  3687. X        if (topline < 1)
  3688. X        {
  3689. X            topline = 1;
  3690. X        }
  3691. X        mustredraw = TRUE;
  3692. X        redrawafter = INFINITY;
  3693. X        preredraw = 0L;
  3694. X        postredraw = 0L;
  3695. X    }
  3696. X
  3697. X    /* Now... do we really have to redraw? */
  3698. X    if (mustredraw)
  3699. X    {
  3700. X        /* If redrawfter (and friends) aren't set, assume we should
  3701. X         * redraw everything.
  3702. X         */
  3703. X        if (redrawafter == INFINITY)
  3704. X        {
  3705. X            redrawafter = 0L;
  3706. X            preredraw = postredraw = INFINITY;
  3707. X        }
  3708. X
  3709. X        /* adjust smartlno to correspond with inserted/deleted lines */
  3710. X        if (smartlno >= redrawafter)
  3711. X        {
  3712. X            if (smartlno < preredraw)
  3713. X            {
  3714. X                smartlno = 0L;
  3715. X            }
  3716. X            else
  3717. X            {
  3718. X                smartlno += (postredraw - preredraw);
  3719. X            }
  3720. X        }
  3721. X
  3722. X        /* should we insert some lines into the screen? */
  3723. X        if (preredraw < postredraw && preredraw <= botline)
  3724. X        {
  3725. X            /* lines were inserted into the file */
  3726. X
  3727. X            /* decide where insertion should start */
  3728. X            if (preredraw < topline)
  3729. X            {
  3730. X                l = topline;
  3731. X            }
  3732. X            else
  3733. X            {
  3734. X                l = preredraw;
  3735. X            }
  3736. X
  3737. X            /* insert the lines... maybe */
  3738. X            if (l + postredraw - preredraw > botline || !has_AL)
  3739. X            {
  3740. X                /* Whoa!  a whole screen full - just redraw */
  3741. X                preredraw = postredraw = INFINITY;
  3742. X            }
  3743. X            else
  3744. X            {
  3745. X                /* really insert 'em */
  3746. X                move((int)(l - topline), 0);
  3747. X                for (i = postredraw - preredraw; i > 0; i--)
  3748. X                {
  3749. X                    insertln();
  3750. X                }
  3751. X
  3752. X                /* NOTE: the contents of those lines will be
  3753. X                 * drawn as part of the regular redraw loop.
  3754. X                 */
  3755. X
  3756. X                /* clear the last line */
  3757. X                move(LINES - 1, 0);
  3758. X                clrtoeol();
  3759. X            }
  3760. X        }
  3761. X
  3762. X        /* do we want to delete some lines from the screen? */
  3763. X        if (preredraw > postredraw && postredraw <= botline)
  3764. X        {
  3765. X            if (preredraw > botline || !has_DL)
  3766. X            {
  3767. X                postredraw = preredraw = INFINITY;
  3768. X            }
  3769. X            else /* we'd best delete some lines from the screen */
  3770. X            {
  3771. X                /* clear the last line, so it doesn't look
  3772. X                 * ugly as it gets pulled up into the screen
  3773. X                 */
  3774. X                move(LINES - 1, 0);
  3775. X                clrtoeol();
  3776. X
  3777. X                /* delete the lines */
  3778. X                move((int)(postredraw - topline), 0);
  3779. X                 for (l = postredraw;
  3780. X                     l < preredraw && l <= botline;
  3781. X                     l++)
  3782. X                {
  3783. X                    deleteln();
  3784. X                }
  3785. X
  3786. X                /* draw the lines that are now newly visible
  3787. X                 * at the bottom of the screen
  3788. X                 */
  3789. X                i = LINES - 1 + (postredraw - preredraw);
  3790. X                move(i, 0);
  3791. X                for (l = topline + i; l <= botline; l++)
  3792. X                {
  3793. X                    /* clear this line */
  3794. X                    clrtoeol();
  3795. X
  3796. X                    /* draw the line, or ~ for non-lines */
  3797. X                    if (l <= nlines)
  3798. X                    {
  3799. X                        text = fetchline(l);
  3800. X                        drawtext(text, FALSE);
  3801. X                    }
  3802. X                    else
  3803. X                    {
  3804. X                        addstr("~\n");
  3805. X                    }
  3806. X                }
  3807. X            }
  3808. X        }
  3809. X
  3810. X        /* redraw the current line */
  3811. X        l = markline(curs);
  3812. X        pfetch(l);
  3813. X        smartdrawtext(ptext, l);
  3814. X
  3815. X        /* decide where we should start redrawing from */
  3816. X        if (redrawafter < topline)
  3817. X        {
  3818. X            l = topline;
  3819. X        }
  3820. X        else
  3821. X        {
  3822. X            l = redrawafter;
  3823. X        }
  3824. X        move((int)(l - topline), 0);
  3825. X
  3826. X        /* draw the other lines */
  3827. X        for (; l <= botline && l < postredraw; l++)
  3828. X        {
  3829. X            /* we already drew the current line, so skip it now */
  3830. X            if (l == smartlno)
  3831. X            {
  3832. X#if OSK
  3833. X                qaddch('\l');
  3834. X#else
  3835. X                qaddch('\n');
  3836. X#endif
  3837. X                continue;
  3838. X            }
  3839. X
  3840. X            /* draw the line, or ~ for non-lines */
  3841. X            if (l <= nlines)
  3842. X            {
  3843. X                text = fetchline(l);
  3844. X                drawtext(text, TRUE);
  3845. X            }
  3846. X            else
  3847. X            {
  3848. X                qaddch('~');
  3849. X                clrtoeol();
  3850. X                addch('\n');
  3851. X            }
  3852. X        }
  3853. X
  3854. X        mustredraw = FALSE;
  3855. X    }
  3856. X
  3857. X    /* force total (non-partial) redraw next time if not set */
  3858. X    redrawafter = INFINITY;
  3859. X    preredraw = 0L;
  3860. X    postredraw = 0L;
  3861. X
  3862. X    /* move the cursor to where it belongs */
  3863. X    move((int)(markline(curs) - topline), physcol);
  3864. X    wqrefresh(stdscr);
  3865. X
  3866. X    chgs = changes;
  3867. X}
  3868. eof
  3869. if test `wc -c <redraw.c` -ne 19816
  3870. then
  3871. echo redraw.c damaged!
  3872. fi
  3873. fi
  3874.  
  3875. exit 0
  3876. -------------------------------------------------------------------------------
  3877. Steve Kirkendall     kirkenda@cs.pdx.edu      Grad student at Portland State U.
  3878.