home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / jove / part02 / disp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-02-02  |  23.6 KB  |  1,216 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "ctype.h"
  10. #include "termcap.h"
  11.  
  12. #include <varargs.h>
  13. #include <signal.h>
  14. #include <sys/stat.h>
  15.  
  16. /* Kludge windows gets called by the routines that delete lines from the
  17.    buffer.  If the w->w_line or w->w_top are deleted and this procedure
  18.    is not called, the redisplay routine will barf. */
  19.  
  20. ChkWindows(line1, line2)
  21. Line    *line1;
  22. register Line    *line2;
  23. {
  24.     register Window    *w = fwind;
  25.     register Line    *lp;
  26.  
  27.     do {
  28.         for (lp = line1->l_next; lp != line2->l_next; lp = lp->l_next) {
  29.             if (lp == w->w_top)
  30.                 w->w_flags |= W_TOPGONE;
  31.             if (lp == w->w_line)
  32.                 w->w_flags |= W_CURGONE;
  33.         }
  34.         w = w->w_next;
  35.     } while (w != fwind);
  36. }
  37.  
  38. extern int    RingBell;
  39.  
  40. redisplay()
  41. {
  42.     register Window    *w = fwind;
  43.     int    lineno,
  44.         done_ID = 0,
  45.         i;
  46.     register struct scrimage    *des_p,
  47.                     *phys_p;
  48.  
  49.     curwind->w_line = curwind->w_bufp->b_dot;
  50.     curwind->w_char = curwind->w_bufp->b_char;
  51.  
  52.     if (InputPending = charp())
  53.         return;
  54.  
  55. #ifdef JOB_CONTROL
  56.     if (UpdFreq)
  57.         sighold(SIGALRM);
  58. #endif
  59.     if (RingBell) {
  60.         dobell(1);
  61.         RingBell = 0;
  62.     }
  63.     if (UpdMesg)
  64.         DrawMesg(YES);
  65.  
  66.     for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) {
  67.         UpdWindow(w, lineno);
  68.         lineno += w->w_height;
  69.     }
  70.  
  71.     des_p = DesiredScreen;
  72.     phys_p = PhysScreen;
  73.     for (i = 0; i < ILI; i++, des_p++, phys_p++) {
  74.         if (!done_ID && (des_p->s_id != phys_p->s_id)) {
  75.             DoIDline(i);
  76.             done_ID++;
  77.         }
  78.         if ((des_p->s_flags & (DIRTY | L_MOD)) ||
  79.             (des_p->s_id != phys_p->s_id) ||
  80.             (des_p->s_vln != phys_p->s_vln) ||
  81.             (des_p->s_offset != phys_p->s_offset))
  82.             UpdLine(i);
  83.         if (InputPending)
  84.             goto ret;
  85.     }
  86.  
  87.     UpdModLine = 0;
  88.  
  89.     if (Asking) {
  90.         Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, Asking)));
  91.             /* Nice kludge */
  92.         flusho();
  93.     } else
  94.         GotoDot();
  95. ret:
  96. #ifdef JOB_CONTROL
  97.     if (UpdFreq)
  98.         sigrelse(SIGALRM);
  99. #else
  100.     ;    /* yuck */
  101. #endif
  102.  
  103. }
  104.  
  105. dobell(n)
  106. {
  107.     while (--n >= 0) {
  108.         if (VisBell && VB)
  109.             putstr(VB);
  110.         else
  111. #ifdef SYSV    /* release 2, at least */
  112.             putpad("$<20>\007", 1) ;
  113. #else
  114.             putpad("20\007", 1);
  115. #endif SYSV
  116.     }
  117.     flusho();
  118. }
  119.  
  120. /* find_pos() returns the position on the line, that c_char represents
  121.    in line. */
  122.  
  123. find_pos(line, c_char)
  124. Line    *line;
  125. {
  126.     return calc_pos(lcontents(line), c_char);
  127. }
  128.  
  129. calc_pos(lp, c_char)
  130. register char    *lp;
  131. register int    c_char;
  132. {
  133.     register int    pos = 0;
  134.     register int    c;
  135.  
  136.     while ((--c_char >= 0) && ((c = *lp++) & 0177) != 0) {
  137.         if (c == '\t')
  138.             pos += (tabstop - (pos % tabstop));
  139.         else if (isctrl(c))
  140.             pos += 2;
  141.         else
  142.             pos++;
  143.      }
  144.     return pos;
  145. }
  146.  
  147. int    UpdModLine = 0,
  148.     UpdMesg = 0,
  149.     CanScroll = 0;
  150.  
  151. DoIDline(start)
  152. {
  153.     register struct scrimage    *des_p = &DesiredScreen[start];
  154.     struct scrimage    *phys_p = &PhysScreen[start];
  155.     register int    i,
  156.             j;
  157.  
  158.     /* Some changes have been made.  Try for insert or delete lines.
  159.        If either case has happened, Addlines and/or DelLines will do
  160.        necessary scrolling, also CONVERTING PhysScreen to account for the
  161.        physical changes.  The comparison continues from where the
  162.        insertion/deletion takes place; this doesn't happen very often,
  163.        usually it happens with more than one window with the same
  164.        buffer. */
  165.  
  166.     if (!CanScroll)
  167.         return;        /* We should never have been called! */
  168.  
  169.     for (i = start; i < ILI; i++, des_p++, phys_p++)
  170.         if (des_p->s_id != phys_p->s_id)
  171.             break;
  172.  
  173.     for (; i < ILI; i++) {
  174.         for (j = i + 1; j < ILI; j++) {
  175.             des_p = &DesiredScreen[j];
  176.             phys_p = &PhysScreen[j];
  177.             if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id)
  178.                 break;
  179.             if (des_p->s_id == PhysScreen[i].s_id) {
  180.                 if (des_p->s_id == 0)
  181.                     continue;
  182.                 if (AddLines(i, j - i)) {
  183.                     DoIDline(j);
  184.                     return;
  185.                 }
  186.                 break;
  187.             }
  188.             if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) {
  189.                 if (des_p->s_id == 0)
  190.                     continue;
  191.                 if (DelLines(i, j - i)) {
  192.                     DoIDline(i);
  193.                     return;
  194.                 }
  195.                 break;
  196.             }
  197.         }
  198.     }
  199. }
  200.  
  201. /* Make DesiredScreen reflect what the screen should look like when we are done
  202.    with the redisplay.  This deals with horizontal scrolling.  Also makes
  203.    sure the current line of the Window is in the window. */
  204.  
  205. UpdWindow(w, start)
  206. register Window    *w;
  207. {
  208.     Line    *lp;
  209.     int    i,
  210.         DotIsHere = 0,
  211.         upper,        /* Top of window */
  212.         lower,        /* Bottom of window */
  213.         ntries = 0;    /* # of tries at updating window. */
  214.     register struct scrimage    *des_p,
  215.                     *phys_p;
  216.     Buffer    *bp = w->w_bufp;
  217.  
  218. retry:
  219.     if (w->w_flags & W_CURGONE) {
  220.         w->w_line = bp->b_dot;
  221.         w->w_char = bp->b_char;
  222.     }
  223.     if (w->w_flags & W_TOPGONE)
  224.         CentWind(w);    /* Reset topline of screen */
  225.     w->w_flags &= ~(W_CURGONE|W_TOPGONE);
  226.     for (i = w->w_height, lp = w->w_top; --i > 0 && lp != 0; lp = lp->l_next)
  227.         if (lp == w->w_line)
  228.             break;
  229.     if (i == 0 || lp == 0) {    /* current line not in window */
  230.         ntries++;
  231.         if (ntries == 1) {
  232.             CalcWind(w);
  233.             goto retry;
  234.         } else if (ntries == 2) {
  235.             w->w_top = w->w_line = w->w_bufp->b_first;
  236.             printf("\rERROR in redisplay: I got hopelessly lost!");
  237.             dobell(2);
  238.             goto retry;
  239.         } else if (ntries == 3) {
  240.             printf("\n\rOops, still lost, quitting ...\r\n");
  241.             finish(1);
  242.         }
  243.     }
  244.  
  245.     upper = start;
  246.     lower = upper + w->w_height - 1;    /* Don't include modeline */
  247.     des_p = &DesiredScreen[upper];
  248.     phys_p = &PhysScreen[upper];
  249.     for (i = upper, lp = w->w_top; lp != 0 && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) {
  250.         des_p->s_window = w;
  251.         des_p->s_lp = lp;
  252.         des_p->s_id = lp->l_dline & ~DIRTY;
  253.         des_p->s_flags = isdirty(lp) ? L_MOD : 0;
  254.         if (w->w_flags & W_NUMLINES)
  255.             des_p->s_vln = w->w_topnum + (i - upper);
  256.         else
  257.             des_p->s_vln = 0;
  258.  
  259.         if (lp == w->w_line) {
  260.             int    diff = (w->w_flags & W_NUMLINES) ? 8 : 0,
  261.                 strt_col = phys_p->s_offset,
  262.                 end_col = strt_col + (CO - 2) - diff;
  263.  
  264.             /* Right now we are displaying from strt_col to
  265.                end_col of the buffer line.  These are PRINT
  266.                colums, not actual characters. */
  267.             w->w_dotline = i;
  268.             w->w_dotcol = find_pos(lp, w->w_char);
  269.             /* if the new dotcol is out of range, reselect
  270.                a horizontal window */
  271.             if (w->w_dotcol < strt_col || w->w_dotcol >= end_col) {
  272.                 if (w->w_dotcol < ((CO - 2) - diff))
  273.                     strt_col = 0;
  274.                 else
  275.                     strt_col = w->w_dotcol - (CO / 2);
  276.             }
  277.             w->w_dotcol += diff;
  278.             des_p->s_offset = strt_col;
  279.             DotIsHere++;
  280.         } else
  281.             des_p->s_offset = 0;
  282.     }
  283.     if (!DotIsHere) {
  284.         f_mess("DotNotHere is impossible!");
  285.         finish(1);
  286.     }
  287.  
  288.     /* Is structure assignment faster than copy each field seperately */
  289.     if (i < lower) {
  290.         static struct scrimage    dirty_plate = { 0, DIRTY, 0, 0, 0, 0 },
  291.                     clean_plate = { 0, 0, 0, 0, 0, 0 };
  292.  
  293.         for (; i < lower; i++, des_p++, phys_p++)
  294.             if (phys_p->s_id != 0)
  295.                 *des_p = dirty_plate;
  296.             else
  297.                 *des_p = clean_plate;
  298.     }
  299.  
  300.     des_p->s_window = w;
  301.     des_p->s_flags = 0;
  302.     if (((des_p->s_id = (int) w->w_bufp) != phys_p->s_id) || UpdModLine)
  303.         des_p->s_flags = MODELINE | DIRTY;
  304. }
  305.  
  306. /* Write whatever is in mesgbuf (maybe we are Asking, or just printed
  307.    a message).  Turns off the UpdateMesg line flag. */
  308.  
  309. DrawMesg(abortable)
  310. {
  311.     if (charp())
  312.         return;
  313.     i_set(ILI, 0);
  314.     if (swrite(mesgbuf, NIL, abortable)) {
  315.         cl_eol();
  316.         UpdMesg = 0;
  317.     }
  318.     flusho();
  319. }
  320.  
  321. /* Goto the current position in the current window.  Presumably redisplay()
  322.    has already been called, and curwind->{w_dotline,w_dotcol} have been set
  323.    correctly. */
  324.  
  325. GotoDot()
  326. {
  327.     if (InputPending)
  328.         return;
  329.     Placur(curwind->w_dotline, curwind->w_dotcol -
  330.                 PhysScreen[curwind->w_dotline].s_offset);
  331.     flusho();
  332. }
  333.  
  334. private
  335. UntilEqual(start)
  336. register int    start;
  337. {
  338.     register struct scrimage    *des_p = &DesiredScreen[start],
  339.                     *phys_p = &PhysScreen[start];
  340.  
  341.     while ((start < ILI) && (des_p->s_id != phys_p->s_id)) {
  342.         des_p++;
  343.         phys_p++;
  344.         start++;
  345.     }
  346.  
  347.     return start;
  348. }
  349.  
  350. /* Calls the routine to do the physical changes, and changes PhysScreen to
  351.    reflect those changes. */
  352.  
  353. AddLines(at, num)
  354. register int    at,
  355.         num;
  356. {
  357.     register  int    i;
  358.     int    bottom = UntilEqual(at + num);
  359.  
  360.     if (num == 0 || num >= ((bottom - 1) - at))
  361.         return 0;    /* We did nothing */
  362.     v_ins_line(num, at, bottom - 1);
  363.  
  364.     /* Now change PhysScreen to account for the physical change. */
  365.  
  366.     for (i = bottom - 1; i - num >= at; i--)
  367.         PhysScreen[i] = PhysScreen[i - num];
  368.     for (i = 0; i < num; i++)
  369.         PhysScreen[at + i].s_id = 0;
  370.     return 1;    /* We did something. */
  371. }
  372.  
  373. DelLines(at, num)
  374. register int    at,
  375.         num;
  376. {
  377.     register int    i;
  378.     int    bottom = UntilEqual(at + num);
  379.  
  380.     if (num == 0 || num >= ((bottom - 1) - at))
  381.         return 0;
  382.     v_del_line(num, at, bottom - 1);
  383.  
  384.     for (i = at; num + i < bottom; i++)
  385.         PhysScreen[i] = PhysScreen[num + i];
  386.     for (i = bottom - num; i < bottom; i++)
  387.         PhysScreen[i].s_id = 0;
  388.     return 1;
  389. }
  390.  
  391. /* Update line linenum in window w.  Only set PhysScreen to DesiredScreen
  392.    if the swrite or cl_eol works, that is nothing is interupted by 
  393.    characters typed. */ 
  394.  
  395. UpdLine(linenum)
  396. register int    linenum;
  397. {
  398.     register struct scrimage    *des_p = &DesiredScreen[linenum];
  399.     register Window    *w = des_p->s_window;
  400.  
  401.     i_set(linenum, 0);
  402.     if (des_p->s_flags & MODELINE)
  403.         ModeLine(w);
  404.     else if (des_p->s_id) {
  405.         des_p->s_lp->l_dline &= ~DIRTY;
  406.         des_p->s_flags &= ~(DIRTY | L_MOD);
  407. #ifdef ID_CHAR
  408.         if (!UseIC && (w->w_flags & W_NUMLINES))
  409. #else
  410.         if (w->w_flags & W_NUMLINES)
  411. #endif
  412.             (void) swrite(sprint("%6d  ", des_p->s_vln), NIL, YES);
  413.  
  414. #ifdef ID_CHAR
  415.         if (UseIC) {
  416.             char    outbuf[256],
  417.                 *lptr;
  418.             int    fromcol = (w->w_flags & W_NUMLINES) ? 8 : 0;
  419.  
  420.             if (w->w_flags & W_NUMLINES)
  421.                 sprintf(outbuf, "%6d  ", des_p->s_vln);
  422.             lptr = lcontents(des_p->s_lp);
  423.             DeTab(des_p->s_offset, lptr, outbuf + fromcol,
  424.                 (sizeof outbuf) - 1 - fromcol,
  425.                 des_p->s_window->w_flags & W_VISSPACE);
  426.             if (IDchar(outbuf, linenum, 0))
  427.                 PhysScreen[linenum] = *des_p;
  428.             else if (i_set(linenum, 0), swrite(outbuf, NIL, YES))
  429.                 do_cl_eol(linenum);
  430.             else
  431.                 PhysScreen[linenum].s_id = -1;
  432.         } else
  433. #endif ID_CHAR
  434.             if (BufSwrite(linenum))
  435.             do_cl_eol(linenum);
  436.         else
  437.             PhysScreen[linenum].s_id = -1;
  438.     } else if (PhysScreen[linenum].s_id)    /* Not the same ... make sure */
  439.         do_cl_eol(linenum);
  440. }
  441.  
  442. do_cl_eol(linenum)
  443. register int    linenum;
  444. {
  445.     cl_eol();
  446.     PhysScreen[linenum] = DesiredScreen[linenum];
  447. }
  448.  
  449. #ifdef ID_CHAR
  450.  
  451. /* From here to the end of the file is code that tries to utilize the
  452.    insert/delete character feature on some terminals.  It is very confusing
  453.    and not so well written code, AND there is a lot of it.  You may want
  454.    to use the space for something else. */
  455.  
  456. extern struct screenline    *Screen;
  457. int    IN_INSmode = 0;
  458.  
  459. int    UseIC;
  460.  
  461. int    DClen,
  462.     MDClen,
  463.     IClen,
  464.     MIClen,
  465.     IMlen,
  466.     CElen;
  467.  
  468. disp_opt_init()
  469. {
  470.     DClen = DC ? strlen(DC) : 0;
  471.     MDClen = M_DC ? strlen(M_DC) : 9999;
  472.     IClen = IC ? strlen(IC) : 0;
  473.     MIClen = M_IC ? strlen(M_IC) : 9999;
  474.     IMlen = IM ? strlen(IM) : 0;
  475.     CElen = CE ? strlen(CE) : 0;
  476.  
  477.     UseIC = (IC || IM || M_IC);
  478. }
  479.  
  480. INSmode(on)
  481. {
  482.     if (on && !IN_INSmode) {
  483.         putpad(IM, 1);
  484.         IN_INSmode++;
  485.     } else if (!on && IN_INSmode) {
  486.         putpad(EI, 1);
  487.         IN_INSmode = 0;
  488.     }
  489. }
  490.  
  491. private
  492. DeTab(s_offset, buf, outbuf, limit, visspace)
  493. register char    *buf;
  494. char    *outbuf;
  495. {
  496.     register char    *phys_p = outbuf,
  497.             c;
  498.     register int    pos = 0;
  499.     char        *limitp = &outbuf[limit];
  500.  
  501. #define OkayOut(ch)    if ((pos++ >= s_offset) && (phys_p < limitp))\
  502.                 *phys_p++ = ch;\
  503.             else
  504.  
  505.     while (c = *buf++) {
  506.         if (c == '\t') {
  507.             int    nchars = (tabstop - (pos % tabstop));
  508.  
  509.             if (visspace) {
  510.                 OkayOut('>');
  511.                 --nchars;
  512.             }
  513.             while (--nchars >= 0)
  514.                 OkayOut(' ');
  515.  
  516.         } else if (isctrl(c)) {
  517.             OkayOut('^');
  518.             OkayOut(c == 0177 ? '?' : c + '@');
  519.         } else {
  520.             if (visspace && c == ' ')
  521.                 c = '_';
  522.             OkayOut(c);
  523.         }
  524.         if (pos - s_offset >= CO) {
  525.             phys_p = &outbuf[CO - 1];
  526.             *phys_p++ = '!';
  527.             break;
  528.         }            
  529.     }
  530.     *phys_p = 0;
  531. }
  532.  
  533. /* ID character routines full of special cases and other fun stuff like that.
  534.    It actually works though ... 
  535.  
  536.       Returns Non-Zero if you are finished (no differences left). */
  537.  
  538. private
  539. IDchar(new, lineno, col)
  540. register char    *new;
  541. {
  542.     register int    i;
  543.     int    j,
  544.         oldlen,
  545.         NumSaved;
  546.     register struct screenline    *sline = &Screen[lineno];
  547.  
  548.     oldlen = sline->s_length - sline->s_line;
  549.  
  550.     for (i = col; i < oldlen && new[i] != 0; i++)
  551.         if (sline->s_line[i] != new[i])
  552.             break;
  553.     if (new[i] == 0 || i == oldlen)
  554.         return (new[i] == 0 && i == oldlen);
  555.  
  556.     for (j = i + 1; j < oldlen && new[j]; j++) {
  557.         if (new[j] == sline->s_line[i]) {
  558.             NumSaved = IDcomp(new + j, sline->s_line + i,
  559.                     strlen(new)) + NumSimilar(new + i,
  560.                         sline->s_line + i, j - i);
  561.             if (OkayInsert(NumSaved, j - i)) {
  562.                 InsChar(lineno, i, j - i, new);
  563.                 return(IDchar(new, lineno, j));
  564.             }
  565.         }
  566.     }
  567.  
  568.     for (j = i + 1; j < oldlen && new[i]; j++) {
  569.         if (new[i] == sline->s_line[j]) {
  570.             NumSaved = IDcomp(new + i, sline->s_line + j,
  571.                     oldlen - j);
  572.             if (OkayDelete(NumSaved, j - i, new[oldlen] == 0)) {
  573.                 DelChar(lineno, i, j - i);
  574.                 return(IDchar(new, lineno, j));
  575.             }
  576.         }
  577.     }
  578.     return 0;
  579. }
  580.  
  581. private
  582. NumSimilar(s, t, n)
  583. register char    *s,
  584.         *t;
  585. {
  586.     register int    num = 0;
  587.  
  588.     while (n--)
  589.         if (*s++ == *t++)
  590.             num++;
  591.     return num;
  592. }
  593.  
  594. private
  595. IDcomp(s, t, len)
  596. register char    *s,
  597.         *t;
  598. {
  599.     register int    i;
  600.     int    num = 0,
  601.         nonspace = 0;
  602.     char    c;
  603.  
  604.     for (i = 0; i < len; i++) {
  605.         if ((c = *s++) != *t++)
  606.             break;
  607.         if (c != ' ')
  608.             nonspace++;
  609.         if (nonspace)
  610.             num++;
  611.     }
  612.  
  613.     return num;
  614. }
  615.  
  616. private
  617. OkayDelete(Saved, num, samelength)
  618. {
  619.     /* If the old and the new are the same length, then we don't
  620.      * have to clear to end of line.  We take that into consideration.
  621.      */
  622.     return ((Saved + (!samelength ? CElen : 0))
  623.         > min(MDClen, DClen * num));
  624. }
  625.  
  626. private
  627. OkayInsert(Saved, num)
  628. {
  629.     register int    n = 0;
  630.  
  631.     if (IC)        /* Per character prefixes */
  632.         n = min(num * IClen, MIClen);
  633.  
  634.     if (IM && !IN_INSmode) {    
  635.         /* Good terminal.  Fewer characters in this case */
  636.         n += IMlen;
  637.     }
  638.  
  639.     n += num;    /* The characters themselves */
  640.  
  641.     return Saved > n;
  642. }
  643.  
  644. extern int    CapCol;
  645. extern char    *cursend;
  646. extern struct screenline    *Curline;
  647.  
  648. private
  649. DelChar(lineno, col, num)
  650. {
  651.     register char    *from,
  652.             *to;
  653.     register int    i;
  654.     struct screenline *sp = (&Screen[lineno]);
  655.  
  656.     Placur(lineno, col);
  657.     if (M_DC && num > 1) {
  658.         char    minibuf[16];
  659.  
  660.         sprintf(minibuf, M_DC, num);
  661.         putpad(minibuf, num);
  662.     } else {
  663.         for (i = num; --i >= 0; )
  664.             putpad(DC, 1);
  665.     }
  666.  
  667.     to = sp->s_line + col;
  668.     from = to + num;
  669.  
  670.     byte_copy(from, to, sp->s_length - from + 1);
  671.     clrline(sp->s_length - num, sp->s_length);
  672.     sp->s_length -= num;
  673. }
  674.  
  675. private
  676. InsChar(lineno, col, num, new)
  677. char    *new;
  678. {
  679.     register char    *sp1,
  680.             *sp2,    /* To push over the array. */
  681.             *sp3;    /* Last character to push over. */
  682.     int    i;
  683.  
  684.     i_set(lineno, 0);
  685.     sp2 = Curline->s_length + num;
  686.  
  687.     if (sp2 >= cursend) {
  688.         i_set(lineno, CO - num - 1);
  689.         cl_eol();
  690.         sp2 = cursend - 1;
  691.     }
  692.     Curline->s_length = sp2;
  693.     sp1 = sp2 - num;
  694.     sp3 = Curline->s_line + col;
  695.  
  696.     while (sp1 >= sp3)
  697.         *sp2-- = *sp1--;
  698.  
  699.     new += col;
  700.     byte_copy(new, sp3, num);
  701.     /* The internal screen is correct, and now we have to do
  702.        the physical stuff. */
  703.  
  704.     Placur(lineno, col);
  705.     if (IM) {
  706.         if (!IN_INSmode)
  707.             INSmode(1);
  708.     } else if (M_IC && num > 1) {
  709.         char    minibuf[16];
  710.  
  711.         sprintf(minibuf, M_IC, num);
  712.         putpad(minibuf, num);
  713.     } else if (IC) {
  714.         for (i = 0; i < num; i++)
  715.             putpad(IC, 1);
  716.     }
  717.     for (i = 0; i < num; i++) {
  718.         putchar(new[i]);
  719.         if (IN_INSmode)
  720.             putpad(IP, 1);
  721.     }
  722.     CapCol += num;
  723. }
  724.  
  725. #endif ID_CHAR
  726.  
  727. /* chkmail() returns nonzero if there is new mail since the
  728.    last time we checked. */
  729.  
  730. char    Mailbox[128];    /* initialized in main */
  731. int    MailInt = 60;    /* check no more often than 60 seconds */
  732. #ifdef BIFF
  733. int    BiffChk = NO;    /* whether or not to turn off biff while in JOVE */
  734. #endif
  735.  
  736. chkmail(force)
  737. {
  738.     time_t    now;
  739.     static time_t    last_chk = 0;
  740.     static int    value = FALSE;
  741.     static off_t    last_size = 0;
  742.     struct stat    stbuf;
  743.     int    last_val;
  744.     extern time_t    time0;
  745.  
  746.     time(&now);
  747.     if (!force && (now < last_chk + MailInt))
  748.         return value;
  749.     if (stat(Mailbox, &stbuf) < 0)
  750.         return FALSE;
  751.     last_val = value;
  752.     value = ((stbuf.st_mtime > time0) &&
  753.          (stbuf.st_size > 0) &&
  754.          (stbuf.st_size > last_size) &&
  755.          (stbuf.st_mtime + 5 > stbuf.st_atime));
  756.     last_chk = now;
  757.     last_size = stbuf.st_size;
  758.     if (value == TRUE && value != last_val)
  759.         dobell(3);
  760.     return value;
  761. }
  762.  
  763. /* Print the mode line. */
  764.  
  765. private char    *mode_p,
  766.         *mend_p;
  767. int    BriteMode = 1;        /* modeline should standout */
  768.  
  769. private
  770. mode_app(str)
  771. register char    *str;
  772. {
  773.     if (mode_p >= mend_p)
  774.         return;
  775.     while ((mode_p < mend_p) && (*mode_p++ = *str++))
  776.         ;
  777.     mode_p--;    /* back over the null */
  778. }
  779.  
  780. char    ModeFmt[120] = "%3c %[%sJOVE (%M)   Buffer: %b  \"%f\" %]%s%m*- %((%t)%s%)%e";
  781.  
  782. ModeLine(w)
  783. register Window    *w;
  784. {
  785.     extern int    i_line;
  786.     int    n,
  787.         ign_some = 0;
  788.     char    line[132],
  789.         *fmt = ModeFmt,
  790.         tmp[16],
  791.         fillc,
  792.         c;
  793.     register Buffer    *thisbuf = w->w_bufp;
  794.     register Buffer *bp;
  795.  
  796.     mode_p = line;
  797.     mend_p = &line[(sizeof line) - 1];
  798.  
  799.     if (BriteMode != 0 && SO == 0)
  800.         BriteMode = 0;
  801.     fillc = BriteMode ? ' ' : '-';
  802.  
  803.     while (c = *fmt++) {
  804.         if (c != '%') {
  805.             if (c == '\\')
  806.                 if ((c = *fmt++) == '\0')
  807.                     break;
  808.             if (!ign_some)
  809.                 *mode_p++ = c;
  810.             continue;
  811.         }
  812.         if ((c = *fmt++) == '\0')    /* char after the '%' */
  813.             break;
  814.         if (ign_some && c != ')')
  815.             continue;
  816.         n = 1;
  817.         if (c >= '0' && c <= '9') {
  818.             n = 0;
  819.             while (c >= '0' && c <= '9') {
  820.                 n = n * 10 + (c - '0');
  821.                 c = *fmt++;
  822.             }
  823.         }
  824.         switch (c) {
  825.         case '(':
  826.             if (w->w_next != fwind)    /* Not bottom window. */
  827.                 ign_some++;
  828.             break;
  829.  
  830.         case ')':
  831.             ign_some = 0;
  832.             break;
  833.  
  834.         case 'c':
  835.             while (--n >= 0)
  836.                 *mode_p++ = fillc;
  837.             break;
  838.  
  839.         case '[':
  840.         case ']':
  841.             {
  842.                 char    *strs = (c == '[') ? "[[[[[[[[[[" : "]]]]]]]]]]";
  843.  
  844.                 mode_app(strs + 10 - RecDepth);
  845.             break;
  846.             }
  847.             
  848.         case 's':
  849.             if (mode_p[-1] == ' ')
  850.                 continue;
  851.             *mode_p++ = ' ';
  852.             break;
  853.  
  854.         case 'M':
  855.             {
  856.                 static char    *mmodes[] = {
  857.                 "Fundamental ",
  858.                 "Text ",
  859.                 "C ",
  860. #ifdef LISP
  861.                 "Lisp ",
  862. #endif
  863.                 0
  864.             };
  865.  
  866.                 mode_app(mmodes[thisbuf->b_major]);
  867.  
  868.             if (BufMinorMode(thisbuf, Fill))
  869.                 mode_app("Fill ");
  870.             if (BufMinorMode(thisbuf, Abbrev))
  871.                 mode_app("Abbrev ");
  872.             if (BufMinorMode(thisbuf, OverWrite))
  873.                 mode_app("OvrWt ");
  874.             if (BufMinorMode(thisbuf, Indent))
  875.                 mode_app("AI ");
  876.             if (KeyMacro.m_flags & DEFINE)
  877.                 mode_app("Def ");
  878.             mode_p--;    /* Back over the extra space. */
  879.             break;
  880.             }
  881.  
  882.         case 'b':
  883.             mode_app(thisbuf->b_name);
  884.             break;
  885.  
  886.         case 'f':
  887.         case 'F':
  888.             if (thisbuf->b_fname == 0)
  889.                 mode_app("[No file]");
  890.             else {
  891.                 if (c == 'f')
  892.                     mode_app(pr_name(thisbuf->b_fname));
  893.                 else
  894.                     mode_app(basename(thisbuf->b_fname));
  895.             }
  896.             break;
  897.  
  898.  
  899.         case 'n':
  900.             for (bp = world, n = 1; bp != 0; bp = bp->b_next, n++)
  901.                 if (bp == thisbuf)
  902.                     break;
  903.  
  904.             sprintf(tmp, "%d", n);
  905.             mode_app(tmp);
  906.             break;
  907.  
  908.         case 'm':
  909.             if (IsModified(w->w_bufp))
  910.                 *mode_p++ = fmt[0];
  911.             else
  912.                 *mode_p++ = fmt[1];
  913.             fmt += 2;    /* skip two characters */
  914.             break;
  915.  
  916.         case 't':
  917.             {
  918.             char    timestr[12];
  919.  
  920.                 mode_app(get_time((time_t *) 0, timestr, 11, 16));
  921.             break;
  922.             }
  923.  
  924. #ifdef LOAD_AV
  925.         case 'l':
  926.             {
  927.             double    theavg;
  928.                 char    minibuf[10];
  929.  
  930.                 get_la(&theavg);
  931.                 theavg += .005;    /* round to nearest .01 */
  932.                 sprintf(minibuf, "%d.%02d",
  933.                    (int) theavg,
  934.                    (int)((theavg - (int) theavg) * 100));
  935.                 mode_app(minibuf);
  936.             }
  937.             break;
  938. #endif
  939.  
  940.         case 'C':    /* check mail here */
  941.             if (chkmail(NO))
  942.                 mode_app("[New mail]");
  943.             break;
  944.  
  945. #ifdef CHDIR
  946.         case 'd':    /* print working directory */
  947.             mode_app(pr_name(pwd()));
  948.             break;
  949. #endif
  950.             
  951.         case 'e':
  952.             {
  953.             /* 2 space pad pluss padding for magic cookies */
  954.             char    *last_p = &line[CO - 2 - (2 * SG)];
  955.  
  956.             while (mode_p < last_p)
  957.                 *mode_p++ = fillc;
  958.  
  959.                 goto outahere;        /* %e means we're done! */
  960.             }
  961.         }
  962.     }
  963.  
  964. outahere:
  965.     *mode_p = 0;
  966.  
  967.     /* Highlight mode line. */
  968.     if (BriteMode) {
  969. #ifdef ID_CHAR
  970.         if (IN_INSmode)
  971.             INSmode(0);
  972. #endif
  973.         putpad(SO, 1);
  974.     }
  975.     if (swrite(line, BriteMode, YES))
  976.         do_cl_eol(i_line);
  977.     if (BriteMode)
  978.         putpad(SE, 1);
  979. }
  980.  
  981. RedrawDisplay()
  982. {
  983.     Line    *newtop = prev_line((curwind->w_line = curline), exp_p ?
  984.                 exp : HALF(curwind));
  985.  
  986.     if (newtop == curwind->w_top)
  987.         v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
  988.     else
  989.         SetTop(curwind, newtop);
  990. }
  991.  
  992. v_clear(line1, line2)
  993. register int    line1;
  994. {
  995.     register struct scrimage    *phys_p, *des_p;
  996.  
  997.     phys_p = &PhysScreen[line1];
  998.     des_p = &DesiredScreen[line1];
  999.  
  1000.     while (line1 <= line2) {
  1001.         i_set(line1++, 0);
  1002.         cl_eol();
  1003.         phys_p->s_id = des_p->s_id = 0;
  1004.         phys_p++, des_p++;
  1005.     }
  1006. }
  1007.  
  1008. ClAndRedraw()
  1009. {
  1010.     cl_scr(1);
  1011. }
  1012.  
  1013. NextPage()
  1014. {
  1015.     Line    *newline;
  1016.  
  1017.     if (Asking)
  1018.         return;
  1019.     if (exp < 0) {
  1020.         exp = -exp;
  1021.         PrevPage();
  1022.         return;
  1023.     }
  1024.     if (exp_p == YES)
  1025.         UpScroll();
  1026.     else {
  1027.         if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
  1028.             rbell();
  1029.             return;
  1030.         }
  1031.         newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
  1032.         SetTop(curwind, curwind->w_line = newline);
  1033.         if (curwind->w_bufp == curbuf)
  1034.             SetLine(newline);
  1035.     }
  1036. }
  1037.  
  1038. PrevPage()
  1039. {
  1040.     Line    *newline;
  1041.  
  1042.     if (Asking)
  1043.         return;
  1044.     if (exp < 0) {
  1045.         exp = -exp;
  1046.         NextPage();
  1047.         return;
  1048.     }
  1049.     if (exp_p == YES)
  1050.         DownScroll();
  1051.     else {
  1052.         newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
  1053.         SetTop(curwind, curwind->w_line = newline);
  1054.         if (curwind->w_bufp == curbuf)
  1055.             SetLine(newline);
  1056.     }
  1057. }
  1058.  
  1059. UpScroll()
  1060. {
  1061.     SetTop(curwind, next_line(curwind->w_top, exp));
  1062.     if ((curwind->w_bufp == curbuf) &&
  1063.         (in_window(curwind, curline) == -1))
  1064.         SetLine(curwind->w_top);
  1065. }
  1066.  
  1067. DownScroll()
  1068. {
  1069.     SetTop(curwind, prev_line(curwind->w_top, exp));
  1070.     if ((curwind->w_bufp == curbuf) &&
  1071.         (in_window(curwind, curline) == -1))
  1072.         SetLine(curwind->w_top);
  1073. }
  1074.  
  1075. int    VisBell = 0,
  1076.     RingBell = 0;    /* So if we have a lot of errors ...
  1077.                ring the bell only ONCE */
  1078. rbell()
  1079. {
  1080.     RingBell++;
  1081. }
  1082.  
  1083. /* Message prints the null terminated string onto the bottom line of the
  1084.    terminal. */
  1085.  
  1086. message(str)
  1087. char    *str;
  1088. {
  1089.     if (InJoverc)
  1090.         return;
  1091.     UpdMesg++;
  1092.     errormsg = 0;
  1093.     if (str != mesgbuf)
  1094.         null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
  1095. }
  1096.  
  1097. /* End of Window */
  1098.  
  1099. Eow()
  1100. {
  1101.     if (Asking)
  1102.         return;
  1103.     SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
  1104.             min(SIZE(curwind) - 1, exp - 1)));
  1105.     if (exp_p == NO)
  1106.         Eol();
  1107. }
  1108.  
  1109. /* Beginning of Window */
  1110.  
  1111. Bow()
  1112. {
  1113.     if (Asking)
  1114.         return;
  1115.     SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, exp - 1)));
  1116. }
  1117.  
  1118. private int    LineNo,
  1119.         last_col,
  1120.         DoAutoNL;
  1121. private Window    *old_wind;    /* save the window we were in BEFORE
  1122.                    before we were called, if UseBuffers
  1123.                    is nonzero */
  1124.  
  1125. int    UseBuffers = FALSE;
  1126. int    TOabort = 0;
  1127.  
  1128. /* This initializes the typeout.  If send-typeout-to-buffers is set
  1129.    the buffer NAME is created (emptied if it already exists) and output
  1130.    goes to the buffer.  Otherwise output is drawn on the screen and
  1131.    erased by TOstop() */
  1132.  
  1133. TOstart(name, auto_newline)
  1134. char    *name;
  1135. {
  1136.     if (UseBuffers) {
  1137.         old_wind = curwind;
  1138.         pop_wind(name, YES, B_SCRATCH);
  1139.     }
  1140.     TOabort = LineNo = last_col = 0;
  1141.     DoAutoNL = auto_newline;
  1142. }
  1143.  
  1144. /* VARARGS1 */
  1145.  
  1146. Typeout(fmt, va_alist)
  1147. char    *fmt;
  1148. va_dcl
  1149. {
  1150.     if (TOabort)
  1151.         return;
  1152.  
  1153.     if (!UseBuffers && (LineNo == ILI - 1)) {
  1154.         register int    c;
  1155.  
  1156.         LineNo = 0;
  1157.         last_col = 0;
  1158.         f_mess("--more--");
  1159.         if ((c = getchar()) != ' ') {
  1160.             TOabort++;
  1161.             if (c != CTL(G) && c != RUBOUT)
  1162.                 Ungetc(c);
  1163.             return;
  1164.         }
  1165.         f_mess(NullStr);
  1166.     }
  1167.  
  1168.     if (fmt) {
  1169.         extern int    i_col;
  1170.         char    string[132];
  1171.         va_list    ap;
  1172.  
  1173.         va_start(ap);
  1174.         format(string, sizeof string, fmt, ap);
  1175.         va_end(ap);
  1176.         if (UseBuffers)
  1177.             ins_str(string, NO);
  1178.         else {
  1179.             i_set(LineNo, last_col);
  1180.             (void) swrite(string, NIL, YES);
  1181.             last_col = i_col;
  1182.         }
  1183.     }
  1184.     if (!UseBuffers) {
  1185.         PhysScreen[LineNo].s_id = -1;
  1186.         if (fmt == 0 || DoAutoNL != 0) {
  1187.             cl_eol();
  1188.             flusho();
  1189.             LineNo++;
  1190.             last_col = 0;
  1191.         }
  1192.     } else if (fmt == 0 || DoAutoNL != 0)
  1193.         ins_str("\n", NO);
  1194. }
  1195.  
  1196. TOstop()
  1197. {
  1198.     int    c;
  1199.  
  1200.     if (UseBuffers) {
  1201.         ToFirst();
  1202.         SetWind(old_wind);
  1203.     } else {
  1204.         if (TOabort)
  1205.             return;
  1206.         if (last_col != 0)
  1207.             Typeout((char *) 0);
  1208.         Typeout("----------");
  1209.         cl_eol();
  1210.         flusho();
  1211.         c = getchar();
  1212.         if (c != ' ')
  1213.             Ungetc(c);
  1214.     }
  1215. }
  1216.