home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / pvic_10a.lzh / SRCE / screen.c < prev    next >
Text File  |  1998-04-23  |  16KB  |  627 lines

  1. /* 
  2.  * Routines to manipulate the screen representations.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include "pvic.h"
  7. #include "locdefs.h"
  8.  
  9. /*
  10.  * This gets set if we ignored an update request while input was pending.
  11.  * We check this when the input is drained to see if the screen should be
  12.  * updated.
  13.  */
  14. int need_redraw=0;
  15.  
  16. /*
  17.  * The following variable is set (in filetonext) to the number of physical
  18.  * lines taken by the line the cursor is on. We use this to avoid extra
  19.  * calls to plines(). The optimized routines lfiletonext() and lnexttoscreen()
  20.  * make sure that the size of the cursor line hasn't changed. If so, lines
  21.  * below the cursor will move up or down and we need to call the routines
  22.  * filetonext() and nexttoscreen() to examine the entire screen.
  23.  */
  24. static  int     cursor_line_size;     /* size (in rows) of the cursor line */
  25. static  int     cursor_line_row;      /* starting row of the cursor line */
  26.  
  27. static  char    *mkline();      /* calculate line string for "number" mode */
  28.  
  29. /*
  30.  * filetonext()
  31.  *
  32.  * Based on the current value of top_char, transfer a screenfull of
  33.  * stuff from file_memory to next_screen, and update bottom_char.
  34.  */
  35.  
  36. static void filetonext(do_allways)
  37. int do_allways;
  38. {
  39.     register int    row, col;
  40.     register char   *screenp = next_screen;
  41.     LPTR    memp;
  42.     LPTR    save;                   /* save pos. in case line won't fit */
  43.     register char   *endscreen;
  44.     register char   *nextrow;
  45.     char    extra[16];
  46.     int     nextra = 0;
  47.     register int    c;
  48.     int     n;
  49.     int     done;           /* if (1), we hit the end of the file */
  50.     int     didline;        /* if (1), we finished the last line */
  51.     int     srow;           /* starting row of the current line */
  52.     int     lno;            /* number of the line we're doing */
  53.     int     coff;           /* column offset */
  54.  
  55.         if(!do_allways && is_input_pending())
  56.         {
  57.                 need_redraw=1;
  58.                 return;
  59.         }
  60.                 
  61.     coff = PARAMETER_VALUE(PARAMETER_NUMBER) ? 8 : 0;
  62.  
  63.     save = memp = *top_char;
  64.  
  65.     if (PARAMETER_VALUE(PARAMETER_NUMBER))
  66.         lno = cntllines(file_memory, top_char);
  67.  
  68.     /*
  69.      * The number of rows shown is current_lines-1.
  70.      * The last line is the status/command line.
  71.      */
  72.     endscreen = &screenp[(current_lines-1)*current_columns];
  73.  
  74.     done = didline = (0);
  75.     srow = row = col = 0;
  76.     /*
  77.      * We go one past the end of the screen so we can find out if the
  78.      * last line fit on the screen or not.
  79.      */
  80.     while ( screenp <= endscreen && !done) {
  81.  
  82.  
  83.         if (PARAMETER_VALUE(PARAMETER_NUMBER) && col == 0 && memp.index == 0) {
  84.             strcpy(extra, mkline(lno++));
  85.             nextra = 8;
  86.         }
  87.  
  88.         /* Get the next character to put on the screen. */
  89.  
  90.         /* The 'extra' array contains the extra stuff that is */
  91.         /* inserted to represent special characters (tabs, and */
  92.         /* other non-printable stuff.  The order in the 'extra' */
  93.         /* array is reversed. */
  94.  
  95.         if ( nextra > 0 )
  96.             c = extra[--nextra];
  97.         else {
  98.             c = (unsigned)(0xff & gchar(&memp));
  99.             if (inc(&memp) == -1)
  100.                 done = 1;
  101.             /* when getting a character from the file, we */
  102.             /* may have to turn it into something else on */
  103.             /* the way to putting it into 'next_screen'. */
  104.             if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
  105.                 strcpy(extra,"        ");
  106.                 /* tab amount depends on current column */
  107.                 nextra = ((PARAMETER_VALUE(PARAMETER_TABSTOP)-1) - (col - coff)%PARAMETER_VALUE(PARAMETER_TABSTOP));
  108.                 c = ' ';
  109.             }
  110.             else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
  111.                 extra[0] = '\0';
  112.                 nextra = 1;
  113.                 c = '$';
  114.             } else if ( (n = chars[c].ch_size) > 1 ) {
  115.                 char *p;
  116.                 nextra = 0;
  117.                 p = chars[c].ch_str;
  118.                 /* copy 'ch-str'ing into 'extra' in reverse */
  119.                 while ( n > 1 )
  120.                     extra[nextra++] = p[--n];
  121.                 c = p[0];
  122.             }
  123.         }
  124.  
  125.         if (screenp == endscreen) {
  126.             /*
  127.              * We're one past the end of the screen. If the
  128.              * current character is null, then we really did
  129.              * finish, so set didline = (1). In either case,
  130.              * break out because we're done.
  131.              */
  132.             dec(&memp);
  133.             if (memp.index != 0 && c == '\0') {
  134.                 didline = (1);
  135.                 inc(&memp);
  136.             }
  137.             break;
  138.         }
  139.  
  140.         if ( c == '\0' ) {
  141.             srow = ++row;
  142.             /*
  143.              * Save this position in case the next line won't
  144.              * fit on the screen completely.
  145.              */
  146.             save = memp;
  147.             /* get pointer to start of next row */
  148.             nextrow = &next_screen[row*current_columns];
  149.             /* blank out the rest of this row */
  150.             while ( screenp != nextrow )
  151.                 *screenp++ = ' ';
  152.             col = 0;
  153.             continue;
  154.         }
  155.         if ( col >= current_columns ) {
  156.             row++;
  157.             col = 0;
  158.         }
  159.         /* store the character in next_screen */
  160.         *screenp++ = c;
  161.         col++;
  162.     }
  163.     /*
  164.      * If we didn't hit the end of the file, and we didn't finish
  165.      * the last line we were working on, then the line didn't fit.
  166.      */
  167.     if (!done && !didline) {
  168.         /*
  169.          * Clear the rest of the screen and mark the unused lines.
  170.          */
  171.         screenp = &next_screen[srow * current_columns];
  172.         while (screenp < endscreen)
  173.             *screenp++ = ' ';
  174.         for (; srow < (current_lines-1) ;srow++)
  175.             next_screen[srow * current_columns] = '@';
  176.         *bottom_char = save;
  177.         return;
  178.     }
  179.     /* make sure the rest of the screen is blank */
  180.     while ( screenp < endscreen )
  181.         *screenp++ = ' ';
  182.     /* put '~'s on rows that aren't part of the file. */
  183.     if ( col != 0 )
  184.         row++;
  185.     while ( row < current_lines ) {
  186.         next_screen[row*current_columns] = '~';
  187.         row++;
  188.     }
  189.     if (done)       /* we hit the end of the file */
  190.         *bottom_char = *end_of_file;
  191.     else
  192.         *bottom_char = memp;        /* FIX - prev? */
  193. }
  194.  
  195. /*
  196.  * nexttoscreen
  197.  *
  198.  * Transfer the contents of next_screen to the screen, using real_screen
  199.  * to avoid unnecesssary output.
  200.  */
  201. static void nexttoscreen(do_allways)
  202. int do_allways;
  203. {
  204.     register char   *np = next_screen;
  205.     register char   *rp = real_screen;
  206.     register char   *endscreen;
  207.     register int    row = 0, col = 0;
  208.     int i;
  209.     int     gorow = -1, gocol = -1;
  210.  
  211.     endscreen = &np[(current_lines-1)*current_columns];
  212.  
  213.     termcap_out(termcap_cursor_invisible);          /* disable cursor */
  214.  
  215.     for (i=0 ; np < endscreen ; np++,rp++,i++ ) {
  216.         if ((i%current_columns)==0 && is_input_pending() &&
  217.                         !do_allways) {
  218.             need_redraw = (1);
  219.             return;
  220.         }
  221.         /* If desired screen (contents of next_screen) does not */
  222.         /* match what's really there, put it there. */
  223.         if ( *np != *rp ) {
  224.             /* if we are positioned at the right place, */
  225.             /* we don't have to use goto_screen_pos(). */
  226.             if (gocol != col || gorow != row) {
  227.                 /*
  228.                  * If we're just off by one, don't send
  229.                  * an entire esc. seq. (this happens a lot!)
  230.                  */
  231.                 if (gorow == row && gocol+1 == col) {
  232.                     putc(*(np-1),stdout);
  233.                     gocol++;
  234.                 } else
  235.                     goto_screen_pos(gorow=row,gocol=col);
  236.             }
  237.             putc(*rp = *np,stdout);
  238.             gocol++;
  239.         }
  240.         if ( ++col >= current_columns ) {
  241.             col = 0;
  242.             row++;
  243.         }
  244.     }
  245.     termcap_out(termcap_cursor_visible);            /* enable cursor again */
  246. }
  247.  
  248. /*
  249.  * lfiletonext() - like filetonext() but only for cursor line
  250.  *
  251.  * Returns true if the size of the cursor line (in rows) hasn't changed.
  252.  * This determines whether or not we need to call filetonext() to examine
  253.  * the entire screen for changes.
  254.  */
  255. static int lfiletonext()
  256. {
  257.     register int    row, col;
  258.     register char   *screenp;
  259.     LPTR    memp;
  260.     register char   *nextrow;
  261.     char    extra[16];
  262.     int     nextra = 0;
  263.     register int    c;
  264.     int     n;
  265.     int     eof;
  266.     int     lno;            /* number of the line we're doing */
  267.     int     coff;           /* column offset */
  268.  
  269.     coff = PARAMETER_VALUE(PARAMETER_NUMBER) ? 8 : 0;
  270.  
  271.     /*
  272.      * This should be done more efficiently.
  273.      */
  274.     if (PARAMETER_VALUE(PARAMETER_NUMBER))
  275.         lno = cntllines(file_memory, cursor_char);
  276.  
  277.     screenp = next_screen + (cursor_line_row * current_columns);
  278.  
  279.     memp = *cursor_char;
  280.     memp.index = 0;
  281.  
  282.     eof = (0);
  283.     col = 0;
  284.     row = cursor_line_row;
  285.  
  286.     while (!eof) {
  287.  
  288.         if (PARAMETER_VALUE(PARAMETER_NUMBER) && col == 0 && memp.index == 0) {
  289.             strcpy(extra, mkline(lno));
  290.             nextra = 8;
  291.         }
  292.  
  293.         /* Get the next character to put on the screen. */
  294.  
  295.         /* The 'extra' array contains the extra stuff that is */
  296.         /* inserted to represent special characters (tabs, and */
  297.         /* other non-printable stuff.  The order in the 'extra' */
  298.         /* array is reversed. */
  299.  
  300.         if ( nextra > 0 )
  301.             c = extra[--nextra];
  302.         else {
  303.             c = (unsigned)(0xff & gchar(&memp));
  304.             if (inc(&memp) == -1)
  305.                 eof = (1);
  306.             /* when getting a character from the file, we */
  307.             /* may have to turn it into something else on */
  308.             /* the way to putting it into 'next_screen'. */
  309.             if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
  310.                 strcpy(extra,"        ");
  311.                 /* tab amount depends on current column */
  312.                 nextra = ((PARAMETER_VALUE(PARAMETER_TABSTOP)-1) - (col - coff)%PARAMETER_VALUE(PARAMETER_TABSTOP));
  313.                 c = ' ';
  314.             } else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
  315.                 extra[0] = '\0';
  316.                 nextra = 1;
  317.                 c = '$';
  318.             } else if ( c != '\0' && (n=chars[c].ch_size) > 1 ) {
  319.                 char *p;
  320.                 nextra = 0;
  321.                 p = chars[c].ch_str;
  322.                 /* copy 'ch-str'ing into 'extra' in reverse */
  323.                 while ( n > 1 )
  324.                     extra[nextra++] = p[--n];
  325.                 c = p[0];
  326.             }
  327.         }
  328.  
  329.         if ( c == '\0' ) {
  330.             row++;
  331.             /* get pointer to start of next row */
  332.             nextrow = &next_screen[row*current_columns];
  333.             /* blank out the rest of this row */
  334.             while ( screenp != nextrow )
  335.                 *screenp++ = ' ';
  336.             col = 0;
  337.             break;
  338.         }
  339.  
  340.         if ( col >= current_columns ) {
  341.             row++;
  342.             col = 0;
  343.         }
  344.         /* store the character in next_screen */
  345.         *screenp++ = c;
  346.         col++;
  347.     }
  348.     return ((row - cursor_line_row) == cursor_line_size);
  349. }
  350.  
  351. /*
  352.  * lnexttoscreen
  353.  *
  354.  * Like nexttoscreen() but only for the cursor line.
  355.  */
  356. static void lnexttoscreen()
  357. {
  358.     register char   *np = next_screen + (cursor_line_row * current_columns);
  359.     register char   *rp = real_screen + (cursor_line_row * current_columns);
  360.     register char   *endline;
  361.     register int    row, col;
  362.     int     gorow = -1, gocol = -1;
  363.  
  364.     if (is_input_pending()) {
  365.         need_redraw = (1);
  366.         return;
  367.     }
  368.  
  369.     endline = np + (cursor_line_size * current_columns);
  370.  
  371.     row = cursor_line_row;
  372.     col = 0;
  373.  
  374.     termcap_out(termcap_cursor_invisible);          /* disable cursor */
  375.  
  376.     for ( ; np < endline ; np++,rp++ ) {
  377.         /* If desired screen (contents of next_screen) does not */
  378.         /* match what's really there, put it there. */
  379.         if ( *np != *rp ) {
  380.             /* if we are positioned at the right place, */
  381.             /* we don't have to use goto_screen_pos(). */
  382.             if (gocol != col || gorow != row) {
  383.                 /*
  384.                  * If we're just off by one, don't send
  385.                  * an entire esc. seq. (this happens a lot!)
  386.                  */
  387.                 if (gorow == row && gocol+1 == col) {
  388.                     putc(*(np-1),stdout);
  389.                     gocol++;
  390.                 } else
  391.                     goto_screen_pos(gorow=row,gocol=col);
  392.             }
  393.             putc(*rp = *np,stdout);
  394.             gocol++;
  395.         }
  396.         if ( ++col >= current_columns ) {
  397.             col = 0;
  398.             row++;
  399.         }
  400.     }
  401.     termcap_out(termcap_cursor_visible);            /* enable cursor again */
  402. }
  403.  
  404. static char * mkline(n)
  405. register int    n;
  406. {
  407.     static  char    lbuf[9];
  408.     register int    i = 2;
  409.  
  410.     strcpy(lbuf, "        ");
  411.  
  412.     lbuf[i++] = (n % 10) + '0';
  413.     n /= 10;
  414.     if (n != 0) {
  415.         lbuf[i++] = (n % 10) + '0';
  416.         n /= 10;
  417.     }
  418.     if (n != 0) {
  419.         lbuf[i++] = (n % 10) + '0';
  420.         n /= 10;
  421.     }
  422.     if (n != 0) {
  423.         lbuf[i++] = (n % 10) + '0';
  424.         n /= 10;
  425.     }
  426.     if (n != 0) {
  427.         lbuf[i++] = (n % 10) + '0';
  428.         n /= 10;
  429.     }
  430.     return lbuf;
  431. }
  432.  
  433. /*
  434.  * update_line() - update the line the cursor is on
  435.  *
  436.  * Updateline() is called after changes that only affect the line that
  437.  * the cursor is on. This improves performance tremendously for normal
  438.  * insert mode operation. The only thing we have to watch for is when
  439.  * the cursor line grows or shrinks around a row boundary. This means
  440.  * we have to repaint other parts of the screen appropriately. If
  441.  * lfiletonext() returns (0), the size of the cursor line (in rows)
  442.  * has changed and we have to call update_screen() to do a complete job.
  443.  */
  444. void update_line()
  445. {
  446.     if (!lfiletonext())
  447.         update_screen(1); /* bag it, do the whole screen */
  448.     else
  449.         lnexttoscreen();
  450. }
  451.  
  452. void update_screen(do_allways)
  453. int do_allways;
  454. {
  455.     extern  int     interactive;
  456.  
  457.         if(!do_allways && is_input_pending())
  458.         {
  459.                 need_redraw=1;
  460.                 return;
  461.         }
  462.  
  463.     if (interactive) {
  464.         filetonext(do_allways);
  465.         nexttoscreen(do_allways);
  466.     }
  467. }
  468.  
  469. /*
  470.  * prt_line() - print the given line
  471.  */
  472. void prt_line(s)
  473. char    *s;
  474. {
  475.     register int    si = 0;
  476.     register int    c;
  477.     register int    col = 0;
  478.  
  479.     char    extra[16];
  480.     int     nextra = 0;
  481.     int     n;
  482.  
  483.     for (;;) {
  484.  
  485.         if ( nextra > 0 )
  486.             c = extra[--nextra];
  487.         else {
  488.             c = s[si++];
  489.             if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) ) {
  490.                 strcpy(extra, "        ");
  491.                 /* tab amount depends on current column */
  492.                 nextra = (PARAMETER_VALUE(PARAMETER_TABSTOP) -
  493.                 1) - col%PARAMETER_VALUE(PARAMETER_TABSTOP);
  494.                 c = ' ';
  495.             } else if ( c == '\0' && PARAMETER_VALUE(PARAMETER_LIST) ) {
  496.                 extra[0] = '\0';
  497.                 nextra = 1;
  498.                 c = '$';
  499.             } else if ( c != '\0' && (n=chars[c].ch_size) > 1 ) {
  500.                 char    *p;
  501.  
  502.                 nextra = 0;
  503.                 p = chars[c].ch_str;
  504.                 /* copy 'ch-str'ing into 'extra' in reverse */
  505.                 while ( n > 1 )
  506.                     extra[nextra++] = p[--n];
  507.                 c = p[0];
  508.             }
  509.         }
  510.  
  511.         if ( c == '\0' )
  512.             break;
  513.  
  514.         putc(c,stdout);
  515.         col++;
  516.     }
  517. }
  518.  
  519. void clear_screen()
  520. {
  521.     register char   *rp, *np;
  522.     register char   *end;
  523.  
  524.     termcap_out(termcap_clear_screen);              /* clear the display */
  525.         termcap_out(termcap_cursor_address,0,0);
  526.  
  527.     rp  = real_screen;
  528.     end = real_screen + current_lines * current_columns;
  529.     np  = next_screen;
  530.  
  531.     /* blank out the stored screens */
  532.     while (rp != end)
  533.         *rp++ = *np++ = ' ';
  534. }
  535.  
  536. void update_cursor(do_allways)
  537. int do_allways;
  538. {
  539.     register LPTR   *p;
  540.     register int    icnt, c, nlines;
  541.     register int    i;
  542.     int     didinc;
  543.  
  544.     if (buffer_empty()) {               /* special case - file is empty */
  545.         *top_char  = *file_memory;
  546.         *cursor_char = *file_memory;
  547.     } else if ( LINEOF(cursor_char) < LINEOF(top_char) ) {
  548.         nlines = cntllines(cursor_char,top_char);
  549.         /* if the cursor is above the top of */
  550.         /* the screen, put it at the top of the screen.. */
  551.         *top_char = *cursor_char;
  552.         top_char->index = 0;
  553.         /* ... and, if we weren't very close to begin with, */
  554.         /* we scroll so that the line is close to the middle. */
  555.         if ( nlines > current_lines/3 ) {
  556.             for (i=0, p = top_char; i < current_lines/3 ;i++, *top_char = *p)
  557.                 if ((p = previous_line(p)) == NULL)
  558.                     break;
  559.         }
  560.         update_screen(do_allways);
  561.     }
  562.     else if (LINEOF(cursor_char) >= LINEOF(bottom_char)) {
  563.         nlines = cntllines(bottom_char,cursor_char);
  564.         /* If the cursor is off the bottom of the screen, */
  565.         /* put it at the top of the screen.. */
  566.         /* ... and back up */
  567.         if ( nlines > current_lines/3 ) {
  568.             p = cursor_char;
  569.             for (i=0; i < (2*current_lines)/3 ;i++)
  570.                 if ((p = previous_line(p)) == NULL)
  571.                     break;
  572.             *top_char = *p;
  573.         } else {
  574.             scroll_up(nlines);
  575.         }
  576.         update_screen(do_allways);
  577.     }
  578.  
  579.     cursor_row = cursor_column = cursor_virtual_column = 0;
  580.     for ( p=top_char; p->linep != cursor_char->linep ;p = next_line(p) )
  581.         cursor_row += plines(p);
  582.  
  583.     cursor_line_row = cursor_row;
  584.     cursor_line_size = plines(p);
  585.  
  586.     if (PARAMETER_VALUE(PARAMETER_NUMBER))
  587.         cursor_column = 8;
  588.  
  589.     for (i=0; i <= cursor_char->index ;i++) {
  590.         c = cursor_char->linep->s[i];
  591.         /* A tab gets expanded, depending on the current column */
  592.         if ( c == CTRL_I && !PARAMETER_VALUE(PARAMETER_LIST) )
  593.             icnt = PARAMETER_VALUE(PARAMETER_TABSTOP) - (cursor_virtual_column % PARAMETER_VALUE(PARAMETER_TABSTOP));
  594.         else
  595.             icnt = chars[(unsigned)(c & 0xff)].ch_size;
  596.         cursor_column += icnt;
  597.         cursor_virtual_column += icnt;
  598.         if ( cursor_column >= current_columns ) {
  599.             cursor_column -= current_columns;
  600.             cursor_row++;
  601.             didinc = (1);
  602.         }
  603.         else
  604.             didinc = (0);
  605.     }
  606.     if (didinc)
  607.         cursor_row--;
  608.  
  609.     if (c == CTRL_I && current_status == STATUS_NORMAL && !PARAMETER_VALUE(PARAMETER_LIST)) {
  610.         cursor_column--;
  611.         cursor_virtual_column--;
  612.     } else {
  613.         cursor_column -= icnt;
  614.         cursor_virtual_column -= icnt;
  615.     }
  616.     if (cursor_column < 0)
  617.         cursor_column += current_columns;
  618.  
  619.     if (set_wanted_cursor_column) {
  620.         wanted_cursor_column = cursor_virtual_column;
  621.         set_wanted_cursor_column = (0);
  622.     }
  623.     if(do_allways || !is_input_pending())
  624.         goto_screen_pos(cursor_row,cursor_column);
  625. }
  626.  
  627.