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

  1. From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
  2. Newsgroups: alt.sources
  3. Subject: Elvis 1.3 fixes
  4. Message-ID: <12@pdxgate.UUCP>
  5. Date: 30 Aug 90 21:15:51 GMT
  6.  
  7. Here are new versions of the ELvis.lnk and Elvis.prj, to fix the problem
  8. with the "termcap" functions; and a new version of cut.c to avoid the MS-DOS
  9. bug that causes "lost clusters" when the temporary file is renamed.
  10.  
  11. Thanks for the bug reports, everybody!  I think I have enough now!
  12.                                 (Well, almost.)
  13. -------------------------------------------------------------------------------
  14. Steve Kirkendall    kirkenda@cs.pdx.edu    uunet!tektronix!psueea!eecs!kirkenda
  15.  
  16.  
  17. # --------------------------- cut here ----------------------------
  18. :
  19. # This is a shar archive.  To unpack it, save it to a file, and delete
  20. # anything above the "cut here" line.  Then run sh on the file.
  21. #
  22. # -rw-r--r--   1 steve    group        343 Aug 30 13:37 Elvis.lnk
  23. # -rw-r--r--   1 steve    group        162 Aug 30 13:37 Elvis.prj
  24. # -rw-r--r--   1 steve    group      10357 Aug 30 13:35 cut.c
  25. #
  26.  
  27. if test -f Elvis.lnk -a "$1" != -f
  28. then
  29. echo Will not overwrite Elvis.lnk
  30. else
  31. echo Extracting Elvis.lnk
  32. sed 's/^X//' >Elvis.lnk <<\eof
  33. Xblk.obj cmd1.obj cmd2.obj curses.obj cut.obj +
  34. Xex.obj input.obj main.obj misc.obj modify.obj +
  35. Xmove1.obj move2.obj move3.obj move4.obj move5.obj +
  36. Xopts.obj recycle.obj redraw.obj regexp.obj +
  37. Xregsub.obj system.obj tio.obj tmp.obj vars.obj +
  38. Xvcmd.obj vi.obj pc.obj sysdos.obj tinytcap.obj +
  39. X/co /noi /map +
  40. X/pac /far /stack:0x2000 
  41. Xelvis.exe; 
  42. eof
  43. if test `wc -c <Elvis.lnk` -ne 343
  44. then
  45. echo Elvis.lnk damaged!
  46. fi
  47. fi
  48.  
  49. if test -f Elvis.prj -a "$1" != -f
  50. then
  51. echo Will not overwrite Elvis.prj
  52. else
  53. echo Extracting Elvis.prj
  54. sed 's/^X//' >Elvis.prj <<\eof
  55. Xblk
  56. Xcmd1
  57. Xcmd2
  58. Xcurses
  59. Xcut
  60. Xex
  61. Xinput
  62. Xmain
  63. Xmisc
  64. Xmodify
  65. Xmove1
  66. Xmove2
  67. Xmove3
  68. Xmove4
  69. Xmove5
  70. Xopts
  71. Xpc
  72. Xrecycle
  73. Xredraw
  74. Xregexp
  75. Xregsub
  76. Xsysdos
  77. Xsystem
  78. Xtio
  79. Xtmp
  80. Xvars
  81. Xvcmd
  82. Xvi
  83. Xtinytcap
  84. eof
  85. if test `wc -c <Elvis.prj` -ne 162
  86. then
  87. echo Elvis.prj damaged!
  88. fi
  89. fi
  90.  
  91. if test -f cut.c -a "$1" != -f
  92. then
  93. echo Will not overwrite cut.c
  94. else
  95. echo Extracting cut.c
  96. sed 's/^X//' >cut.c <<\eof
  97. X/* cut.c */
  98. X
  99. X/* Author:
  100. X *    Steve Kirkendall
  101. X *    16820 SW Tallac Way
  102. X *    Beaverton, OR 97006
  103. X *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  104. X */
  105. X
  106. X
  107. X/* This file contains function which manipulate the cut buffers. */
  108. X
  109. X#include "config.h"
  110. X#include "vi.h"
  111. X#if    TURBOC
  112. X#include <process.h>        /* needed for getpid */
  113. X#endif
  114. X#if    TOS
  115. X#include <osbind.h>
  116. X#define    rename(a,b)    Frename(0,a,b)
  117. X#endif
  118. X
  119. X# define NANNONS    9    /* number of annonymous buffers */
  120. X
  121. Xstatic struct cutbuf
  122. X{
  123. X    short    *phys;    /* pointer to an array of #s of BLKs containing text */
  124. X    int    nblks;    /* number of blocks in phys[] array */
  125. X    int    start;    /* offset into first block of start of cut */
  126. X    int    end;    /* offset into last block of end of cut */
  127. X    int    fd;    /* fd of tmp file, or -1 to use tmpfd */
  128. X    char    lnmode;    /* boolean: line-mode cut? (as opposed to char-mode) */
  129. X}
  130. X    named[27],    /* cut buffers "a through "z and ". */
  131. X    annon[NANNONS];    /* annonymous cut buffers */
  132. X
  133. Xstatic char    cbname;    /* name chosen for next cut/paste operation */
  134. X
  135. X
  136. X#ifndef NO_RECYCLE
  137. X/* This function builds a list of all blocks needed in the current tmp file
  138. X * for the contents of cut buffers.
  139. X * !!! WARNING: if you have more than ~450000 bytes of text in all of the
  140. X * cut buffers, then this will fail disastrously, because buffer overflow
  141. X * is *not* allowed for.
  142. X */
  143. Xint cutneeds(need)
  144. X    BLK        *need;    /* this is where we deposit the list */
  145. X{
  146. X    struct cutbuf    *cb;    /* used to count through cut buffers */
  147. X    int        i;    /* used to count through blocks of a cut buffer */
  148. X    int        n;    /* total number of blocks in list */
  149. X
  150. X    n = 0;
  151. X
  152. X    /* first the named buffers... */
  153. X    for (cb = named; cb < &named[27]; cb++)
  154. X    {
  155. X        if (cb->fd > 0)
  156. X            continue;
  157. X
  158. X        for (i = cb->nblks; i-- > 0; )
  159. X        {
  160. X            need->n[n++] = cb->phys[i];
  161. X        }
  162. X    }
  163. X
  164. X    /* then the anonymous buffers */
  165. X    for (cb = annon; cb < &annon[NANNONS]; cb++)
  166. X    {
  167. X        if (cb->fd > 0)
  168. X            continue;
  169. X
  170. X        for (i = cb->nblks; i-- > 0; )
  171. X        {
  172. X            need->n[n++] = cb->phys[i];
  173. X        }
  174. X    }
  175. X
  176. X    return n;
  177. X}
  178. X#endif
  179. X
  180. X/* This function is called when we are about to abort a tmp file.  If any
  181. X * cut buffers still need the file, then a copy of the file should be
  182. X * created for use by the cut buffers.
  183. X *
  184. X * To minimize the number of extra files lying around, only named cut buffers
  185. X * are preserved in a file switch; the annonymous buffers just go away.
  186. X */
  187. Xcutswitch(tmpname)
  188. X    char    *tmpname; /* name of the tmp file */
  189. X{
  190. X    char    cutname[50];    /* used to build a new name for the tmp file */
  191. X    int    fd;        /* a new fd for the current tmp file */
  192. X    int    i, j;
  193. X
  194. X    /* discard all annonymous cut buffers */
  195. X    for (i = 0; i < NANNONS; i++)
  196. X    {
  197. X        cutfree(&annon[i]);
  198. X    }
  199. X
  200. X    /* find the first named buffer that uses this tmp file */
  201. X    for (i = 0; i < 27; i++)
  202. X    {
  203. X        if (named[i].nblks > 0 && named[i].fd < 0)
  204. X        {
  205. X            break;
  206. X        }
  207. X    }
  208. X
  209. X    /* if none of them use this tmp file, then we're done */
  210. X    if (i == 27)
  211. X    {
  212. X        return;
  213. X    }
  214. X
  215. X    /* else we'll need this file and an fd a little longer */
  216. X        /* !!! we could use some error checking here */
  217. X#if MSDOS || TOS
  218. X    strcpy(cutname, o_directory);
  219. X    if ((j = strlen(cutname)) && !strchr(":/\\", cutname[j-1]))
  220. X        cutname[j++]=SLASH;
  221. X    close(tmpfd);
  222. X    fd = open(tmpname, O_RDONLY|O_BINARY);
  223. X    close(fd);
  224. X    sprintf(cutname+j, CUTNAME+3, getpid(), fd);
  225. X    rename(tmpname, cutname);
  226. X    fd = open(cutname, O_RDONLY|O_BINARY);
  227. X    tmpfd = -1; /* we'll try to close this in tmp.c, but who cares? */
  228. X#else
  229. X    fd = dup(tmpfd);
  230. X    sprintf(cutname, CUTNAME, o_directory, getpid(), fd);
  231. X    link(tmpname, cutname) || unlink(tmpname);
  232. X#endif
  233. X
  234. X    /* have all cut buffers use the new fd instead */
  235. X    for (; i < 27; i++)
  236. X    {
  237. X        if (named[i].nblks > 0 && named[i].fd < 0)
  238. X        {
  239. X            named[i].fd = fd;
  240. X        }
  241. X    }
  242. X}
  243. X
  244. X
  245. X/* This function frees a cut buffer */
  246. Xstatic cutfree(buf)
  247. X    struct cutbuf    *buf;
  248. X{
  249. X    char    cutname[50];
  250. X    int    i;
  251. X
  252. X    /* return immediately if the buffer is already empty */
  253. X    if (buf->nblks <= 0)
  254. X    {
  255. X        return;
  256. X    }
  257. X
  258. X    /* else free up stuff */
  259. X    buf->nblks = 0;
  260. X    free(buf->phys);
  261. X
  262. X    /* see if anybody else needs this tmp file */
  263. X    if (buf->fd >= 0)
  264. X    {
  265. X        for (i = 0; i < 27; i++)
  266. X        {
  267. X#if    0
  268. X            if (named[i].nblks > 0 && named[i].fd >= 0)
  269. X#else
  270. X            if (named[i].nblks > 0 && named[i].fd == buf->fd)
  271. X#endif
  272. X            {
  273. X                break;
  274. X            }
  275. X        }
  276. X    }
  277. X
  278. X    /* if nobody else needs it, then discard the tmp file */
  279. X    if (buf->fd >= 0 && i == 27)
  280. X    {
  281. X        close(buf->fd);
  282. X#if    MSDOS || TOS
  283. X        strcpy(cutname, o_directory);
  284. X        if ((i = strlen(cutname)) && !strchr(":/\\", cutname[i-1]))
  285. X            cutname[i++]=SLASH;
  286. X        sprintf(cutname+i, CUTNAME+3, getpid(), buf->fd);
  287. X#else
  288. X        sprintf(cutname, CUTNAME, o_directory, getpid(), buf->fd);
  289. X#endif
  290. X        unlink(cutname);
  291. X    }
  292. X}
  293. X
  294. X/* This function should be called just before termination of vi */
  295. Xcutend()
  296. X{
  297. X    int    i;
  298. X
  299. X    /* free all named cut buffers, since they might be forcing an older
  300. X     * tmp file to be retained.
  301. X     */
  302. X    for (i = 0; i < 27; i++)
  303. X    {
  304. X        cutfree(&named[i]);
  305. X    }
  306. X}
  307. X
  308. X
  309. X/* This function is used to select the cut buffer to be used next */
  310. Xcutname(name)
  311. X    int    name;    /* a single character */
  312. X{
  313. X    cbname = name;
  314. X}
  315. X
  316. X
  317. X
  318. X
  319. X/* This function copies a selected segment of text to a cut buffer */
  320. Xcut(from, to)
  321. X    MARK    from;        /* start of text to cut */
  322. X    MARK    to;        /* end of text to cut */
  323. X{
  324. X    int        first;    /* logical number of first block in cut */
  325. X    int        last;    /* logical number of last block used in cut */
  326. X    long        line;    /* a line number */
  327. X    register struct cutbuf *cb;
  328. X    register long    l;
  329. X    register int    i;
  330. X    register char    *scan;
  331. X    char        *blkc;
  332. X
  333. X    /* decide which cut buffer to use */
  334. X    if (!cbname)
  335. X    {
  336. X        /* free up the last annonymous cut buffer */
  337. X        cutfree(&annon[NANNONS - 1]);
  338. X
  339. X        /* shift the annonymous cut buffers */
  340. X        for (i = NANNONS - 1; i > 0; i--)
  341. X        {
  342. X            annon[i] = annon[i - 1];
  343. X        }
  344. X
  345. X        /* use the first annonymous cut buffer */
  346. X        cb = annon;
  347. X        cb->nblks = 0;
  348. X    }
  349. X    else if (cbname >= 'a' && cbname <= 'z')
  350. X    {
  351. X        cb = &named[cbname - 'a'];
  352. X        cutfree(cb);
  353. X    }
  354. X    else if (cbname == '.')
  355. X    {
  356. X        cb = &named[26];
  357. X        cutfree(cb);
  358. X    }
  359. X    else
  360. X    {
  361. X        msg("Invalid cut buffer name: \"%c", cbname);
  362. X        cbname = '\0';
  363. X        return;
  364. X    }
  365. X    cbname = '\0';
  366. X    cb->fd = -1;
  367. X
  368. X    /* detect whether we're doing a line mode cut */
  369. X    cb->lnmode = (markidx(from) == 0 && markidx(to) == 0);
  370. X
  371. X    /* ---------- */
  372. X
  373. X    /* Reporting... */    
  374. X    if (markidx(from) == 0 && markidx(to) == 0)
  375. X    {
  376. X        rptlines = markline(to) - markline(from);
  377. X        rptlabel = "yanked";
  378. X    }
  379. X
  380. X    /* ---------- */
  381. Xblksync();
  382. X    /* find the first block in the cut */
  383. X    line = markline(from);
  384. X    for (first = 1; line > lnum[first]; first++)
  385. X    {
  386. X    }
  387. X
  388. X    /* fetch text of the block containing that line */
  389. X    blkc = scan = blkget(first)->c;
  390. X
  391. X    /* find the mark in the block */
  392. X    for (l = lnum[first - 1]; ++l < line; )
  393. X    {
  394. X        while (*scan++ != '\n')
  395. X        {
  396. X        }
  397. X    }
  398. X    scan += markidx(from);
  399. X
  400. X    /* remember the offset of the start */
  401. X    cb->start = scan - blkc;
  402. X
  403. X    /* ---------- */
  404. X
  405. X    /* find the last block in the cut */
  406. X    line = markline(to);
  407. X    for (last = first; line > lnum[last]; last++)
  408. X    {
  409. X    }
  410. X
  411. X    /* fetch text of the block containing that line */
  412. X    if (last != first)
  413. X    {
  414. X        blkc = scan = blkget(last)->c;
  415. X    }
  416. X    else
  417. X    {
  418. X        scan = blkc;
  419. X    }
  420. X
  421. X    /* find the mark in the block */
  422. X    for (l = lnum[last - 1]; ++l < line; )
  423. X    {
  424. X        while (*scan++ != '\n')
  425. X        {
  426. X        }
  427. X    }
  428. X    if (markline(to) <= nlines)
  429. X    {
  430. X        scan += markidx(to);
  431. X    }
  432. X
  433. X    /* remember the offset of the end */
  434. X    cb->end = scan - blkc;
  435. X
  436. X    /* ------- */
  437. X
  438. X    /* remember the physical block numbers of all included blocks */
  439. X    cb->nblks = last - first;
  440. X    if (cb->end > 0)
  441. X    {
  442. X        cb->nblks++;
  443. X    }
  444. X    cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
  445. X    for (i = 0; i < cb->nblks; i++)
  446. X    {
  447. X        cb->phys[i] = hdr.n[first++];
  448. X    }
  449. X}
  450. X
  451. X
  452. Xstatic readcutblk(cb, blkno)
  453. X    struct cutbuf    *cb;
  454. X    int        blkno;
  455. X{
  456. X    int        fd;    /* either tmpfd or cb->fd */
  457. X
  458. X    /* decide which fd to use */
  459. X    if (cb->fd >= 0)
  460. X    {
  461. X        fd = cb->fd;
  462. X    }
  463. X    else
  464. X    {
  465. X        fd = tmpfd;
  466. X    }
  467. X
  468. X    /* get the block */
  469. X    lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
  470. X    if (read(fd, tmpblk.c, BLKSIZE) != BLKSIZE)
  471. X    {
  472. X        msg("Error reading back from tmp file for pasting!");
  473. X    }
  474. X}
  475. X
  476. X
  477. X/* This function inserts text from a cut buffer, and returns the MARK where
  478. X * insertion ended.  Return MARK_UNSET on errors.
  479. X */
  480. XMARK paste(at, after, retend)
  481. X    MARK    at;    /* where to insert the text */
  482. X    int    after;    /* boolean: insert after mark? (rather than before) */
  483. X    int    retend;    /* boolean: return end marker (rather than start) */
  484. X{
  485. X    register struct cutbuf    *cb;
  486. X    register int        i;
  487. X
  488. X    /* decide which cut buffer to use */
  489. X    if (cbname >= 'a' && cbname <= 'z')
  490. X    {
  491. X        cb = &named[cbname - 'a'];
  492. X    }
  493. X    else if (cbname >= '1' && cbname <= '9')
  494. X    {
  495. X        cb = &annon[cbname - '1'];
  496. X    }
  497. X    else if (cbname == '.')
  498. X    {
  499. X        cb = &named[26];
  500. X    }
  501. X    else if (!cbname)
  502. X    {
  503. X        cb = annon;
  504. X    }
  505. X    else
  506. X    {
  507. X        msg("Invalid cut buffer name: \"%c", cbname);
  508. X        return MARK_UNSET;
  509. X    }
  510. X
  511. X    /* make sure it isn't empty */
  512. X    if (cb->nblks == 0)
  513. X    {
  514. X        if (cbname)
  515. X            msg("Cut buffer \"%c is empty", cbname);
  516. X        else
  517. X            msg("Cut buffer is empty");
  518. X        cbname = '\0';
  519. X        return MARK_UNSET;
  520. X    }
  521. X    cbname = '\0';
  522. X
  523. X    /* adjust the insertion MARK for "after" and line-mode cuts */
  524. X    if (cb->lnmode)
  525. X    {
  526. X        at &= ~(BLKSIZE - 1);
  527. X        if (after)
  528. X        {
  529. X            at += BLKSIZE;
  530. X        }
  531. X    }
  532. X    else if (after)
  533. X    {
  534. X        /* careful! if markidx(at) == 0 we might be pasting into an
  535. X         * empty line -- so we can't blindly increment "at".
  536. X         */
  537. X        if (markidx(at) == 0)
  538. X        {
  539. X            pfetch(markline(at));
  540. X            if (plen != 0)
  541. X            {
  542. X                at++;
  543. X            }
  544. X        }
  545. X        else
  546. X        {
  547. X            at++;
  548. X        }
  549. X    }
  550. X
  551. X    /* put a copy of the "at" mark in the mark[] array, so it stays in
  552. X     * sync with changes made via add().
  553. X     */
  554. X    mark[27] = at;
  555. X
  556. X    /* simple one-block paste? */
  557. X    if (cb->nblks == 1)
  558. X    {
  559. X        /* get the block */
  560. X        readcutblk(cb, 0);
  561. X
  562. X        /* isolate the text we need within it */
  563. X        if (cb->end)
  564. X        {
  565. X            tmpblk.c[cb->end] = '\0';
  566. X        }
  567. X
  568. X        /* insert it */
  569. X        ChangeText
  570. X        {
  571. X            add(at, &tmpblk.c[cb->start]);
  572. X        }
  573. X    }
  574. X    else
  575. X    {
  576. X        /* multi-block paste */
  577. X
  578. X        ChangeText
  579. X        {
  580. X            i = cb->nblks - 1;
  581. X
  582. X            /* add text from the last block first */
  583. X            if (cb->end > 0)
  584. X            {
  585. X                readcutblk(cb, i);
  586. X                tmpblk.c[cb->end] = '\0';
  587. X                add(at, tmpblk.c);
  588. X                i--;
  589. X            }
  590. X
  591. X            /* add intervening blocks */
  592. X            while (i > 0)
  593. X            {
  594. X                readcutblk(cb, i);
  595. X                add(at, tmpblk.c);
  596. X                i--;
  597. X            }
  598. X
  599. X            /* add text from the first cut block */
  600. X            readcutblk(cb, 0);
  601. X            add(at, &tmpblk.c[cb->start]);
  602. X        }
  603. X    }
  604. X
  605. X    /* Reporting... */
  606. X    rptlines = markline(mark[27]) - markline(at);
  607. X    rptlabel = "pasted";
  608. X
  609. X    /* correct the redraw range */
  610. X    redrawafter = preredraw = markline(at);
  611. X    postredraw = markline(mark[27]);
  612. X
  613. X    /* return the mark at the beginning of inserted text */
  614. X    if (retend)
  615. X    {
  616. X        return mark[27] - 1L;
  617. X    }
  618. X    return at;
  619. X}
  620. eof
  621. if test `wc -c <cut.c` -ne 10357
  622. then
  623. echo cut.c damaged!
  624. fi
  625. fi
  626.  
  627. exit 0
  628. -------------------------------------------------------------------------------
  629. Steve Kirkendall    kirkenda@cs.pdx.edu    uunet!tektronix!psueea!eecs!kirkenda
  630.