home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume4 / uemacs3.6 / part5 < prev    next >
Text File  |  1986-11-30  |  49KB  |  1,813 lines

  1. Subject: MicroEMACS 3.6 (Part 5 of 8)
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 4, Issue 102
  6. Submitted by: ihnp4!itivax!duncan!lawrence
  7.  
  8. echo x - display.c
  9. sed 's/^X//' >display.c <<'*-*-END-of-display.c-*-*'
  10. X/*
  11. X * The functions in this file handle redisplay. There are two halves, the
  12. X * ones that update the virtual display screen, and the ones that make the
  13. X * physical display screen the same as the virtual display screen. These
  14. X * functions use hints that are left in the windows by the commands.
  15. X *
  16. X */
  17. X
  18. X#include        <stdio.h>
  19. X#include    "estruct.h"
  20. X#include        "edef.h"
  21. X
  22. X#define WFDEBUG 0                       /* Window flag debug. */
  23. X
  24. Xtypedef struct  VIDEO {
  25. X        short   v_flag;                 /* Flags */
  26. X        char    v_text[1];              /* Screen data. */
  27. X}       VIDEO;
  28. X
  29. X#define VFCHG   0x0001                  /* Changed flag            */
  30. X#define    VFEXT    0x0002            /* extended (beyond column 80)    */
  31. X#define    VFREV    0x0004            /* reverse video status        */
  32. X#define    VFREQ    0x0008            /* reverse video request    */
  33. X
  34. Xint     vtrow   = 0;                    /* Row location of SW cursor */
  35. Xint     vtcol   = 0;                    /* Column location of SW cursor */
  36. Xint     ttrow   = HUGE;                 /* Row location of HW cursor */
  37. Xint     ttcol   = HUGE;                 /* Column location of HW cursor */
  38. Xint    lbound    = 0;            /* leftmost column of current line
  39. X                       being displayed */
  40. X
  41. XVIDEO   **vscreen;                      /* Virtual screen. */
  42. XVIDEO   **pscreen;                      /* Physical screen. */
  43. X
  44. X/*
  45. X * Initialize the data structures used by the display code. The edge vectors
  46. X * used to access the screens are set up. The operating system's terminal I/O
  47. X * channel is set up. All the other things get initialized at compile time.
  48. X * The original window has "WFCHG" set, so that it will get completely
  49. X * redrawn on the first call to "update".
  50. X */
  51. Xvtinit()
  52. X{
  53. X    register int i;
  54. X    register VIDEO *vp;
  55. X    char *malloc();
  56. X
  57. X    (*term.t_open)();
  58. X    (*term.t_rev)(FALSE);
  59. X    vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  60. X
  61. X    if (vscreen == NULL)
  62. X        exit(1);
  63. X
  64. X    pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  65. X
  66. X    if (pscreen == NULL)
  67. X        exit(1);
  68. X
  69. X    for (i = 0; i < term.t_nrow; ++i)
  70. X        {
  71. X        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  72. X
  73. X        if (vp == NULL)
  74. X            exit(1);
  75. X
  76. X    vp->v_flag = 0;
  77. X        vscreen[i] = vp;
  78. X        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  79. X
  80. X        if (vp == NULL)
  81. X            exit(1);
  82. X
  83. X    vp->v_flag = 0;
  84. X        pscreen[i] = vp;
  85. X        }
  86. X}
  87. X
  88. X/*
  89. X * Clean up the virtual terminal system, in anticipation for a return to the
  90. X * operating system. Move down to the last line and clear it out (the next
  91. X * system prompt will be written in the line). Shut down the channel to the
  92. X * terminal.
  93. X */
  94. Xvttidy()
  95. X{
  96. X    mlerase();
  97. X    movecursor(term.t_nrow, 0);
  98. X    (*term.t_close)();
  99. X}
  100. X
  101. X/*
  102. X * Set the virtual cursor to the specified row and column on the virtual
  103. X * screen. There is no checking for nonsense values; this might be a good
  104. X * idea during the early stages.
  105. X */
  106. Xvtmove(row, col)
  107. X{
  108. X    vtrow = row;
  109. X    vtcol = col;
  110. X}
  111. X
  112. X/*
  113. X * Write a character to the virtual screen. The virtual row and column are
  114. X * updated. If the line is too long put a "$" in the last column. This routine
  115. X * only puts printing characters into the virtual terminal buffers. Only
  116. X * column overflow is checked.
  117. X */
  118. Xvtputc(c)
  119. X    int c;
  120. X{
  121. X    register VIDEO      *vp;
  122. X
  123. X    vp = vscreen[vtrow];
  124. X
  125. X    if (vtcol >= term.t_ncol) {
  126. X        vtcol = (vtcol + 0x07) & ~0x07;
  127. X        vp->v_text[term.t_ncol - 1] = '$';
  128. X    } else if (c == '\t')
  129. X        {
  130. X        do
  131. X            {
  132. X            vtputc(' ');
  133. X            }
  134. X        while ((vtcol&0x07) != 0);
  135. X        }
  136. X    else if (c < 0x20 || c == 0x7F)
  137. X        {
  138. X        vtputc('^');
  139. X        vtputc(c ^ 0x40);
  140. X        }
  141. X    else
  142. X    vp->v_text[vtcol++] = c;
  143. X}
  144. X
  145. X/*    put a character to the virtual screen in an extended line. If we are
  146. X    not yet on left edge, don't print it yet. check for overflow on
  147. X    the right margin                        */
  148. X
  149. Xvtpute(c)
  150. X
  151. Xint c;
  152. X
  153. X{
  154. X    register VIDEO      *vp;
  155. X
  156. X    vp = vscreen[vtrow];
  157. X
  158. X    if (vtcol >= term.t_ncol) {
  159. X        vtcol = (vtcol + 0x07) & ~0x07;
  160. X        vp->v_text[term.t_ncol - 1] = '$';
  161. X    } else if (c == '\t')
  162. X        {
  163. X        do
  164. X            {
  165. X            vtpute(' ');
  166. X            }
  167. X        while (((vtcol + lbound)&0x07) != 0);
  168. X        }
  169. X    else if (c < 0x20 || c == 0x7F)
  170. X        {
  171. X        vtpute('^');
  172. X        vtpute(c ^ 0x40);
  173. X        }
  174. X    else {
  175. X    if (vtcol >= 0)
  176. X        vp->v_text[vtcol] = c;
  177. X    ++vtcol;
  178. X    }
  179. X}
  180. X
  181. X/*
  182. X * Erase from the end of the software cursor to the end of the line on which
  183. X * the software cursor is located.
  184. X */
  185. Xvteeol()
  186. X{
  187. X    register VIDEO      *vp;
  188. X
  189. X    vp = vscreen[vtrow];
  190. X    while (vtcol < term.t_ncol)
  191. X        vp->v_text[vtcol++] = ' ';
  192. X}
  193. X
  194. X/*
  195. X * Make sure that the display is right. This is a three part process. First,
  196. X * scan through all of the windows looking for dirty ones. Check the framing,
  197. X * and refresh the screen. Second, make sure that "currow" and "curcol" are
  198. X * correct for the current window. Third, make the virtual and physical
  199. X * screens the same.
  200. X */
  201. Xupdate()
  202. X{
  203. X    register LINE *lp;
  204. X    register WINDOW *wp;
  205. X    register VIDEO *vp1;
  206. X    register VIDEO *vp2;
  207. X    register int i;
  208. X    register int j;
  209. X    register int c;
  210. X
  211. X#if    TYPEAH
  212. X    if (typahead())
  213. X    return(TRUE);
  214. X#endif
  215. X
  216. X    /* update the reverse video flags for any mode lines out there */
  217. X    for (i = 0; i < term.t_nrow; ++i)
  218. X        vscreen[i]->v_flag &= ~VFREQ;
  219. X
  220. X#if    REVSTA
  221. X    wp = wheadp;
  222. X    while (wp != NULL) {
  223. X        vscreen[wp->w_toprow+wp->w_ntrows]->v_flag |= VFREQ;
  224. X        wp = wp->w_wndp;
  225. X    }
  226. X#endif
  227. X
  228. X    wp = wheadp;
  229. X
  230. X    while (wp != NULL)
  231. X        {
  232. X        /* Look at any window with update flags set on. */
  233. X
  234. X        if (wp->w_flag != 0)
  235. X            {
  236. X            /* If not force reframe, check the framing. */
  237. X
  238. X            if ((wp->w_flag & WFFORCE) == 0)
  239. X                {
  240. X                lp = wp->w_linep;
  241. X
  242. X                for (i = 0; i < wp->w_ntrows; ++i)
  243. X                    {
  244. X                    if (lp == wp->w_dotp)
  245. X                        goto out;
  246. X
  247. X                    if (lp == wp->w_bufp->b_linep)
  248. X                        break;
  249. X
  250. X                    lp = lforw(lp);
  251. X                    }
  252. X                }
  253. X
  254. X            /* Not acceptable, better compute a new value for the line at the
  255. X             * top of the window. Then set the "WFHARD" flag to force full
  256. X             * redraw.
  257. X             */
  258. X            i = wp->w_force;
  259. X
  260. X            if (i > 0)
  261. X                {
  262. X                --i;
  263. X
  264. X                if (i >= wp->w_ntrows)
  265. X                  i = wp->w_ntrows-1;
  266. X                }
  267. X            else if (i < 0)
  268. X                {
  269. X                i += wp->w_ntrows;
  270. X
  271. X                if (i < 0)
  272. X                    i = 0;
  273. X                }
  274. X            else
  275. X                i = wp->w_ntrows/2;
  276. X
  277. X            lp = wp->w_dotp;
  278. X
  279. X            while (i != 0 && lback(lp) != wp->w_bufp->b_linep)
  280. X                {
  281. X                --i;
  282. X                lp = lback(lp);
  283. X                }
  284. X
  285. X            wp->w_linep = lp;
  286. X            wp->w_flag |= WFHARD;       /* Force full. */
  287. X
  288. Xout:
  289. X            /* Try to use reduced update. Mode line update has its own special
  290. X             * flag. The fast update is used if the only thing to do is within
  291. X             * the line editing.
  292. X             */
  293. X            lp = wp->w_linep;
  294. X            i = wp->w_toprow;
  295. X
  296. X            if ((wp->w_flag & ~WFMODE) == WFEDIT)
  297. X                {
  298. X                while (lp != wp->w_dotp)
  299. X                    {
  300. X                    ++i;
  301. X                    lp = lforw(lp);
  302. X                    }
  303. X
  304. X                vscreen[i]->v_flag |= VFCHG;
  305. X                vtmove(i, 0);
  306. X
  307. X                for (j = 0; j < llength(lp); ++j)
  308. X                    vtputc(lgetc(lp, j));
  309. X
  310. X                vteeol();
  311. X                }
  312. X             else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0)
  313. X                {
  314. X                while (i < wp->w_toprow+wp->w_ntrows)
  315. X                    {
  316. X                    vscreen[i]->v_flag |= VFCHG;
  317. X                    vtmove(i, 0);
  318. X
  319. X            /* if line has been changed */
  320. X                    if (lp != wp->w_bufp->b_linep)
  321. X                        {
  322. X                        for (j = 0; j < llength(lp); ++j)
  323. X                            vtputc(lgetc(lp, j));
  324. X
  325. X                        lp = lforw(lp);
  326. X                        }
  327. X
  328. X                    vteeol();
  329. X                    ++i;
  330. X                    }
  331. X                }
  332. X#if ~WFDEBUG
  333. X            if ((wp->w_flag&WFMODE) != 0)
  334. X                modeline(wp);
  335. X
  336. X            wp->w_flag  = 0;
  337. X            wp->w_force = 0;
  338. X#endif
  339. X            }
  340. X#if WFDEBUG
  341. X        modeline(wp);
  342. X        wp->w_flag =  0;
  343. X        wp->w_force = 0;
  344. X#endif
  345. X
  346. X    /* and onward to the next window */
  347. X        wp = wp->w_wndp;
  348. X        }
  349. X
  350. X    /* Always recompute the row and column number of the hardware cursor. This
  351. X     * is the only update for simple moves.
  352. X     */
  353. X    lp = curwp->w_linep;
  354. X    currow = curwp->w_toprow;
  355. X
  356. X    while (lp != curwp->w_dotp)
  357. X        {
  358. X        ++currow;
  359. X        lp = lforw(lp);
  360. X        }
  361. X
  362. X    curcol = 0;
  363. X    i = 0;
  364. X
  365. X    while (i < curwp->w_doto)
  366. X        {
  367. X        c = lgetc(lp, i++);
  368. X
  369. X        if (c == '\t')
  370. X            curcol |= 0x07;
  371. X        else if (c < 0x20 || c == 0x7F)
  372. X            ++curcol;
  373. X
  374. X        ++curcol;
  375. X        }
  376. X
  377. X    if (curcol >= term.t_ncol - 1) {          /* extended line. */
  378. X    /* flag we are extended and changed */
  379. X    vscreen[currow]->v_flag |= VFEXT | VFCHG;
  380. X    updext();                /* and output extended line */
  381. X    } else
  382. X    lbound = 0;                /* not extended line */
  383. X
  384. X/* make sure no lines need to be de-extended because the cursor is
  385. X   no longer on them */
  386. X
  387. X    wp = wheadp;
  388. X
  389. X    while (wp != NULL) {
  390. X    lp = wp->w_linep;
  391. X    i = wp->w_toprow;
  392. X
  393. X    while (i < wp->w_toprow + wp->w_ntrows) {
  394. X        if (vscreen[i]->v_flag & VFEXT) {
  395. X            /* always flag extended lines as changed */
  396. X            vscreen[i]->v_flag |= VFCHG;
  397. X            if ((wp != curwp) || (lp != wp->w_dotp) ||
  398. X               (curcol < term.t_ncol - 1)) {
  399. X                vtmove(i, 0);
  400. X                            for (j = 0; j < llength(lp); ++j)
  401. X                                vtputc(lgetc(lp, j));
  402. X                vteeol();
  403. X
  404. X                /* this line no longer is extended */
  405. X                vscreen[i]->v_flag &= ~VFEXT;
  406. X            }
  407. X        }
  408. X        lp = lforw(lp);
  409. X        ++i;
  410. X    }
  411. X    /* and onward to the next window */
  412. X        wp = wp->w_wndp;
  413. X    }
  414. X
  415. X    /* Special hacking if the screen is garbage. Clear the hardware screen,
  416. X     * and update your copy to agree with it. Set all the virtual screen
  417. X     * change bits, to force a full update.
  418. X     */
  419. X    if (sgarbf != FALSE)
  420. X        {
  421. X        for (i = 0; i < term.t_nrow; ++i)
  422. X            {
  423. X            vscreen[i]->v_flag |= VFCHG;
  424. X            vp1 = pscreen[i];
  425. X            for (j = 0; j < term.t_ncol; ++j)
  426. X                vp1->v_text[j] = ' ';
  427. X            }
  428. X
  429. X        movecursor(0, 0);               /* Erase the screen. */
  430. X        (*term.t_eeop)();
  431. X        sgarbf = FALSE;                 /* Erase-page clears */
  432. X        mpresf = FALSE;                 /* the message area. */
  433. X        }
  434. X
  435. X    /* Make sure that the physical and virtual displays agree. Unlike before,
  436. X     * the "updateline" code is only called with a line that has been updated
  437. X     * for sure.
  438. X     */
  439. X    for (i = 0; i < term.t_nrow; ++i)
  440. X        {
  441. X        vp1 = vscreen[i];
  442. X
  443. X    /* for each line that needs to be updated, or that needs its
  444. X       reverse video status changed, call the line updater    */
  445. X    j = vp1->v_flag;
  446. X        if (((j & VFCHG) != 0) || (((j & VFREV) == 0) != ((j & VFREQ) == 0)))
  447. X            {
  448. X#if    TYPEAH
  449. X        if (typahead())
  450. X        return(TRUE);
  451. X#endif
  452. X            vp2 = pscreen[i];
  453. X            updateline(i, &vp1->v_text[0], &vp2->v_text[0], &vp1->v_flag);
  454. X            }
  455. X        }
  456. X
  457. X    /* Finally, update the hardware cursor and flush out buffers. */
  458. X
  459. X    movecursor(currow, curcol - lbound);
  460. X    (*term.t_flush)();
  461. X}
  462. X
  463. X/*    updext: update the extended line which the cursor is currently
  464. X        on at a column greater than the terminal width. The line
  465. X        will be scrolled right or left to let the user see where
  466. X        the cursor is
  467. X                                */
  468. X
  469. Xupdext()
  470. X
  471. X{
  472. X    register int rcursor;    /* real cursor location */
  473. X    register LINE *lp;    /* pointer to current line */
  474. X    register int j;        /* index into line */
  475. X
  476. X    /* calculate what column the real cursor will end up in */
  477. X    rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
  478. X    lbound = curcol - rcursor + 1;
  479. X
  480. X    /* scan through the line outputing characters to the virtual screen */
  481. X    /* once we reach the left edge                    */
  482. X    vtmove(currow, -lbound);    /* start scanning offscreen */
  483. X    lp = curwp->w_dotp;        /* line to output */
  484. X    for (j=0; j<llength(lp); ++j)    /* until the end-of-line */
  485. X        vtpute(lgetc(lp, j));
  486. X
  487. X    /* truncate the virtual line */
  488. X    vteeol();
  489. X
  490. X    /* and put a '$' in column 1 */
  491. X    vscreen[currow]->v_text[0] = '$';
  492. X}
  493. X
  494. X/*
  495. X * Update a single line. This does not know how to use insert or delete
  496. X * character sequences; we are using VT52 functionality. Update the physical
  497. X * row and column variables. It does try an exploit erase to end of line. The
  498. X * RAINBOW version of this routine uses fast video.
  499. X */
  500. Xupdateline(row, vline, pline, flags)
  501. X    char vline[];    /* what we want it to end up as */
  502. X    char pline[];    /* what it looks like now       */
  503. X    short *flags;    /* and how we want it that way  */
  504. X{
  505. X#if RAINBOW
  506. X    register char *cp1;
  507. X    register char *cp2;
  508. X    register int nch;
  509. X
  510. X    /* since we don't know how to make the rainbow do this, turn it off */
  511. X    flags &= (~VFREV & ~VFREQ);
  512. X
  513. X    cp1 = &vline[0];                    /* Use fast video. */
  514. X    cp2 = &pline[0];
  515. X    putline(row+1, 1, cp1);
  516. X    nch = term.t_ncol;
  517. X
  518. X    do
  519. X        {
  520. X        *cp2 = *cp1;
  521. X        ++cp2;
  522. X        ++cp1;
  523. X        }
  524. X    while (--nch);
  525. X    *flags &= ~VFCHG;
  526. X#else
  527. X    register char *cp1;
  528. X    register char *cp2;
  529. X    register char *cp3;
  530. X    register char *cp4;
  531. X    register char *cp5;
  532. X    register int nbflag;    /* non-blanks to the right flag? */
  533. X    int rev;        /* reverse video flag */
  534. X    int req;        /* reverse video request flag */
  535. X
  536. X
  537. X    /* set up pointers to virtual and physical lines */
  538. X    cp1 = &vline[0];
  539. X    cp2 = &pline[0];
  540. X
  541. X#if    REVSTA
  542. X    /* if we need to change the reverse video status of the
  543. X       current line, we need to re-write the entire line     */
  544. X    rev = *flags & VFREV;
  545. X    req = *flags & VFREQ;
  546. X    if (rev != req) {
  547. X        movecursor(row, 0);    /* Go to start of line. */
  548. X        (*term.t_rev)(req != FALSE);    /* set rev video if needed */
  549. X
  550. X        /* scan through the line and dump it to the screen and
  551. X           the virtual screen array                */
  552. X        cp3 = &vline[term.t_ncol];
  553. X        while (cp1 < cp3) {
  554. X            (*term.t_putchar)(*cp1);
  555. X            ++ttcol;
  556. X            *cp2++ = *cp1++;
  557. X        }
  558. X        (*term.t_rev)(FALSE);        /* turn rev video off */
  559. X
  560. X        /* update the needed flags */
  561. X        *flags &= ~VFCHG;
  562. X        if (req)
  563. X            *flags |= VFREV;
  564. X        else
  565. X            *flags &= ~VFREV;
  566. X        return(TRUE);
  567. X    }
  568. X#endif
  569. X
  570. X    /* advance past any common chars at the left */
  571. X    while (cp1 != &vline[term.t_ncol] && cp1[0] == cp2[0]) {
  572. X        ++cp1;
  573. X        ++cp2;
  574. X    }
  575. X
  576. X/* This can still happen, even though we only call this routine on changed
  577. X * lines. A hard update is always done when a line splits, a massive
  578. X * change is done, or a buffer is displayed twice. This optimizes out most
  579. X * of the excess updating. A lot of computes are used, but these tend to
  580. X * be hard operations that do a lot of update, so I don't really care.
  581. X */
  582. X    /* if both lines are the same, no update needs to be done */
  583. X    if (cp1 == &vline[term.t_ncol])
  584. X        return(TRUE);
  585. X
  586. X    /* find out if there is a match on the right */
  587. X    nbflag = FALSE;
  588. X    cp3 = &vline[term.t_ncol];
  589. X    cp4 = &pline[term.t_ncol];
  590. X
  591. X    while (cp3[-1] == cp4[-1]) {
  592. X        --cp3;
  593. X        --cp4;
  594. X        if (cp3[0] != ' ')        /* Note if any nonblank */
  595. X            nbflag = TRUE;        /* in right match. */
  596. X    }
  597. X
  598. X    cp5 = cp3;
  599. X
  600. X    if (nbflag == FALSE && eolexist == TRUE) {    /* Erase to EOL ? */
  601. X        while (cp5!=cp1 && cp5[-1]==' ')
  602. X            --cp5;
  603. X
  604. X        if (cp3-cp5 <= 3)        /* Use only if erase is */
  605. X            cp5 = cp3;        /* fewer characters. */
  606. X    }
  607. X
  608. X    movecursor(row, cp1-&vline[0]);    /* Go to start of line. */
  609. X
  610. X    while (cp1 != cp5) {        /* Ordinary. */
  611. X        (*term.t_putchar)(*cp1);
  612. X        ++ttcol;
  613. X        *cp2++ = *cp1++;
  614. X    }
  615. X
  616. X    if (cp5 != cp3) {        /* Erase. */
  617. X        (*term.t_eeol)();
  618. X        while (cp1 != cp3)
  619. X            *cp2++ = *cp1++;
  620. X    }
  621. X    *flags &= ~VFCHG;        /* flag this line is changed */
  622. X#endif
  623. X}
  624. X
  625. X/*
  626. X * Redisplay the mode line for the window pointed to by the "wp". This is the
  627. X * only routine that has any idea of how the modeline is formatted. You can
  628. X * change the modeline format by hacking at this routine. Called by "update"
  629. X * any time there is a dirty window.
  630. X */
  631. Xmodeline(wp)
  632. X    WINDOW *wp;
  633. X{
  634. X    register char *cp;
  635. X    register int c;
  636. X    register int n;        /* cursor position count */
  637. X    register BUFFER *bp;
  638. X    register i;            /* loop index */
  639. X    register lchar;        /* character to draw line in buffer with */
  640. X    register firstm;        /* is this the first mode? */
  641. X    char tline[NLINE];        /* buffer for part of mode line */
  642. X
  643. X    n = wp->w_toprow+wp->w_ntrows;      /* Location. */
  644. X    vscreen[n]->v_flag |= VFCHG;        /* Redraw next time. */
  645. X    vtmove(n, 0);                       /* Seek to right line. */
  646. X    if (wp == curwp)            /* mark the current buffer */
  647. X    lchar = '=';
  648. X    else
  649. X#if    REVSTA
  650. X    if (revexist)
  651. X        lchar = ' ';
  652. X    else
  653. X#endif
  654. X        lchar = '-';
  655. X
  656. X    vtputc(lchar);
  657. X    bp = wp->w_bufp;
  658. X
  659. X    if ((bp->b_flag&BFCHG) != 0)                /* "*" if changed. */
  660. X        vtputc('*');
  661. X    else
  662. X        vtputc(lchar);
  663. X
  664. X    n  = 2;
  665. X    strcpy(tline, " MicroEMACS 3.6 (");        /* Buffer name. */
  666. X
  667. X    /* display the modes */
  668. X
  669. X    firstm = TRUE;
  670. X    for (i = 0; i < NUMMODES; i++)    /* add in the mode flags */
  671. X        if (wp->w_bufp->b_mode & (1 << i)) {
  672. X            if (firstm != TRUE)
  673. X                strcat(tline, " ");
  674. X            firstm = FALSE;
  675. X            strcat(tline, modename[i]);
  676. X        }
  677. X    strcat(tline,") ");
  678. X
  679. X    cp = &tline[0];
  680. X    while ((c = *cp++) != 0)
  681. X        {
  682. X        vtputc(c);
  683. X        ++n;
  684. X        }
  685. X
  686. X    vtputc(lchar);
  687. X    vtputc(lchar);
  688. X    vtputc(' ');
  689. X    n += 3;
  690. X    cp = &bp->b_bname[0];
  691. X
  692. X    while ((c = *cp++) != 0)
  693. X        {
  694. X        vtputc(c);
  695. X        ++n;
  696. X        }
  697. X
  698. X    vtputc(' ');
  699. X    vtputc(lchar);
  700. X    vtputc(lchar);
  701. X    n += 3;
  702. X
  703. X    if (bp->b_fname[0] != 0)            /* File name. */
  704. X        {
  705. X    vtputc(' ');
  706. X    ++n;
  707. X        cp = "File: ";
  708. X
  709. X        while ((c = *cp++) != 0)
  710. X            {
  711. X            vtputc(c);
  712. X            ++n;
  713. X            }
  714. X
  715. X        cp = &bp->b_fname[0];
  716. X
  717. X        while ((c = *cp++) != 0)
  718. X            {
  719. X            vtputc(c);
  720. X            ++n;
  721. X            }
  722. X
  723. X        vtputc(' ');
  724. X        ++n;
  725. X        }
  726. X
  727. X#if WFDEBUG
  728. X    vtputc(lchar);
  729. X    vtputc((wp->w_flag&WFMODE)!=0  ? 'M' : lchar);
  730. X    vtputc((wp->w_flag&WFHARD)!=0  ? 'H' : lchar);
  731. X    vtputc((wp->w_flag&WFEDIT)!=0  ? 'E' : lchar);
  732. X    vtputc((wp->w_flag&WFMOVE)!=0  ? 'V' : lchar);
  733. X    vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar);
  734. X    n += 6;
  735. X#endif
  736. X
  737. X    while (n < term.t_ncol)             /* Pad to full width. */
  738. X        {
  739. X        vtputc(lchar);
  740. X        ++n;
  741. X        }
  742. X}
  743. X
  744. Xupmode()    /* update all the mode lines */
  745. X
  746. X{
  747. X    register WINDOW *wp;
  748. X
  749. X    wp = wheadp;
  750. X    while (wp != NULL) {
  751. X        wp->w_flag |= WFMODE;
  752. X        wp = wp->w_wndp;
  753. X    }
  754. X}
  755. X
  756. X/*
  757. X * Send a command to the terminal to move the hardware cursor to row "row"
  758. X * and column "col". The row and column arguments are origin 0. Optimize out
  759. X * random calls. Update "ttrow" and "ttcol".
  760. X */
  761. Xmovecursor(row, col)
  762. X    {
  763. X    if (row!=ttrow || col!=ttcol)
  764. X        {
  765. X        ttrow = row;
  766. X        ttcol = col;
  767. X        (*term.t_move)(row, col);
  768. X        }
  769. X    }
  770. X
  771. X/*
  772. X * Erase the message line. This is a special routine because the message line
  773. X * is not considered to be part of the virtual screen. It always works
  774. X * immediately; the terminal buffer is flushed via a call to the flusher.
  775. X */
  776. Xmlerase()
  777. X    {
  778. X    int i;
  779. X    
  780. X    movecursor(term.t_nrow, 0);
  781. X    if (eolexist == TRUE)
  782. X        (*term.t_eeol)();
  783. X    else {
  784. X        for (i = 0; i < term.t_ncol - 1; i++)
  785. X            (*term.t_putchar)(' ');
  786. X        movecursor(term.t_nrow, 1);    /* force the move! */
  787. X        movecursor(term.t_nrow, 0);
  788. X    }
  789. X    (*term.t_flush)();
  790. X    mpresf = FALSE;
  791. X    }
  792. X
  793. X/*
  794. X * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  795. X * ABORT. The ABORT status is returned if the user bumps out of the question
  796. X * with a ^G. Used any time a confirmation is required.
  797. X */
  798. X
  799. Xmlyesno(prompt)
  800. X
  801. Xchar *prompt;
  802. X
  803. X{
  804. X    char c;            /* input character */
  805. X    char buf[NPAT];        /* prompt to user */
  806. X
  807. X    for (;;) {
  808. X        /* build and prompt the user */
  809. X        strcpy(buf, prompt);
  810. X        strcat(buf, " [y/n]? ");
  811. X        mlwrite(buf);
  812. X
  813. X        /* get the responce */
  814. X        c = (*term.t_getchar)();
  815. X
  816. X        if (c == BELL)        /* Bail out! */
  817. X            return(ABORT);
  818. X
  819. X        if (c=='y' || c=='Y')
  820. X            return(TRUE);
  821. X
  822. X        if (c=='n' || c=='N')
  823. X            return(FALSE);
  824. X    }
  825. X}
  826. X
  827. X/*
  828. X * Write a prompt into the message line, then read back a response. Keep
  829. X * track of the physical position of the cursor. If we are in a keyboard
  830. X * macro throw the prompt away, and return the remembered response. This
  831. X * lets macros run at full speed. The reply is always terminated by a carriage
  832. X * return. Handle erase, kill, and abort keys.
  833. X */
  834. X
  835. Xmlreply(prompt, buf, nbuf)
  836. X    char *prompt;
  837. X    char *buf;
  838. X{
  839. X    return(mlreplyt(prompt,buf,nbuf,'\n'));
  840. X}
  841. X
  842. X/*    A more generalized prompt/reply function allowing the caller
  843. X    to specify the proper terminator. If the terminator is not
  844. X    a return ('\n') it will echo as "<NL>"
  845. X                            */
  846. Xmlreplyt(prompt, buf, nbuf, eolchar)
  847. X
  848. Xchar *prompt;
  849. Xchar *buf;
  850. Xchar eolchar;
  851. X
  852. X{
  853. X    register int cpos;
  854. X    register int i;
  855. X    register int c;
  856. X
  857. X    cpos = 0;
  858. X
  859. X    if (kbdmop != NULL) {
  860. X        while ((c = *kbdmop++) != '\0')
  861. X            buf[cpos++] = c;
  862. X
  863. X        buf[cpos] = 0;
  864. X
  865. X        if (buf[0] == 0)
  866. X            return(FALSE);
  867. X
  868. X        return(TRUE);
  869. X    }
  870. X
  871. X    /* check to see if we are executing a command line */
  872. X    if (clexec) {
  873. X        nxtarg(buf);
  874. X        return(TRUE);
  875. X    }
  876. X
  877. X    mlwrite(prompt);
  878. X
  879. X    for (;;) {
  880. X    /* get a character from the user. if it is a <ret>, change it
  881. X       to a <NL>                            */
  882. X        c = (*term.t_getchar)();
  883. X        if (c == 0x0d)
  884. X            c = '\n';
  885. X
  886. X        if (c == eolchar) {
  887. X            buf[cpos++] = 0;
  888. X
  889. X            if (kbdmip != NULL) {
  890. X                if (kbdmip+cpos > &kbdm[NKBDM-3]) {
  891. X                    ctrlg(FALSE, 0);
  892. X                    (*term.t_flush)();
  893. X                    return(ABORT);
  894. X                }
  895. X
  896. X                for (i=0; i<cpos; ++i)
  897. X                    *kbdmip++ = buf[i];
  898. X                }
  899. X
  900. X                (*term.t_putchar)('\r');
  901. X                ttcol = 0;
  902. X                (*term.t_flush)();
  903. X
  904. X                if (buf[0] == 0)
  905. X                    return(FALSE);
  906. X
  907. X                return(TRUE);
  908. X
  909. X            } else if (c == 0x07) {    /* Bell, abort */
  910. X                (*term.t_putchar)('^');
  911. X                (*term.t_putchar)('G');
  912. X                ttcol += 2;
  913. X                ctrlg(FALSE, 0);
  914. X                (*term.t_flush)();
  915. X                return(ABORT);
  916. X
  917. X            } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  918. X                if (cpos != 0) {
  919. X                    (*term.t_putchar)('\b');
  920. X                    (*term.t_putchar)(' ');
  921. X                    (*term.t_putchar)('\b');
  922. X                    --ttcol;
  923. X
  924. X                    if (buf[--cpos] < 0x20) {
  925. X                        (*term.t_putchar)('\b');
  926. X                        (*term.t_putchar)(' ');
  927. X                        (*term.t_putchar)('\b');
  928. X                        --ttcol;
  929. X                    }
  930. X
  931. X                    if (buf[cpos] == '\n') {
  932. X                        (*term.t_putchar)('\b');
  933. X                        (*term.t_putchar)('\b');
  934. X                        (*term.t_putchar)(' ');
  935. X                        (*term.t_putchar)(' ');
  936. X                        (*term.t_putchar)('\b');
  937. X                        (*term.t_putchar)('\b');
  938. X                        --ttcol;
  939. X                        --ttcol;
  940. X                    }
  941. X
  942. X                    (*term.t_flush)();
  943. X                }
  944. X
  945. X            } else if (c == 0x15) {    /* C-U, kill */
  946. X                while (cpos != 0) {
  947. X                    (*term.t_putchar)('\b');
  948. X                    (*term.t_putchar)(' ');
  949. X                    (*term.t_putchar)('\b');
  950. X                    --ttcol;
  951. X
  952. X                    if (buf[--cpos] < 0x20) {
  953. X                        (*term.t_putchar)('\b');
  954. X                        (*term.t_putchar)(' ');
  955. X                        (*term.t_putchar)('\b');
  956. X                        --ttcol;
  957. X                    }
  958. X                }
  959. X
  960. X                (*term.t_flush)();
  961. X
  962. X            } else {
  963. X                if (cpos < nbuf-1) {
  964. X                    buf[cpos++] = c;
  965. X
  966. X                    if ((c < ' ') && (c != '\n')) {
  967. X                        (*term.t_putchar)('^');
  968. X                        ++ttcol;
  969. X                        c ^= 0x40;
  970. X                    }
  971. X
  972. X                    if (c != '\n')
  973. X                        (*term.t_putchar)(c);
  974. X                    else {    /* put out <NL> for <ret> */
  975. X                        (*term.t_putchar)('<');
  976. X                        (*term.t_putchar)('N');
  977. X                        (*term.t_putchar)('L');
  978. X                        (*term.t_putchar)('>');
  979. X                        ttcol += 3;
  980. X                    }
  981. X                ++ttcol;
  982. X                (*term.t_flush)();
  983. X            }
  984. X        }
  985. X    }
  986. X}
  987. X
  988. X/*
  989. X * Write a message into the message line. Keep track of the physical cursor
  990. X * position. A small class of printf like format items is handled. Assumes the
  991. X * stack grows down; this assumption is made by the "++" in the argument scan
  992. X * loop. Set the "message line" flag TRUE.
  993. X */
  994. X
  995. Xmlwrite(fmt, arg)
  996. X    char *fmt;
  997. X    {
  998. X    register int c;
  999. X    register char *ap;
  1000. X
  1001. X    if (eolexist == FALSE) {
  1002. X        mlerase();
  1003. X        (*term.t_flush)();
  1004. X    }
  1005. X
  1006. X    movecursor(term.t_nrow, 0);
  1007. X    ap = (char *) &arg;
  1008. X    while ((c = *fmt++) != 0) {
  1009. X        if (c != '%') {
  1010. X            (*term.t_putchar)(c);
  1011. X            ++ttcol;
  1012. X            }
  1013. X        else
  1014. X            {
  1015. X            c = *fmt++;
  1016. X            switch (c) {
  1017. X                case 'd':
  1018. X                    mlputi(*(int *)ap, 10);
  1019. X                    ap += sizeof(int);
  1020. X                    break;
  1021. X
  1022. X                case 'o':
  1023. X                    mlputi(*(int *)ap,  8);
  1024. X                    ap += sizeof(int);
  1025. X                    break;
  1026. X
  1027. X                case 'x':
  1028. X                    mlputi(*(int *)ap, 16);
  1029. X                    ap += sizeof(int);
  1030. X                    break;
  1031. X
  1032. X                case 'D':
  1033. X                    mlputli(*(long *)ap, 10);
  1034. X                    ap += sizeof(long);
  1035. X                    break;
  1036. X
  1037. X                case 's':
  1038. X                    mlputs(*(char **)ap);
  1039. X                    ap += sizeof(char *);
  1040. X                    break;
  1041. X
  1042. X                default:
  1043. X                    (*term.t_putchar)(c);
  1044. X                    ++ttcol;
  1045. X                }
  1046. X            }
  1047. X        }
  1048. X    if (eolexist == TRUE)
  1049. X        (*term.t_eeol)();
  1050. X    (*term.t_flush)();
  1051. X    mpresf = TRUE;
  1052. X    }
  1053. X
  1054. X/*
  1055. X * Write out a string. Update the physical cursor position. This assumes that
  1056. X * the characters in the string all have width "1"; if this is not the case
  1057. X * things will get screwed up a little.
  1058. X */
  1059. Xmlputs(s)
  1060. X    char *s;
  1061. X    {
  1062. X    register int c;
  1063. X
  1064. X    while ((c = *s++) != 0)
  1065. X        {
  1066. X        (*term.t_putchar)(c);
  1067. X        ++ttcol;
  1068. X        }
  1069. X    }
  1070. X
  1071. X/*
  1072. X * Write out an integer, in the specified radix. Update the physical cursor
  1073. X * position. This will not handle any negative numbers; maybe it should.
  1074. X */
  1075. Xmlputi(i, r)
  1076. X    {
  1077. X    register int q;
  1078. X    static char hexdigits[] = "0123456789ABCDEF";
  1079. X
  1080. X    if (i < 0)
  1081. X        {
  1082. X        i = -i;
  1083. X        (*term.t_putchar)('-');
  1084. X        }
  1085. X
  1086. X    q = i/r;
  1087. X
  1088. X    if (q != 0)
  1089. X        mlputi(q, r);
  1090. X
  1091. X    (*term.t_putchar)(hexdigits[i%r]);
  1092. X    ++ttcol;
  1093. X    }
  1094. X
  1095. X/*
  1096. X * do the same except as a long integer.
  1097. X */
  1098. Xmlputli(l, r)
  1099. X    long l;
  1100. X    {
  1101. X    register long q;
  1102. X
  1103. X    if (l < 0)
  1104. X        {
  1105. X        l = -l;
  1106. X        (*term.t_putchar)('-');
  1107. X        }
  1108. X
  1109. X    q = l/r;
  1110. X
  1111. X    if (q != 0)
  1112. X        mlputli(q, r);
  1113. X
  1114. X    (*term.t_putchar)((int)(l%r)+'0');
  1115. X    ++ttcol;
  1116. X    }
  1117. X
  1118. X#if RAINBOW
  1119. X
  1120. Xputline(row, col, buf)
  1121. X    int row, col;
  1122. X    char buf[];
  1123. X    {
  1124. X    int n;
  1125. X
  1126. X    n = strlen(buf);
  1127. X    if (col + n - 1 > term.t_ncol)
  1128. X        n = term.t_ncol - col + 1;
  1129. X    Put_Data(row, col, n, buf);
  1130. X    }
  1131. X#endif
  1132. X
  1133. X/* get a command name from the command line. Command completion means
  1134. X   that pressing a <SPACE> will attempt to complete an unfinished command
  1135. X   name if it is unique.
  1136. X*/
  1137. X
  1138. Xint (*getname())()
  1139. X
  1140. X{
  1141. X    register int cpos;    /* current column on screen output */
  1142. X    register int c;
  1143. X    register char *sp;    /* pointer to string for output */
  1144. X    register NBIND *ffp;    /* first ptr to entry in name binding table */
  1145. X    register NBIND *cffp;    /* current ptr to entry in name binding table */
  1146. X    register NBIND *lffp;    /* last ptr to entry in name binding table */
  1147. X    char buf[NSTRING];    /* buffer to hold tentative command name */
  1148. X    int (*fncmatch())();
  1149. X
  1150. X    /* starting at the begining of the string buffer */
  1151. X    cpos = 0;
  1152. X
  1153. X    /* if we are executing a keyboard macro, fill our buffer from there,
  1154. X       and attempt a straight match */
  1155. X    if (kbdmop != NULL) {
  1156. X        while ((c = *kbdmop++) != '\0')
  1157. X            buf[cpos++] = c;
  1158. X
  1159. X        buf[cpos] = 0;
  1160. X
  1161. X        /* return the result of a match */
  1162. X        return(fncmatch(&buf[0]));
  1163. X    }
  1164. X
  1165. X    /* if we are executing a command line get the next arg and match it */
  1166. X    if (clexec) {
  1167. X        nxtarg(buf);
  1168. X        return(fncmatch(&buf[0]));
  1169. X    }
  1170. X
  1171. X    /* build a name string from the keyboard */
  1172. X    while (TRUE) {
  1173. X        c = (*term.t_getchar)();
  1174. X
  1175. X        /* if we are at the end, just match it */
  1176. X        if (c == 0x0d) {
  1177. X            buf[cpos] = 0;
  1178. X
  1179. X            /* save keyboard macro string if needed */
  1180. X            if (kbdtext(&buf[0]) == ABORT)
  1181. X                return( (int (*)()) NULL);
  1182. X
  1183. X            /* and match it off */
  1184. X            return(fncmatch(&buf[0]));
  1185. X
  1186. X        } else if (c == 0x07) {    /* Bell, abort */
  1187. X            (*term.t_putchar)('^');
  1188. X            (*term.t_putchar)('G');
  1189. X            ttcol += 2;
  1190. X            ctrlg(FALSE, 0);
  1191. X            (*term.t_flush)();
  1192. X            return( (int (*)()) NULL);
  1193. X
  1194. X        } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  1195. X            if (cpos != 0) {
  1196. X                (*term.t_putchar)('\b');
  1197. X                (*term.t_putchar)(' ');
  1198. X                (*term.t_putchar)('\b');
  1199. X                --ttcol;
  1200. X                --cpos;
  1201. X                (*term.t_flush)();
  1202. X            }
  1203. X
  1204. X        } else if (c == 0x15) {    /* C-U, kill */
  1205. X            while (cpos != 0) {
  1206. X                (*term.t_putchar)('\b');
  1207. X                (*term.t_putchar)(' ');
  1208. X                (*term.t_putchar)('\b');
  1209. X                --cpos;
  1210. X                --ttcol;
  1211. X            }
  1212. X
  1213. X            (*term.t_flush)();
  1214. X
  1215. X        } else if (c == ' ') {
  1216. X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  1217. X    /* attempt a completion */
  1218. X    buf[cpos] = 0;        /* terminate it for us */
  1219. X    ffp = &names[0];    /* scan for matches */
  1220. X    while (ffp->n_func != NULL) {
  1221. X        if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
  1222. X            /* a possible match! More than one? */
  1223. X            if ((ffp + 1)->n_func == NULL ||
  1224. X               (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
  1225. X                /* no...we match, print it */
  1226. X                sp = ffp->n_name + cpos;
  1227. X                while (*sp)
  1228. X                    (*term.t_putchar)(*sp++);
  1229. X                (*term.t_flush)();
  1230. X                return(ffp->n_func);
  1231. X            } else {
  1232. X/* << << << << << << << << << << << << << << << << << */
  1233. X    /* try for a partial match against the list */
  1234. X
  1235. X    /* first scan down until we no longer match the current input */
  1236. X    lffp = (ffp + 1);
  1237. X    while ((lffp+1)->n_func != NULL) {
  1238. X        if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
  1239. X            break;
  1240. X        ++lffp;
  1241. X    }
  1242. X
  1243. X    /* and now, attempt to partial complete the string, char at a time */
  1244. X    while (TRUE) {
  1245. X        /* add the next char in */
  1246. X        buf[cpos] = ffp->n_name[cpos];
  1247. X
  1248. X        /* scan through the candidates */
  1249. X        cffp = ffp + 1;
  1250. X        while (cffp <= lffp) {
  1251. X            if (cffp->n_name[cpos] != buf[cpos])
  1252. X                goto onward;
  1253. X            ++cffp;
  1254. X        }
  1255. X
  1256. X        /* add the character */
  1257. X        (*term.t_putchar)(buf[cpos++]);
  1258. X    }
  1259. X/* << << << << << << << << << << << << << << << << << */
  1260. X            }
  1261. X        }
  1262. X        ++ffp;
  1263. X    }
  1264. X
  1265. X    /* no match.....beep and onward */
  1266. X    (*term.t_beep)();
  1267. Xonward:;
  1268. X    (*term.t_flush)();
  1269. X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  1270. X        } else {
  1271. X            if (cpos < NSTRING-1 && c > ' ') {
  1272. X                buf[cpos++] = c;
  1273. X                (*term.t_putchar)(c);
  1274. X            }
  1275. X
  1276. X            ++ttcol;
  1277. X            (*term.t_flush)();
  1278. X        }
  1279. X    }
  1280. X}
  1281. X
  1282. Xkbdtext(buf)    /* add this text string to the current keyboard macro
  1283. X           definition                        */
  1284. X
  1285. Xchar *buf;    /* text to add to keyboard macro */
  1286. X
  1287. X{
  1288. X    /* if we are defining a keyboard macro, save it */
  1289. X    if (kbdmip != NULL) {
  1290. X        if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
  1291. X            ctrlg(FALSE, 0);
  1292. X            (*term.t_flush)();
  1293. X            return(ABORT);
  1294. X        }
  1295. X
  1296. X        /* copy string in and null terminate it */
  1297. X        while (*buf)
  1298. X            *kbdmip++ = *buf++;
  1299. X        *kbdmip++ = 0;
  1300. X    }
  1301. X    return(TRUE);
  1302. X}
  1303. *-*-END-of-display.c-*-*
  1304. echo x - file.c
  1305. sed 's/^X//' >file.c <<'*-*-END-of-file.c-*-*'
  1306. X/*
  1307. X * The routines in this file
  1308. X * handle the reading and writing of
  1309. X * disk files. All of details about the
  1310. X * reading and writing of the disk are
  1311. X * in "fileio.c".
  1312. X */
  1313. X#include        <stdio.h>
  1314. X#include    "estruct.h"
  1315. X#include        "edef.h"
  1316. X
  1317. X/*
  1318. X * Read a file into the current
  1319. X * buffer. This is really easy; all you do it
  1320. X * find the name of the file, and call the standard
  1321. X * "read a file into the current buffer" code.
  1322. X * Bound to "C-X C-R".
  1323. X */
  1324. Xfileread(f, n)
  1325. X{
  1326. X        register int    s;
  1327. X        char fname[NFILEN];
  1328. X
  1329. X        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
  1330. X                return(s);
  1331. X        return(readin(fname, TRUE));
  1332. X}
  1333. X
  1334. X/*
  1335. X * Insert a file into the current
  1336. X * buffer. This is really easy; all you do it
  1337. X * find the name of the file, and call the standard
  1338. X * "insert a file into the current buffer" code.
  1339. X * Bound to "C-X C-I".
  1340. X */
  1341. Xinsfile(f, n)
  1342. X{
  1343. X        register int    s;
  1344. X        char fname[NFILEN];
  1345. X
  1346. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  1347. X        return(rdonly());    /* we are in read only mode    */
  1348. X        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
  1349. X                return(s);
  1350. X        return(ifile(fname));
  1351. X}
  1352. X
  1353. X/*
  1354. X * Select a file for editing.
  1355. X * Look around to see if you can find the
  1356. X * fine in another buffer; if you can find it
  1357. X * just switch to the buffer. If you cannot find
  1358. X * the file, create a new buffer, read in the
  1359. X * text, and switch to the new buffer.
  1360. X * Bound to C-X C-F.
  1361. X */
  1362. Xfilefind(f, n)
  1363. X{
  1364. X        char fname[NFILEN];    /* file user wishes to find */
  1365. X        register int s;        /* status return */
  1366. X
  1367. X        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
  1368. X                return(s);
  1369. X    return(getfile(fname, TRUE));
  1370. X}
  1371. X
  1372. Xviewfile(f, n)    /* visit a file in VIEW mode */
  1373. X{
  1374. X        char fname[NFILEN];    /* file user wishes to find */
  1375. X        register int s;        /* status return */
  1376. X    register WINDOW *wp;    /* scan for windows that need updating */
  1377. X
  1378. X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
  1379. X                return (s);
  1380. X    s = getfile(fname, FALSE);
  1381. X    if (s) {    /* if we succeed, put it in view mode */
  1382. X        curwp->w_bufp->b_mode |= MDVIEW;
  1383. X
  1384. X        /* scan through and update mode lines of all windows */
  1385. X        wp = wheadp;
  1386. X        while (wp != NULL) {
  1387. X            wp->w_flag |= WFMODE;
  1388. X            wp = wp->w_wndp;
  1389. X        }
  1390. X    }
  1391. X    return(s);
  1392. X}
  1393. X
  1394. Xgetfile(fname, lockfl)
  1395. X
  1396. Xchar fname[];        /* file name to find */
  1397. Xint lockfl;        /* check the file for locks? */
  1398. X
  1399. X{
  1400. X        register BUFFER *bp;
  1401. X        register LINE   *lp;
  1402. X        register int    i;
  1403. X        register int    s;
  1404. X        char bname[NBUFN];    /* buffer name to put file */
  1405. X
  1406. X        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  1407. X                if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
  1408. X                        if (--curbp->b_nwnd == 0) {
  1409. X                                curbp->b_dotp  = curwp->w_dotp;
  1410. X                                curbp->b_doto  = curwp->w_doto;
  1411. X                                curbp->b_markp = curwp->w_markp;
  1412. X                                curbp->b_marko = curwp->w_marko;
  1413. X                        }
  1414. X            swbuffer(bp);
  1415. X                        lp = curwp->w_dotp;
  1416. X                        i = curwp->w_ntrows/2;
  1417. X                        while (i-- && lback(lp)!=curbp->b_linep)
  1418. X                                lp = lback(lp);
  1419. X                        curwp->w_linep = lp;
  1420. X                        curwp->w_flag |= WFMODE|WFHARD;
  1421. X                        mlwrite("[Old buffer]");
  1422. X                        return (TRUE);
  1423. X                }
  1424. X        }
  1425. X        makename(bname, fname);                 /* New buffer name.     */
  1426. X        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
  1427. X                s = mlreply("Buffer name: ", bname, NBUFN);
  1428. X                if (s == ABORT)                 /* ^G to just quit      */
  1429. X                        return (s);
  1430. X                if (s == FALSE) {               /* CR to clobber it     */
  1431. X                        makename(bname, fname);
  1432. X                        break;
  1433. X                }
  1434. X        }
  1435. X        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
  1436. X                mlwrite("Cannot create buffer");
  1437. X                return (FALSE);
  1438. X        }
  1439. X        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
  1440. X                curbp->b_dotp = curwp->w_dotp;
  1441. X                curbp->b_doto = curwp->w_doto;
  1442. X                curbp->b_markp = curwp->w_markp;
  1443. X                curbp->b_marko = curwp->w_marko;
  1444. X        }
  1445. X        curbp = bp;                             /* Switch to it.        */
  1446. X        curwp->w_bufp = bp;
  1447. X        curbp->b_nwnd++;
  1448. X        return(readin(fname, lockfl));          /* Read it in.          */
  1449. X}
  1450. X
  1451. X/*
  1452. X * Read file "fname" into the current
  1453. X * buffer, blowing away any text found there. Called
  1454. X * by both the read and find commands. Return the final
  1455. X * status of the read. Also called by the mainline,
  1456. X * to read in a file specified on the command line as
  1457. X * an argument. If the filename ends in a ".c", CMODE is
  1458. X * set for the current buffer.
  1459. X */
  1460. Xreadin(fname, lockfl)
  1461. X
  1462. Xchar    fname[];    /* name of file to read */
  1463. Xint    lockfl;        /* check for file locks? */
  1464. X
  1465. X{
  1466. X        register LINE   *lp1;
  1467. X        register LINE   *lp2;
  1468. X        register int    i;
  1469. X        register WINDOW *wp;
  1470. X        register BUFFER *bp;
  1471. X        register int    s;
  1472. X        register int    nbytes;
  1473. X        register int    nline;
  1474. X    register char    *sptr;        /* pointer into filename string */
  1475. X    int        lflag;        /* any lines longer than allowed? */
  1476. X        char            line[NLINE];
  1477. X
  1478. X#if    FILOCK
  1479. X    if (lockfl && lockchk(fname) == ABORT)
  1480. X        return(ABORT);
  1481. X#endif
  1482. X        bp = curbp;                             /* Cheap.               */
  1483. X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
  1484. X                return (s);
  1485. X        bp->b_flag &= ~(BFTEMP|BFCHG);
  1486. X    if (strlen(fname) > 1) {        /* check if a 'C' file    */
  1487. X        sptr = fname + strlen(fname) - 2;
  1488. X        if (*sptr == '.' &&
  1489. X           *(sptr + 1) == 'c' || *(sptr + 1) == 'h')
  1490. X            bp->b_mode |= MDCMOD;
  1491. X    }
  1492. X        strcpy(bp->b_fname, fname);
  1493. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1494. X                goto out;
  1495. X        if (s == FIOFNF) {                      /* File not found.      */
  1496. X                mlwrite("[New file]");
  1497. X                goto out;
  1498. X        }
  1499. X        mlwrite("[Reading file]");
  1500. X        nline = 0;
  1501. X    lflag = FALSE;
  1502. X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
  1503. X        if (s == FIOLNG)
  1504. X            lflag = TRUE;
  1505. X                nbytes = strlen(line);
  1506. X                if ((lp1=lalloc(nbytes)) == NULL) {
  1507. X                        s = FIOERR;             /* Keep message on the  */
  1508. X                        break;                  /* display.             */
  1509. X                }
  1510. X                lp2 = lback(curbp->b_linep);
  1511. X                lp2->l_fp = lp1;
  1512. X                lp1->l_fp = curbp->b_linep;
  1513. X                lp1->l_bp = lp2;
  1514. X                curbp->b_linep->l_bp = lp1;
  1515. X                for (i=0; i<nbytes; ++i)
  1516. X                        lputc(lp1, i, line[i]);
  1517. X                ++nline;
  1518. X        }
  1519. X        ffclose();                              /* Ignore errors.       */
  1520. X        if (s == FIOEOF) {                      /* Don't zap message!   */
  1521. X                if (nline == 1)
  1522. X                        mlwrite("[Read 1 line]");
  1523. X                else
  1524. X                        mlwrite("[Read %d lines]", nline);
  1525. X        }
  1526. X    if (lflag)
  1527. X        mlwrite("[Read %d line(s), Long lines wrapped]",nline);
  1528. Xout:
  1529. X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  1530. X                if (wp->w_bufp == curbp) {
  1531. X                        wp->w_linep = lforw(curbp->b_linep);
  1532. X                        wp->w_dotp  = lforw(curbp->b_linep);
  1533. X                        wp->w_doto  = 0;
  1534. X                        wp->w_markp = NULL;
  1535. X                        wp->w_marko = 0;
  1536. X                        wp->w_flag |= WFMODE|WFHARD;
  1537. X                }
  1538. X        }
  1539. X        if (s == FIOERR || s == FIOFNF)        /* False if error.      */
  1540. X                return(FALSE);
  1541. X        return (TRUE);
  1542. X}
  1543. X
  1544. X/*
  1545. X * Take a file name, and from it
  1546. X * fabricate a buffer name. This routine knows
  1547. X * about the syntax of file names on the target system.
  1548. X * I suppose that this information could be put in
  1549. X * a better place than a line of code.
  1550. X */
  1551. Xmakename(bname, fname)
  1552. Xchar    bname[];
  1553. Xchar    fname[];
  1554. X{
  1555. X        register char   *cp1;
  1556. X        register char   *cp2;
  1557. X
  1558. X        cp1 = &fname[0];
  1559. X        while (*cp1 != 0)
  1560. X                ++cp1;
  1561. X
  1562. X#if     AMIGA
  1563. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
  1564. X                --cp1;
  1565. X#endif
  1566. X#if     VMS
  1567. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  1568. X                --cp1;
  1569. X#endif
  1570. X#if     CPM
  1571. X        while (cp1!=&fname[0] && cp1[-1]!=':')
  1572. X                --cp1;
  1573. X#endif
  1574. X#if     MSDOS
  1575. X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  1576. X                --cp1;
  1577. X#endif
  1578. X#if     V7
  1579. X        while (cp1!=&fname[0] && cp1[-1]!='/')
  1580. X                --cp1;
  1581. X#endif
  1582. X        cp2 = &bname[0];
  1583. X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  1584. X                *cp2++ = *cp1++;
  1585. X        *cp2 = 0;
  1586. X}
  1587. X
  1588. X/*
  1589. X * Ask for a file name, and write the
  1590. X * contents of the current buffer to that file.
  1591. X * Update the remembered file name and clear the
  1592. X * buffer changed flag. This handling of file names
  1593. X * is different from the earlier versions, and
  1594. X * is more compatable with Gosling EMACS than
  1595. X * with ITS EMACS. Bound to "C-X C-W".
  1596. X */
  1597. Xfilewrite(f, n)
  1598. X{
  1599. X        register WINDOW *wp;
  1600. X        register int    s;
  1601. X        char            fname[NFILEN];
  1602. X
  1603. X        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
  1604. X                return (s);
  1605. X        if ((s=writeout(fname)) == TRUE) {
  1606. X                strcpy(curbp->b_fname, fname);
  1607. X                curbp->b_flag &= ~BFCHG;
  1608. X                wp = wheadp;                    /* Update mode lines.   */
  1609. X                while (wp != NULL) {
  1610. X                        if (wp->w_bufp == curbp)
  1611. X                                wp->w_flag |= WFMODE;
  1612. X                        wp = wp->w_wndp;
  1613. X                }
  1614. X        }
  1615. X        return (s);
  1616. X}
  1617. X
  1618. X/*
  1619. X * Save the contents of the current
  1620. X * buffer in its associatd file. No nothing
  1621. X * if nothing has changed (this may be a bug, not a
  1622. X * feature). Error if there is no remembered file
  1623. X * name for the buffer. Bound to "C-X C-S". May
  1624. X * get called by "C-Z".
  1625. X */
  1626. Xfilesave(f, n)
  1627. X{
  1628. X        register WINDOW *wp;
  1629. X        register int    s;
  1630. X
  1631. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  1632. X        return(rdonly());    /* we are in read only mode    */
  1633. X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
  1634. X                return (TRUE);
  1635. X        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
  1636. X                mlwrite("No file name");
  1637. X                return (FALSE);
  1638. X        }
  1639. X        if ((s=writeout(curbp->b_fname)) == TRUE) {
  1640. X                curbp->b_flag &= ~BFCHG;
  1641. X                wp = wheadp;                    /* Update mode lines.   */
  1642. X                while (wp != NULL) {
  1643. X                        if (wp->w_bufp == curbp)
  1644. X                                wp->w_flag |= WFMODE;
  1645. X                        wp = wp->w_wndp;
  1646. X                }
  1647. X        }
  1648. X        return (s);
  1649. X}
  1650. X
  1651. X/*
  1652. X * This function performs the details of file
  1653. X * writing. Uses the file management routines in the
  1654. X * "fileio.c" package. The number of lines written is
  1655. X * displayed. Sadly, it looks inside a LINE; provide
  1656. X * a macro for this. Most of the grief is error
  1657. X * checking of some sort.
  1658. X */
  1659. Xwriteout(fn)
  1660. Xchar    *fn;
  1661. X{
  1662. X        register int    s;
  1663. X        register LINE   *lp;
  1664. X        register int    nline;
  1665. X
  1666. X        if ((s=ffwopen(fn)) != FIOSUC)          /* Open writes message. */
  1667. X                return (FALSE);
  1668. X    mlwrite("[Writing..]");            /* tell us were writing */
  1669. X        lp = lforw(curbp->b_linep);             /* First line.          */
  1670. X        nline = 0;                              /* Number of lines.     */
  1671. X        while (lp != curbp->b_linep) {
  1672. X                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  1673. X                        break;
  1674. X                ++nline;
  1675. X                lp = lforw(lp);
  1676. X        }
  1677. X        if (s == FIOSUC) {                      /* No write error.      */
  1678. X                s = ffclose();
  1679. X                if (s == FIOSUC) {              /* No close error.      */
  1680. X                        if (nline == 1)
  1681. X                                mlwrite("[Wrote 1 line]");
  1682. X                        else
  1683. X                                mlwrite("[Wrote %d lines]", nline);
  1684. X                }
  1685. X        } else                                  /* Ignore close error   */
  1686. X                ffclose();                      /* if a write error.    */
  1687. X        if (s != FIOSUC)                        /* Some sort of error.  */
  1688. X                return (FALSE);
  1689. X        return (TRUE);
  1690. X}
  1691. X
  1692. X/*
  1693. X * The command allows the user
  1694. X * to modify the file name associated with
  1695. X * the current buffer. It is like the "f" command
  1696. X * in UNIX "ed". The operation is simple; just zap
  1697. X * the name in the BUFFER structure, and mark the windows
  1698. X * as needing an update. You can type a blank line at the
  1699. X * prompt if you wish.
  1700. X */
  1701. Xfilename(f, n)
  1702. X{
  1703. X        register WINDOW *wp;
  1704. X        register int    s;
  1705. X        char            fname[NFILEN];
  1706. X
  1707. X        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
  1708. X                return (s);
  1709. X        if (s == FALSE)
  1710. X                strcpy(curbp->b_fname, "");
  1711. X        else
  1712. X                strcpy(curbp->b_fname, fname);
  1713. X        wp = wheadp;                            /* Update mode lines.   */
  1714. X        while (wp != NULL) {
  1715. X                if (wp->w_bufp == curbp)
  1716. X                        wp->w_flag |= WFMODE;
  1717. X                wp = wp->w_wndp;
  1718. X        }
  1719. X    curbp->b_mode &= ~MDVIEW;    /* no longer read only mode */
  1720. X        return (TRUE);
  1721. X}
  1722. X
  1723. X/*
  1724. X * Insert file "fname" into the current
  1725. X * buffer, Called by insert file command. Return the final
  1726. X * status of the read.
  1727. X */
  1728. Xifile(fname)
  1729. Xchar    fname[];
  1730. X{
  1731. X        register LINE   *lp0;
  1732. X        register LINE   *lp1;
  1733. X        register LINE   *lp2;
  1734. X        register int    i;
  1735. X        register BUFFER *bp;
  1736. X        register int    s;
  1737. X        register int    nbytes;
  1738. X        register int    nline;
  1739. X    int        lflag;        /* any lines longer than allowed? */
  1740. X        char            line[NLINE];
  1741. X
  1742. X        bp = curbp;                             /* Cheap.               */
  1743. X        bp->b_flag |= BFCHG;            /* we have changed    */
  1744. X    bp->b_flag &= ~BFTEMP;            /* and are not temporary*/
  1745. X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
  1746. X                goto out;
  1747. X        if (s == FIOFNF) {                      /* File not found.      */
  1748. X                mlwrite("[No such file]");
  1749. X        return(FALSE);
  1750. X        }
  1751. X        mlwrite("[Inserting file]");
  1752. X
  1753. X    /* back up a line and save the mark here */
  1754. X    curwp->w_dotp = lback(curwp->w_dotp);
  1755. X    curwp->w_doto = 0;
  1756. X    curwp->w_markp = curwp->w_dotp;
  1757. X    curwp->w_marko = 0;
  1758. X
  1759. X        nline = 0;
  1760. X    lflag = FALSE;
  1761. X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
  1762. X        if (s == FIOLNG)
  1763. X            lflag = TRUE;
  1764. X                nbytes = strlen(line);
  1765. X                if ((lp1=lalloc(nbytes)) == NULL) {
  1766. X                        s = FIOERR;             /* Keep message on the  */
  1767. X                        break;                  /* display.             */
  1768. X                }
  1769. X        lp0 = curwp->w_dotp;    /* line previous to insert */
  1770. X        lp2 = lp0->l_fp;    /* line after insert */
  1771. X
  1772. X        /* re-link new line between lp0 and lp2 */
  1773. X        lp2->l_bp = lp1;
  1774. X        lp0->l_fp = lp1;
  1775. X        lp1->l_bp = lp0;
  1776. X        lp1->l_fp = lp2;
  1777. X
  1778. X        /* and advance and write out the current line */
  1779. X        curwp->w_dotp = lp1;
  1780. X                for (i=0; i<nbytes; ++i)
  1781. X                        lputc(lp1, i, line[i]);
  1782. X                ++nline;
  1783. X        }
  1784. X        ffclose();                              /* Ignore errors.       */
  1785. X    curwp->w_markp = lforw(curwp->w_markp);
  1786. X        if (s == FIOEOF) {                      /* Don't zap message!   */
  1787. X                if (nline == 1)
  1788. X                        mlwrite("[Inserted 1 line]");
  1789. X                else
  1790. X                        mlwrite("[Inserted %d lines]", nline);
  1791. X        }
  1792. X    if (lflag)
  1793. X        mlwrite("[Inserted %d line(s), Long lines wrapped]",nline);
  1794. Xout:
  1795. X    /* advance to the next line and mark the window for changes */
  1796. X    curwp->w_dotp = lforw(curwp->w_dotp);
  1797. X    curwp->w_flag |= WFHARD;
  1798. X
  1799. X    /* copy window parameters back to the buffer structure */
  1800. X    curbp->b_dotp = curwp->w_dotp;
  1801. X    curbp->b_doto = curwp->w_doto;
  1802. X    curbp->b_markp = curwp->w_markp;
  1803. X    curbp->b_marko = curwp->w_marko;
  1804. X
  1805. X        if (s == FIOERR)                        /* False if error.      */
  1806. X                return (FALSE);
  1807. X        return (TRUE);
  1808. X}
  1809. *-*-END-of-file.c-*-*
  1810. exit
  1811.  
  1812.  
  1813.