home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / pico / display.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-06  |  55.2 KB  |  2,545 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: display.c,v 4.16 1993/11/19 04:01:12 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Display functions
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  * Copyright 1991-1993  University of Washington
  19.  *
  20.  *  Permission to use, copy, modify, and distribute this software and its
  21.  * documentation for any purpose and without fee to the University of
  22.  * Washington is hereby granted, provided that the above copyright notice
  23.  * appears in all copies and that both the above copyright notice and this
  24.  * permission notice appear in supporting documentation, and that the name
  25.  * of the University of Washington not be used in advertising or publicity
  26.  * pertaining to distribution of the software without specific, written
  27.  * prior permission.  This software is made available "as is", and
  28.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  29.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  30.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  31.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  32.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  33.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  34.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  35.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  36.  *
  37.  * Pine and Pico are trademarks of the University of Washington.
  38.  * No commercial use of these trademarks may be made without prior
  39.  * written permission of the University of Washington.
  40.  *
  41.  */
  42. /*
  43.  * The functions in this file handle redisplay. There are two halves, the
  44.  * ones that update the virtual display screen, and the ones that make the
  45.  * physical display screen the same as the virtual display screen. These
  46.  * functions use hints that are left in the windows by the commands.
  47.  *
  48.  */
  49.  
  50. #include        <stdio.h>
  51. #include    "osdep.h"
  52. #include        "pico.h"
  53. #include    "estruct.h"
  54. #include        "edef.h"
  55. #include        "efunc.h"
  56. #ifdef HEBREW
  57. #include "hebrew.h"
  58. #endif
  59.  
  60.  
  61. #ifdef    ANSI
  62.     int vtmove(int, int);
  63.     int vtputc(CELL);
  64.     int vtpute(CELL);
  65.     int vteeol(void);
  66.     int updateline(int, CELL *, CELL *, short *,short *);
  67.     int updext(void);
  68.     int mlputi(int, int);
  69.     int mlputli(long, int);
  70.     int showCompTitle(void);
  71.     int nlforw(void);
  72.     int dumbroot(int, int);
  73.     int dumblroot(long, int);
  74. #else
  75.     int vtmove();
  76.     int vtputc();
  77.     int vtpute();
  78.     int vteeol();
  79.     int updateline();
  80.     int updext();
  81.     int mlputi();
  82.     int mlputli();
  83.     int showCompTitle();
  84.     int nlforw();
  85.     int dumbroot();
  86.     int dumblroot();
  87. #endif
  88.  
  89.  
  90. #define WFDEBUG 0                       /* Window flag debug. */
  91.  
  92. typedef struct  VIDEO {
  93.         short   v_flag;                 /* Flags */
  94.         CELL    v_text[1];              /* Screen data. */
  95. }       VIDEO;
  96.  
  97. #define VFCHG   0x0001                  /* Changed flag            */
  98. #define    VFEXT    0x0002            /* extended (beyond column 80)    */
  99. #define    VFREV    0x0004            /* reverse video status        */
  100. #define    VFREQ    0x0008            /* reverse video request    */
  101. #ifdef HEBREW
  102. #define VHEBR   0x1000  
  103. #endif
  104.  
  105. int     vtrow   = 0;                    /* Row location of SW cursor */
  106. int     vtcol   = 0;                    /* Column location of SW cursor */
  107. int     ttrow   = HUGE;                 /* Row location of HW cursor */
  108. int     ttcol   = HUGE;                 /* Column location of HW cursor */
  109. int    lbound    = 0;            /* leftmost column of current line
  110.                        being displayed */
  111.  
  112. VIDEO   **vscreen;                      /* Virtual screen. */
  113. VIDEO   **pscreen;                      /* Physical screen. */
  114.  
  115.  
  116. /*
  117.  * Initialize the data structures used by the display code. The edge vectors
  118.  * used to access the screens are set up. The operating system's terminal I/O
  119.  * channel is set up. All the other things get initialized at compile time.
  120.  * The original window has "WFCHG" set, so that it will get completely
  121.  * redrawn on the first call to "update".
  122.  */
  123. vtinit()
  124. {
  125.     register int i;
  126.     register VIDEO *vp;
  127.  
  128.     (*term.t_open)();
  129.  
  130.     (*term.t_rev)(FALSE);
  131.     vscreen = (VIDEO **) malloc((term.t_nrow+1)*sizeof(VIDEO *));
  132.     if (vscreen == NULL){
  133.     emlwrite("Allocating memory for virtual display failed.", NULL);
  134.         return(FALSE);
  135.     }
  136.  
  137.  
  138.     pscreen = (VIDEO **) malloc((term.t_nrow+1)*sizeof(VIDEO *));
  139.     if (pscreen == NULL){
  140.     free((void *)vscreen);
  141.     emlwrite("Allocating memory for physical display failed.", NULL);
  142.         return(FALSE);
  143.     }
  144.  
  145.  
  146.     for (i = 0; i <= term.t_nrow; ++i) {
  147.         vp = (VIDEO *) malloc(sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  148.  
  149.         if (vp == NULL){
  150.         free((void *)vscreen);
  151.         free((void *)pscreen);
  152.         emlwrite("Allocating memory for virtual display lines failed.",
  153.              NULL);
  154.             return(FALSE);
  155.     }
  156.  
  157.     vp->v_flag = 0;
  158.         vscreen[i] = vp;
  159.         vp = (VIDEO *) malloc(sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  160.  
  161.         if (vp == NULL){
  162.             free((void *)vscreen[i]);
  163.         while(--i >= 0){
  164.         free((void *)vscreen[i]);
  165.         free((void *)pscreen[i]);
  166.         }
  167.  
  168.         free((void *)vscreen);
  169.         free((void *)pscreen);
  170.         emlwrite("Allocating memory for physical display lines failed.",
  171.              NULL);
  172.             return(FALSE);
  173.     }
  174.  
  175.     vp->v_flag = 0;
  176.         pscreen[i] = vp;
  177.     }
  178.  
  179.     return(TRUE);
  180. }
  181.  
  182.  
  183. /*
  184.  * Clean up the virtual terminal system, in anticipation for a return to the
  185.  * operating system. Move down to the last line and clear it out (the next
  186.  * system prompt will be written in the line). Shut down the channel to the
  187.  * terminal.
  188.  */
  189. vttidy()
  190. {
  191.     movecursor(term.t_nrow-1, 0);
  192.     peeol();
  193.     movecursor(term.t_nrow, 0);
  194.     peeol();
  195.     (*term.t_close)();
  196. }
  197.  
  198.  
  199. /*
  200.  * Set the virtual cursor to the specified row and column on the virtual
  201.  * screen. There is no checking for nonsense values; this might be a good
  202.  * idea during the early stages.
  203.  */
  204. vtmove(row, col)
  205. int row, col;
  206. {
  207.     vtrow = row;
  208.     vtcol = col;
  209. }
  210.  
  211.  
  212. /*
  213.  * Write a character to the virtual screen. The virtual row and column are
  214.  * updated. If the line is too long put a "$" in the last column. This routine
  215.  * only puts printing characters into the virtual terminal buffers. Only
  216.  * column overflow is checked.
  217.  */
  218. vtputc(c)
  219. CELL c;
  220. {
  221.     register VIDEO      *vp;
  222.     CELL     ac;
  223.  
  224.     vp = vscreen[vtrow];
  225.     ac.c = ' ';
  226.     ac.a = c.a;
  227.  
  228.     if (vtcol >= term.t_ncol) {
  229.         vtcol = (vtcol + 0x07) & ~0x07;
  230.     ac.c = '$';
  231.         vp->v_text[term.t_ncol - 1] = ac;
  232.     }
  233.     else if (c.c == '\t') {
  234.         do {
  235.             vtputc(ac);
  236.     }
  237.         while ((vtcol&0x07) != 0);
  238.     }
  239.     else if (c.c < 0x20 || c.c == 0x7F) {
  240.     ac.c = '^';
  241.         vtputc(ac);
  242.     ac.c = (c.c ^ 0x40);
  243.         vtputc(ac);
  244.     }
  245.     else
  246.       vp->v_text[vtcol++] = c;
  247. }
  248.  
  249.  
  250. /* put a character to the virtual screen in an extended line. If we are
  251.  * not yet on left edge, don't print it yet. check for overflow on
  252.  * the right margin.
  253.  */
  254. vtpute(c)
  255. CELL c;
  256. {
  257.     register VIDEO      *vp;
  258.     CELL                 ac;
  259.  
  260.     vp = vscreen[vtrow];
  261.     ac.c = ' ';
  262.     ac.a = c.a;
  263.  
  264.     if (vtcol >= term.t_ncol) {
  265.         vtcol = (vtcol + 0x07) & ~0x07;
  266.     ac.c = '$';
  267.         vp->v_text[term.t_ncol - 1] = ac;
  268.     }
  269.     else if (c.c == '\t'){
  270.         do {
  271.             vtpute(ac);
  272.         }
  273.         while (((vtcol + lbound)&0x07) != 0 && vtcol < term.t_ncol);
  274.     }
  275.     else if (c.c < 0x20 || c.c == 0x7F) {
  276.     ac.c = '^';
  277.         vtpute(ac);
  278.     ac.c = (c.c ^ 0x40);
  279.         vtpute(ac);
  280.     }
  281.     else {
  282.     if (vtcol >= 0)
  283.       vp->v_text[vtcol] = c;
  284.     ++vtcol;
  285.     }
  286. }
  287.  
  288.  
  289. /*
  290.  * Erase from the end of the software cursor to the end of the line on which
  291.  * the software cursor is located.
  292.  */
  293. vteeol()
  294. {
  295.     register VIDEO      *vp;
  296.     CELL     c;
  297.  
  298.     c.c = ' ';
  299.     c.a = 0;
  300.     vp = vscreen[vtrow];
  301.     while (vtcol < term.t_ncol)
  302.       vp->v_text[vtcol++] = c;
  303. }
  304.  
  305.  
  306. /*
  307.  * Make sure that the display is right. This is a three part process. First,
  308.  * scan through all of the windows looking for dirty ones. Check the framing,
  309.  * and refresh the screen. Second, make sure that "currow" and "curcol" are
  310.  * correct for the current window. Third, make the virtual and physical
  311.  * screens the same.
  312.  */
  313. update()
  314. {
  315.     register LINE   *lp;
  316.     register WINDOW *wp;
  317.     register VIDEO  *vp1;
  318.     register VIDEO  *vp2;
  319.     register int     i;
  320.     register int     j;
  321.     register int     scroll = 0;
  322.     CELL         c;
  323.  
  324. #if    TYPEAH
  325.     if (typahead())
  326.     return(TRUE);
  327. #endif
  328.  
  329. /*
  330.  * BUG: setting and unsetting whole region at a time is dumb.  fix this.
  331.  */
  332.     if(curwp->w_markp){
  333.     unmarkbuffer();
  334.     markregion(1);
  335.     }
  336.  
  337.     wp = wheadp;
  338.  
  339.     while (wp != NULL){
  340.         /* Look at any window with update flags set on. */
  341.  
  342.         if (wp->w_flag != 0){
  343.             /* If not force reframe, check the framing. */
  344.  
  345.             if ((wp->w_flag & WFFORCE) == 0){
  346.                 lp = wp->w_linep;
  347.  
  348.                 for (i = 0; i < wp->w_ntrows; ++i){
  349.                     if (lp == wp->w_dotp)
  350.               goto out;
  351.  
  352.                     if (lp == wp->w_bufp->b_linep)
  353.               break;
  354.  
  355.                     lp = lforw(lp);
  356.         }
  357.         }
  358.  
  359.             /* Not acceptable, better compute a new value for the line at the
  360.              * top of the window. Then set the "WFHARD" flag to force full
  361.              * redraw.
  362.              */
  363.             i = wp->w_force;
  364.  
  365.             if (i > 0){
  366.                 --i;
  367.  
  368.                 if (i >= wp->w_ntrows)
  369.                   i = wp->w_ntrows-1;
  370.         }
  371.             else if (i < 0){
  372.                 i += wp->w_ntrows;
  373.  
  374.                 if (i < 0)
  375.           i = 0;
  376.         }
  377.             else if(optimize){
  378.         /* 
  379.          * find dotp, if its been moved just above or below the 
  380.          * window, use scrollxxx() to facilitate quick redisplay...
  381.          */
  382.         lp = lforw(wp->w_dotp);
  383.         if(lp != wp->w_dotp){
  384.             if(lp == wp->w_linep && lp != wp->w_bufp->b_linep){
  385.             scroll = 1;
  386.             }
  387.             else {
  388.             lp = wp->w_linep;
  389.             for(j=0;j < wp->w_ntrows; ++j){
  390.                 if(lp != wp->w_bufp->b_linep)
  391.                   lp = lforw(lp);
  392.                 else
  393.                   break;
  394.             }
  395.             if(lp == wp->w_dotp && j == wp->w_ntrows)
  396.               scroll = 2;
  397.             }
  398.         }
  399.         j = i = wp->w_ntrows/2;
  400.         }
  401.         else
  402.           i = wp->w_ntrows/2;
  403.  
  404.             lp = wp->w_dotp;
  405.  
  406.             while (i != 0 && lback(lp) != wp->w_bufp->b_linep){
  407.                 --i;
  408.                 lp = lback(lp);
  409.         }
  410.  
  411.         /*
  412.          * this is supposed to speed things up by using tcap sequences
  413.          * to efficiently scroll the terminal screen.  the thinking here
  414.          * is that its much faster to update pscreen[] than to actually
  415.          * write the stuff to the screen...
  416.          */
  417.         if(optimize){
  418.         switch(scroll){
  419.           case 1:            /* scroll text down */
  420.             j = j-i+1;            /* add one for dot line */
  421.             /* 
  422.              * do we scroll down the header as well?  Well, only 
  423.              * if we're not editing the header, we've backed up 
  424.              * to the top, and the composer is not being 
  425.              * displayed...
  426.              */
  427.             if(Pmaster && !ComposerEditing 
  428.                && (lback(lp) == wp->w_bufp->b_linep)
  429.                && (ComposerTopLine == COMPOSER_TOP_LINE))
  430.               j += entry_line(LASTHDR, TRUE);
  431.  
  432.             scrolldown(wp, -1, j);
  433.             break;
  434.           case 2:            /* scroll text up */
  435.             j = wp->w_ntrows - (j-i);    /* we chose new top line! */
  436.             if(Pmaster && j){
  437.             /* 
  438.              * do we scroll down the header as well?  Well, only 
  439.              * if we're not editing the header, we've backed up 
  440.              * to the top, and the composer is not being 
  441.              * displayed...
  442.              */
  443.             if(!ComposerEditing 
  444.                && (ComposerTopLine != COMPOSER_TOP_LINE))
  445.               scrollup(wp, COMPOSER_TOP_LINE, 
  446.                    j+entry_line(LASTHDR, TRUE));
  447.             else
  448.               scrollup(wp, -1, j);
  449.             }
  450.             else
  451.               scrollup(wp, -1, j);
  452.             break;
  453.             default :
  454.               break;
  455.         }
  456.         }
  457.  
  458.             wp->w_linep = lp;
  459.             wp->w_flag |= WFHARD;       /* Force full. */
  460. out:
  461.         /*
  462.          * if the line at the top of the page is the top line
  463.          * in the body, show the header...
  464.          */
  465.         if(Pmaster && !ComposerEditing){
  466.         if(lback(wp->w_linep) == wp->w_bufp->b_linep){
  467.             if(ComposerTopLine == COMPOSER_TOP_LINE){
  468.             i = term.t_nrow - 4 - HeaderLen();
  469.             if(i > 0 && nlforw() >= i) {    /* room for header ? */
  470.                 if((i = nlforw()/2) == 0 && term.t_nrow&1)
  471.                   i = 1;
  472.                 while(wp->w_linep != wp->w_bufp->b_linep && i--)
  473.                   wp->w_linep = lforw(wp->w_linep);
  474.                 
  475.             }
  476.             else
  477.               ToggleHeader(1);
  478.             }
  479.         }
  480.         else{
  481.             if(ComposerTopLine != COMPOSER_TOP_LINE)
  482.               ToggleHeader(0);        /* hide it ! */
  483.         }
  484.         }
  485.  
  486.             /* Try to use reduced update. Mode line update has its own special
  487.              * flag. The fast update is used if the only thing to do is within
  488.              * the line editing.
  489.              */
  490.             lp = wp->w_linep;
  491.             i = wp->w_toprow;
  492.  
  493.             if ((wp->w_flag & ~WFMODE) == WFEDIT){
  494.                 while (lp != wp->w_dotp){
  495.                     ++i;
  496.                     lp = lforw(lp);
  497.         }
  498. #ifdef HEBREW
  499.         if(lp->l_type==L_HEB)vscreen[i]->v_flag |= VHEBR;
  500.         else vscreen[i]->v_flag &= ~VHEBR;
  501. #endif
  502.  
  503.                 vscreen[i]->v_flag |= VFCHG;
  504.                 vtmove(i, 0);
  505.  
  506.                 for (j = 0; j < llength(lp); ++j)
  507.                     vtputc(lgetc(lp, j));
  508.  
  509.                 vteeol();
  510.         }
  511.         else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0){
  512.                 while (i < wp->w_toprow+wp->w_ntrows){
  513.                     vscreen[i]->v_flag |= VFCHG;
  514. #ifdef HEBREW
  515.             if(lp->l_type==L_HEB)vscreen[i]->v_flag |= VHEBR;
  516.             else vscreen[i]->v_flag &= ~VHEBR;
  517. #endif
  518.                     vtmove(i, 0);
  519.  
  520.             /* if line has been changed */
  521.                     if (lp != wp->w_bufp->b_linep){
  522.                         for (j = 0; j < llength(lp); ++j)
  523.                             vtputc(lgetc(lp, j));
  524.  
  525.                         lp = lforw(lp);
  526.             }
  527.  
  528.                     vteeol();
  529.                     ++i;
  530.         }
  531.         }
  532. #if ~WFDEBUG
  533.             if ((wp->w_flag&WFMODE) != 0)
  534.                 modeline(wp);
  535.  
  536.             wp->w_flag  = 0;
  537.             wp->w_force = 0;
  538. #endif
  539.     }
  540. #if WFDEBUG
  541.         modeline(wp);
  542.         wp->w_flag =  0;
  543.         wp->w_force = 0;
  544. #endif
  545.  
  546.     /* and onward to the next window */
  547.         wp = wp->w_wndp;
  548.     }
  549.  
  550.     /* Always recompute the row and column number of the hardware cursor. This
  551.      * is the only update for simple moves.
  552.      */
  553.     lp = curwp->w_linep;
  554.     currow = curwp->w_toprow;
  555.  
  556.     while (lp != curwp->w_dotp){
  557.         ++currow;
  558.         lp = lforw(lp);
  559.     }
  560.  
  561.     curcol = 0;
  562.     i = 0;
  563.  
  564.     while (i < curwp->w_doto){
  565.     c = lgetc(lp, i++);
  566.  
  567.         if (c.c == '\t')
  568.             curcol |= 0x07;
  569.         else if (c.c < 0x20 || c.c == 0x7F)
  570.             ++curcol;
  571.  
  572.         ++curcol;
  573.     }
  574.  
  575.     if (curcol >= term.t_ncol - 1) {         /* extended line. */
  576.     /* flag we are extended and changed */
  577.     vscreen[currow]->v_flag |= VFEXT | VFCHG;
  578.     updext();                /* and output extended line */
  579.     } else
  580.       lbound = 0;                /* not extended line */
  581.  
  582.     /* make sure no lines need to be de-extended because the cursor is
  583.      * no longer on them 
  584.      */
  585.  
  586.     wp = wheadp;
  587.  
  588.     while (wp != NULL) {
  589.     lp = wp->w_linep;
  590.     i = wp->w_toprow;
  591.  
  592.     while (i < wp->w_toprow + wp->w_ntrows) {
  593.         if (vscreen[i]->v_flag & VFEXT) {
  594.         /* always flag extended lines as changed */
  595.         vscreen[i]->v_flag |= VFCHG;
  596.         if ((wp != curwp) || (lp != wp->w_dotp) ||
  597.             (curcol < term.t_ncol - 1)) {
  598.             vtmove(i, 0);
  599.             for (j = 0; j < llength(lp); ++j)
  600.               vtputc(lgetc(lp, j));
  601.             vteeol();
  602.  
  603.             /* this line no longer is extended */
  604.             vscreen[i]->v_flag &= ~VFEXT;
  605.         }
  606.         }
  607.         lp = lforw(lp);
  608.         ++i;
  609.     }
  610.     /* and onward to the next window */
  611.         wp = wp->w_wndp;
  612.     }
  613.  
  614.     /* Special hacking if the screen is garbage. Clear the hardware screen,
  615.      * and update your copy to agree with it. Set all the virtual screen
  616.      * change bits, to force a full update.
  617.      */
  618.  
  619.     if (sgarbf != FALSE){
  620.     if(Pmaster){
  621.         showCompTitle();
  622.  
  623.         if(ComposerTopLine != COMPOSER_TOP_LINE){
  624.         UpdateHeader();            /* arrange things */
  625.         PaintHeader(COMPOSER_TOP_LINE, TRUE);
  626.         }
  627.  
  628.         /*
  629.          * since we're using only a portion of the screen and only 
  630.          * one buffer, only clear enough screen for the current window
  631.          * which is to say the *only* window.
  632.          */
  633.         for(i=wheadp->w_toprow;i<=term.t_nrow; i++){
  634.         movecursor(i, 0);
  635.         peeol();
  636.         vscreen[i]->v_flag |= VFCHG;
  637.         }
  638.         movecursor(wheadp->w_toprow, 0);
  639.     }
  640.     else{
  641.         for (i = 0; i < term.t_nrow - 2; ++i){
  642.         vscreen[i]->v_flag |= VFCHG;
  643.         vp1 = pscreen[i];
  644.         c.c = ' ';
  645.         c.a = 0;
  646.         for (j = 0; j < term.t_ncol; ++j)
  647.           vp1->v_text[j] = c;
  648.         }
  649.  
  650.         movecursor(0, 0);                   /* Erase the screen. */
  651.         (*term.t_eeop)();
  652.  
  653.     }
  654.  
  655.         sgarbf = FALSE;                /* Erase-page clears */
  656.         mpresf = FALSE;                /* the message area. */
  657.  
  658.     if(Pmaster)
  659.       modeline(curwp);
  660.     else
  661.       sgarbk = TRUE;            /* fix the keyhelp as well...*/
  662.     }
  663.  
  664.     /* Make sure that the physical and virtual displays agree. Unlike before,
  665.      * the "updateline" code is only called with a line that has been updated
  666.      * for sure.
  667.      */
  668.     if(Pmaster){
  669.     i = curwp->w_toprow;
  670.     c.c = term.t_nrow-2;
  671.     }
  672.     else{
  673.     i = 0;
  674.     c.c = term.t_nrow;
  675.     }
  676.  
  677.     for (; i < (int)c.c; ++i){
  678.  
  679.         vp1 = vscreen[i];
  680. #ifdef HEBREW            
  681.         if(i!=0 && !control_mode && compose_heb){
  682.           hebmode=((vp1->v_flag & VHEBR) == VHEBR);
  683.         }
  684.         else hebmode=0;
  685. #endif
  686.  
  687.     /* for each line that needs to be updated, or that needs its
  688.        reverse video status changed, call the line updater    */
  689.     j = vp1->v_flag;
  690.         if (j & VFCHG){
  691.  
  692. #if    TYPEAH
  693.         if (typahead())
  694.             return(TRUE);
  695. #endif
  696.             vp2 = pscreen[i];
  697.  
  698.             updateline(i, &vp1->v_text[0], &vp2->v_text[0], &vp1->v_flag, &vp2->v_flag);
  699.  
  700.  
  701.     }
  702.     }
  703.  
  704.     if(Pmaster == NULL){
  705. #ifdef HEBREW
  706.       hebmode=0;
  707. #endif
  708.  
  709.     if(sgarbk != FALSE){
  710.         movecursor(term.t_nrow-1, 0);
  711.         peeol();
  712.         movecursor(term.t_nrow, 0);
  713.         peeol();
  714.         if(lastflag&CFFILL){
  715. #ifndef HEBREW
  716.         wkeyhelp("GORYKCXJWVU^",
  717.                  "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Cur Pos,Exit,Justify,Where is,Next Pg,UnJustify,Set Mark");
  718. #else
  719. if(compose_heb){
  720.         wkeyhelp("GORYKtX^WVUT",
  721.                          "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Direction,Exit,Set Mark,Where is,Next Pg,UnCut Text,  Heb/Eng");
  722.           }
  723. else{
  724.         wkeyhelp("GORYKCXJWVU^",
  725.                  "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Cur Pos,Exit,Justify,Where is,Next Pg,UnJustify,Set Mark");
  726.           }
  727. #endif
  728.           }
  729.         emlwrite("Can now UnJustify!", NULL);
  730.         mpresf = HUGE;    /* remove this after next keystroke! */
  731.       }
  732.         else{
  733. #ifndef HEBREW
  734.         wkeyhelp("GORYKCXJWVU^",
  735.                  "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Cur Pos,Exit,Justify,Where is,Next Pg,UnCut Text,Set Mark");
  736. #else
  737. if(compose_heb){
  738.         wkeyhelp("GORYKtX^WVUT",
  739.                          "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Direction,Exit,Set Mark,Where is,Next Pg,UnCut Text,  Heb/Eng");
  740.           }
  741. else{
  742.         wkeyhelp("GORYKCXJWVU^",
  743.                  "Get Help,WriteOut,Read File,Prev Pg,Cut Text,Cur Pos,Exit,Justify,Where is,Next Pg,UnCut Text,Set Mark");
  744.           }
  745. #endif
  746.           }
  747.         sgarbk = FALSE;
  748.     }
  749.  
  750.  
  751.     /* Finally, update the hardware cursor and flush out buffers. */
  752.  
  753. #ifdef HEBREW
  754.         if(!control_mode && compose_heb){
  755.           hebmode=hebmain; 
  756.         }
  757. #endif
  758.     movecursor(currow, curcol - lbound);
  759.     (*term.t_flush)();
  760. #ifdef HEBREW
  761.     hebmode=0;
  762. #endif
  763. }
  764.  
  765. /* updext - update the extended line which the cursor is currently
  766.  *        on at a column greater than the terminal width. The line
  767.  *        will be scrolled right or left to let the user see where
  768.  *        the cursor is
  769.  */
  770. updext()
  771. {
  772.     register int rcursor;        /* real cursor location */
  773.     register LINE *lp;            /* pointer to current line */
  774.     register int j;            /* index into line */
  775.  
  776.     /* calculate what column the real cursor will end up in */
  777.     rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
  778.     lbound = curcol - rcursor + 1;
  779.  
  780.     /* scan through the line outputing characters to the virtual screen
  781.      * once we reach the left edge
  782.      */
  783.     vtmove(currow, -lbound);        /* start scanning offscreen */
  784.     lp = curwp->w_dotp;            /* line to output */
  785.     for (j=0; j<llength(lp); ++j)    /* until the end-of-line */
  786.       vtpute(lgetc(lp, j));
  787.  
  788.     /* truncate the virtual line */
  789.     vteeol();
  790.  
  791.     /* and put a '$' in column 1 */
  792.     vscreen[currow]->v_text[0].c = '$';
  793.     vscreen[currow]->v_text[0].a = 0;
  794. }
  795.  
  796.  
  797. /*
  798.  * Update a single line. This does not know how to use insert or delete
  799.  * character sequences; we are using VT52 functionality. Update the physical
  800.  * row and column variables. It does try an exploit erase to end of line. The
  801.  * RAINBOW version of this routine uses fast video.
  802.  */
  803. updateline(row, vline, pline, flags, pflags)
  804. int  row;
  805. CELL vline[];                /* what we want it to end up as */
  806. CELL pline[];                /* what it looks like now       */
  807. short *flags;                /* and how we want it that way  */
  808. short *pflags;
  809. {
  810.     register CELL *cp1;
  811.     register CELL *cp2;
  812.     register CELL *cp3;
  813.     register CELL *cp4;
  814.     register CELL *cp5;
  815.     register CELL *cp6;
  816.     register CELL *cp7;
  817.     register int  display = TRUE;
  818.     register int nbflag;        /* non-blanks to the right flag? */
  819.  
  820.     char mode=5;
  821. #ifndef HEBREW
  822.     /* set up pointers to virtual and physical lines */
  823.     cp1 = &vline[0];
  824.     cp2 = &pline[0];
  825.     cp3 = &vline[term.t_ncol];
  826.  
  827.     /* advance past any common chars at the left */
  828.     while (cp1 != cp3 && cp1[0].c == cp2[0].c && cp1[0].a == cp2[0].a) {
  829.     ++cp1;
  830.     ++cp2;
  831.     }
  832.  
  833. /* This can still happen, even though we only call this routine on changed
  834.  * lines. A hard update is always done when a line splits, a massive
  835.  * change is done, or a buffer is displayed twice. This optimizes out most
  836.  * of the excess updating. A lot of computes are used, but these tend to
  837.  * be hard operations that do a lot of update, so I don't really care.
  838.  */
  839.     /* if both lines are the same, no update needs to be done */
  840.     if (cp1 == cp3){
  841.     *flags &= ~VFCHG;            /* mark it clean */
  842.     return(TRUE);
  843.     }
  844.  
  845.     /* find out if there is a match on the right */
  846.     nbflag = FALSE;
  847.     cp3 = &vline[term.t_ncol];
  848.     cp4 = &pline[term.t_ncol];
  849.  
  850.     while (cp3[-1].c == cp4[-1].c && cp3[-1].a == cp4[-1].a) {
  851.     --cp3;
  852.     --cp4;
  853.     if (cp3[0].c != ' ' || cp3[0].a != 0)/* Note if any nonblank */
  854.       nbflag = TRUE;        /* in right match. */
  855.     }
  856.  
  857.     cp5 = cp3;
  858.  
  859.     if (nbflag == FALSE && eolexist == TRUE) {    /* Erase to EOL ? */
  860.     while (cp5 != cp1 && cp5[-1].c == ' ' && cp5[-1].a == 0)
  861.       --cp5;
  862.  
  863.     if (cp3-cp5 <= 3)        /* Use only if erase is */
  864.       cp5 = cp3;            /* fewer characters. */
  865.  
  866.       }
  867.     movecursor(row, cp1-&vline[0]);        /* Go to start of line. */
  868. #else
  869.   if(!compose_heb || (*flags&VHEBR)==(*pflags&VHEBR)){
  870.     /* set up pointers to virtual and physical lines */
  871.     cp1 = &vline[0];
  872.     cp2 = &pline[0];
  873.     cp3 = &vline[term.t_ncol];
  874.  
  875.     /* advance past any common chars at the left */
  876.     while (cp1 != cp3 && cp1[0].c == cp2[0].c && cp1[0].a == cp2[0].a) {
  877.     ++cp1;
  878.     ++cp2;
  879.     }
  880.  
  881.     /* if both lines are the same, no update needs to be done */
  882.     if (cp1 == cp3){
  883.     *flags &= ~VFCHG;            /* mark it clean */
  884.     return(TRUE);
  885.     }
  886.  
  887.     /* find out if there is a match on the right */
  888.     nbflag = FALSE;
  889.     cp3 = &vline[term.t_ncol];
  890.     cp4 = &pline[term.t_ncol];
  891.  
  892.     while (cp3[-1].c == cp4[-1].c && cp3[-1].a == cp4[-1].a) {
  893.     --cp3;
  894.     --cp4;
  895.     if (cp3[0].c != ' ' || cp3[0].a != 0)/* Note if any nonblank */
  896.       nbflag = TRUE;        /* in right match. */
  897.     }
  898.  
  899.     cp5 = cp3;
  900.  
  901.     if (nbflag == FALSE && eolexist == TRUE) {    /* Erase to EOL ? */
  902.     while (cp5 != cp1 && cp5[-1].c == ' ' && cp5[-1].a == 0)
  903.       --cp5;
  904.  
  905.     if (cp3-cp5 <= 3)        /* Use only if erase is */
  906.       cp5 = cp3;            /* fewer characters. */
  907.       }
  908.  
  909.     movecursor(row, cp1-&vline[0]);        /* Go to start of line. */
  910.     mode=0;
  911.   }
  912.   else{ /* if the vline and pline modes are different (Hebrew & English) */
  913.     if(*flags&VHEBR){
  914.     /* set up pointers to virtual and physical lines */
  915.     cp1 = &vline[term.t_ncol-1];
  916.     cp2 = &pline[0];
  917.     cp3 = &vline[-1];
  918.  
  919.     /* advance past any common chars at the left */
  920.     while (cp1 != cp3 && cp1[0].c == cp2[0].c && cp1[0].a == cp2[0].a) {
  921.     --cp1;
  922.     ++cp2;
  923.     }
  924.  
  925.     /* if both lines are the same, no update needs to be done */
  926.     if (cp1 == cp3){
  927.     *flags &= ~VFCHG;            /* mark it clean */
  928.     return(TRUE);
  929.     }
  930.  
  931.     /* find out if there is a match on the right */
  932.     nbflag = FALSE;
  933.     cp3 = &vline[-1];
  934.     cp4 = &pline[term.t_ncol];
  935.  
  936.     while (cp3[1].c == cp4[-1].c && cp3[1].a == cp4[-1].a) {
  937.     ++cp3;
  938.     --cp4;
  939.     if (cp3[0].c != ' ' || cp3[0].a != 0)/* Note if any nonblank */
  940.       nbflag = TRUE;        /* in right match. */
  941.     }
  942.  
  943.     cp5 = cp3;
  944.  
  945.     if (nbflag == FALSE && eolexist == TRUE) {    /* Erase to EOB ? */
  946.     while (cp5 != cp1 && cp5[1].c == ' ' && cp5[1].a == 0)
  947.       ++cp5;
  948.  
  949.     if (cp5-cp3 <= 3)        /* Use only if erase is */
  950.       cp5 = cp3;            /* fewer characters. */
  951.       }
  952.     movecursor(row, cp1-&vline[0]);        /* Go to start of line. */
  953.     mode=1;  
  954.     ttcol-=2;
  955.     }/*end if(*flags&VHEBR)*/
  956.     else{ /*if(*pflags&VHEBR)*/
  957.     /* set up pointers to virtual and physical lines */
  958.     cp1 = &vline[0];
  959.     cp2 = &pline[term.t_ncol-1];
  960.     cp3 = &vline[term.t_ncol];
  961.  
  962.     /* advance past any common chars at the left */
  963.     while (cp1 != cp3 && cp1[0].c == cp2[0].c && cp1[0].a == cp2[0].a) {
  964.     ++cp1;
  965.     --cp2;
  966.     }
  967.  
  968.     /* if both lines are the same, no update needs to be done */
  969.     if (cp1 == cp3){
  970.     *flags &= ~VFCHG;            /* mark it clean */
  971.     return(TRUE);
  972.     }
  973.  
  974.     /* find out if there is a match on the right */
  975.     nbflag = FALSE;
  976.     cp3 = &vline[term.t_ncol];
  977.     cp4 = &pline[-1];
  978.  
  979.     while (cp3[-1].c == cp4[1].c && cp3[-1].a == cp4[1].a) {
  980.     --cp3;
  981.     ++cp4;
  982.     if (cp3[0].c != ' ' || cp3[0].a != 0)/* Note if any nonblank */
  983.       nbflag = TRUE;        /* in right match. */
  984.       }
  985.  
  986.     cp5 = cp3;
  987.  
  988.     if (nbflag == FALSE && eolexist == TRUE) {    /* Erase to EOL ? */
  989.     while (cp5 != cp1 && cp5[-1].c == ' ' && cp5[-1].a == 0)
  990.       --cp5;
  991.  
  992.     if (cp3-cp5 <= 3)        /* Use only if erase is */
  993.       cp5 = cp3;            /* fewer characters. */
  994.  
  995.       }
  996.     movecursor(row, cp1-&vline[0]);        /* Go to start of line. */
  997.     mode=2;
  998.     }/*end if(*pflags&VHEBR)*/
  999.   }
  1000. #endif
  1001.  
  1002.  
  1003.  
  1004. #ifdef HEBREW
  1005.     if(compose_heb)goto show;
  1006. #endif
  1007.     if (!nbflag) {                /* use insert or del char? */
  1008.     cp6 = cp3;
  1009.     cp7 = cp4;
  1010.  
  1011.     if(inschar&&(cp7!=cp2 && cp6[0].c==cp7[-1].c && cp6[0].a==cp7[-1].a)){
  1012.         while (cp7 != cp2 && cp6[0].c==cp7[-1].c && cp6[0].a==cp7[-1].a){
  1013.         --cp7;
  1014.         --cp6;
  1015.         }
  1016.  
  1017.         if (cp7==cp2 && cp4-cp2 > 3){
  1018.         o_insert((char)cp1->c);     /* insert the char */
  1019.         display = FALSE;        /* only do it once!! */
  1020.         }
  1021.     }
  1022.     else if(delchar && cp3 != cp1 && cp7[0].c == cp6[-1].c
  1023.         && cp7[0].a == cp6[-1].a){
  1024.         while (cp6 != cp1 && cp7[0].c==cp6[-1].c && cp7[0].a==cp6[-1].a){
  1025.         --cp7;
  1026.         --cp6;
  1027.         }
  1028.  
  1029.         if (cp6==cp1 && cp5-cp6 > 3){
  1030.         o_delete();        /* insert the char */
  1031.         display = FALSE;        /* only do it once!! */
  1032.         }
  1033.     }
  1034.     }
  1035.  
  1036.  show:
  1037.  
  1038. /*    hide_cur();*/
  1039.  
  1040.     while (cp1 != cp5) {        /* Ordinary. */
  1041.     if(display){
  1042.         (*term.t_rev)(cp1->a);    /* set inverse for this char */
  1043.         (*term.t_putchar)(cp1->c);
  1044.     }
  1045.  
  1046. #ifndef HEBREW
  1047.     *cp2++ = *cp1++;
  1048.     ++ttcol;
  1049. #else
  1050.     switch(mode){
  1051.     case 0:
  1052.       *cp2++ = *cp1++;
  1053.       ++ttcol;
  1054.       break;
  1055.     case 1:
  1056.       *cp2++ = *cp1--;
  1057.       --ttcol;
  1058.       break;
  1059.     case 2:
  1060.       *cp2-- = *cp1++;
  1061.       ++ttcol;
  1062.       break;
  1063.     }
  1064. #endif
  1065.       }
  1066.  
  1067.     (*term.t_rev)(0);            /* turn off inverse anyway! */
  1068. /*    show_cur();*/
  1069. #ifdef HEBREW
  1070.     if (cp5 != cp3) {            /* Erase. */
  1071.     while (cp1 != cp3){
  1072.       switch(mode){
  1073.       case 0:
  1074.         *cp2++ = *cp1++;
  1075.         break;
  1076.       case 1:
  1077.         *cp2++ = *cp1--;
  1078.         break;
  1079.       case 2:
  1080.         *cp2-- = *cp1++;
  1081.         break;
  1082.       }
  1083.     }
  1084.     if(mode==1)hebmode=0;
  1085.     if(display){
  1086.       if(mode==2){
  1087.         pebol();
  1088.       }
  1089.       else{
  1090.         peeol();
  1091.       }
  1092.  
  1093.     }
  1094.     if(mode==1)hebmode=1;
  1095.       }
  1096.     if(compose_heb){
  1097.       if((*flags&VHEBR)&&(!(*pflags&VHEBR))){
  1098.     *pflags |= VHEBR;
  1099.     reverse_line(&pline[0],term.t_ncol);
  1100.       }
  1101.       else if((!(*flags&VHEBR))&&(*pflags&VHEBR)){
  1102.     *pflags &= ~VHEBR;
  1103.     reverse_line(&pline[0],term.t_ncol);
  1104.       }
  1105.     }
  1106. #else
  1107.     if (cp5 != cp3) {            /* Erase. */
  1108.     if(display)
  1109.       peeol();
  1110.     while (cp1 != cp3){
  1111.       *cp2++ = *cp1++;
  1112.     }
  1113.       }
  1114. #endif
  1115.     *flags &= ~VFCHG;            /* flag this line is changed */
  1116.  
  1117.   }
  1118.  
  1119.  
  1120. /*
  1121.  * Redisplay the mode line for the window pointed to by the "wp". This is the
  1122.  * only routine that has any idea of how the modeline is formatted. You can
  1123.  * change the modeline format by hacking at this routine. Called by "update"
  1124.  * any time there is a dirty window.
  1125.  */
  1126. modeline(wp)
  1127. WINDOW *wp;
  1128. {
  1129.     if(Pmaster){
  1130.     static char keys[13], labels[160];
  1131.     
  1132.         if(ComposerEditing)
  1133.       ShowPrompt();
  1134.     else{
  1135. #ifndef HEBREW
  1136.         sprintf(keys, "GCRYKOXJ%cVU^", 
  1137.             (Pmaster->alt_ed != NULL) ? '_' : 'W');
  1138.         sprintf(labels, "Get Help,Cancel,Read File,Prev Pg,Cut Text,Postpone,Send,Justify,%s,Next Pg,%s,Set Mark",  
  1139.             (Pmaster->alt_ed) ? "Alt Edit" : "Where is",
  1140.             (thisflag&CFFILL) ? "UnFill" : "UnCut Text");
  1141. #else
  1142. if(compose_heb){
  1143.         sprintf(keys, "GCRYKtX^OVUT"); 
  1144.         sprintf(labels, "Get Help,Cancel,Read File,Prev Pg,Cut Text,Direction,Send,Set Mark,Postpone,Next Pg,UnCut Text,  Heb/Eng");
  1145. }
  1146. else{
  1147.         sprintf(keys, "GCRYKOXJ%cVU^", 
  1148.             (Pmaster->alt_ed != NULL) ? '_' : 'W');
  1149.         sprintf(labels, "Get Help,Cancel,Read File,Prev Pg,Cut Text,Postpone,Send,Justify,%s,Next Pg,%s,Set Mark",  
  1150.             (Pmaster->alt_ed) ? "Alt Edit" : "Where is",
  1151.             (thisflag&CFFILL) ? "UnFill" : "UnCut Text");
  1152. }
  1153. #endif
  1154.         wkeyhelp(keys, labels);
  1155.     }
  1156.     }
  1157.     else{
  1158.     register char *cp;
  1159.     register int n;        /* cursor position count */
  1160.     register BUFFER *bp;
  1161.     register i;        /* loop index */
  1162.     register lchar;        /* character to draw line in buffer with */
  1163.     char     tline[NLINE];    /* buffer for part of mode line */
  1164.     CELL     c;
  1165. #ifdef HEBREW
  1166.         char tmp[32];         /* for gcc */
  1167. #endif
  1168.     n = 0;
  1169.     c.a = 1;
  1170. #if     MSDOS
  1171.     vtmove(1, 0);
  1172.     vteeol();
  1173. #endif
  1174.     vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */
  1175.     vtmove(n, 0);        /* Seek to right line. */
  1176.  
  1177. #if    REVSTA
  1178.     if (revexist)
  1179.       lchar = ' ';
  1180.     else
  1181. #endif
  1182.       lchar = '-';
  1183.  
  1184.     c.c = lchar;
  1185.     vtputc(c);
  1186.     bp = wp->w_bufp;
  1187.  
  1188.     n = 1;
  1189.  
  1190.     sprintf((cp=tline), "  UW PICO(tm) %s  ", version);    /* VERSION */
  1191.     
  1192.     while ((c.c = *cp++) != 0) {
  1193.         vtputc(c);
  1194.         ++n;
  1195.     }
  1196.  
  1197.     if (bp->b_fname[0] != 0){            /* File name. */
  1198.         sprintf(tline," File: ");
  1199.         cp = &bp->b_fname[0];
  1200.  
  1201.         if(strlen(cp) > (term.t_ncol-n-22)){   /* room for full path ? */
  1202.         strcat(tline,".../");
  1203.         while(strlen(cp) >= (term.t_ncol-n-22)){
  1204.             if(strchr(cp,'/') == NULL)
  1205.               cp = (char *)strchr(&bp->b_fname[0],'\0')-term.t_ncol-n-22;
  1206.             else
  1207.               cp = (char *)strchr(cp,'/') + 1;
  1208.         }
  1209.         }
  1210.  
  1211.         strcat(tline,cp);
  1212.  
  1213.         c.c = ' ';
  1214.         for(i=((term.t_ncol-n-12-strlen(tline))/2); i > 0; n++, i--)
  1215.           vtputc(c);
  1216.  
  1217.         cp = &tline[0];
  1218.  
  1219.         while ((c.c = *cp++) != 0){
  1220.         vtputc(c);
  1221.         ++n;
  1222.             }
  1223.  
  1224.         }
  1225.         else{
  1226.         cp = " New Buffer ";
  1227.         c.c = lchar;
  1228.             for(i=(term.t_ncol-strlen(cp))/2; n < i; n++)
  1229.           vtputc(c);
  1230.         while ((c.c = *cp++) != 0) {
  1231.         vtputc(c);
  1232.         ++n;
  1233.             }
  1234.     }
  1235.  
  1236. #if WFDEBUG
  1237.     vtputc(lchar);
  1238.     vtputc((wp->w_flag&WFMODE)!=0  ? 'M' : lchar);
  1239.     vtputc((wp->w_flag&WFHARD)!=0  ? 'H' : lchar);
  1240.     vtputc((wp->w_flag&WFEDIT)!=0  ? 'E' : lchar);
  1241.     vtputc((wp->w_flag&WFMOVE)!=0  ? 'V' : lchar);
  1242.     vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar);
  1243.     n += 6;
  1244. #endif
  1245.  
  1246. #ifndef HEBREW
  1247.     if ((bp->b_flag&BFCHG) != 0)                /* "MOD" if changed. */
  1248.       cp = "Modified         ";
  1249.     else
  1250.       cp = "                 ";
  1251. #else
  1252.     cp=tmp;
  1253.     if ((bp->b_flag&BFCHG) != 0)               
  1254.       strcpy(cp,"Modified         ");
  1255.     else
  1256.       strcpy(cp,"                 ");
  1257.  
  1258.     if(compose_heb){
  1259.       if(eng_in_heb==hebmain)strcpy(cp+10,"Eng ");
  1260.       else          strcpy(cp+10,"Heb ");
  1261.       if(hebmain)strcpy(cp+14,"<- ");
  1262.       else strcpy(cp+14,"-> ");
  1263.     }  
  1264. #endif
  1265.  
  1266.     c.c = lchar;
  1267.     while (n < (term.t_ncol - strlen(cp))){        /* Pad to full width. */
  1268.         vtputc(c);
  1269.         ++n;
  1270.         }
  1271.  
  1272.     while ((c.c = *cp++) != 0){
  1273.         vtputc(c);
  1274.         ++n;
  1275.     }
  1276.     }
  1277. }
  1278.  
  1279. #ifdef HEBREW
  1280. mode_lang()
  1281. {
  1282. char str[16];
  1283. char *cp;
  1284.  
  1285. if(compose_heb){
  1286.   hide_cur();
  1287.   if(eng_in_heb==hebmain)strcpy(str,"Eng ");
  1288.   else strcpy(str,"Heb ");
  1289.   if(hebmain)strcat(str,"<- ");
  1290.   else strcat(str,"-> ");
  1291.   movecursor(0, term.t_ncol - strlen(str));
  1292.   (*term.t_rev)(1);
  1293.   for(cp=str;*cp;cp++){
  1294.       (*term.t_putchar)(*cp);
  1295.   }
  1296.   (*term.t_rev)(0);
  1297.   ttflush();
  1298.   show_cur();
  1299. }
  1300. }
  1301. #endif
  1302.  
  1303.  
  1304. /*
  1305.  * Send a command to the terminal to move the hardware cursor to row "row"
  1306.  * and column "col". The row and column arguments are origin 0. Optimize out
  1307.  * random calls. Update "ttrow" and "ttcol".
  1308.  */
  1309. movecursor(row, col)
  1310. int row, col;
  1311. {
  1312. #ifndef HEBREW
  1313.     if (row!=ttrow || col!=ttcol) {
  1314. #endif
  1315.         ttrow = row;
  1316.         ttcol = col;
  1317.         (*term.t_move)(row, col);
  1318. #ifndef HEBREW
  1319.     }
  1320. #endif
  1321. }
  1322.  
  1323.  
  1324. /*
  1325.  * Erase the message line. This is a special routine because the message line
  1326.  * is not considered to be part of the virtual screen. It always works
  1327.  * immediately; the terminal buffer is flushed via a call to the flusher.
  1328.  */
  1329. mlerase()
  1330. {
  1331.     int i;
  1332.  
  1333.     movecursor(term.t_nrow - 2, 0);
  1334.     (*term.t_rev)(0);
  1335.     if (eolexist == TRUE)
  1336.       peeol();
  1337.     else {
  1338.         for (i = 0; i < term.t_ncol - 1; i++)
  1339.       (*term.t_putchar)(' ');
  1340.         movecursor(term.t_nrow - 2, 1);    /* force the move! */
  1341.         movecursor(term.t_nrow - 2, 0);
  1342.     }
  1343.     (*term.t_flush)();
  1344.     mpresf = FALSE;
  1345. }
  1346.  
  1347.  
  1348. /*
  1349.  * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  1350.  * ABORT. The ABORT status is returned if the user bumps out of the question
  1351.  * with a ^G. if d >= 0, d is the default answer returned. Otherwise there
  1352.  * is no default.
  1353.  */
  1354. mlyesno(prompt, dflt)
  1355. char  *prompt;
  1356. int   dflt;
  1357. {
  1358.     int  c;                /* input character */
  1359.  
  1360. #ifdef    MAYBELATER
  1361.     wkeyhelp("0C0000000000", "Cancel");
  1362.     if(Pmaster)
  1363.       curwp->w_flag |= WFMODE;
  1364.     else
  1365.       sgarbf = TRUE;
  1366. #endif
  1367.     if(dflt >= 0)
  1368.       sprintf(s, "%s? [%c] : ", prompt, (dflt) ? 'y' : 'n');
  1369.     else
  1370.       sprintf(s, "%s (y/n)? ", prompt);
  1371.  
  1372.     while(1){
  1373. #ifdef HEBREW
  1374.     message_mode=1;
  1375. #endif
  1376.     mlwrite(s, NULL);
  1377.  
  1378.     (*term.t_rev)(1);
  1379.     while((c = GetKey()) == NODATA)
  1380.       ;                /* don't repaint if timeout */
  1381. #ifdef HEBREW
  1382.     message_mode=0;
  1383. #endif
  1384.     (*term.t_rev)(0);
  1385.  
  1386.     if(dflt >= 0 && c == (CTRL|'M')){
  1387.         (*term.t_rev)(1);
  1388.         pputs((dflt) ? "Yes" : "No", 1);
  1389.         (*term.t_rev)(0);
  1390.         return(dflt);
  1391.     }
  1392.  
  1393.     if (c == (CTRL|'C') || c == F3){    /* Bail out! */
  1394.         (*term.t_rev)(1);
  1395.         pputs("ABORT", 1);
  1396.         (*term.t_rev)(0);
  1397.         return(ABORT);
  1398.     }
  1399.  
  1400.     if (c=='y' || c=='Y'){
  1401.         (*term.t_rev)(1);
  1402.         pputs("Yes", 1);
  1403.         (*term.t_rev)(0);
  1404.         return(TRUE);
  1405.     }
  1406.  
  1407.     if (c=='n' || c=='N'){
  1408.         (*term.t_rev)(1);
  1409.         pputs("No", 1);
  1410.         (*term.t_rev)(0);
  1411.         return(FALSE);
  1412.     }
  1413.     else
  1414.       (*term.t_beep)();
  1415.     }
  1416. }
  1417.  
  1418.  
  1419.  
  1420. /*
  1421.  * Write a prompt into the message line, then read back a response. Keep
  1422.  * track of the physical position of the cursor. If we are in a keyboard
  1423.  * macro throw the prompt away, and return the remembered response. This
  1424.  * lets macros run at full speed. The reply is always terminated by a carriage
  1425.  * return. Handle erase, kill, and abort keys.
  1426.  */
  1427. mlreply(prompt, buf, nbuf, flg)
  1428. char  *prompt, *buf;
  1429. int    nbuf, flg;
  1430. {
  1431.     return(mlreplyd(prompt, buf, nbuf, flg|QDEFLT));
  1432. }
  1433.  
  1434.  
  1435. /*
  1436.  * function key mappings
  1437.  */
  1438. static int rfkm[12][2] = {
  1439.     { F1,  (CTRL|'G')},
  1440.     { F2,  0 },
  1441.     { F3,  (CTRL|'C')},
  1442.     { F4,  (CTRL|'T')},
  1443.     { F5,  0 },
  1444.     { F6,  0 },
  1445.     { F7,  0 },
  1446.     { F8,  0 },
  1447.     { F9,  0 },
  1448.     { F10, 0 },
  1449.     { F11, 0 },
  1450.     { F12, 0 }
  1451. };
  1452.  
  1453.  
  1454. /*
  1455.  * mlreplyd - write the prompt to the message line along with an default
  1456.  *          answer already typed in.  Carraige return accepts the
  1457.  *          default.  answer returned in buf which also holds the initial
  1458.  *            default, nbuf is it's length, def set means use default value,
  1459.  *            and ff means for-file which checks that all chars are allowed
  1460.  *            in file names.
  1461.  */
  1462. mlreplyd(prompt, buf, nbuf, flg)
  1463. char  *prompt;
  1464. char  *buf;
  1465. int    nbuf, flg;
  1466. {
  1467.     register int    c;                /* current char       */
  1468.     register char   *b;                /* pointer in buf     */
  1469.     register int    i;
  1470.     register int    maxl;
  1471.     register int    plen;
  1472.     int      changed = FALSE;
  1473.     int ret;
  1474. #ifdef HEBREW
  1475.     char e_in_h=eng_in_heb;
  1476.  
  1477.     if(search_mode){
  1478.       hebmode=1;
  1479.       eng_in_heb=0;
  1480.     }
  1481. #endif    
  1482.  
  1483.     mlwrite(prompt, NULL);
  1484.     plen = strlen(prompt);
  1485.     if(!(flg&QDEFLT))
  1486.       *buf = '\0';
  1487.  
  1488.     (*term.t_rev)(1);
  1489.  
  1490.     maxl = (nbuf < term.t_ncol - plen - 1) ? nbuf : term.t_ncol - plen - 1;
  1491.  
  1492.     pputs(buf, 1);
  1493.     b = &buf[strlen(buf)];
  1494.     
  1495.     for (;;) {
  1496.     movecursor(ttrow, plen+b-buf);
  1497.     (*term.t_flush)();
  1498. #ifdef HEBREW
  1499.     message_mode=1;
  1500. #endif
  1501.  
  1502.     while((c = GetKey()) == NODATA)
  1503.       ;
  1504. #ifdef HEBREW
  1505.     message_mode=0;
  1506. #endif
  1507.  
  1508.     switch(normal(c, rfkm, 2)){
  1509.       case (CTRL|'A') :            /* CTRL-A beginning     */
  1510.         b = buf;
  1511.         continue;
  1512.  
  1513.       case (CTRL|'B') :            /* CTRL-B back a char   */
  1514.         if(ttcol > plen)
  1515.         b--;
  1516.         continue;
  1517.  
  1518.       case (CTRL|'C') :            /* CTRL-C abort        */
  1519.         pputs("^C", 1);
  1520.         ctrlg(FALSE, 0);
  1521.         (*term.t_rev)(0);
  1522.         (*term.t_flush)();
  1523.         ret=ABORT;
  1524.         goto quit;
  1525.  
  1526.       case (CTRL|'E') :            /* CTRL-E end of line   */
  1527.         b = &buf[strlen(buf)];
  1528.         continue;
  1529.  
  1530.       case (CTRL|'F') :            /* CTRL-F forward a char*/
  1531.         if(*b != '\0')
  1532.         b++;
  1533.         continue;
  1534.  
  1535.       case (CTRL|'G') :            /* CTRL-G help        */
  1536.         pputs("HELP", 1);
  1537.         (*term.t_rev)(0);
  1538.         (*term.t_flush)();
  1539.         ret=HELPCH;
  1540.         goto quit;
  1541.  
  1542.       case (CTRL|'H') :            /* CTRL-H backspace    */
  1543.       case 0x7f :                /*        rubout    */
  1544.         if (b <= buf)
  1545.           break;
  1546.         b--;
  1547.         ttcol--;                /* cheating!  no pputc */
  1548. #ifndef HEBREW
  1549.         (*term.t_putchar)('\b');
  1550. #else
  1551.         if(search_mode) (*term.t_putchar)(' ');
  1552.         else (*term.t_putchar)('\b');
  1553. #endif
  1554.  
  1555.       case (CTRL|'D') :            /* CTRL-D delete char   */
  1556.         changed=TRUE;
  1557.         i = 0;
  1558.         do                    /* blat out left char   */
  1559.           b[i] = b[i+1];
  1560.         while(b[i++] != '\0');
  1561.         break;
  1562.  
  1563.       case (CTRL|'L') :            /* CTRL-L redraw    */
  1564.         (*term.t_rev)(0);
  1565.         ret=CTRL|'L';
  1566.         goto quit;
  1567.  
  1568.       case (CTRL|'T') :            /* CTRL-T special    */
  1569.         (*term.t_rev)(0);
  1570.         ret=CTRL|'T';
  1571. #ifdef HEBREW
  1572.         if(compose_heb && search_mode){
  1573.           eng_in_heb= !eng_in_heb;
  1574.           break;
  1575.         }
  1576. #endif
  1577.         goto quit;
  1578.  
  1579.       case (CTRL|'K') :            /* CTRL-K kill line    */
  1580.         changed=TRUE;
  1581.         buf[0] = '\0';
  1582.         b = buf;
  1583.         movecursor(ttrow, plen);
  1584.         break;
  1585.  
  1586.       case K_PAD_LEFT:
  1587. #ifndef HEBREW
  1588.         if(ttcol > plen)b--;
  1589. #else
  1590.         if(!search_mode){
  1591.           if(ttcol > plen)b--;
  1592.         }
  1593.         else{
  1594.           if(*b != '\0')b++;
  1595.         }
  1596. #endif
  1597.         continue;
  1598.  
  1599.       case K_PAD_RIGHT:
  1600. #ifndef HEBREW
  1601.         if(*b != '\0')b++;
  1602. #else
  1603.         if(!search_mode){
  1604.           if(*b != '\0')b++;
  1605.         }
  1606.         else{
  1607.           if(ttcol > plen)b--;          
  1608.         }
  1609. #endif
  1610.         continue;
  1611.  
  1612.       case F3 :                /* abort */
  1613.         pputs("ABORT", 1);
  1614.         ctrlg(FALSE, 0);
  1615.         (*term.t_rev)(0);
  1616.         (*term.t_flush)();
  1617.         ret=ABORT;
  1618.         goto quit;
  1619.  
  1620.       case F1 :                /* sort of same thing */
  1621.         (*term.t_rev)(0);
  1622.         (*term.t_flush)();
  1623.         ret=HELPCH;
  1624.         goto quit;
  1625.  
  1626.       case (CTRL|'M') :            /*        newline       */
  1627.         (*term.t_rev)(0);
  1628.         (*term.t_flush)();
  1629.         ret=changed;
  1630.         goto quit;
  1631.  
  1632.       default : 
  1633.         if(strlen(buf) >= maxl){        /* contain the text      */
  1634.         (*term.t_beep)();
  1635.         continue;
  1636.         }
  1637.         changed=TRUE;
  1638.  
  1639.         if(c&(~0xff)){            /* bag ctrl/special chars */
  1640.         (*term.t_beep)();
  1641.         }
  1642.         else{
  1643.         i = strlen(b);
  1644.         if(flg&QFFILE){
  1645.             if(!fallowc(c)){         /* c OK in filename? */
  1646.             (*term.t_beep)();
  1647.             continue;
  1648.             }
  1649.         }
  1650.         do                /* blat out left char   */
  1651.           b[i+1] = b[i];
  1652.         while(i-- >= 0);
  1653. #ifndef HEBREW
  1654.         *b++ = c;
  1655.         pputc(c, 0);
  1656. #else
  1657.         if(!search_mode || !eng_in_heb){
  1658.           *b++ = c;
  1659.           pputc(c, 0);
  1660.         }
  1661.         else{
  1662.           *b=c;
  1663.         }
  1664. #endif
  1665.         }
  1666.     }
  1667.  
  1668.     pputs(b, 1);                /* show default */
  1669.     i = term.t_ncol-1;
  1670.     while(pscreen[ttrow]->v_text[i].c == ' ' 
  1671.           && pscreen[ttrow]->v_text[i].a == 0)
  1672.       i--;
  1673.  
  1674.     while(ttcol <= i)
  1675.       pputc(' ', 0);
  1676.     }
  1677.   quit:
  1678. #ifdef HEBREW
  1679.     if(search_mode)hebmode=0;
  1680.     eng_in_heb=e_in_h;
  1681. #endif
  1682.     return ret;
  1683. }
  1684.  
  1685.  
  1686. /*
  1687.  * emlwrite() - write the message string to the error half of the screen
  1688.  *              center justified.  much like mlwrite (which is still used
  1689.  *              to paint the line for prompts and such), except it center
  1690.  *              the text.
  1691.  */
  1692. void
  1693. emlwrite(message, arg) 
  1694. char    *message;
  1695. void    *arg;
  1696. {
  1697.     register char *bufp = message;
  1698.     register char *ap;
  1699.     register long l;
  1700.  
  1701.     mlerase();
  1702.  
  1703.     if((l = strlen(message)) == 0)        /* nothing to write, bag it */
  1704.       return;
  1705.  
  1706.     /*
  1707.      * next, figure out where the to move the cursor so the message 
  1708.      * comes out centered
  1709.      */
  1710.     if((ap=(char *)strchr(message, '%')) != NULL){
  1711.     l -= 2;
  1712.     switch(ap[1]){
  1713.       case '%':
  1714.       case 'c':
  1715.         l += 1;
  1716.         break;
  1717.       case 'd':
  1718.         l += (long)dumbroot((int)arg, 10);
  1719.         break;
  1720.       case 'D':
  1721.         l += (long)dumblroot((long)arg, 10);
  1722.         break;
  1723.       case 'o':
  1724.         l += (long)dumbroot((int)arg, 8);
  1725.         break;
  1726.       case 'x':
  1727.         l += (long)dumbroot((int)arg, 16);
  1728.         break;
  1729.       case 's':
  1730.             l += strlen((char *)arg);
  1731.         break;
  1732.     }
  1733.     }
  1734.  
  1735.     if(l-4 <= term.t_ncol)            /* this wouldn't be good */
  1736.       movecursor(term.t_nrow-2, (term.t_ncol - (int)l - 4)/2);
  1737.     else
  1738.       movecursor(term.t_nrow-2, 0);
  1739.  
  1740.     (*term.t_rev)(1);
  1741.     pputs("[ ", 1);
  1742.     while (*bufp != '\0' && ttcol < term.t_ncol-2){
  1743.     if(*bufp == '\007')
  1744.       (*term.t_beep)();
  1745.     else if(*bufp == '%'){
  1746.         switch(*++bufp){
  1747.           case 'c':
  1748.         pputc((char)(int)arg, 0);
  1749.         break;
  1750.           case 'd':
  1751.         mlputi((int)arg, 10);
  1752.         break;
  1753.           case 'D':
  1754.         mlputli((long)arg, 10);
  1755.         break;
  1756.           case 'o':
  1757.         mlputi((int)arg, 16);
  1758.         break;
  1759.           case 'x':
  1760.         mlputi((int)arg, 8);
  1761.         break;
  1762.           case 's':
  1763.         pputs((char *)arg, 0);
  1764.         break;
  1765.           case '%':
  1766.           default:
  1767.         pputc(*bufp, 0);
  1768.         break;
  1769.         }
  1770.     }
  1771.     else
  1772.       pputc(*bufp, 0);
  1773.     bufp++;
  1774.     }
  1775.  
  1776.     pputs(" ]", 1);
  1777.     (*term.t_rev)(0);
  1778.     (*term.t_flush)();
  1779.     mpresf = TRUE;
  1780. }
  1781.  
  1782.  
  1783. /*
  1784.  * Write a message into the message line. Keep track of the physical cursor
  1785.  * position. A small class of printf like format items is handled. Assumes the
  1786.  * stack grows down; this assumption is made by the "++" in the argument scan
  1787.  * loop. Set the "message line" flag TRUE.
  1788.  */
  1789. mlwrite(fmt, arg)
  1790. char *fmt;
  1791. void *arg;
  1792. {
  1793.     register int c;
  1794.     register char *ap;
  1795.  
  1796.     /*
  1797.      * the idea is to only highlight if there is something to show
  1798.      */
  1799.     mlerase();
  1800.  
  1801.     ttcol = 0;
  1802.     (*term.t_rev)(1);
  1803.     ap = (char *) &arg;
  1804.     while ((c = *fmt++) != 0) {
  1805.         if (c != '%') {
  1806.             (*term.t_putchar)(c);
  1807.             ++ttcol;
  1808.     }
  1809.         else {
  1810.             c = *fmt++;
  1811.             switch (c) {
  1812.           case 'd':
  1813.         mlputi(*(int *)ap, 10);
  1814.         ap += sizeof(int);
  1815.         break;
  1816.  
  1817.           case 'o':
  1818.         mlputi(*(int *)ap,  8);
  1819.         ap += sizeof(int);
  1820.         break;
  1821.  
  1822.           case 'x':
  1823.         mlputi(*(int *)ap, 16);
  1824.         ap += sizeof(int);
  1825.         break;
  1826.  
  1827.           case 'D':
  1828.         mlputli(*(long *)ap, 10);
  1829.         ap += sizeof(long);
  1830.         break;
  1831.  
  1832.           case 's':
  1833.         pputs(*(char **)ap, 1);
  1834.         ap += sizeof(char *);
  1835.         break;
  1836.  
  1837.               default:
  1838.         (*term.t_putchar)(c);
  1839.         ++ttcol;
  1840.         }
  1841.     }
  1842.     }
  1843.  
  1844.     c = ttcol;
  1845.     while(ttcol < term.t_ncol)
  1846.       pputc(' ', 0);
  1847.  
  1848.     movecursor(term.t_nrow - 2, c);
  1849.     (*term.t_rev)(0);
  1850.     (*term.t_flush)();
  1851.     mpresf = TRUE;
  1852. }
  1853.  
  1854.  
  1855. /*
  1856.  * Write out an integer, in the specified radix. Update the physical cursor
  1857.  * position. This will not handle any negative numbers; maybe it should.
  1858.  */
  1859. mlputi(i, r)
  1860. int i, r;
  1861. {
  1862.     register int q;
  1863.     static char hexdigits[] = "0123456789ABCDEF";
  1864.  
  1865.     if (i < 0){
  1866.         i = -i;
  1867.     pputc('-', 1);
  1868.     }
  1869.  
  1870.     q = i/r;
  1871.  
  1872.     if (q != 0)
  1873.       mlputi(q, r);
  1874.  
  1875.     pputc(hexdigits[i%r], 1);
  1876. }
  1877.  
  1878.  
  1879. /*
  1880.  * do the same except as a long integer.
  1881.  */
  1882. mlputli(l, r)
  1883. long l;
  1884. int  r;
  1885. {
  1886.     register long q;
  1887.  
  1888.     if (l < 0){
  1889.         l = -l;
  1890.         pputc('-', 1);
  1891.     }
  1892.  
  1893.     q = l/r;
  1894.  
  1895.     if (q != 0)
  1896.       mlputli(q, r);
  1897.  
  1898.     pputc((int)(l%r)+'0', 1);
  1899. }
  1900.  
  1901.  
  1902. /*
  1903.  * scrolldown - use stuff to efficiently move blocks of text on the
  1904.  *              display, and update the pscreen array to reflect those
  1905.  *              moves...
  1906.  *
  1907.  *        wp is the window to move in
  1908.  *        r  is the row at which to begin scrolling
  1909.  *        n  is the number of lines to scrol
  1910.  */
  1911. scrolldown(wp, r, n)
  1912. WINDOW *wp;
  1913. int     r, n;
  1914. {
  1915. #ifdef    TERMCAP
  1916.     register int i;
  1917.     register int l;
  1918.     register VIDEO *vp1;
  1919.     register VIDEO *vp2;
  1920.  
  1921.     if(!n)
  1922.       return;
  1923.  
  1924.     if(r < 0){
  1925.     r = wp->w_toprow;
  1926.     l = wp->w_ntrows;
  1927.     }
  1928.     else{
  1929.     if(r > wp->w_toprow)
  1930.         vscreen[r-1]->v_flag |= VFCHG;
  1931.     l = wp->w_toprow+wp->w_ntrows-r;
  1932.     }
  1933.  
  1934.     o_scrolldown(r, n);
  1935.  
  1936.     for(i=l-n-1; i >=  0; i--){
  1937.     vp1 = pscreen[r+i]; 
  1938.     vp2 = pscreen[r+i+n];
  1939.     bcopy(vp1, vp2, term.t_ncol * sizeof(CELL));
  1940.     }
  1941.     pprints(r+n-1, r);
  1942.     ttrow = HUGE;
  1943.     ttcol = HUGE;
  1944. #endif /* TERMCAP */
  1945. }
  1946.  
  1947.  
  1948. /*
  1949.  * scrollup - use tcap stuff to efficiently move blocks of text on the
  1950.  *            display, and update the pscreen array to reflect those
  1951.  *            moves...
  1952.  */
  1953. scrollup(wp, r, n)
  1954. WINDOW *wp;
  1955. int     r, n;
  1956. {
  1957. #ifdef    TERMCAP
  1958.     register int i;
  1959.     register VIDEO *vp1;
  1960.     register VIDEO *vp2;
  1961.  
  1962.     if(!n)
  1963.       return;
  1964.  
  1965.     if(r < 0)
  1966.       r = wp->w_toprow;
  1967.  
  1968.     o_scrollup(r, n);
  1969.  
  1970.     i = 0;
  1971.     while(1){
  1972.     if(Pmaster){
  1973.         if(!(r+i+n < wp->w_toprow+wp->w_ntrows))
  1974.           break;
  1975.     }
  1976.     else{
  1977.         if(!((i < wp->w_ntrows-n)&&(r+i+n < wp->w_toprow+wp->w_ntrows)))
  1978.           break;
  1979.     }
  1980.     vp1 = pscreen[r+i+n]; 
  1981.     vp2 = pscreen[r+i];
  1982.     bcopy(vp1, vp2, term.t_ncol * sizeof(CELL));
  1983.     i++;
  1984.     }
  1985.     pprints(wp->w_toprow+wp->w_ntrows-n, wp->w_toprow+wp->w_ntrows-1);
  1986.     ttrow = HUGE;
  1987.     ttcol = HUGE;
  1988. #endif /* TERMCAP */
  1989. }
  1990.  
  1991.  
  1992. /*
  1993.  * print spaces in the physical screen starting from row abs(n) working in
  1994.  * either the positive or negative direction (depending on sign of n).
  1995.  */
  1996. pprints(x, y)
  1997. int x, y;
  1998. {
  1999.     register int i;
  2000.     register int j;
  2001.  
  2002.     if(x < y){
  2003.     for(i = x;i <= y; ++i){
  2004.         for(j = 0; j < term.t_ncol; j++){
  2005.         pscreen[i]->v_text[j].c = ' ';
  2006.         pscreen[i]->v_text[j].a = 0;
  2007.         }
  2008.         }
  2009.     }
  2010.     else{
  2011.     for(i = x;i >= y; --i){
  2012.         for(j = 0; j < term.t_ncol; j++){
  2013.         pscreen[i]->v_text[j].c = ' ';
  2014.         pscreen[i]->v_text[j].a = 0;
  2015.         }
  2016.         }
  2017.     }
  2018.     ttrow = y;
  2019.     ttcol = 0;
  2020. }
  2021.  
  2022.  
  2023.  
  2024. /*
  2025.  * doton - return the physical line number that the dot is on in the
  2026.  *         current window, and by side effect the number of lines remaining
  2027.  */
  2028. doton(r, chs)
  2029. int       *r;
  2030. unsigned  *chs;
  2031. {
  2032.     register int  i = 0;
  2033.     register LINE *lp = curwp->w_linep;
  2034.     int      l = -1;
  2035.  
  2036.     *chs = 0;
  2037.     while(i++ < curwp->w_ntrows){
  2038.     if(lp == curwp->w_dotp)
  2039.       l = i-1;
  2040.     lp = lforw(lp);
  2041.     if(lp == curwp->w_bufp->b_linep){
  2042.         i++;
  2043.         break;
  2044.     }
  2045.     if(l >= 0)
  2046.       (*chs) += llength(lp);
  2047.     }
  2048.     *r = i-l-2;
  2049.     return(l+curwp->w_toprow);
  2050. }
  2051.  
  2052.  
  2053.  
  2054. /*
  2055.  * resize_pico - given new window dimensions, allocate new resources
  2056.  */
  2057. resize_pico(row, col)
  2058. int  row, col;
  2059. {
  2060.     int old_nrow, old_ncol;
  2061.     register int i;
  2062.     register VIDEO *vp;
  2063.  
  2064.     old_nrow = term.t_nrow;
  2065.     old_ncol = term.t_ncol;
  2066.  
  2067.     term.t_nrow = row;
  2068.     term.t_ncol = col;
  2069.  
  2070.     if (old_ncol == term.t_ncol && old_nrow == term.t_nrow)
  2071.       return(TRUE);
  2072.  
  2073.     curwp->w_toprow = 2;
  2074.     curwp->w_ntrows = term.t_nrow-4;           /* "-4" for mode line and keys */
  2075.  
  2076.     if(Pmaster)
  2077.       fillcol = (term.t_ncol > 80) ? 77 : term.t_ncol - 6;
  2078.     else
  2079.       fillcol = term.t_ncol - 6;           /* we control the fill column */
  2080.  
  2081.     /* 
  2082.      * free unused screen space ...
  2083.      */
  2084.     for(i=term.t_nrow+1; i <= old_nrow; ++i){
  2085.     free((char *) vscreen[i]);
  2086.     free((char *) pscreen[i]);
  2087.     }
  2088.  
  2089.     /* 
  2090.      * realloc new space for screen ...
  2091.      */
  2092.     if((vscreen=(VIDEO **)realloc(vscreen,(term.t_nrow+1)*sizeof(VIDEO *))) == NULL){
  2093.     if(Pmaster)
  2094.       return(-1);
  2095.     else
  2096.       exit(1);
  2097.     }
  2098.  
  2099.     if((pscreen=(VIDEO **)realloc(pscreen,(term.t_nrow+1)*sizeof(VIDEO *))) == NULL){
  2100.     if(Pmaster)
  2101.       return(-1);
  2102.     else
  2103.       exit(1);
  2104.     }
  2105.  
  2106.     for (i = 0; i <= term.t_nrow; ++i) {
  2107.     if(i <= old_nrow)
  2108.       vp = (VIDEO *) realloc(vscreen[i], sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  2109.     else
  2110.       vp = (VIDEO *) malloc(sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  2111.  
  2112.     if (vp == NULL)
  2113.       exit(1);
  2114.     vp->v_flag = VFCHG;
  2115.     vscreen[i] = vp;
  2116.     if(old_ncol < term.t_ncol){  /* don't let any garbage in */
  2117.         vtrow = i;
  2118.         vtcol = (i < old_nrow) ? old_ncol : 0;
  2119.         vteeol();
  2120.     }
  2121.  
  2122.     if(i <= old_nrow)
  2123.       vp = (VIDEO *) realloc(pscreen[i], sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  2124.     else
  2125.       vp = (VIDEO *) malloc(sizeof(VIDEO)+(term.t_ncol*sizeof(CELL)));
  2126.  
  2127.     if (vp == NULL)
  2128.       exit(1);
  2129.  
  2130.     vp->v_flag = VFCHG;
  2131.     pscreen[i] = vp;
  2132.     }
  2133.  
  2134.     if(!ResizeBrowser()){
  2135.     if(Pmaster){
  2136.         ResizeHeader();
  2137.     }
  2138.     else{
  2139.         lchange(WFHARD);                   /* set update flags... */
  2140.         curwp->w_flag |= WFMODE;           /* and modeline so we  */
  2141.         refresh(0, 1);                     /* redraw the whole enchilada. */
  2142.         update();                          /* do it */
  2143.     }
  2144.     }
  2145.  
  2146.     return(TRUE);
  2147. }
  2148.  
  2149.  
  2150. /*
  2151.  * showCompTitle - display the anchor line passed in from pine
  2152.  */
  2153. showCompTitle()
  2154. {
  2155. #ifdef HEBREW
  2156.   char str[16];
  2157.   char *cp;
  2158. #endif
  2159.     if(Pmaster){
  2160.     register char *bufp;
  2161.     extern   char *pico_anchor;
  2162.  
  2163.     if((bufp = pico_anchor) == NULL)
  2164.       return(1);
  2165.  
  2166.     movecursor(COMPOSER_TITLE_LINE, 0);
  2167.     (*term.t_rev)(1);   
  2168.     while (ttcol < term.t_ncol)
  2169.       if(*bufp != '\0')
  2170.         pputc(*bufp++, 1);
  2171.           else
  2172.         pputc(' ', 1);
  2173.  
  2174. #ifdef HEBREW
  2175.     if(compose_heb){
  2176.       if(eng_in_heb)strcpy(str," Eng ");
  2177.       else strcpy(str," Heb ");
  2178.       if(hebmain)strcat(str,"<- ");
  2179.       else strcat(str,"-> ");
  2180.       movecursor(0, term.t_ncol - strlen(str));
  2181.       for(cp=str;*cp;cp++){
  2182.         pputc(*cp,1);
  2183.       }
  2184.     }
  2185. #endif
  2186.     (*term.t_rev)(0);
  2187.     movecursor(COMPOSER_TITLE_LINE + 1, 0);
  2188.     peeol();
  2189.     }
  2190. }
  2191.  
  2192.  
  2193.  
  2194. /*
  2195.  * zotdisplay - blast malloc'd space created for display maps
  2196.  */
  2197. zotdisplay()
  2198. {
  2199.     register int i;
  2200.  
  2201.     for (i = 0; i <= term.t_nrow; ++i){        /* free screens */
  2202.     free((char *) vscreen[i]);
  2203.     free((char *) pscreen[i]);
  2204.     }
  2205.  
  2206.     free((char *) vscreen);
  2207.     free((char *) pscreen);
  2208. }
  2209.  
  2210.  
  2211.  
  2212. /*
  2213.  * nlforw() - returns the number of lines from the top to the dot
  2214.  */
  2215. nlforw()
  2216. {
  2217.     register int  i = 0;
  2218.     register LINE *lp = curwp->w_linep;
  2219.     
  2220.     while(lp != curwp->w_dotp){
  2221.     lp = lforw(lp);
  2222.     i++;
  2223.     }
  2224.     return(i);
  2225. }
  2226.  
  2227.  
  2228.  
  2229. /*
  2230.  * pputc - output the given char, keep track of it on the physical screen
  2231.  *       array, and keep track of the cursor
  2232.  */
  2233. pputc(c, a)
  2234. int   c;                /* char to write */
  2235. int   a;                /* and its attribute */
  2236. {
  2237.     if((ttcol >= 0 && ttcol < term.t_ncol) 
  2238.        && (ttrow >= 0 && ttrow <= term.t_nrow)){
  2239. /*    (*term.t_rev)(a);*/
  2240.     (*term.t_putchar)(c);            /* write it */
  2241. /*    (*term.t_rev)(!a);*/
  2242.     pscreen[ttrow]->v_text[ttcol].c = c;    /* keep track of it */
  2243.     pscreen[ttrow]->v_text[ttcol++].a = a;    /* keep track of it */
  2244.     }
  2245. }
  2246.  
  2247.  
  2248. /*
  2249.  * pputs - print a string and keep track of the cursor
  2250.  */
  2251. pputs(s, a)
  2252. register char *s;            /* string to write */
  2253. register int   a;            /* and its attribute */
  2254. {
  2255.     while (*s != '\0')
  2256.       pputc(*s++, a);
  2257. }
  2258.  
  2259.  
  2260. /*
  2261.  * peeol - physical screen array erase to end of the line.  remember to
  2262.  *       track the cursor.
  2263.  */
  2264. peeol()
  2265. {
  2266.     register int r = ttrow;
  2267.     register int c = ttcol;
  2268.     CELL         cl;
  2269.  
  2270.     if(c < term.t_ncol){
  2271.       cl.c = ' ';
  2272.       cl.a = 0;
  2273.       (*term.t_eeol)();
  2274.       while(c < term.t_ncol && c >= 0 && r <= term.t_nrow && r >= 0)
  2275.     pscreen[r]->v_text[c++] = cl;
  2276.     }
  2277. }
  2278.  
  2279. pebol()
  2280. {
  2281.     register int r = ttrow;
  2282.     register int c = ttcol;
  2283.     CELL         cl;
  2284.  
  2285.     if(c >= 0){
  2286.       cl.c = ' ';
  2287.       cl.a = 0;
  2288.       (*term.t_eeol)();
  2289.       while(c < term.t_ncol && c >= 0 && r <= term.t_nrow && r >= 0)
  2290.     pscreen[r]->v_text[c--] = cl;
  2291.     }
  2292. }
  2293.  
  2294.  
  2295. /*
  2296.  * pscr - return the character cell on the physical screen map on the 
  2297.  *        given line, l, and offset, o.
  2298.  */
  2299. CELL *
  2300. pscr(l, o)
  2301. int l, o;
  2302. {
  2303.     if((l >= 0 && l <= term.t_nrow) && (o >= 0 && o < term.t_ncol))
  2304.       return(&(pscreen[l]->v_text[o]));
  2305.     else
  2306.       return(NULL);
  2307. }
  2308.  
  2309.  
  2310. /*
  2311.  * pclear() - clear the physical screen from row x through row y
  2312.  */
  2313. pclear(x, y)
  2314. register int x;
  2315. register int y;
  2316. {
  2317.     register int i;
  2318.  
  2319.     for(i=x; i < y; i++){
  2320.     movecursor(i, 0);
  2321.     peeol();
  2322.     }
  2323. }
  2324.  
  2325.  
  2326. /*
  2327.  * dumbroot - just get close 
  2328.  */
  2329. dumbroot(x, b)
  2330. int x, b;
  2331. {
  2332.     if(x < b)
  2333.       return(1);
  2334.     else
  2335.       return(dumbroot(x/b, b) + 1);
  2336. }
  2337.  
  2338.  
  2339. /*
  2340.  * dumblroot - just get close 
  2341.  */
  2342. dumblroot(x, b)
  2343. long x;
  2344. int  b;
  2345. {
  2346.     if(x < b)
  2347.       return(1);
  2348.     else
  2349.       return(dumblroot(x/b, b) + 1);
  2350. }
  2351.  
  2352.  
  2353. /*
  2354.  * pinsertc - use optimized insert, fixing physical screen map.
  2355.  *            returns true if char written, false otherwise
  2356.  */
  2357. pinsert(c)
  2358. CELL c;
  2359. {
  2360.     register int   i;
  2361.     register CELL *p;
  2362.  
  2363.     if(o_insert((char)c.c)){        /* if we've got it, use it! */
  2364.     p = pscreen[ttrow]->v_text;    /* then clean up physical screen */
  2365.     for(i = term.t_ncol-1; i > ttcol; i--)
  2366.       p[i] = p[i-1];        /* shift right */
  2367.     p[ttcol++] = c;            /* insert new char */
  2368.     
  2369.     return(1);
  2370.     }
  2371.  
  2372.     return(0);
  2373. }
  2374.  
  2375.  
  2376. /*
  2377.  * pdel - use optimized delete to rub out the current char and
  2378.  *        fix the physical screen array.
  2379.  *        returns true if optimized the delete, false otherwise
  2380.  */
  2381. pdel()
  2382. {
  2383.     register int   i;
  2384.     register CELL *c;
  2385.  
  2386.     if(delchar){            /* if we've got it, use it! */
  2387.     (*term.t_putchar)('\b');     /* move left a char */
  2388.     --ttcol;
  2389.     o_delete();            /* and delete it */
  2390.  
  2391.     c = pscreen[ttrow]->v_text;    /* then clean up physical screen */
  2392.     for(i=ttcol; i < term.t_ncol; i++)
  2393.       c[i] = c[i+1];
  2394.     c[i].c = ' ';
  2395.     c[i].a = 0;
  2396.     
  2397.     return(1);
  2398.     }
  2399.  
  2400.     return(0);
  2401. }
  2402.  
  2403.  
  2404.  
  2405. /*
  2406.  * wstripe - write out the given string at the given location, and reverse
  2407.  *           video on flagged characters.  Does the same thing as pine's
  2408.  *           stripe.
  2409.  */
  2410. void
  2411. wstripe(line, column, pmt, key)
  2412. int    line, column;
  2413. char    *pmt;
  2414. int      key;
  2415. {
  2416.     register char *buf;
  2417.     register int  i = 0;
  2418.     register int  j = 0;
  2419.     register int  l;
  2420.  
  2421.     l = strlen(pmt);
  2422.     while(1){
  2423.     if(i >= term.t_ncol || j >= l)
  2424.       return;                /* equal strings */
  2425.  
  2426.     if(pmt[j] == key)
  2427.       j++;
  2428.  
  2429.     if(pscr(line, i)->c != pmt[j]){
  2430.         if(j >= 1 && pmt[j-1] == key)
  2431.           j--;
  2432.         break;
  2433.     }
  2434.  
  2435.     j++;
  2436.     i++;
  2437.     }
  2438.  
  2439.     movecursor(line, column+i);
  2440.     buf = &pmt[j];
  2441.     do{
  2442.     if(*buf == key){
  2443.         buf++;
  2444.         (*term.t_rev)(1);
  2445.         pputc(*buf, 1);
  2446.         (*term.t_rev)(0);
  2447.     }
  2448.     else{
  2449.         pputc(*buf, 0);
  2450.     }
  2451.     }    
  2452.     while(*++buf != '\0');
  2453.     peeol();
  2454.     (*term.t_flush)();
  2455. }
  2456.  
  2457.  
  2458.  
  2459. /*
  2460.  *  wkeyhelp - paint list of possible commands on the bottom
  2461.  *             of the display (yet another pine clone)
  2462.  */
  2463. wkeyhelp(keys, helptxt)
  2464. char    *keys;
  2465. char    *helptxt;
  2466. {
  2467.     char *obufp, *ibufp = helptxt, *kbufp = HelpKeyNames, *startp;
  2468.     int  i, j, spaces, index, copy, extra;
  2469.  
  2470.     /*
  2471.      * make hardware cursor position change known!!
  2472.      */
  2473. #if    defined(DOS) && defined(MOUSE)
  2474.     register_keys(keys, helptxt, NODATA);
  2475. #endif
  2476.     extra  = (kbufp && kbufp[2] == ',') ? 2 : 3;
  2477.     spaces = term.t_ncol/6;
  2478.     for(i=1;i>=0;i--){
  2479.     *s = '\0';
  2480.     obufp = &s[strlen(s)];
  2481.     for(j=1;j<=6;j++){
  2482.         index = j + (6*(1 - i));
  2483.         copy = keys[index-1] - '0';
  2484.         if(kbufp != NULL){
  2485.         do{
  2486.             if((*kbufp == '~') && (!copy))
  2487.               kbufp++;
  2488.             if(copy)
  2489.               *obufp++ = *kbufp++;
  2490.             else{
  2491.             *obufp++ = ' ';
  2492.             kbufp++;
  2493.             }
  2494.         }
  2495.         while((*kbufp != ',')? 1 : !(kbufp++));
  2496.         }
  2497.         else{
  2498.         if(copy){
  2499.           if(keys[index-1]>='a'){
  2500.             *obufp++ = '~';
  2501.             *obufp++ = 'E';
  2502.             *obufp++ = '~';
  2503.             *obufp++ = 's';
  2504.             *obufp++ = '~';
  2505.             *obufp++ = 'c';
  2506.             *obufp++ = '~';
  2507.             *obufp++ = keys[index-1] -'a'+'A';
  2508.           }
  2509.           else{
  2510.             *obufp++ = '~';
  2511.             *obufp++ = '^';
  2512.             *obufp++ = '~';
  2513.             *obufp++ = copy + '0';
  2514.           }
  2515.         }
  2516.         else{
  2517.             *obufp++ = ' ';
  2518.             *obufp++ = ' ';
  2519.         }
  2520.         }
  2521.  
  2522.         *obufp++ = ' ';
  2523.         startp = obufp;
  2524.         /*
  2525.          * we use "spaces-3" because of length key names
  2526.          */
  2527.         while(obufp - startp < (spaces-extra)) {
  2528.         if((copy) && ((*ibufp != '\0') && (*ibufp != ',')))
  2529.           *obufp++ = *ibufp++;
  2530.         else
  2531.           *obufp++ = ' ';
  2532.         }
  2533.         if(copy){
  2534.         while((*ibufp != ',') && (*ibufp != '\0'))
  2535.           ibufp++;
  2536.         if(*ibufp != '\0')
  2537.           ibufp++;
  2538.         }
  2539.         *obufp = '\0';
  2540.     }
  2541.     wstripe(term.t_nrow-i,0,s,'~');
  2542.     }
  2543. }
  2544.  
  2545.