home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / se / part03 / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-01-25  |  22.7 KB  |  1,105 lines

  1. #ifndef lint
  2. static char RCSid[] = "$Header: screen.c,v 1.3 86/07/17 17:22:19 arnold Exp $";
  3. #endif
  4.  
  5. /*
  6.  * $Log:    screen.c,v $
  7.  * Revision 1.3  86/07/17  17:22:19  arnold
  8.  * Senddelay() moved to term.c, where it belongs.
  9.  * 
  10.  * Revision 1.2  86/05/27  17:46:46  osadr
  11.  * Fix for early 4.2 BSD systems to use <sys/time.h> instead of <time.h>.
  12.  * 
  13.  * Revision 1.1  86/05/06  13:38:18  osadr
  14.  * Initial revision
  15.  * 
  16.  * 
  17.  */
  18.  
  19. /*
  20. ** screen.c
  21. **
  22. ** screen handling functions for the screen editor.
  23. */
  24.  
  25.  
  26. #include "se.h"
  27. #include "extern.h"
  28. #ifdef BSD4_2
  29. #include <sys/time.h>
  30. #else
  31. #include <time.h>
  32. #endif
  33.  
  34. /* clrrow --- clear out all of a row except the bar */
  35.  
  36. clrrow (row)
  37. register int row;
  38. {
  39.     loadstr ("", row, 0, BARCOL - 1);
  40.     loadstr ("", row, BARCOL + 1, Ncols - 1);
  41. }
  42.  
  43.  
  44.  
  45. /* display_message --- copy contents of message file to screen */
  46.  
  47. display_message (fp)
  48. FILE *fp;
  49. {
  50.     char lin[MAXCOLS];
  51.     char *fgets ();
  52.     int row, col, eof, k;
  53.     static char more[] = " M O R E   T O   C O M E ";
  54.  
  55.     if (Toprow > 0)
  56.     {
  57.         Topln = max (0, Topln - (Toprow - 1));
  58.         Toprow = 0;
  59.     }
  60.  
  61.     eof = NO;
  62.     for (row = Toprow; row <= Botrow; row++)
  63.     {
  64.         if (fgets (lin, Ncols, fp) == NULL)
  65.         {
  66.             eof = YES;
  67.             break;
  68.         }
  69.         Toprow++;
  70.         Topln++;
  71.         lin[strlen (lin)] = EOS;        /* remove '\n' */
  72.         loadstr (lin, row, 0, Ncols);
  73.     }
  74.  
  75.     if (eof == NO)
  76.     {
  77.         k = (Ncols - strlen (more)) / 2;
  78.         for (col = 0; col < k; col++)
  79.             load ('*', row, col);
  80.  
  81.         for (k = 0; more[k] != EOS; k++, col++)
  82.             load (more[k], row, col);
  83.  
  84.         for (; col < Ncols; col++)
  85.             load ('*', row, col);
  86.  
  87.         Toprow++;
  88.         Topln++;
  89.         row++;
  90.     }
  91.  
  92.     for (col = 0; col < Ncols; col++)
  93.         load ('-', row, col);
  94.     Toprow++;
  95.     Topln++;
  96.  
  97.     if (Topln > Lastln)
  98.         adjust_window (0, Lastln);
  99.  
  100.     if (Curln < Topln)
  101.         Curln = Topln;
  102.  
  103.     First_affected = Topln;        /* must rewrite the whole screen */
  104.  
  105.     mesg ("Enter o- to restore display", HELP_MSG);
  106.  
  107.     if (eof == YES)
  108.         return (EOF);
  109.  
  110.     return (OK);
  111. }
  112.  
  113. static char smargin[] = "MARGIN";
  114.  
  115. /* getcmd --- read a line from the terminal (for se) */
  116.  
  117. getcmd (lin, col1, curpos, termchar)
  118. char *lin, *termchar;
  119. int col1, *curpos;
  120. {
  121.     int cursor, nlpos, prev_cursor, prev_status, status,
  122.     scan_pos, tab_pos, first, strlen (),
  123.     scan_tab (), scan_char (), cread ();
  124.     char c;
  125.  
  126.     nlpos = strlen (lin) - 1;
  127.     if (nlpos == -1 || lin[nlpos] != '\n')
  128.         nlpos++;
  129.  
  130.     if (*curpos < 0)
  131.         cursor = 0;
  132.     else if (*curpos >= MAXLINE - 1)
  133.         cursor = nlpos;
  134.     else
  135.         set_cursor (*curpos, &status, &cursor, &nlpos, lin);
  136.     prev_cursor = cursor;
  137.  
  138.     watch ();    /* display the time of day */
  139.  
  140.     switch (Nchoise) {    /* update the line number display */
  141.     case CURLINE:
  142.         litnnum ("line ", Curln, LINE_MSG);
  143.         break;
  144.     case LASTLINE:
  145.         litnnum ("$ = ", Lastln, LINE_MSG);
  146.         break;
  147.     case TOPLINE:
  148.         litnnum ("# = ", Topln, LINE_MSG);
  149.         break;
  150.     default:
  151.         mesg ("", LINE_MSG);
  152.         break;
  153.     }
  154.  
  155.     if (cursor + 1 < Warncol)    /* erase the column display */
  156.         mesg ("", COL_MSG);
  157.  
  158.     *termchar = EOS;    /* not yet terminated */
  159.     status = OK;
  160.     prev_status = ERR;
  161.     first = col1;
  162.  
  163.     while (*termchar == EOS)
  164.     {
  165.         lin[nlpos] = EOS;    /* make sure the line has an EOS */
  166.         if (status == ERR)    /* last iteration generated an error */
  167.             twrite (1, "\007", 1);    /* Bell */
  168.         else if (prev_status == ERR)    /* last one OK but one before had error */
  169.             mesg ("", CHAR_MSG);
  170.  
  171.         prev_status = status;
  172.         status = OK;
  173.  
  174.         if (first > cursor)     /* do horiz. scroll if needed */
  175.             first = cursor;
  176.         else if (first < cursor - Ncols + POOPCOL + 1)
  177.             first = cursor - Ncols + POOPCOL + 1;
  178.  
  179.         if (first == col1)      /* indicate horizontally shifted line */
  180.             load ('|', Cmdrow, BARCOL);
  181.         else if (first > col1)
  182.             load ('<', Cmdrow, BARCOL);
  183.         else if (first < col1)
  184.             load ('>', Cmdrow, BARCOL);
  185.         loadstr (&lin[first], Cmdrow, POOPCOL, Ncols - 1);
  186.  
  187.         if (cursor == Warncol - 1 && prev_cursor < Warncol - 1)
  188.             twrite (1, "\007", 1);   /* Bell */
  189.         if (cursor >= Warncol - 1)
  190.             litnnum ("col ", cursor + 1, COL_MSG);
  191.         else if (prev_cursor >= Warncol - 1)
  192.             mesg ("", COL_MSG);
  193.  
  194.         position_cursor (Cmdrow, cursor + POOPCOL - first);
  195.         prev_cursor = cursor;
  196.  
  197.         /* get a character  */
  198.         switch (c = cread()) {        /* branch on character value */
  199.  
  200.     /* Literal characters: */
  201.         case ' ': case '!': case '"': case '#': case '$': case '%': 
  202.         case '&': case '\'': case '(': case ')': case '*': case '+':
  203.         case ',': case '-': case '.': case '/': case '0': case '1': 
  204.         case '2': case '3': case '4': case '5': case '6': case '7':
  205.         case '8': case '9': case ':': case ';': case '<': case '=': 
  206.         case '>': case '?': case '@': case '[': case '\\': case ']':
  207.         case '^': case '_': case '`': case '{': case '|': case '}': 
  208.         case '~': case 'A': case 'B': case 'C': case 'D': case 'E':
  209.         case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': 
  210.         case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q':
  211.         case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': 
  212.         case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c':
  213.         case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': 
  214.         case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
  215.         case 'p': case 'q': case 'r': case 's': case 't': case 'u': 
  216.         case 'v': case 'w': case 'x': case 'y': case 'z': case ESC:
  217.             if (c == ESC) /* take next char literally */
  218.             {
  219.                 if ((c = cread()) == '\r')
  220.                     c = '\n';
  221.             }
  222.             else if (Invert_case == YES && isalpha (c))
  223.                 c ^= 040;       /* toggle case (ASCII only) */
  224.             if (Insert_mode == YES)
  225.                 insert (1, &nlpos, &status, cursor, lin);
  226.             else if (cursor >= MAXLINE - 2)
  227.             {
  228.                 status = ERR;
  229.                 mesg (smargin, CHAR_MSG);
  230.             }
  231.             if (status != ERR)
  232.             {
  233.                 lin[cursor++] = c;
  234.                 if (nlpos < cursor)
  235.                     nlpos = cursor;
  236.                 if (c == '\n')
  237.                     *termchar = CURSOR_SAME;
  238.             }
  239.             break;
  240.  
  241.     /* Leftward cursor functions: */
  242.         case CURSOR_LEFT:
  243.             set_cursor (cursor - 1, &status, &cursor, &nlpos, lin);
  244.             break;
  245.  
  246.         case TAB_LEFT:
  247.             tab_pos = scan_tab (TAB_LEFT, cursor, &status);
  248.             if (status != ERR)
  249.                 cursor = tab_pos;
  250.             break;
  251.  
  252.         case SKIP_LEFT:
  253.             cursor = 0;
  254.             break;
  255.  
  256.         case SCAN_LEFT:
  257.             scan_pos = scan_char (c, YES, cursor, nlpos,
  258.                 lin, &status);
  259.             if (status != ERR)
  260.                 cursor = scan_pos;
  261.             break;
  262.  
  263.         case G_LEFT:
  264.             set_cursor (cursor - 1, &status, &cursor, &nlpos, lin);
  265.             if (status != ERR)
  266.                 gobble (1, cursor, &status, &nlpos, lin);
  267.             break;
  268.  
  269.         case G_TAB_LEFT:
  270.             tab_pos = scan_tab (TAB_LEFT, cursor, &status);
  271.             if (status != ERR)
  272.             {
  273.                 cursor = tab_pos;
  274.                 gobble (prev_cursor - tab_pos, cursor,
  275.                     &status, &nlpos, lin);
  276.             }
  277.             break;
  278.  
  279.         case KILL_LEFT:
  280.             cursor = 0;
  281.             gobble (prev_cursor /* - 1 */, cursor, &status, &nlpos, lin);
  282.             break;
  283.  
  284.         case G_SCAN_LEFT:
  285.             scan_pos = scan_char (c, NO, cursor, nlpos,
  286.                 lin, &status);
  287.             if (status != ERR)
  288.             {
  289.                 cursor = scan_pos;
  290.                 gobble (prev_cursor - scan_pos, cursor,
  291.                     &status, &nlpos, lin);
  292.             }
  293.             break;
  294.  
  295.     /* Rightward cursor functions: */
  296.         case CURSOR_RIGHT:
  297.             set_cursor (cursor + 1, &status, &cursor, &nlpos, lin);
  298.             break;
  299.  
  300.         case TAB_RIGHT:
  301.             tab_pos = scan_tab (TAB_RIGHT, cursor, &status);
  302.             if (status != ERR)
  303.                 set_cursor (tab_pos, &status, &cursor,
  304.                     &nlpos, lin);
  305.             break;
  306.  
  307.         case SKIP_RIGHT:
  308.             cursor = nlpos;
  309.             first = col1;
  310.             break;
  311.  
  312.         case SCAN_RIGHT:
  313.             scan_pos = scan_char (c, YES, cursor, nlpos,
  314.                 lin, &status);
  315.             if (status != ERR)
  316.                 cursor = scan_pos;
  317.             break;
  318.  
  319.         case G_RIGHT:
  320.             gobble (1, cursor, &status, &nlpos, lin);
  321.             break;
  322.  
  323.         case G_TAB_RIGHT:
  324.             tab_pos = scan_tab (TAB_RIGHT, cursor,
  325.                 &status);
  326.             if (status != ERR)
  327.                 gobble (tab_pos - cursor, cursor, &status,
  328.                     &nlpos, lin);
  329.             break;
  330.  
  331.         case KILL_RIGHT:
  332.             gobble (nlpos - cursor, cursor, &status, &nlpos, lin);
  333.             break;
  334.  
  335.         case G_SCAN_RIGHT:
  336.             scan_pos = scan_char (c, NO, cursor, nlpos,
  337.                 lin, &status);
  338.             if (status != ERR)
  339.                 gobble (scan_pos - cursor, cursor, &status,
  340.                     &nlpos, lin);
  341.             break;
  342.  
  343.     /* Line termination functions: */
  344.         case T_SKIP_RIGHT:
  345.             cursor = nlpos;
  346.             *termchar = c;
  347.             break;
  348.  
  349.         case T_KILL_RIGHT:
  350.             nlpos = cursor;
  351.             *termchar = c;
  352.             break;
  353.  
  354.         case FUNNY:
  355.         case CURSOR_UP:
  356.         case CURSOR_DOWN:
  357.             *termchar = c;
  358.             break;
  359.  
  360.     /* Insertion functions: */
  361.         case INSERT_BLANK:
  362.             insert (1, &nlpos, &status, cursor, lin);
  363.             if (status != ERR)
  364.                 lin[cursor] = ' ';
  365.             break;
  366.  
  367.         case INSERT_NEWLINE:
  368.             insert (1, &nlpos, &status, cursor, lin);
  369.             if (status != ERR)
  370.             {
  371.                 lin[cursor] = '\n';
  372.                 *termchar = CURSOR_UP;
  373.             }
  374.             break;
  375.  
  376.         case INSERT_TAB:
  377.             while (lin[cursor] == ' ' || lin[cursor] == '\t')
  378.                 cursor++;
  379.             tab_pos = scan_tab (TAB_RIGHT, cursor, &status);
  380.             if (status != ERR)
  381.                 insert (tab_pos - cursor, &nlpos, &status,
  382.                     cursor, lin);
  383.             if (status != ERR)
  384.                 for (; cursor < tab_pos; cursor++)
  385.                     lin[cursor] = ' ';
  386.             cursor = prev_cursor;
  387.             break;
  388.  
  389.     /* Miscellanious control functions: */
  390.         case TOGGLE_INSERT_MODE:
  391.             Insert_mode = YES + NO - Insert_mode;
  392.             if (Insert_mode == NO)
  393.                 mesg ("", INS_MSG);
  394.             else
  395.                 mesg ("INSERT", INS_MSG);
  396.             break;
  397.  
  398.         case SHIFT_CASE:
  399.             Invert_case = YES + NO - Invert_case;
  400.             if (Invert_case == NO)
  401.                 mesg ("", CASE_MSG);
  402.             else
  403.                 mesg ("CASE", CASE_MSG);
  404.             break;
  405.  
  406.         case KILL_ALL:
  407.             nlpos = cursor = 0;
  408.             break;
  409.  
  410.         case FIX_SCREEN:
  411.             restore_screen ();
  412.             break;
  413.  
  414.         default:
  415.             status = ERR;
  416.             mesg ("WHA?", CHAR_MSG);
  417.             break;
  418.         } /* end switch */
  419.     } /* while (termchar == EOS) */
  420.  
  421.     lin[nlpos] = '\n';
  422.     lin[nlpos + 1] = EOS;
  423.  
  424.     load ('|', Cmdrow, BARCOL);
  425.     if (nlpos <= col1)
  426.         loadstr ("", Cmdrow, POOPCOL, Ncols - 1);
  427.     else
  428.         loadstr (&lin[col1], Cmdrow, POOPCOL, Ncols - 1);
  429.  
  430.     if (cursor >= Warncol - 1)
  431.         litnnum ("col ", cursor + 1, COL_MSG);
  432.     else if (prev_cursor >= Warncol - 1)
  433.         mesg ("", COL_MSG);
  434.  
  435.     *curpos = cursor;
  436. }
  437.  
  438.  
  439.  
  440. /* cread --- read a character, handle interrupts and hangups */
  441. /*              ALL keyboard input should pass through this routine */
  442.  
  443. int cread ()
  444. {
  445.     char c;
  446.     int read ();
  447.  
  448.     tflush ();
  449.     if (Peekc)
  450.     {
  451.         c = Peekc;
  452.         Peekc = EOS;
  453.     }
  454.     else
  455.     {
  456. #ifdef BSD4_2
  457.         Reading = YES;
  458. #endif
  459.         if (read (0, &c, 1) == -1)
  460.             if (Hup_caught)
  461.                 hangup ();
  462.             else    /* must be a SIGINT at present */
  463.             {
  464.                 Int_caught = 0;
  465.                 Errcode = ENOERR;
  466.                 c = '\177';
  467.             }
  468. #ifdef BSD4_2
  469.         Reading = NO;
  470. #endif
  471.     }
  472.  
  473.     return c;
  474. }
  475.  
  476.  
  477.  
  478. /* scan_char --- scan current line for a character */
  479.  
  480. static int scan_char (chr, wrap, cursor, nlpos, lin, status)
  481. char chr, *lin;
  482. int wrap, cursor, nlpos, *status;
  483. {
  484.     register char c;
  485.     register int inc, scan_pos;
  486.     int cread ();
  487.  
  488.     c = cread ();
  489.     if (Invert_case == YES && isalpha (c))
  490.         c ^= 040;       /* toggle case */
  491.     if (c == chr)
  492.         c = Last_char_scanned;
  493.     Last_char_scanned = c;
  494.  
  495.     if (chr == SCAN_LEFT || chr == G_SCAN_LEFT)
  496.         inc = -1;
  497.     else
  498.         inc = 1;
  499.  
  500.     /* NOTE:  modify this code AT YOUR OWN RISK! */
  501.     scan_pos = cursor;
  502.     do
  503.     {
  504.         if (scan_pos < 0)
  505.             if (wrap == NO)
  506.                 break;
  507.             else
  508.                 scan_pos = nlpos;
  509.         else if (scan_pos > nlpos)
  510.             if (wrap == NO)
  511.                 break;
  512.             else
  513.                 scan_pos = 0;
  514.         else
  515.             scan_pos += inc;
  516.         if (-1 < scan_pos && scan_pos < nlpos && lin[scan_pos] == c)
  517.             break;
  518.     } while (scan_pos != cursor);
  519.  
  520.     if (scan_pos < 0 || scan_pos >= nlpos || lin[scan_pos] != c)
  521.     {
  522.         *status = ERR;
  523.         mesg ("NOCHAR", CHAR_MSG);
  524.     }
  525.  
  526.     return (scan_pos);
  527. }
  528.  
  529.  
  530.  
  531. static int scan_tab (chr, cursor, status)
  532. char chr;
  533. int cursor, *status;
  534. {
  535.     register int inc, tab_pos;
  536.  
  537.     if (chr == TAB_LEFT)
  538.     {
  539.         inc = -1;
  540.         tab_pos = cursor - 1;
  541.     }
  542.     else
  543.     {
  544.         inc = 1;
  545.         tab_pos = cursor + 1;
  546.     }
  547.  
  548.     for (; -1 < tab_pos && tab_pos < MAXLINE; tab_pos += inc)
  549.         if (Tabstops[tab_pos] == YES)
  550.             break;
  551.  
  552.     if (tab_pos < 0 || tab_pos >= MAXLINE - 1)
  553.     {
  554.         *status = ERR;
  555.         mesg (smargin, CHAR_MSG);
  556.     }
  557.  
  558.     return (tab_pos);
  559. }
  560.  
  561.  
  562.  
  563. /* gobble --- delete characters starting at the current cursor position */
  564.  
  565. static gobble (len, cursor, status, nlpos, lin)
  566. int len, cursor, *status, *nlpos;
  567. char *lin;
  568. {
  569.     if (cursor + len > *nlpos)
  570.     {
  571.         *status = ERR;
  572.         mesg (smargin, CHAR_MSG);
  573.     }
  574.     else if (len > 0)
  575.     {
  576.         strcpy (&lin[cursor], &lin[cursor + len]);
  577.         *nlpos -= len;
  578.     }
  579. }
  580.  
  581.  
  582.  
  583. /* insert --- shift characters right starting at the current cursor position */
  584.  
  585. static insert (len, nlpos, status, cursor, lin)
  586. register int len, *nlpos, cursor;
  587. int *status;
  588. register char *lin;
  589. {
  590.     register int fr, to;
  591.  
  592.     if (*nlpos + len >= MAXLINE - 1)
  593.     {
  594.         *status = ERR;
  595.         mesg (smargin, CHAR_MSG);
  596.     }
  597.     else
  598.     {
  599.         for (fr = *nlpos, to = *nlpos + len; fr >= cursor; fr--, to--)
  600.             lin[to] = lin[fr];
  601.         *nlpos += len;
  602.     }
  603. }
  604.  
  605.  
  606.  
  607. /* set_cursor --- move the cursor, extend line if necessary */
  608.  
  609. static set_cursor (pos, status, cursor, nlpos, lin)
  610. register int pos, *status, *cursor, *nlpos;
  611. register char *lin;
  612. {
  613.     if (pos < 0 || pos >= MAXLINE - 1)
  614.     {
  615.         *status = ERR;
  616.         mesg (smargin, CHAR_MSG);
  617.     }
  618.     else
  619.     {
  620.         *cursor = pos;
  621.         for (; *nlpos < *cursor; (*nlpos)++)
  622.             lin[*nlpos] = ' ';
  623.     }
  624. }
  625.  
  626.  
  627. /* litnnum --- display literal and number in message area */
  628.  
  629. litnnum (lit, num, type)
  630. register char *lit;
  631. register int num, type;
  632. {
  633.     char msg[MAXLINE];
  634.  
  635.     sprintf (msg, "%s%d", lit, num);
  636.     mesg (msg, type);
  637. }
  638.  
  639.  
  640.  
  641. /* load --- load a character onto the screen at given coordinates */
  642.  
  643. load (chr, row, col)
  644. register char chr;
  645. register int row, col;
  646. {
  647.     register char ch;
  648.  
  649.     ch = (chr < ' ' || chr >= DEL) ? Unprintable : chr;
  650.  
  651.     if (row >= 0 && row < Nrows && col >= 0 && col < Ncols
  652.         && Screen_image[row][col] != ch)
  653.     {
  654.         position_cursor (row, col);
  655.         Screen_image[row][col] = ch;
  656.         send (ch);
  657.     }
  658. }
  659.  
  660.  
  661. /* loadstr --- load a string into a field of the screen */
  662.  
  663. loadstr (str, row, stcol, endcol)
  664. register char *str;
  665. int row, stcol, endcol;
  666. {
  667.     register char ch;
  668.     register int p, c, limit;
  669.  
  670.     if (row >= 0 && row < Nrows && stcol >= 0)
  671.     {
  672.         c = stcol;
  673.         for (p = 0; str[p] != EOS; p++)
  674.         {
  675.             if (c >= Ncols)
  676.                 break;
  677.             ch = str[p];
  678.             if (ch < ' ' || ch >= DEL)
  679.                 ch = Unprintable;
  680.             if (Screen_image[row][c] != ch)
  681.             {
  682.                 Screen_image[row][c] = ch;
  683.                 position_cursor (row, c);
  684.                 send (ch);
  685.             }
  686.             c++;
  687.         }
  688.         if (endcol >= Ncols - 1 && c < Ncols - 1)
  689.             clear_to_eol (row, c);
  690.         else
  691.         {
  692.             limit = (endcol < Ncols - 1) ? endcol : Ncols - 1;
  693.             for (; c <= limit; c++)
  694.                 if (Screen_image[row][c] != ' ')
  695.                 {
  696.                     Screen_image[row][c] = ' ';
  697.                     position_cursor (row, c);
  698.                     send (' ');
  699.                 }
  700.         }
  701.     }
  702. }
  703.  
  704.  
  705. /* mesg --- display a message in the status row */
  706.  
  707. mesg (s, t)
  708. char *s;
  709. register int t;
  710. {
  711.     register int col, need, c, first, last;
  712.     int strlen ();
  713.  
  714.     for (first = 0; first < Ncols; first++)
  715.         if (Msgalloc[first] == t)
  716.             break;
  717.     for (last = first; last < Ncols; last++)
  718.     {
  719.         if (Msgalloc[last] != t)
  720.             break;
  721.         Msgalloc[last] = NOMSG;
  722.     }
  723.     for (; first > 0 && Msgalloc[first - 1] == NOMSG; first--)
  724.         ;
  725.  
  726.     need = strlen (s) + 2;  /* for two blanks */
  727.  
  728.     if (need > 2)           /* non-empty message */
  729.     {
  730.         if (need <= last - first)       /* fits in previous slot */
  731.             col = first;        /* keep it there */
  732.         else        /* needs a new slot */
  733.             for (col = 0; col < Ncols - 1; col = c)
  734.             {
  735.                 while (col < Ncols - 1
  736.                     && Msgalloc[col] != NOMSG)
  737.                     col++;
  738.                 for (c = col; Msgalloc[c] == NOMSG; c++)
  739.                     if (c >= Ncols - 1)
  740.                         break;
  741.                 if (c - col >= need)
  742.                     break;
  743.             }
  744.  
  745.         if (col + need >= Ncols)        /* have to collect garbage */
  746.         {
  747.             col = 0;
  748.             for (c = 0; c < Ncols; c++)
  749.                 if (Msgalloc[c] != NOMSG)
  750.                 {
  751.                     load (Screen_image[Nrows - 1][c],
  752.                         Nrows - 1, col);
  753.                     Msgalloc[col] = Msgalloc[c];
  754.                     col++;
  755.                 }
  756.             for (c = col; c < Ncols; c++)
  757.                 Msgalloc[c] = NOMSG;
  758.         }
  759.  
  760.         load (' ', Nrows - 1, col);
  761.         loadstr (s, Nrows - 1, col + 1, 0);
  762.         load (' ', Nrows - 1, col + need - 1);
  763.         last = col + need - 1;
  764.         if (last > Ncols - 1)
  765.             last = Ncols - 1;
  766.         for (c = col; c <= last; c++)
  767.             Msgalloc[c] = t;
  768.     }
  769.  
  770.     for (col = 0; col < Ncols; col++)
  771.         if (Msgalloc[col] == NOMSG)
  772.             load ('.', Nrows - 1, col);
  773.     tflush ();
  774. }
  775.  
  776. /* prompt --- load str into margin of command line */
  777.  
  778. prompt (str)
  779. char *str;
  780. {
  781.     loadstr (str, Cmdrow, 0, BARCOL - 1);
  782.     tflush ();
  783. }
  784.  
  785.  
  786.  
  787. /* restore_screen --- screen has been garbaged; fix it */
  788.  
  789. restore_screen ()
  790. {
  791.     register int row, col;
  792.     int intrpt ();
  793.  
  794.     clrscreen ();
  795.     for (row = 0; row < Nrows && ! intrpt (); row++)
  796.         for (col = 0; col < Ncols; col++)
  797.             if (Screen_image[row][col] != ' ')
  798.             {
  799.                 position_cursor (row, col);
  800.                 send (Screen_image[row][col]);
  801.             }
  802.  
  803.     remark ("");    /* get rid of 'type control-q....' */
  804. }
  805.  
  806. /* saynum --- display a number in the message area */
  807.  
  808. saynum (n)
  809. int n;
  810. {
  811.     char s[MAXLINE];
  812.  
  813.     sprintf (s, "%d", n);
  814.     remark (s);
  815. }
  816.  
  817. /* updscreen --- update screen from edit buffer */
  818.  
  819. updscreen ()
  820. {
  821.     char abs_lineno[10], rel_lineno[10];
  822.     register int line, row;
  823.     register int i;
  824.     int prevln ();
  825.     register LINEDESC *k;
  826.     LINEDESC *getind ();
  827.  
  828.     fixscreen ();
  829.  
  830.     line = Topln;
  831.     k = getind (line);
  832.  
  833.     for (row = Toprow; row <= Botrow; row++)
  834.     {
  835.         if (line > Lastln || line < 1)
  836.         {
  837.             loadstr ("", row, 0, BARCOL - 1);
  838.             load ('|', row, BARCOL);
  839.             loadstr ("", row, BARCOL + 1, Ncols - 1);
  840.         }
  841.         else
  842.         {
  843.             if (line == Curln)
  844.                 loadstr (".  ->", row, 0, NAMECOL - 1);
  845.             else if (line == 1)
  846.                 loadstr ("1", row, 0, NAMECOL - 1);
  847.             else if (line == Lastln)
  848.                 loadstr ("$", row, 0, NAMECOL - 1);
  849.             else if (Absnos == NO && row <= 25)
  850.             {
  851.                 rel_lineno[0] = Rel_a + row;
  852.                 rel_lineno[1] = EOS;
  853.                 loadstr (rel_lineno, row, 0, NAMECOL - 1);
  854.             }
  855.             else
  856.             {
  857.                 sprintf (abs_lineno, "%d", line);
  858.                 loadstr (abs_lineno, row, 0, NAMECOL - 1);
  859.             }
  860.  
  861.             load ((char) k->Markname, row, NAMECOL);
  862.             load ('|', row, BARCOL);
  863.  
  864.             if (line >= First_affected)
  865.             {
  866.                 gtxt (k);
  867.                 if (Firstcol >= k->Lineleng)
  868.                     loadstr ("", row, POOPCOL, Ncols - 1);
  869.                 else
  870.                     loadstr (&Txt[Firstcol], row, POOPCOL,
  871.                         Ncols - 1);
  872.             }
  873.         }
  874.  
  875.         line++;
  876.         k = NEXTLINE(k);
  877.     }
  878.  
  879.     First_affected = Lastln;
  880.  
  881.     Sctop = Topln;
  882.     Sclen = Botrow - Toprow + 1;
  883.     for (i = 0; i < Sclen; i++)
  884.         Scline[i] = Sctop + i <= Lastln ? i : -1;
  885. }
  886.  
  887.  
  888.  
  889. /* warn_deleted --- indicate which rows on screen are no longer valid */
  890.  
  891. warn_deleted (from, to)
  892. register int from, to;
  893. {
  894.     register int row;
  895.  
  896.     for (row = Toprow; row <= Botrow; row++)
  897.         if (Topln + row - Toprow >= from
  898.             && Topln + row - Toprow <= to)
  899.             loadstr ("gone", row, 0, BARCOL - 1);
  900. }
  901.  
  902.  
  903. /* watch --- keep time displayed on screen for users without watches */
  904.  
  905. watch ()
  906. {
  907.     long clock;
  908.     struct tm *now, *localtime ();
  909.     char face[10];
  910.  
  911.     time (&clock);
  912.     now = localtime (&clock);
  913.     sprintf (face, "%02d:%02d", now->tm_hour, now->tm_min);
  914.     mesg (face, TIME_MSG);
  915. }
  916.  
  917. /* adjust_window --- position window to include lines 'from' through 'to' */
  918.  
  919. adjust_window (from, to)
  920. register int from, to;
  921. {
  922.     register int i, l1, l2, hw;
  923.     int hwinsdel();
  924.  
  925.     /* see if the whole range of lines is on the screen */
  926.     if (from < Topln || to > Topln + (Botrow - Toprow))
  927.     {
  928.         /* find the first and last lines that are on the screen */
  929.         for (i = 0; i < Sclen && Scline[i] == -1; i++)
  930.             ;
  931.         l1 = i < Sclen ? Scline[i] + Sctop : Lastln + 1;
  932.         for (i = Sclen - 1; i >= 0 && Scline[i] == -1; i--)
  933.             ;
  934.         l2 = i >= 0 ? Scline[i] + Sctop : 0;
  935.  
  936.         /* see if we have hardware line insert/delete */
  937.         hw = hwinsdel();
  938.  
  939.         /* now find the best place to move the screen */
  940.         if (to - from > Botrow - Toprow)
  941.             Topln = to - (Botrow - Toprow);     /* put last part on screen */
  942.         else if (hw && from >= l1 && to <= l2)
  943.             Topln = (l1 + l2 + Toprow - Botrow) / 2;/* center l1 through l2 */
  944.         else if (hw && from < l1 && l1 - from < (Botrow - Toprow + 1) / 2)
  945.             Topln = from;                       /* slide the screen down */
  946.         else if (hw && to > l2 && to - l2 < (Botrow - Toprow + 1) / 2)
  947.             Topln = to - (Botrow - Toprow);     /* slide the screen up */
  948.         else
  949.             Topln = (from + to + Toprow - Botrow) / 2; /* center the range */
  950.         if (Topln + (Botrow - Toprow) > Lastln)
  951.             Topln = Lastln - (Botrow - Toprow);
  952.         if (Topln < 1)
  953.             Topln = 1;
  954.         if (First_affected > Topln)
  955.             First_affected = Topln;
  956.     }
  957. }
  958.  
  959.  
  960. /* svdel --- record the deletion of buffer lines for screen update */
  961.  
  962. svdel (ln, n)
  963. register int ln, n;
  964. {
  965.     register int i, j, lb, ub;
  966.  
  967.     if (ln + n <= Sctop)
  968.         Sctop -= n;
  969.     else if (ln < Sctop)
  970.     {
  971.         ub = ln + n - Sctop;
  972.         for (i = 0; i < Sclen; i++)
  973.             if (Scline[i] == -1)
  974.                 ;
  975.             else if (Scline[i] < ub)
  976.                 Scline[i] = -1;
  977.             else
  978.                 Scline[i] -= ub;
  979.         Sctop = ln;
  980.     }
  981.     else
  982.     {
  983.         lb = ln - Sctop;
  984.         ub = ln + n - Sctop;
  985.         for (i = 0; i < Sclen; i++)
  986.             if (Scline[i] == -1 || Scline[i] < lb)
  987.                 ;
  988.             else if (Scline[i] < ub)
  989.                 Scline[i] = -1;
  990.             else
  991.                 Scline[i] -= n;
  992.     }
  993. }
  994.  
  995.  
  996. /* svins --- record a buffer insertion for screen updating */
  997.  
  998. svins (ln, n)
  999. register int ln, n;
  1000. {
  1001.     register int i, lb;
  1002.  
  1003.     if (ln < Sctop)
  1004.         Sctop += n;
  1005.     else
  1006.     {
  1007.         lb = ln - Sctop;
  1008.         for (i = 0; i < Sclen; i++)
  1009.             if (Scline[i] != -1 && Scline[i] > lb)
  1010.                 Scline[i] += n;
  1011.     }
  1012.  
  1013. }
  1014.  
  1015.  
  1016. /* fixscreen --- try to patch up the screen using insert/delete line */
  1017.  
  1018. fixscreen ()
  1019. {
  1020.     register int oi;    /* "old" screen index */
  1021.     register int ni;    /* "new" screen index */
  1022.     register int dc;    /* number of deletions in current block */
  1023.     register int ic;    /* number of insertions in current block */
  1024.     register int ul;    /* number of lines that must be rewritten if */
  1025.                 /* we don't update by insert/delete */
  1026.     int wline[MAXROWS];    /* new screen contents; Scline contains old */
  1027.     int p;
  1028.  
  1029.     /* if the screen width was changed, give up before it's too late */
  1030.     if (Botrow - Toprow + 1 != Sclen || ! hwinsdel())
  1031.         return;
  1032.  
  1033.     /* scale the offsets in Scline to the new Topln; set any that are */
  1034.     /* off the screen to -1 so we won't have to fool with them */
  1035.     for (oi = 0; oi < Sclen; oi++)
  1036.         if (Scline[oi] == -1 || Scline[oi] + Sctop < Topln
  1037.             || Scline[oi] + Sctop > Topln + (Botrow - Toprow))
  1038.             Scline[oi] = -1;
  1039.         else
  1040.             Scline[oi] += Sctop - Topln;
  1041.  
  1042.     /* fill in wline with only those numbers that are in Scline */
  1043.     for (oi = 0, ni = 0; ni < Sclen; ni++)
  1044.     {
  1045.         while (oi < Sclen && Scline[oi] == -1)
  1046.             oi++;
  1047.         if (oi < Sclen && Scline[oi] == ni)
  1048.         {
  1049.             wline[ni] = ni;
  1050.             oi++;
  1051.         }
  1052.         else
  1053.             wline[ni] = -1;
  1054.     }
  1055.  
  1056.     /* see if it's still advisable to fix the screen: if the number */
  1057.     /* of lines that must be rewritten is less than 2 + the number */
  1058.     /* of lines that must be inserted, don't bother (this is a dumb */
  1059.     /* but fairly effective heuristic) */
  1060.     ul = ni = 0;
  1061.     for (oi = 0; oi < Sclen; oi++)
  1062.     {
  1063.         if (Scline[oi] != wline[oi] || Scline[oi] == -1)
  1064.             ul++;
  1065.         if (wline[oi] == -1)
  1066.             ni++;
  1067.     }
  1068.     if (ul < ni + 2)
  1069.         return;
  1070.  
  1071.     /* Now scan the screens backwards and put out delete-lines */
  1072.     /* for all deletions and changes with more old lines than new */
  1073.     oi = ni = Sclen - 1;
  1074.     while (oi >= 0 || ni >= 0)
  1075.     {
  1076.         for (dc = 0; oi >= 0 && Scline[oi] == -1; dc++)
  1077.             oi--;
  1078.         for (ic = 0; ni >= 0 && wline[ni] == -1; ic++)
  1079.             ni--;
  1080.         if (dc > ic)
  1081.             dellines (oi + 1 + Toprow + ic, dc - ic);
  1082.         while (oi >= 0 && Scline[oi] != -1
  1083.             && ni >= 0 && wline[ni] == Scline[oi])
  1084.             oi--, ni--;
  1085.     }
  1086.  
  1087.     /* At last, scan the screens forward and put out insert-lines */
  1088.     /* for all insertions and changes with more new lines than old */
  1089.     oi = ni = 0;
  1090.     while (oi < Sclen || ni < Sclen)
  1091.     {
  1092.         p = ni;
  1093.         for (dc = 0; oi < Sclen && Scline[oi] == -1; dc++)
  1094.             oi++;
  1095.         for (ic = 0; ni < Sclen && wline[ni] == -1; ic++)
  1096.             ni++;
  1097.         if (ic > dc)
  1098.             inslines (p + Toprow + dc, ic - dc);
  1099.         while (oi < Sclen && Scline[oi] != -1
  1100.             && ni < Sclen && wline[ni] == Scline[oi])
  1101.             oi++, ni++;
  1102.     }
  1103.  
  1104. }
  1105.