home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  42.3 KB  |  1,962 lines

  1. /*
  2.  *  Copyright (c) 1992, 1994 John E. Davis  (davis@amy.tch.harvard.edu)
  3.  *  All Rights Reserved.
  4.  */
  5. #ifdef FLOAT_TYPE
  6. # define JED_VERSION "0.F97.1"
  7. #else
  8. # define JED_VERSION "0.97.1"
  9. #endif 
  10.  
  11. #include "config.h"
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #ifdef pc_system
  16. #include <dos.h>
  17. #endif
  18.  
  19. #include "buffer.h"
  20. #include "screen.h"
  21. #include "window.h"
  22. #include "paste.h"
  23.  
  24. #include "ins.h"
  25. #include "ledit.h"
  26. #include "display.h"
  27. #include "sysdep.h"
  28. #include "misc.h"
  29. #include "vterm.h"
  30. #include "slang.h"
  31. #include "hooks.h"
  32.  
  33. #define fputs(s,f) write(fileno(f), s, strlen(s))
  34.  
  35. Screen_Type JScreen[MAX_SCREEN_SIZE];
  36.  
  37. int Screen_Row = 1;
  38. int Screen_Col = 1;
  39. int Cursor_Motion;    /* indicates cursor movement only -1 ^ v +1 < > */
  40. int Scroll_Region_1;
  41. int Scroll_Region_2;
  42. int Scroll_Lines;
  43. int User_Prefers_Line_Numbers = 0;
  44. int Mode_Has_Syntax_Highlight;
  45. int Wants_Syntax_Highlight;           /* if non-zero, highlight the syntax.
  46.                     */
  47. int Wants_Attributes = 1;
  48. int Wants_HScroll = 20;               /* controls automatic horizontal
  49.                     * scrolling.  If positive, scroll
  50.                     * only line, if negative, whole wind
  51.                     */
  52. int Term_Supports_Color = 1;           /* optimistic assumption */
  53. static Line *HScroll_Line;
  54. static int HScroll;               /* amount to scroll line by */
  55. static int Absolute_Column;
  56.  
  57. void (*X_Update_Open_Hook)(void);      /* hooks called when starting */
  58. void (*X_Update_Close_Hook)(void);     /* and finishing update */
  59.  
  60. int Goal_Column;
  61. int Display_Eight_Bit = 0;
  62. int JED_CSI = -1;
  63.  
  64. unsigned short Point_On_Char;               /* character at cursor position */
  65. static int Point_Cursor_Flag = 1;      /* if non-zero, point cursor */
  66.  
  67. static Line Eob_Line =
  68. {
  69.    NULL, NULL, (unsigned char *) "[EOB]", 5, 5
  70. };
  71.  
  72. int Want_Eob = 0;
  73. int Display_Time = 1;                  /* Turn on %t processing in status line */
  74.  
  75. void blank_line(int row)
  76. {
  77.    int n = JWindow->width;
  78.    register unsigned short *p, *pmax;
  79.    p = JScreen[row].old;
  80.    pmax = p + n;
  81.  
  82.    while (p < pmax) {*p++ = 32; *p++ = 32; *p++ = 32; *p++ = 32;}
  83. }
  84.  
  85. void update_screen_txt(int row)
  86. {
  87.    unsigned short *tmp;
  88.     tmp = JScreen[row].neew;
  89.     JScreen[row].neew = JScreen[row].old;
  90.     JScreen[row].old = tmp;
  91. }
  92. static unsigned char char_width[256];
  93. static int dis8bit = -100;
  94. static int j_csi = -1;
  95. static int Selective_Display = -0x7FFF;
  96.  
  97. #define FIX_CHAR_WIDTH \
  98.   if ((Display_Eight_Bit != dis8bit) || (JED_CSI != j_csi)\
  99.       || (Selective_Display != Buffer_Local.sd)) fix_char_width()
  100.  
  101.  
  102. static int fix_attributes(register unsigned short *p, register unsigned short *pmax, 
  103.               unsigned int color)
  104. {
  105.    if (pmax == NULL) pmax = p + JWindow->width;
  106.    if (p >= pmax) return(0);
  107.    color = color << 8;
  108.    while (p < pmax)
  109.      {
  110.     *p = color | (*p & 0xFF);
  111.     p++;
  112.      }
  113.    return(1);
  114. }
  115.  
  116.  
  117. int output(unsigned char *line, int len, int row, register int max_col, 
  118.        register int column_offset, unsigned char *hi_beg, unsigned char *hi_end)
  119. {
  120.    register unsigned char ch, *p, *pmax, *b;
  121.    register unsigned short *outp;
  122.    register int count;
  123.    unsigned char expb[80];
  124.    unsigned short *out, *mark, *hi0_outp = NULL, *hi1_outp = NULL, *sp, *spmax;
  125.    int tab, tabsize, visible, i, mini, w;
  126.    int done = 0;
  127.  
  128.    outp = out = JScreen[row - 1].neew;
  129.    if (outp == NULL) return 1;
  130.    tab = Buffer_Local.tab;
  131.    count = 0;
  132.    visible = 0;
  133.  
  134.    mini = 1;
  135.    while(mini >= 0)
  136.      {
  137.     /* deal with mini_buffer prompt */
  138.     if (mini && (IS_MINIBUFFER) && Mini_Info.prompt_len)
  139.       {
  140.          p = (unsigned char *) Mini_Info.prompt;
  141.          pmax = p + Mini_Info.prompt_len;
  142.          mini = 0;
  143.       }
  144.     else
  145.       {
  146.          p = line;
  147.          pmax = p + len;
  148.          mini = -1;
  149.       }
  150.  
  151.     while(p < pmax)
  152.       {
  153.          if (p == hi_beg) hi0_outp = outp;
  154.          if (p == hi_end) hi1_outp = outp;
  155.  
  156.          ch = (unsigned char) *p++;
  157.          b = expb;
  158.          /* expand char to display form */
  159.          
  160.          w = *(char_width + (unsigned int) ch);
  161.          if (w == 1)
  162.            {
  163.           /* try to optimize this by putting this here */
  164.           
  165.           count++;
  166.           if ((count < max_col) && (count >= column_offset))
  167.             {
  168.                *outp++ = (unsigned short) ch;
  169.             }
  170.           else if (count >= max_col)
  171.             {
  172.                done = 1;
  173.                p = pmax;
  174.             }
  175.           continue;
  176.            }
  177.          else if (w == 3)
  178.            {
  179.           if (ch == '\r')
  180.             {
  181.                *b++ = '.'; *b++ = '.'; *b++ = '.';
  182.                done = -1;
  183.                p = pmax;
  184.             }
  185.           else
  186.             {
  187.                *b++ = '~';
  188.                *b++ = '^';
  189.                
  190.                /* Be better to replace following by:
  191.             * *b++ = ch - '@';
  192.             */
  193.                ch &= 0x7F;
  194.                *b++ = (ch == 127) ? '?' : ch  + 'A' - 1;
  195.             }
  196.           
  197.            }
  198.          else if (w == 2)
  199.            {
  200.           if ((ch == '\t') && (tab > 0))
  201.             {
  202.                tabsize = tab * (count / tab + 1) - count;
  203.                i = 0; while (i++ < tabsize) *b++ = ' ';
  204.                w = tabsize;
  205.             }
  206.           else if (ch & 0x80)
  207.             {
  208.                *b++ = '~'; *b++ = ch & 0x7F;
  209.             }
  210.           else
  211.             {
  212.                *b++ = '^';
  213.                /* Be better to replace following by:
  214.             * *b++ = (ch | 0x80) - '@';
  215.             */
  216.                
  217.                *b++ = (ch == 127) ? '?' : ch  + 'A' - 1;
  218.             }
  219.            
  220.            }
  221.          else               /* w = 0 */
  222.            {
  223.           ch = *p++;           /* skip next char */
  224.           continue;
  225.            }
  226.  
  227.          b = expb;
  228.          while (w--)
  229.            {
  230.           count++;
  231.           if (count >= max_col)
  232.             {
  233.                done = 1;
  234.                p = pmax;
  235.             }
  236.           
  237.           else if (count >= column_offset)
  238.             {
  239.                *outp++ = (unsigned short) *b;
  240.             }
  241.           b++;
  242.            }
  243.       }
  244.      }
  245.  
  246.  
  247.    sp = out;
  248.    while (sp < outp) 
  249.      {
  250.     if (*sp++ != ' ') 
  251.       {
  252.          visible++;
  253.          break;
  254.       }
  255.      }
  256.    
  257.    if (outp == out)
  258.      {
  259.     *outp++ = '$';
  260.     visible = 1;
  261.      }
  262.    else if (column_offset > 1)
  263.      {
  264.     *out = '$';
  265.     visible++;
  266.      }
  267.    
  268.    if (Wants_Syntax_Highlight && Mode_Has_Syntax_Highlight
  269. #if !defined(pc_system) && !defined(__os2__)
  270.        && (*tt_Use_Ansi_Colors && Term_Supports_Color)
  271. #endif
  272.        && (line != Eob_Line.data))
  273.      syntax_highlight (out, outp);
  274.  
  275.    
  276.    mark = outp;
  277.    sp = outp;  spmax = out + JWindow->width;
  278. #if defined(msdos) && !defined(__WATCOMC__)
  279.    asm mov bx, di
  280.    asm mov cx, word ptr spmax
  281.    asm sub cx, word ptr outp
  282.    asm shr cx, 1
  283.    asm mov ax, 32
  284.    asm les di, dword ptr outp
  285.    asm cld
  286.    asm rep stosw
  287.    asm mov di, bx
  288.    /* Note that outp is not updated here! */
  289. #else
  290. /*   MEMSET((char *) sp, (char) ' ',  sizeof(short) * (int) (spmax - sp)); */
  291.    /* This line burns some CPU */
  292.    while (sp < spmax) {*sp++ = 0x0020; *sp++ = 0x0020; *sp++ = 0x0020; *sp++ = 0x0020;}
  293. #endif
  294.    if (done == 1)
  295.      {
  296.     mark = out + (JWindow->width - 1);
  297.     *mark = '$';
  298.     visible += 1;
  299.     if ((hi_beg != NULL) && (hi0_outp == NULL)) hi0_outp = mark;
  300.     mark = NULL;
  301.      }
  302.    out[JWindow->width] = '\0';
  303.    
  304.    /* fix highlighting on this line */
  305.    if ((Wants_Attributes) && (hi0_outp != NULL))
  306.      {
  307.     if (hi1_outp == NULL) hi1_outp = outp + 1;
  308.     visible += fix_attributes(hi0_outp, hi1_outp, JREGION_COLOR);
  309.      }
  310.    
  311.  
  312.    if (visible)
  313.      {
  314. #ifdef msdos
  315.     (void) mark;
  316.     /* 2nd and last parameters not used in msdos smartputs so they do
  317.        not need to be valid */
  318.     tt_smart_puts(out, out, *tt_Screen_Cols, row - 1);
  319. #else
  320.     /* if (mark != NULL) *mark = 0; */
  321.     tt_smart_puts(out, JScreen[row-1].old, *tt_Screen_Cols, row - 1);
  322.     /* if (mark != NULL) *mark = ' ';  */
  323. #endif
  324.     JScreen[row-1].n = visible;
  325.     Point_Cursor_Flag = 1;
  326.      }
  327.  
  328.    /* else take care of it in calling routine */
  329.    return(visible);
  330. }
  331.  
  332. void display_line(Line *line, int row)
  333. {
  334.    int len, cofs = JWindow->column;
  335.    Screen_Type *s = &JScreen[row - 1];
  336.  
  337.    if (line != NULL)
  338.      {
  339.     len = line->len;
  340.     if (len && (row != *tt_Screen_Rows)
  341.         && (line->data[len - 1] == '\n')) 
  342.       {
  343.          if ((s->hi1 != NULL) && (s->hi1 == line->data + len)) s->hi1--;
  344.          len--;
  345.       }
  346.     
  347.     if ((len > 0) || (cofs > 1)
  348.         || ((row == *tt_Screen_Rows) && Mini_Info.prompt_len))
  349.       {
  350.          if (Wants_HScroll && (line == HScroll_Line) && HScroll)
  351.            {
  352.           cofs += HScroll;
  353.            }
  354.          
  355.          len = output(line->data, len, row,
  356.               cofs + JWindow->width - 1, cofs,
  357.               s->hi0, s->hi1);
  358.       }
  359.      }
  360.    else len = 0;
  361.    
  362.    if (len <= 0)
  363.      {
  364.     if (s->n)
  365.       {
  366.          tt_goto_rc(row - 1, 0);
  367.          Screen_Row = row;
  368.          tt_del_eol();
  369.       }
  370.     blank_line(row - 1);
  371.     s->n = 0;
  372.      }
  373.    s->line = line;
  374.    s->flags = 0;
  375.    /* s->hi0 = s->hi1 = NULL; */
  376.    if (len > 0) update_screen_txt(row-1);
  377. }
  378.  
  379. static void mark_window_attributes(int wa)
  380. {
  381.    register Screen_Type *s = &JScreen[JWindow->top - 1], 
  382.      *smax = s + JWindow->rows, *s1, *s2;
  383.    Mark *m;
  384.    register Line *l = JWindow->beg.line, *ml;
  385.    unsigned char *hi0, *hi1;
  386.    int mn, pn, dn;
  387.    
  388.    s1 = s;
  389.    
  390.    if ((CBuf->vis_marks == 0) || (wa == 0) || (Wants_Attributes == 0))
  391.      {
  392.     s2 = s;
  393.     goto done;               /* I hate gotos but they are convenient */
  394.      }
  395.    m = CBuf->marks;
  396.    
  397.    while ((m->flags & VISIBLE_MARK) == 0) m = m->next;    
  398.    ml = m->line;
  399.    mn = m->n;                   /* already in canonical form */
  400.    pn = LineNum + CBuf->nup;           /* not in canonical form */
  401.    dn = pn - mn;
  402.    
  403.    while (l != CLine)               /* find pos of point in window */
  404.      {
  405.     s1++;
  406.     l = l->next;
  407.      }
  408.    
  409.    /* s1 now points at current line */
  410.    /* The whole point of all of this is to preserve the screen flags without
  411.       touching the screen.  */
  412.    
  413.    if (dn > 0)                   /* mark on prev lines */
  414.      {
  415.     s2 = s1 + 1;
  416.     hi0 = l->data;
  417.     hi1 = l->data + Point;
  418.     if ((s1->hi0 != hi0) || (s1->hi1 != hi1))
  419.       {
  420.          s1->hi0 = hi0; s1->hi1 = hi1;
  421.          s1->flags = 1;
  422.       }
  423.     l = l->prev; s1--;
  424.     while ((s1 >= s) && (l != ml)) 
  425.       {
  426.          hi0 = l->data;
  427.          hi1 = l->data + l->len;
  428.          if ((s1->hi0 != hi0) || (s1->hi1 != hi1))
  429.            {
  430.           s1->hi0 = hi0; s1->hi1 = hi1;
  431.           s1->flags = 1;
  432.            }
  433.          l = l->prev; s1--;
  434.       }
  435.     if (s1 >= s)
  436.       {
  437.          hi0 = ml->data + m->point;
  438.          hi1 = ml->data + ml->len;
  439.          if ((s1->hi0 != hi0) || (s1->hi1 != hi1))
  440.            {
  441.           s1->hi0 = hi0; s1->hi1 = hi1;
  442.           s1->flags = 1;
  443.            }
  444.          s1--;
  445.       }
  446.      }
  447.    else if (dn < 0)               /* mark ahead of point */
  448.      {
  449.     s2 = s1;
  450.     s1--;
  451.     hi0 = l->data + Point;
  452.     hi1 = l->data + l->len;
  453.     if ((s2->hi0 != hi0) || (s2->hi1 != hi1))
  454.       {
  455.          s2->hi0 = hi0; s2->hi1 = hi1;
  456.          s2->flags = 1;
  457.       }
  458.     
  459.     l = l->next;
  460.     s2++;
  461.     while ((s2 < smax) && (l != ml)) 
  462.       {
  463.          hi0 = l->data;
  464.          hi1 = l->data + l->len;
  465.          if ((s2->hi0 != hi0) || (s2->hi1 != hi1))
  466.            {
  467.           s2->hi0 = hi0; s2->hi1 = hi1;
  468.           s2->flags = 1;
  469.            }
  470.          l = l->next;
  471.          s2++;
  472.       }
  473.     if (s2 < smax)
  474.       {
  475.          hi0 = ml->data;
  476.          hi1 = ml->data + m->point;
  477.          if ((s2->hi0 != hi0) || (s2->hi1 != hi1))
  478.            {
  479.           s2->hi0 = hi0; s2->hi1 = hi1;
  480.           s2->flags = 1;
  481.            }
  482.          s2++;
  483.       }
  484.      }
  485.    else                       /* same line */
  486.      {
  487.     if (Point < m->point)
  488.       {
  489.          s1->hi0 = l->data + Point;
  490.          s1->hi1 = l->data + m->point;
  491.       }
  492.     else
  493.       {
  494.          s1->hi1 = l->data + Point;
  495.          s1->hi0 = l->data + m->point;
  496.       }
  497.     s1->flags = 1;
  498.     s2 = s1 + 1;
  499.     s1--;
  500.      }
  501.    
  502.    done:                   /* reached if there is no mark */
  503.    
  504.    /* now do area outside the region */
  505.    while (s1 >= s)
  506.      {
  507.     if (s1->hi0 != NULL)
  508.       {
  509.          s2->hi1 = s1->hi0 = NULL;
  510.          s1->flags = 1;
  511.       }
  512.     s1--;
  513.      }
  514.    
  515.    while (s2 < smax)
  516.      {
  517.     if (s2->hi0 != NULL)
  518.       {
  519.          s2->hi1 = s2->hi0 = NULL;
  520.          s2->flags = 1;
  521.       }
  522.     s2++;
  523.      }
  524. }
  525.  
  526.  
  527. void open_scroll(void)
  528. {
  529.     Scroll_Region_1 = 1;
  530.     Scroll_Region_2 = *tt_Screen_Rows;
  531.     Scroll_Lines = 0;
  532. }
  533.  
  534. void do_scroll_up(int n)
  535. {
  536.    tt_goto_rc(0,0);
  537.    tt_delete_nlines(n);
  538. }
  539.  
  540. void do_scroll_down(int n)
  541. {
  542.    tt_goto_rc(0, 0);
  543.    tt_reverse_index(n);
  544. }
  545.  
  546. void execute_scroll(void)
  547. {
  548.    if (Scroll_Lines > 0)
  549.      {
  550.     tt_set_scroll_region(Scroll_Region_1 - 1, Scroll_Region_2 - 1);
  551.     execute_vscroll_up(Scroll_Region_1, Scroll_Region_2, Scroll_Lines);
  552.     do_scroll_up(Scroll_Lines);
  553.     
  554.      }
  555.    else if (Scroll_Lines < 0)
  556.      {
  557.     tt_set_scroll_region(Scroll_Region_1 - 1, Scroll_Region_2 - 1);
  558.     execute_vscroll_down(Scroll_Region_1, Scroll_Region_2, -Scroll_Lines);
  559.     do_scroll_down(-Scroll_Lines);
  560.      }
  561.    Scroll_Lines = 0;
  562. }
  563.  
  564. void queue_scroll(int n, int r1, int r2)
  565. {
  566.    if ((r1 != Scroll_Region_1) || (r2 != Scroll_Region_2))
  567.      {
  568. /*    if ((n == -1) && (Scroll_Region_1 == r1 + Scroll_Lines)
  569.            && (Scroll_Region_2 == r2))  */
  570.     if ((n == -1) && (Scroll_Region_1 == r1 + Scroll_Lines)
  571.         && (Scroll_Region_2 == r2))  Scroll_Lines--;
  572.     else if ((n == -1) && (Scroll_Region_1 == r1 + Scroll_Lines)
  573.          && (Scroll_Region_2 == r2 - 1))
  574.       {
  575.          Scroll_Region_2 = r2;
  576.          Scroll_Lines--;
  577.       }
  578.  
  579.     else
  580.       {
  581.          execute_scroll();
  582.          Scroll_Region_1 = r1;
  583.          Scroll_Region_2 = r2;
  584.          Scroll_Lines = n;
  585.       }
  586.      }
  587.    else Scroll_Lines += n;
  588. }
  589.  
  590. void close_scroll(void)
  591. {
  592.     if (Scroll_Lines) execute_scroll();
  593.     if ((Scroll_Region_1 != 1) || (Scroll_Region_2 != *tt_Screen_Rows))
  594.      tt_reset_scroll_region();
  595. }
  596.  
  597. /* Here a scrolling region (t,b) is used to scroll line t + n to t.  All
  598.    that is assumed is that  the line at t + n exists! */
  599.  
  600. int scroll_up(int n, int t, int b)
  601. {
  602.     int i, necess;
  603.  
  604.     if (n == 0) return(0);
  605.  
  606.     /* t = JWindow->top - 1 + t;
  607.        b = JWindow->top - 1 + b; */
  608.  
  609.     /* check to see if this is really necessary */
  610.     necess = 0;
  611.     for (i = t - 1; i < b; i++)
  612.       {
  613.           if (JScreen[i].n)
  614.             {
  615.                 necess = 1;
  616.                 break;
  617.             }
  618.       }
  619.  
  620.     if (!necess) return(0);
  621.  
  622.     queue_scroll(n, t, b);
  623.  
  624.     vscroll_up(t,b,n);
  625.  
  626.     return(necess);
  627. }
  628.  
  629. /* Here a scrolling region (t,b) is used to scroll line t + n to t. */
  630.  
  631. void scroll_down(int n, int t, int b)
  632. {
  633.     if (n == 0) return;
  634.  
  635.     /* t = JWindow->top - 1 + t;
  636.        b = JWindow->top - 1 + b; */
  637.     tt_set_scroll_region(t - 1,b - 1);
  638.     tt_reverse_index(n);
  639.     tt_reset_scroll_region();
  640.  
  641.     vscroll_down(t,b,n);
  642. }
  643.  
  644. int update_insert_line(int r1, Line *line)
  645. {
  646.     int i, r2, r, necess;
  647.     Line *bot;
  648.  
  649.     /* normalize r1: */
  650.     /* r1 = JWindow->top - 1 + r1; */
  651.  
  652.     /* find the first one that is blank to delimit the region so that the
  653.        loss will be minimal */
  654.  
  655.     r = r1;   /* not r1 + 1 as obvious (but naive) as it seems */
  656.     r2 = JWindow->rows + JWindow->top - 1;
  657.     while (r < r2)
  658.       {
  659.      bot = JScreen[r - 1].line;
  660.      if ((bot == NULL) || (bot == &Eob_Line)) break;
  661.           r++;
  662.       }
  663.  
  664.     if ((r1 != r2) && (r == r2))
  665.     /* we may have failed so check the bottom up so we don't push linesoff. */
  666.      {
  667.     bot = line;
  668.     for (r = r1 + 1; r <= r2; r++)
  669.       {
  670.          bot = bot->next;
  671.          if (bot == NULL) break;
  672.          if (JScreen[r-1].line == bot) break;
  673.       }
  674.     if ((bot != NULL) && (r <= r2)) r--;
  675.     if (r > r2) r = r2;
  676.      }
  677.  
  678.    if (r < r1) r = r1;
  679.    r2 = r;
  680.  
  681.     /* check to see if we gain by doing this */
  682.     necess = 0;
  683.     for (i = r1 - 1; i < r2; i++)
  684.       {
  685.           if (JScreen[i].n)
  686.             {
  687.                 necess = 1;
  688.                 break;
  689.             }
  690.       }
  691.     if (r1 == r2) return(0);
  692.     if (!necess) return(0);
  693.  
  694.     queue_scroll(-1, r1, r2);
  695.  
  696.     vscroll_down(r1, r2, 1);
  697.     return(1);
  698. }
  699.  
  700. Line *find_top()
  701. {
  702.     int n, i;
  703.     Line *line, *next, *prev, *tthis;
  704.    
  705.     n = JWindow->rows - 1;
  706.  
  707.     if (!n) return(CLine);
  708.     /* Check the top window line.  Chances are that one of the lines
  709.      above CLine will match in usual situations */
  710.     line = JScreen[JWindow->top - 1].line;
  711.     prev = CLine;
  712.  
  713.     if (line != NULL) for (i = 0; i < JWindow->rows; i++)
  714.       {
  715.           if (prev == line) return(line);
  716.           tthis = prev->prev;
  717.           if (tthis == NULL) break;
  718.           else prev = tthis;
  719.       }
  720.  
  721.     /*  That was the obvious choice now try some others */
  722.     /* try bottom (or punt) */
  723.    if (*tt_Term_Cannot_Scroll) 
  724.      {
  725.     if (*tt_Term_Cannot_Scroll == -1)
  726.       {
  727.          if ((line != NULL) && (CLine->next == line)) return (CLine);
  728.          if (CLine->prev != JScreen[JWindow->rows + JWindow->top - 2].line) n = n / 2;
  729.       }
  730.     else n = n / 2;
  731.     goto no_scroll;
  732.      }
  733.    
  734.    line = JScreen[JWindow->rows + JWindow->top - 2].line;
  735.    next = CLine;
  736.  
  737.     if (line != NULL) for (i = 0; i < JWindow->rows; i++)
  738.       {
  739.           if (next == line)
  740.             {
  741.                 line = CLine;
  742.                 while(i < JWindow->rows - 1)
  743.                   {
  744.                       prev = line->prev;
  745.                       if (prev == NULL) return(line);
  746.                       line = prev;
  747.                       i++;
  748.                   }
  749.                 return(line);
  750.             }
  751.           next = next->next;
  752.           if (next == NULL) break;
  753.       }
  754.     /* try to find CLine somewhere in the window */
  755.  
  756.     next = CLine->next;
  757.     prev = CLine->prev;
  758.  
  759.     for (i = JWindow->top - 1; i < JWindow->top - 1 + JWindow->rows; i++)
  760.       {
  761.          tthis = JScreen[i].line;
  762.          if (tthis == CLine)
  763.            {
  764.               line = CLine;
  765.               while(i > JWindow->top - 1)
  766.                 {
  767.             i--;
  768.             line = line->prev;
  769.             if (line == NULL) return(CLine);
  770.                 }
  771.  
  772.               return(line);
  773.            }
  774.          else if ((tthis == prev) && (tthis != NULL))
  775.            {
  776.                i--;
  777.                while(i-- > JWindow->top - 1)
  778.                  {
  779.                      if (prev->prev == NULL) return(prev);
  780.                      prev = prev->prev;
  781.                  }
  782.                return(prev);
  783.            }
  784.          else if ((tthis == next) && (tthis != NULL))
  785.            {
  786.                i++;
  787.                while(i-- > JWindow->top - 1)
  788.                  {
  789.                      if (next->prev == NULL) return(next);
  790.                      next = next->prev;
  791.                  }
  792.                return(next);
  793.            }
  794.  
  795.       }
  796.  
  797.     /* not found so check neighbors */
  798.     line = CLine->next;
  799.     if ((line != NULL) && (line == JScreen[JWindow->top - 1].line)) return(CLine);
  800.  
  801.     line = CLine->prev;
  802.     if ((line == NULL) || (line != JScreen[n + JWindow->top - 1].line))
  803.       {
  804.          n = n / 2;
  805.       }
  806.    
  807.    no_scroll:                   /* on terms that cannot scroll */
  808.    
  809.     line = prev = CLine;
  810.     while(n--)
  811.       {
  812.           line = line->prev;
  813.           if (line == NULL) return(prev);
  814.           prev = line;
  815.       }
  816.  
  817.     return(line);
  818. }
  819.  
  820. void do_scroll(register Line *top)
  821. {
  822.    Line *bot, *middle1, *middle2, *s;
  823.    register Line *sline;
  824.    int r1, r, r2, match, overwrite = 1, scroll_region_set = 0, srs, nrows;
  825.    int n1, n2, n3 = 0;
  826.    /* unsigned short sh; */
  827.    
  828.    nrows = JWindow->rows;
  829.     r1 = JWindow->top;
  830.     r2 = r1 + nrows - 1;
  831.    
  832.    /* Actually it might be more benificial to extend r2 to a status line.  
  833.      The status line is easy to detect since it begins with a highlighted
  834.      minus sign.  */
  835. /*   
  836.    r = r2;
  837.    while (r < *tt_Screen_Rows - 1)
  838.      {
  839.     sh = JScreen[r].old[0];
  840.     if (((sh & 0xFF) == '-') && (sh >> 8)) break;
  841.     r++;
  842.      }
  843.    nrows = r - r1 + 1;
  844.    r2 = r;
  845. */
  846.      
  847.  
  848.     open_scroll();
  849.     if (top != NULL) bot = top->next; else bot = NULL;
  850.  
  851.    
  852.     middle1 = middle2 = NULL;
  853.    r = 1;
  854.    bot = top;
  855.    n1 = nrows / 3;
  856.    n2 = 2 * n1;
  857.    
  858.    /* I do not want to use CLine and the previous one as a basis 
  859.     for determining scroll region since we may have just created it. 
  860.     There is nothing right or wrong about it--- just a feeling that
  861.     results in optimization of screen update. */
  862.    while (r++ < nrows)
  863.      {
  864.     if ((r >= n1) && (middle1 == NULL) && (bot != NULL)
  865.         && (bot != CLine) && (bot != CLine->prev)) middle1 = bot;
  866.     if ((r >= n2) && (middle2 == NULL) && (bot != NULL)
  867.         && (bot != CLine) && (bot != CLine->prev))
  868.     
  869.       {
  870.          middle2 = bot;
  871.          n2 = bot->len;
  872.       }
  873.     
  874.     if (bot != NULL) bot = bot -> next;
  875.      }
  876.    /* if the middle or the bottom lines match, we do not overwrite */
  877.  
  878.    if (bot != NULL) n3 = bot->len;
  879.    if (middle1 == NULL) overwrite = 0; 
  880.    else
  881.      {
  882.     n1 = middle1->len;
  883.     /* I do not want to scroll if only 1 thing matches */
  884.     for (r = r1; r <= r2; r++) 
  885.       {
  886.          s = JScreen[r - 1].line;
  887.          if (((middle1 == s) && (n1 == s->len)
  888.           && (middle1->data[n1 / 2] == s->data[n1 / 2]))
  889.          || ((middle2 == s) && (middle2 != NULL) && (n2 == s->len)
  890.           && (middle2->data[n2 / 2] == s->data[n2 / 2]))
  891.          || ((bot != NULL) && (bot == s) && (n3 > 4) && (n3 == s->len)
  892.              && (bot->data[n3/2] == s->data[n3 / 2])))
  893.            {
  894.           overwrite = 0;
  895.           break;
  896.            }
  897.       }
  898.      }
  899.    
  900.    while(r1 <= r2)
  901.      {
  902.      if (top == NULL) break;
  903.      match = 0;
  904.      for(r = r1; r <= r2; r++)
  905.        {
  906.           sline = JScreen[r - 1].line;
  907.           if (sline == top)
  908.         {
  909.            if (r != r1)
  910.              {
  911.             scroll_region_set = 0;
  912.             scroll_up(r - r1, r1, r2);
  913.              }
  914.  
  915.            r1++;
  916.            match = 1;
  917.            if (top != NULL) top = top->next;
  918.            break;
  919.         }
  920.        }
  921.  
  922.      if (match) continue;
  923.  
  924.      /* not found so insert it */
  925.      if ((top != NULL) && (!overwrite))
  926.        {
  927.           srs = update_insert_line(r1, top);
  928.           if (!scroll_region_set) scroll_region_set = srs;
  929.        }
  930.      if (top != NULL) top = top->next;
  931.      r1++;
  932.       }
  933.  
  934.    /*     if (scroll_region_set) reset_scroll_region(); */
  935.    close_scroll();
  936.    if (overwrite) touch_window();
  937. }
  938.  
  939. static void fix_char_width(void)
  940. {
  941.    int i;
  942.    for (i = 0; i < 32; i++) 
  943.      {
  944.     char_width[i] = 2;
  945.     char_width[i + 128] = 3;
  946.      }
  947.    
  948.    for (i = 32; i < 127; i++) 
  949.      {
  950.     char_width[i] = 1;
  951.     char_width[i + 128] = 2;
  952.      }
  953.    char_width[127] = 2;
  954.    char_width[255] = 3;
  955.    
  956.    if (Display_Eight_Bit > 0)
  957.      {
  958.     for (i = (Display_Eight_Bit > 127 ? Display_Eight_Bit : 128);
  959.          i < 256; i++)
  960.       {
  961.          char_width[i] = 1;
  962.       }
  963.      }
  964.    dis8bit = Display_Eight_Bit;
  965.    if ((Selective_Display = Buffer_Local.sd) < 0)
  966.      {
  967.     char_width[(unsigned char) '\r'] = 3;
  968.      }
  969.    if (JED_CSI > 0) char_width[(unsigned char) JED_CSI] = 0;
  970.    j_csi = JED_CSI;
  971. }
  972.  
  973.  
  974. void point_column(int n)
  975. {
  976.    register unsigned char *p, *pmax;
  977.    register int i;
  978.    int tab, w;
  979.  
  980.    FIX_CHAR_WIDTH;
  981.    if (IS_MINIBUFFER) n -= Mini_Info.effective_prompt_len;
  982.  
  983.     p = CLine->data;
  984.  
  985.     pmax = p + (CLine->len - 1);
  986.     if (*pmax != '\n') pmax++;
  987.  
  988.     tab = Buffer_Local.tab;
  989.     i = 0;
  990.     n--;   /* start at 0 */
  991.     while(p < pmax)
  992.       {
  993.          if ((*p == '\t') && tab)
  994.        {
  995.           i = tab * (i / tab + 1);
  996.        }
  997.      else 
  998.        {
  999.           w = char_width[*p];
  1000.           i +=  w;
  1001.           if (w == 0) p++;
  1002.        }
  1003.      
  1004.      if ((i > n) || ((Selective_Display < 0) && (*p == '\r'))) break;
  1005.      p++;
  1006.       }
  1007.     Point = (int) (p - CLine->data);
  1008. }
  1009.  
  1010. /* given a position in a line, return apparant distance from bol
  1011.    expanding tabs, etc... up to pos.  
  1012.  
  1013.    Note**** misc.c calls this using the minibuffer prompt.  This routine
  1014.    can only depend on Point and CLine->data but not CLine->len!!
  1015. */
  1016. int calculate_column()
  1017. {
  1018.    register int i;
  1019.    int tab, w;
  1020.    register unsigned char *cw = char_width;
  1021.    register unsigned char ch, *pos, *this_pos;
  1022.  
  1023.    FIX_CHAR_WIDTH;
  1024.    pos = CLine->data;
  1025.     this_pos = pos + Point;
  1026.     i = 1;
  1027.     tab = Buffer_Local.tab;
  1028.     while(pos < this_pos)
  1029.       {
  1030.      ch = *pos++;
  1031.      if ((ch == '\t') && tab)
  1032.        {
  1033.           i = tab * ((i - 1)/tab + 1) + 1;  /* tab column tabs */
  1034.        }
  1035.      else 
  1036.        {
  1037.           w = cw[ch];
  1038.           /* w = char_width[ch]; */
  1039.           i += w;
  1040.           if (w == 0) pos++;
  1041.        }
  1042.      
  1043.      if ((ch == '\r') && (Selective_Display < 0)) break;
  1044.       }
  1045.    Absolute_Column = i;
  1046.  
  1047.     if (IS_MINIBUFFER) i += Mini_Info.effective_prompt_len;
  1048.  
  1049.     Screen_Col = i;
  1050.     return (i);
  1051. }
  1052.  
  1053. void point_cursor(int c)
  1054. {
  1055.     int r, row;
  1056.     Line *tthis;
  1057.  
  1058.    if (JWindow->trashed) return;
  1059.     r = 0;
  1060.    Point_Cursor_Flag = 0;
  1061.    for (row = JWindow->top; row < JWindow->top + JWindow->rows; row++)
  1062.      {
  1063.      tthis = JScreen[row-1].line;
  1064.      if (tthis == NULL) break;
  1065.      if ((tthis == CLine) || (tthis == &Eob_Line))
  1066.        {
  1067.           r = row;
  1068.           break;
  1069.        }
  1070.       }
  1071.    
  1072.     if (Point >= CLine->len)
  1073.       {
  1074.       Point = CLine->len - 1;
  1075.  
  1076.       if (Point < 0) Point = 0;
  1077.       else if ((*(CLine->data + Point) != '\n') 
  1078.            || (CBuf == MiniBuffer)) Point++;
  1079.       }
  1080.  
  1081.     if (r)
  1082.       {
  1083.      if (!c) c = calculate_column();
  1084.      
  1085.      c = c - JWindow->column + 1;
  1086.      if (CLine == HScroll_Line) c -= HScroll;
  1087.      if (c < 1) c = 1; else if (c > JWindow->width) c = JWindow->width;
  1088.      Point_On_Char = JScreen[r - 1].old[c - 1];
  1089.      tt_goto_rc (r - 1 , c - 1);
  1090.      Screen_Row = r;
  1091.      Screen_Col = c;
  1092.       }
  1093.     else
  1094.      {
  1095.     msg_error("Point not visible in Window.");
  1096.     c = 1;
  1097.      }
  1098.    flush_output ();
  1099.    if (!Cursor_Motion) Goal_Column = c;
  1100. }
  1101.  
  1102. static unsigned short *stat_cpy(register unsigned short *s1, register unsigned char *v, register unsigned short *smax)
  1103. {
  1104.    register char ch;
  1105.    if (v == NULL) return (s1);
  1106.    
  1107.    while ((s1 < smax) && ((ch = *v++) != 0))
  1108.      {
  1109.     if (ch < ' ')
  1110.       {
  1111.          *s1++ = (unsigned short) '^';
  1112.          if (s1 < smax) *s1++ = (unsigned short) (ch + '@');
  1113.       }
  1114.     else *s1++ = ch;
  1115.      }
  1116.    return (s1);
  1117. }
  1118.  
  1119. /* site.sl should modify this */
  1120.  
  1121. char Default_Status_Line[80] = 
  1122.        " ^Ke: quit, ^Kg: get file, ^K^W: write file | %b  (%m%n%o) %p";
  1123.  
  1124. static unsigned long Status_Last_Time;
  1125. static unsigned long Status_This_Time;
  1126.  
  1127. static char *status_get_time(void)
  1128. {
  1129.    static char status_time[10];
  1130.    register char *t, ch, *t1;
  1131.    char am;
  1132.    int n;
  1133.    
  1134.    if (Display_Time == 0) return (NULL);
  1135.    if (Status_This_Time == 0) Status_This_Time = sys_time();
  1136.    if (Status_This_Time - Status_Last_Time >= 30)
  1137.      {
  1138.     Status_Last_Time = Status_This_Time;
  1139.     am = 'a';
  1140.     t = get_time();
  1141.     /* returns a string like:  "Tue Nov 2 13:18:19 1993" */
  1142.     t1 = status_time;
  1143.     while (ch = *t, (ch <= '0') || (ch > '9')) t++;
  1144.     /* on date number, skip it */
  1145.     while (*t++ != ' ');
  1146.     if (*t == '0') t++;
  1147.     if (Display_Time > 0)
  1148.       {
  1149.          n = 0;
  1150.          while ((ch = *t++) != ':')
  1151.            {
  1152.           n = 10 * n + (int) (ch - '0');
  1153.            }
  1154.          if (n >= 12) am = 'p';
  1155.          n = n % 12;
  1156.          if (n == 0) n = 12;
  1157.          if (n >= 10)
  1158.            {
  1159.           n -= 10;
  1160.           *t1++ = '1';
  1161.            }
  1162.          *t1++ = '0' + n;
  1163.          *t1++ = ':';
  1164.          while ((*t1++ = *t++) != ':');
  1165.          *(t1 - 1) = am; *t1++ = 'm'; *t1 = 0;
  1166.       }
  1167.     else
  1168.       {
  1169.          *t1++ = '[';
  1170.          while ((*t1++ = *t++) != ':');
  1171.          while ((*t1++ = *t++) != ':');
  1172.          *--t1 = ']'; *++t1 = 0;
  1173.       }
  1174.      }
  1175.    return (status_time);
  1176. }
  1177.  
  1178. static unsigned short *finish_status(unsigned short *s1, unsigned short *smax, int col_flag)
  1179. {
  1180.    unsigned int line, maxline;
  1181.    register char *v, ch;
  1182.    Line *l;
  1183.    int top, rows;
  1184.    char pstr[20], *str, col_buf[20];
  1185.    unsigned short *s1_save = s1;
  1186.    
  1187.  
  1188.    /* line = w->mark.n - buf->nup; */
  1189.    line = LineNum;
  1190.    maxline = Max_LineNum;
  1191.    
  1192.    if (!User_Prefers_Line_Numbers)
  1193.      {
  1194.     top = JWindow->top - 1;    rows = JWindow->rows - 1;
  1195.     l = JScreen[top + rows].line;
  1196.     if (l == CBuf->end) l = NULL;
  1197.     if (JScreen[top].line == CBuf->beg)
  1198.       {
  1199.          if (l == NULL) strcpy(pstr,"All");
  1200.          else strcpy(pstr,"Top");
  1201.       }
  1202.     else if (l == NULL) strcpy(pstr, "Bot");
  1203.     else
  1204.       {
  1205.          sprintf(pstr, "%d%%", 
  1206.              (int) ((line * 100L) / (long) maxline));
  1207.       } 
  1208.      }
  1209.    else sprintf(pstr, "%d/%d", line, maxline);
  1210.    
  1211.    v = CBuf->status_line;
  1212.    if (*v == 0) v = Default_Status_Line;
  1213.    
  1214.    while (((ch = *v++) != 0) && (s1 < smax))
  1215.      {
  1216.     if (ch != '%') *s1++ = ch;
  1217.     else 
  1218.       {
  1219.          ch = *v++;
  1220.          switch (ch)
  1221.            {
  1222.         case 'a': 
  1223.           if (CBuf->flags & ABBREV_MODE) str = " abbrev"; else str = NULL;
  1224.           break;
  1225.         case 'f': str = CBuf->file; break;
  1226.         case 'n': 
  1227.           if (CBuf->narrow != NULL) str = " Narrow"; else str = NULL;
  1228.           break;
  1229.         case 'o':
  1230.           if (CBuf->flags & OVERWRITE_MODE) str = " Ovwrt"; else str = NULL;
  1231.           break;
  1232.         case 'b': str = CBuf->name; break;
  1233.         case 'p': str = pstr; break;
  1234.         case 'v': str = JED_VERSION; break;
  1235.         case 'm': str = CBuf->mode_str; break;
  1236.         case 't': str = status_get_time(); break;
  1237.         case 'c': if (User_Prefers_Line_Numbers > 1)
  1238.             {
  1239.                if (col_flag) (void) calculate_column ();
  1240.                sprintf(col_buf, "%d",  Absolute_Column);
  1241.                str = col_buf;
  1242.             }
  1243.           else 
  1244.             {
  1245.                /* 100 to 1 that there is punctuation before this, kill it */
  1246.                if (s1 > s1_save) s1--;
  1247.                str = NULL;
  1248.             }
  1249.           
  1250.           break;
  1251.             
  1252.                
  1253.         case '%': str = "%"; break;
  1254.         default: return(s1);
  1255.            }
  1256.          if (str != NULL) s1 = stat_cpy(s1, (unsigned char *) str, smax);
  1257.       }
  1258.      }
  1259.    return (s1);
  1260. }
  1261.  
  1262. void set_status_format(char *f, int *local)
  1263. {
  1264.    char *s;
  1265.    if (*local) s = Default_Status_Line; else s = CBuf->status_line;
  1266.    strncpy(s, f, 79);
  1267.    s[79] = 0;
  1268. }
  1269.  
  1270.  
  1271.  
  1272. void make_status_line(int col_flag)
  1273. {
  1274.    unsigned short mrk, flag, spot, star, ubit = '-';
  1275.    register unsigned short *s1, *s, *smax;
  1276.  
  1277.    if (JWindow->top == *tt_Screen_Rows) return;   /* minibuffer ? */
  1278.    s = JScreen[JWindow->rows + JWindow->top - 1].neew;
  1279.    smax = s + JWindow->width;
  1280.    mrk = flag = spot = star = '-';
  1281.    if (CBuf->marks != NULL) mrk = 'm';
  1282.    if (CBuf->flags & FILE_MODIFIED) flag = 'd';
  1283.    if (CBuf->spots != NULL) spot = 's';
  1284.    if (CBuf->flags & BUFFER_TRASHED) star = '*';
  1285.    if (CBuf->flags & READ_ONLY) star = '%';
  1286.    if (CBuf->flags & UNDO_ENABLED) ubit = '+';
  1287.  
  1288.    s1 = s;
  1289.    if (JWindow->column != 1) *s1++ = '<'; else *s1++ = '-';
  1290.    *s1++ = star; *s1++ = star; *s1++ = mrk; *s1++ = flag; 
  1291.    *s1++ = spot; 
  1292.  
  1293.    if (CBuf->flags & BINARY_FILE) *s1++ = 'B'; 
  1294. #ifdef pc_system
  1295.    else if ((CBuf->flags & ADD_CR_ON_WRITE_FLAG) == 0) *s1++ = 'L';
  1296. #else
  1297. #ifdef unix
  1298.    else if (CBuf->flags & ADD_CR_ON_WRITE_FLAG) *s1++ = 'C';
  1299. #endif
  1300. #endif
  1301.    else *s1++ = '-';
  1302.  
  1303.    *s1++ = ubit; 
  1304.    s1 = finish_status(s1, smax, col_flag);
  1305.    if (Defining_Keyboard_Macro) s1 = stat_cpy(s1, (unsigned char *) " [Macro]", smax);
  1306.    while (s1 < smax) *s1++ = '-';
  1307.    *smax = 0;
  1308.    (void) fix_attributes (s, smax, JSTATUS_COLOR);
  1309. }
  1310.  
  1311. int update_status_line(int col_flag)
  1312. {
  1313.     int r;
  1314.  
  1315.    if (JWindow->top == *tt_Screen_Rows) return(0);   /* minibuffer ? */
  1316.    r = JWindow->rows + JWindow->top - 1;
  1317.    make_status_line(col_flag);
  1318.    
  1319.    tt_smart_puts(JScreen[r].neew, JScreen[r].old, *tt_Screen_Cols, r);
  1320.    Point_Cursor_Flag = 1;
  1321.    update_screen_txt(r);
  1322.    JScreen[r].n = *tt_Screen_Cols;
  1323.    return(1);
  1324. }
  1325.  
  1326. /* if force then do update otherwise return 1 if update or 0 if not */
  1327. int update_1(Line *top, int force)
  1328. {
  1329.    int i;
  1330.    Window_Type *w;
  1331.    int did_eob = 0, time_has_expired = 0;
  1332.    
  1333.  
  1334.    if (Batch || 
  1335.        (!force 
  1336.     && (Executing_Keyboard_Macro || (Repeat_Factor != NULL)
  1337.         || Input_Buffer_Len || input_pending(&Number_Zero) 
  1338.         || (Read_This_Character != NULL)))
  1339.        || (CBuf != JWindow->buffer))
  1340.        
  1341.      {
  1342.      return(0);
  1343.      }
  1344.    
  1345.    if (Suspend_Screen_Update != 0) 
  1346.      {
  1347.     Suspend_Screen_Update = 0;
  1348.     touch_screen ();
  1349.      }
  1350.    
  1351.    
  1352.    JWindow->mark.line = CLine;
  1353.    JWindow->mark.point = Point;
  1354.    JWindow->mark.n = LineNum + CBuf->nup;
  1355.    CBuf->linenum = LineNum;
  1356.    CBuf->max_linenum = Max_LineNum;
  1357.    
  1358.    if (Wants_Attributes && CBuf->vis_marks)
  1359.      {
  1360.     JWindow->trashed = 1;
  1361.      }
  1362.    
  1363.    /* Do not bother setting this unless it is really needed */
  1364.    if (Display_Time) 
  1365.      {
  1366.     Status_This_Time = sys_time();
  1367.     time_has_expired = (Status_This_Time > Status_Last_Time + 45);
  1368.      }
  1369.    
  1370.    /* if cursor moves just left right, do not update status line */
  1371.    if (!force && !JWindow->trashed && 
  1372.        ((JWindow == JWindow->next) || (User_Prefers_Line_Numbers && Cursor_Motion))
  1373.     /* if % wanted, assume user is like me and gets annoyed with 
  1374.        screen updates */
  1375.        && (User_Prefers_Line_Numbers || time_has_expired))
  1376.        
  1377.      {
  1378.     update_status_line(0);
  1379.     return(1);
  1380.      }
  1381.  
  1382.    if (!JWindow->trashed && Cursor_Motion) return(1);
  1383.  
  1384.     w = JWindow;
  1385.     do
  1386.       {
  1387.      if (Wants_Syntax_Highlight) init_syntax_highlight ();
  1388.      did_eob = 0;
  1389.      if (top == NULL) top = find_top();
  1390.      JWindow->beg.line = top;
  1391.  
  1392.      /* scroll the screen to optimal location */
  1393.      if (0 == *tt_Term_Cannot_Scroll) do_scroll(top);
  1394.      
  1395.      mark_window_attributes((w == JWindow) || (w->buffer != CBuf));
  1396.  
  1397.      for (i = JWindow->top - 1; i < JWindow->rows + JWindow->top - 1; i++)
  1398.        {
  1399.           /* the next line is really optional */
  1400. #ifndef pc_system
  1401.           if (!force && (Exit_From_MiniBuffer ||  
  1402.                  input_pending(&Number_Zero))) break;
  1403. #endif
  1404.           if ((JScreen[i].line != top) || (JScreen[i].flags)
  1405.           || (Want_Eob && !did_eob && (i != *tt_Screen_Rows - 1)))
  1406.         {
  1407.            if (((top == NULL) || (top->len == 0)) 
  1408.                && (Want_Eob && !did_eob && !(CBuf->flags & READ_ONLY)))
  1409.              {
  1410.             display_line(&Eob_Line, i + 1);
  1411.             
  1412.             /* JScreen[i].line = top; */
  1413.             did_eob = 1;
  1414.              }
  1415.            else display_line(top, i + 1);
  1416.         }
  1417.           if (top != NULL) top = top->next;
  1418.        }
  1419.      
  1420.      HScroll_Line = NULL;
  1421.      Mode_Has_Syntax_Highlight = 0;
  1422.      if (!force && input_pending(&Number_Zero))
  1423.        {
  1424.           while(JWindow != w) other_window();
  1425.           JWindow->trashed = 1;  /* since cursor not pointed */
  1426.           return(0);
  1427.        }
  1428.      else update_status_line(w != JWindow);
  1429.      JWindow->trashed = 0;
  1430.      other_window();
  1431.      top = NULL;
  1432.      /* if (!JWindow->trashed) top = JWindow->beg.line; else  top = NULL; */
  1433.      
  1434.       } while(JWindow != w);
  1435.    return(1);
  1436. }
  1437.  
  1438. int Mini_Ghost = 0;
  1439.  
  1440. void update_minibuffer(void)
  1441. {
  1442.    Window_Type *w;
  1443.  
  1444.    if (Executing_Keyboard_Macro) return;
  1445.    if (MiniBuffer != NULL)
  1446.      {
  1447.     w = JWindow;
  1448.     while (!IS_MINIBUFFER) other_window();
  1449.     if ((*Message_Buffer) && JScreen[*tt_Screen_Rows - 1].n) (void) input_pending(&Number_Ten);
  1450.     JWindow->beg.line = CLine;
  1451.     mark_window_attributes(1);
  1452.     display_line(CLine, *tt_Screen_Rows);
  1453.     while (w != JWindow) other_window();
  1454.     Mini_Ghost = 1;
  1455.      }
  1456.    else if (Mini_Ghost && !*Error_Buffer && !*Message_Buffer)
  1457.      {
  1458.     /* if < 0, it is a result of flush message so let it pass this round */
  1459.     if (Mini_Ghost < 0) Mini_Ghost = 1;
  1460.     else
  1461.       {
  1462.          display_line(NULL, *tt_Screen_Rows);
  1463.          if (!JWindow->trashed) point_cursor(0);
  1464.          Mini_Ghost = 0;
  1465.       }
  1466.      }
  1467.    else Mini_Ghost = ((*Message_Buffer) || (*Error_Buffer));
  1468. }
  1469.  
  1470. void do_dialog(char *b)
  1471. {
  1472.    int len = 0, dout, row = *tt_Screen_Rows - 1;
  1473.    char *quit = "Quit!";
  1474.    
  1475.    if (Batch) return;
  1476.    FIX_CHAR_WIDTH;
  1477.    if (! *b)
  1478.      {
  1479.     if(!SLKeyBoard_Quit) return;
  1480.     b = quit; 
  1481.      }
  1482.    if (MiniBuffer)
  1483.      {
  1484.     len = Mini_Info.prompt_len;
  1485.     Mini_Info.prompt_len = 0;
  1486.      }
  1487.  
  1488.    if ((b == Error_Buffer) || (b == quit)) touch_screen();
  1489.    dout = output((unsigned char *) b, strlen(b), 
  1490.          *tt_Screen_Rows, *tt_Screen_Cols, 1, NULL, NULL);
  1491.    if (MiniBuffer) Mini_Info.prompt_len = len;
  1492.    
  1493.    if ((b == Error_Buffer) || (SLKeyBoard_Quit))
  1494.      {
  1495.     beep();
  1496.     flush_input();
  1497.      }
  1498.    
  1499.    if (!dout)
  1500.      {
  1501.     if (JScreen[row].n)
  1502.       {
  1503.          tt_goto_rc(*tt_Screen_Rows - 1, 0);
  1504.          tt_del_eol();
  1505.       }
  1506.     blank_line(row);
  1507.     JScreen[row].n = 0;
  1508.       }
  1509.    else 
  1510.      {
  1511.     update_screen_txt(row);
  1512.     if (MiniBuffer != NULL) 
  1513.       {
  1514.          flush_output ();
  1515.          (void) input_pending(&Number_Ten);
  1516.       }
  1517.      }
  1518.    
  1519.    Mini_Ghost = -dout;
  1520. }
  1521.  
  1522. static void set_hscroll(int col)
  1523. {
  1524.    int hdiff, whs = abs(Wants_HScroll), wc = JWindow->column - 1,
  1525.       sw = *tt_Screen_Cols - 1;
  1526.    static Line *last;
  1527.    Line *tmp;
  1528.    
  1529.    /* take care of last effect of horizontal scroll */
  1530.    if (last != NULL)
  1531.      {
  1532.     tmp = CLine;
  1533.     CLine = last;
  1534.     register_change(0);
  1535.     CLine = tmp;
  1536.     if (last != CLine) 
  1537.       {
  1538. #if 0
  1539.          /* I need to think about this more */
  1540.          if (Wants_HScroll < 0) 
  1541.            {
  1542.           if (wc != 0)
  1543.             {
  1544.                JWindow->column = 1;
  1545.                wc = 0;
  1546.                touch_window ();
  1547.             }
  1548.            }
  1549. #endif
  1550.          HScroll = 0;
  1551.       }
  1552.     
  1553.     last = NULL;
  1554.      }
  1555.    
  1556.    col--;                   /* use 0 origin */
  1557.    hdiff = col - wc;
  1558.    if ((HScroll >= hdiff) 
  1559.        || (HScroll <= hdiff - sw))
  1560.      {
  1561.     if (hdiff >= sw)
  1562.       {
  1563.          HScroll = hdiff - sw + whs;
  1564.       }
  1565.     else if ((hdiff == 0) && (wc == 0)) HScroll = 0;
  1566.     else if (hdiff <= 1)
  1567.       {
  1568.          HScroll = hdiff - whs - 1;
  1569.       }
  1570.     else HScroll = 0;
  1571.      }
  1572.    
  1573.    if (HScroll)
  1574.      {
  1575.     if (wc + HScroll < 0) HScroll = -wc;
  1576.  
  1577.     if (Wants_HScroll < 0)
  1578.       {
  1579.          JWindow->column += HScroll;
  1580.          touch_window();
  1581.          HScroll = 0;
  1582.       }
  1583.     else 
  1584.       {
  1585.          register_change(0);
  1586.          last = HScroll_Line = CLine;
  1587.       }
  1588.      }
  1589. }
  1590.    
  1591. static char Top_Screen_Line_Buffer[132] = "If you see this, you have an installation problem.";
  1592.  
  1593. void define_top_screen_line (char *neew)
  1594. {
  1595.    SLang_push_string (Top_Screen_Line_Buffer);
  1596.    strncpy (Top_Screen_Line_Buffer, neew, 130);
  1597.    Top_Screen_Line_Buffer[131] = 0;
  1598.    JScreen[0].flags = 1;
  1599. }
  1600.  
  1601. static void update_top_screen_line (void)
  1602. {
  1603.    register unsigned short *s, *smax, *s1;
  1604.    register unsigned char ch, *chp;
  1605.    
  1606.    if (Top_Window_Row == 1) return;
  1607.    
  1608.    chp = (unsigned char *) Top_Screen_Line_Buffer;
  1609.    
  1610.    s = s1 = JScreen[0].neew;
  1611.    smax = s + JWindow->width;
  1612.    
  1613.    while ((s1 < smax) && ((ch = *chp++) != 0))
  1614.      {
  1615.     *s1++ = (unsigned short) ch;
  1616.      }
  1617.    while (s1 < smax) *s1++ = ' ';
  1618.    *smax = 0;
  1619.    (void) fix_attributes (s, smax, JMENU_COLOR);
  1620.    
  1621.    tt_smart_puts(JScreen[0].neew, JScreen[0].old, *tt_Screen_Cols, 0);
  1622.    Point_Cursor_Flag = 1;
  1623.    update_screen_txt(0);
  1624.    JScreen[0].n = *tt_Screen_Cols;
  1625.    JScreen[0].flags = 0;
  1626. }
  1627.  
  1628.     
  1629.  
  1630. /* if flag is non-zero, do not touch the message/error buffers */
  1631. void update(Line *line, int force, int flag)
  1632. {
  1633.    int pc_flag = 1;
  1634.    int col;
  1635.    static unsigned long last_time;
  1636.    Line *hscroll_line_save;
  1637.  
  1638.    if (Batch) return;
  1639.    
  1640.    if (!force && !SLang_Error && !SLKeyBoard_Quit && (!*Error_Buffer))
  1641.      {
  1642.     if (Input_Buffer_Len || input_pending (&Number_Zero))
  1643.       {
  1644.          JWindow->trashed = 1;
  1645.          return;
  1646.       }
  1647.      }
  1648.    
  1649.    
  1650.    if (last_time + 30 < Status_This_Time)
  1651.      {
  1652.     if (last_time == 0) last_time = Status_This_Time;
  1653.     else
  1654.       {
  1655.          last_time = Status_This_Time;
  1656.          (void) SLang_run_hooks ("update_timer_hook", NULL, NULL);
  1657.          flag = 0;
  1658.       }
  1659.      }
  1660.    
  1661.  
  1662.    if (Suspend_Screen_Update != 0) 
  1663.      {
  1664.     Suspend_Screen_Update = 0;
  1665.     touch_screen ();
  1666.      }
  1667.  
  1668.    if (X_Update_Open_Hook != NULL) (*X_Update_Open_Hook) ();
  1669.    FIX_CHAR_WIDTH;
  1670.    
  1671.    col = calculate_column();
  1672.    HScroll_Line = NULL;
  1673.    if (Wants_HScroll) set_hscroll(col); else HScroll = 0;
  1674.    hscroll_line_save = HScroll_Line;
  1675.    
  1676.    if (SLang_Error) flag = 0;           /* update hook invalidates flag */
  1677.    
  1678.    if (SLang_Error && !(*Error_Buffer || SLKeyBoard_Quit)) SLang_doerror(NULL);
  1679.    
  1680.    if (!flag && (*Error_Buffer || SLKeyBoard_Quit))
  1681.      {
  1682.     do_dialog(Error_Buffer);
  1683.     SLKeyBoard_Quit = 0;
  1684.     SLang_restart(0);
  1685.     SLang_Error = 0;
  1686.     flag = 0;
  1687.     Mini_Ghost = 1;
  1688.     (void) update_1(line, 1);
  1689.     update_minibuffer();
  1690.      }
  1691.    else if (!flag && *Message_Buffer)
  1692.      {
  1693.     if (!update_1(line, force))
  1694.       {
  1695.          /* *Message_Buffer = 0; */
  1696.          goto done;
  1697.       }
  1698.     Mini_Ghost = 1;
  1699.     do_dialog(Message_Buffer);
  1700.     update_minibuffer();
  1701.      }
  1702.    else
  1703.      {
  1704.     pc_flag = JWindow->trashed || (JWindow != JWindow->next) || Cursor_Motion;
  1705.     if (!flag) update_minibuffer();
  1706.     if (!update_1(line, force)) goto done;
  1707.      }
  1708.    if (!flag) *Error_Buffer = *Message_Buffer = 0;
  1709.    
  1710.    if ((Top_Window_Row != 1) && JScreen[0].flags)
  1711.      {
  1712.     update_top_screen_line ();
  1713.      }
  1714.    
  1715.    
  1716.    done:
  1717.  
  1718.    HScroll_Line = hscroll_line_save;
  1719.  
  1720.    if (Point_Cursor_Flag || pc_flag) point_cursor(col);
  1721.    if (X_Update_Close_Hook != NULL) (*X_Update_Close_Hook) ();
  1722.    flush_output ();
  1723. }
  1724.  
  1725. /* search for the CLine in the SCreen and flag it as changed */
  1726. /* n = 0 means line was changed, n = 1 means it was destroyed */
  1727. void register_change(int n)
  1728. {
  1729.    Window_Type *w;
  1730.    register Screen_Type *s, *smax;
  1731.    register Line *cl = CLine;
  1732.  
  1733.    JWindow->trashed = 1;
  1734.    if (Suspend_Screen_Update) return;
  1735.    if (No_Screen_Update)
  1736.       {
  1737.       No_Screen_Update = 0;
  1738.           if (((n == CINSERT) || (n == CDELETE)) && (JWindow->next == JWindow))
  1739.         {
  1740.            /* Since no screen update, we are probably safe to do: */
  1741.            /* JScreen[Screen_Row - 1].flags = 1; */
  1742.            return;
  1743.         }
  1744.       w = JWindow->next;  /* skip this window */
  1745.       }
  1746.     else w = JWindow;
  1747.  
  1748.     do
  1749.       {
  1750.      s = &JScreen[w->top - 1];
  1751.      smax = s + w->rows;
  1752.      
  1753.      while (s < smax)
  1754.         {
  1755.            if (s->line == cl)
  1756.          {
  1757.             s->flags = 1;
  1758.             if ((n == NLDELETE) || (n == LDELETE)) s->line = NULL;
  1759.             w->trashed = 1;
  1760.          }
  1761.            s++;
  1762.         }
  1763.       w = w->next;
  1764.       }
  1765.     while(w != JWindow);
  1766. }
  1767.  
  1768. void reset_display()
  1769. {
  1770.    int i;
  1771.    unsigned short *p;
  1772.    if (Batch) return;
  1773.      
  1774.    tt_reset_video ();
  1775.    tt_del_eol ();
  1776.    for (i = 0; i < *tt_Screen_Rows; i++)
  1777.      {
  1778.     p = JScreen[i].old;  if (p != NULL) SLFREE(p); JScreen[i].old = NULL;
  1779.     p = JScreen[i].neew;  if (p != NULL) SLFREE(p); JScreen[i].neew = NULL;
  1780.      }
  1781.    flush_output ();
  1782. }
  1783.  
  1784. void init_display(int g)
  1785. {
  1786.    int i, r, c;
  1787.    unsigned short *old, *neew = NULL;
  1788.  
  1789.    if (Batch) return;
  1790.    if (g) 
  1791.      {
  1792.     get_term_dimensions(&c, &r);
  1793.     if (r > MAX_SCREEN_SIZE) r = MAX_SCREEN_SIZE;
  1794.     if (JWindow != NULL)
  1795.       {
  1796.          /* Note that this next call will call this routine again 
  1797.             with g = 0. */
  1798.          change_screen_size (c, r);
  1799.          return;
  1800.       }
  1801.     
  1802.     *tt_Screen_Cols = c; 
  1803.     *tt_Screen_Rows = r;
  1804.      }
  1805.    
  1806.    tt_init_video();
  1807.    
  1808.    for (i = 0; i < *tt_Screen_Rows; i++)
  1809.      {
  1810.     /* these are bigger to handle overflow in output routine in case
  1811.      * special char occurs at end as well as allowing code as in blank_line*/
  1812.     if ((NULL == (old = (unsigned short *) SLCALLOC(*tt_Screen_Cols + 3, sizeof(short))))
  1813.         || (NULL == (neew = (unsigned short *) SLCALLOC(*tt_Screen_Cols + 3, sizeof(short)))))
  1814.       {
  1815.          exit_error("init_display(): malloc error.", 0);
  1816.       }
  1817.  
  1818.     JScreen[i].line = NULL;
  1819.     JScreen[i].flags = 1;
  1820.     JScreen[i].n = 0;
  1821.     JScreen[i].old = old;
  1822.     JScreen[i].neew = neew;
  1823.     neew = old + *tt_Screen_Cols;
  1824.     while (old < neew) *old++ = ' ';
  1825.      }
  1826. }
  1827.  
  1828.  
  1829. void redraw_screen(int force)
  1830. {
  1831.    int row, center;
  1832.    Window_Type *w;
  1833.    Line *l;
  1834.    
  1835.    
  1836.    if (Batch) return;
  1837. #ifndef msdos
  1838.    /* send_string_to_term("\033[?6h"); */  /* relative origin mode */
  1839.    tt_reset_scroll_region();
  1840.    tt_end_insert();
  1841. #endif
  1842.    tt_normal_video ();
  1843.    tt_cls();
  1844.    for (row = 0; row < *tt_Screen_Rows; row++)
  1845.      {
  1846.     JScreen[row].line = NULL;
  1847.     JScreen[row].n = 0;
  1848.     JScreen[row].flags = 1;
  1849.     blank_line(row);
  1850.      }
  1851.     w = JWindow;
  1852.     center = JWindow->trashed;
  1853.     do
  1854.       {
  1855.      w->trashed = 1;
  1856.      w = w->next;
  1857.       }
  1858.     while(w != JWindow);
  1859.    
  1860.    if (center)
  1861.      {
  1862.     for (row = 0; row < JWindow->rows; row++)
  1863.       {
  1864.          JScreen[row + JWindow->top - 1].line = NULL;
  1865.       }
  1866.     l = NULL;
  1867.      }
  1868.    else l = JWindow->beg.line;
  1869.    update(l, force, 0);
  1870. }
  1871.  
  1872. int redraw ()
  1873. {
  1874.    redraw_screen(0);
  1875.    return 0;
  1876. }
  1877.  
  1878. void recenter(int *np)
  1879. {
  1880.    Line *l = CLine;
  1881.    int i, n = *np;
  1882.    
  1883.    JWindow->trashed = 1;
  1884.    if (n == 0) 
  1885.      {
  1886.     n = JWindow->rows / 2;
  1887.     for (i = 0; i < n; i++)
  1888.       {
  1889.          if (l->prev == NULL) break;
  1890.          l = l->prev;
  1891.       }
  1892.     JWindow->beg.line = l;
  1893.     JWindow->beg.n -= i;
  1894.     JWindow->beg.point = 0;
  1895.     redraw();
  1896.     return;
  1897.      }
  1898.    
  1899.    if (CBuf != JWindow->buffer) return;
  1900.    
  1901.    if ((n <= 0) || (n > JWindow->rows)) n = JWindow->rows / 2;
  1902.    while (--n)
  1903.      { 
  1904.     l = l->prev;
  1905.     if (l == NULL)
  1906.       {
  1907.          l = CBuf->beg;
  1908.          break;
  1909.       }
  1910.      }
  1911.    
  1912.    update(l, 0, 0);
  1913. }
  1914.  
  1915.  
  1916. int window_line(void)
  1917. {
  1918.    Line *top = find_top();
  1919.    int n = 1;
  1920.    
  1921.    if (CBuf != JWindow->buffer) return(0);
  1922.    while ((top != NULL) && (top != CLine))
  1923.      {
  1924.     n++;
  1925.     top = top->next;
  1926.      }
  1927.    return(n);
  1928. }
  1929.  
  1930.    
  1931. void touch_window()
  1932. {
  1933.     int i;
  1934.  
  1935.    if (Suspend_Screen_Update) return;
  1936.     for (i = 0; i < JWindow->rows; i++)
  1937.       {
  1938.      JScreen[i + JWindow->top - 1].flags = 1;
  1939.       }
  1940.  
  1941.     JWindow->trashed = 1;
  1942. }
  1943.  
  1944.  
  1945. void touch_screen()
  1946. {
  1947.    Window_Type *w;
  1948.    
  1949.    No_Screen_Update = 0;
  1950.    if (Suspend_Screen_Update) return;
  1951.    w = JWindow;
  1952.    do
  1953.      {
  1954.     touch_window();
  1955.     JWindow = JWindow->next;
  1956.      }
  1957.    while(w != JWindow);
  1958.    if (Top_Window_Row != 1) JScreen[0].flags = 1;
  1959. }
  1960.  
  1961.  
  1962.