home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / pico / display.c < prev    next >
C/C++ Source or Header  |  1998-12-29  |  55KB  |  2,431 lines

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