home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / less373.zip / output.c < prev    next >
C/C++ Source or Header  |  2002-01-14  |  8KB  |  437 lines

  1. /*
  2.  * Copyright (C) 1984-2000  Mark Nudelman
  3.  *
  4.  * You may distribute under the terms of either the GNU General Public
  5.  * License or the Less License, as specified in the README file.
  6.  *
  7.  * For more information about less, or for information on how to 
  8.  * contact the author, see the README file.
  9.  */
  10.  
  11.  
  12. /*
  13.  * High level routines dealing with the output to the screen.
  14.  */
  15.  
  16. #include "less.h"
  17. #if MSDOS_COMPILER==WIN32C
  18. #include "windows.h"
  19. #endif
  20.  
  21. public int errmsgs;    /* Count of messages displayed by error() */
  22. public int need_clr;
  23. public int final_attr;
  24.  
  25. extern int sigs;
  26. extern int sc_width;
  27. extern int so_s_width, so_e_width;
  28. extern int screen_trashed;
  29. extern int any_display;
  30. extern int is_tty;
  31.  
  32. /*
  33.  * Display the line which is in the line buffer.
  34.  */
  35.     public void
  36. put_line()
  37. {
  38.     register int c;
  39.     register int i;
  40.     int a;
  41.     int curr_attr;
  42.  
  43.     if (ABORT_SIGS())
  44.     {
  45.         /*
  46.          * Don't output if a signal is pending.
  47.          */
  48.         screen_trashed = 1;
  49.         return;
  50.     }
  51.  
  52.     curr_attr = AT_NORMAL;
  53.  
  54.     for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
  55.     {
  56.         if (a != curr_attr)
  57.         {
  58.             /*
  59.              * Changing attributes.
  60.              * Display the exit sequence for the old attribute
  61.              * and the enter sequence for the new one.
  62.              */
  63.             switch (curr_attr)
  64.             {
  65.             case AT_UNDERLINE:    ul_exit();    break;
  66.             case AT_BOLD:        bo_exit();    break;
  67.             case AT_BLINK:        bl_exit();    break;
  68.             case AT_STANDOUT:    so_exit();    break;
  69.             }
  70.             switch (a)
  71.             {
  72.             case AT_UNDERLINE:    ul_enter();    break;
  73.             case AT_BOLD:        bo_enter();    break;
  74.             case AT_BLINK:        bl_enter();    break;
  75.             case AT_STANDOUT:    so_enter();    break;
  76.             }
  77.             curr_attr = a;
  78.         }
  79.         if (curr_attr == AT_INVIS)
  80.             continue;
  81.         if (c == '\b')
  82.             putbs();
  83.         else
  84.             putchr(c);
  85.     }
  86.  
  87.     switch (curr_attr)
  88.     {
  89.     case AT_UNDERLINE:    ul_exit();    break;
  90.     case AT_BOLD:        bo_exit();    break;
  91.     case AT_BLINK:        bl_exit();    break;
  92.     case AT_STANDOUT:    so_exit();    break;
  93.     }
  94.     final_attr = curr_attr;
  95. }
  96.  
  97. static char obuf[OUTBUF_SIZE];
  98. static char *ob = obuf;
  99.  
  100. /*
  101.  * Flush buffered output.
  102.  *
  103.  * If we haven't displayed any file data yet,
  104.  * output messages on error output (file descriptor 2),
  105.  * otherwise output on standard output (file descriptor 1).
  106.  *
  107.  * This has the desirable effect of producing all
  108.  * error messages on error output if standard output
  109.  * is directed to a file.  It also does the same if
  110.  * we never produce any real output; for example, if
  111.  * the input file(s) cannot be opened.  If we do
  112.  * eventually produce output, code in edit() makes
  113.  * sure these messages can be seen before they are
  114.  * overwritten or scrolled away.
  115.  */
  116.     public void
  117. flush()
  118. {
  119.     register int n;
  120.     register int fd;
  121.  
  122.     n = ob - obuf;
  123.     if (n == 0)
  124.         return;
  125. #if MSDOS_COMPILER==WIN32C
  126.     if (is_tty && any_display)
  127.     {
  128.         char *op;
  129.         DWORD nwritten = 0;
  130.         CONSOLE_SCREEN_BUFFER_INFO scr;
  131.         int row;
  132.         int col;
  133.         int olen;
  134.         extern HANDLE con_out;
  135.  
  136.         olen = ob - obuf;
  137.         /*
  138.          * There is a bug in Win32 WriteConsole() if we're
  139.          * writing in the last cell with a different color.
  140.          * To avoid color problems in the bottom line,
  141.          * we scroll the screen manually, before writing.
  142.          */
  143.         GetConsoleScreenBufferInfo(con_out, &scr);
  144.         col = scr.dwCursorPosition.X;
  145.         row = scr.dwCursorPosition.Y;
  146.         for (op = obuf;  op < obuf + olen;  op++)
  147.         {
  148.             if (*op == '\n')
  149.             {
  150.                 col = 0;
  151.                 row++;
  152.             } else
  153.             {
  154.                 col++;
  155.                 if (col >= sc_width)
  156.                 {
  157.                     col = 0;
  158.                     row++;
  159.                 }
  160.             }
  161.         }
  162.         if (row > scr.srWindow.Bottom)
  163.             win32_scroll_up(row - scr.srWindow.Bottom);
  164.         WriteConsole(con_out, obuf, olen, &nwritten, NULL);
  165.         ob = obuf;
  166.         return;
  167.     }
  168. #else
  169. #if MSDOS_COMPILER==MSOFTC
  170.     if (is_tty && any_display)
  171.     {
  172.         *ob = '\0';
  173.         _outtext(obuf);
  174.         ob = obuf;
  175.         return;
  176.     }
  177. #else
  178. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  179.     if (is_tty && any_display)
  180.     {
  181.         *ob = '\0';
  182.         cputs(obuf);
  183.         ob = obuf;
  184.         return;
  185.     }
  186. #endif
  187. #endif
  188. #endif
  189.     fd = (any_display) ? 1 : 2;
  190.     if (write(fd, obuf, n) != n)
  191.         screen_trashed = 1;
  192.     ob = obuf;
  193. }
  194.  
  195. /*
  196.  * Output a character.
  197.  */
  198.     public int
  199. putchr(c)
  200.     int c;
  201. {
  202.     if (need_clr)
  203.     {
  204.         need_clr = 0;
  205.         clear_bot();
  206.     }
  207. #if MSDOS_COMPILER
  208.     if (c == '\n' && is_tty)
  209.     {
  210.         /* remove_top(1); */
  211.         putchr('\r');
  212.     }
  213. #else
  214. #ifdef _OSK
  215.     if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
  216.         putchr(0x0A);
  217. #endif
  218. #endif
  219.     /*
  220.      * Some versions of flush() write to *ob, so we must flush
  221.      * when we are still one char from the end of obuf.
  222.      */
  223.     if (ob >= &obuf[sizeof(obuf)-1])
  224.         flush();
  225.     *ob++ = c;
  226.     return (c);
  227. }
  228.  
  229. /*
  230.  * Output a string.
  231.  */
  232.     public void
  233. putstr(s)
  234.     register char *s;
  235. {
  236.     while (*s != '\0')
  237.         putchr(*s++);
  238. }
  239.  
  240.  
  241. /*
  242.  * Output an integer in a given radix.
  243.  */
  244.     static int
  245. iprintnum(num, radix)
  246.     int num;
  247.     int radix;
  248. {
  249.     register char *s;
  250.     int r;
  251.     int neg;
  252.     char buf[INT_STRLEN_BOUND(num)];
  253.  
  254.     neg = (num < 0);
  255.     if (neg)
  256.         num = -num;
  257.  
  258.     s = buf;
  259.     do
  260.     {
  261.         *s++ = (num % radix) + '0';
  262.     } while ((num /= radix) != 0);
  263.  
  264.     if (neg)
  265.         *s++ = '-';
  266.     r = s - buf;
  267.  
  268.     while (s > buf)
  269.         putchr(*--s);
  270.     return (r);
  271. }
  272.  
  273. /*
  274.  * This function implements printf-like functionality
  275.  * using a more portable argument list mechanism than printf's.
  276.  */
  277.     static int
  278. less_printf(fmt, parg)
  279.     register char *fmt;
  280.     PARG *parg;
  281. {
  282.     register char *s;
  283.     register int n;
  284.     register int col;
  285.  
  286.     col = 0;
  287.     while (*fmt != '\0')
  288.     {
  289.         if (*fmt != '%')
  290.         {
  291.             putchr(*fmt++);
  292.             col++;
  293.         } else
  294.         {
  295.             ++fmt;
  296.             switch (*fmt++) {
  297.             case 's':
  298.                 s = parg->p_string;
  299.                 parg++;
  300.                 while (*s != '\0')
  301.                 {
  302.                     putchr(*s++);
  303.                     col++;
  304.                 }
  305.                 break;
  306.             case 'd':
  307.                 n = parg->p_int;
  308.                 parg++;
  309.                 col += iprintnum(n, 10);
  310.                 break;
  311.             }
  312.         }
  313.     }
  314.     return (col);
  315. }
  316.  
  317. /*
  318.  * Get a RETURN.
  319.  * If some other non-trivial char is pressed, unget it, so it will
  320.  * become the next command.
  321.  */
  322.     public void
  323. get_return()
  324. {
  325.     int c;
  326.  
  327. #if ONLY_RETURN
  328.     while ((c = getchr()) != '\n' && c != '\r')
  329.         bell();
  330. #else
  331.     c = getchr();
  332.     if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
  333.         ungetcc(c);
  334. #endif
  335. }
  336.  
  337. /*
  338.  * Output a message in the lower left corner of the screen
  339.  * and wait for carriage return.
  340.  */
  341.     public void
  342. error(fmt, parg)
  343.     char *fmt;
  344.     PARG *parg;
  345. {
  346.     int col = 0;
  347.     static char return_to_continue[] = "  (press RETURN)";
  348.  
  349.     errmsgs++;
  350.  
  351.     if (any_display && is_tty)
  352.     {
  353.         clear_bot();
  354.         so_enter();
  355.         col += so_s_width;
  356.     }
  357.  
  358.     col += less_printf(fmt, parg);
  359.  
  360.     if (!(any_display && is_tty))
  361.     {
  362.         putchr('\n');
  363.         return;
  364.     }
  365.  
  366.     putstr(return_to_continue);
  367.     so_exit();
  368.     col += sizeof(return_to_continue) + so_e_width;
  369.  
  370.     get_return();
  371.     lower_left();
  372.  
  373.     if (col >= sc_width)
  374.         /*
  375.          * Printing the message has probably scrolled the screen.
  376.          * {{ Unless the terminal doesn't have auto margins,
  377.          *    in which case we just hammered on the right margin. }}
  378.          */
  379.         screen_trashed = 1;
  380.  
  381.     flush();
  382. }
  383.  
  384. static char intr_to_abort[] = "... (interrupt to abort)";
  385.  
  386. /*
  387.  * Output a message in the lower left corner of the screen
  388.  * and don't wait for carriage return.
  389.  * Usually used to warn that we are beginning a potentially
  390.  * time-consuming operation.
  391.  */
  392.     public void
  393. ierror(fmt, parg)
  394.     char *fmt;
  395.     PARG *parg;
  396. {
  397.     clear_bot();
  398.     so_enter();
  399.     (void) less_printf(fmt, parg);
  400.     putstr(intr_to_abort);
  401.     so_exit();
  402.     flush();
  403.     need_clr = 1;
  404. }
  405.  
  406. /*
  407.  * Output a message in the lower left corner of the screen
  408.  * and return a single-character response.
  409.  */
  410.     public int
  411. query(fmt, parg)
  412.     char *fmt;
  413.     PARG *parg;
  414. {
  415.     register int c;
  416.     int col = 0;
  417.  
  418.     if (any_display && is_tty)
  419.         clear_bot();
  420.  
  421.     (void) less_printf(fmt, parg);
  422.     c = getchr();
  423.  
  424.     if (!(any_display && is_tty))
  425.     {
  426.         putchr('\n');
  427.         return (c);
  428.     }
  429.  
  430.     lower_left();
  431.     if (col >= sc_width)
  432.         screen_trashed = 1;
  433.     flush();
  434.  
  435.     return (c);
  436. }
  437.