Logo Search packages:      
Sourcecode: jless version File versions  Download package

output.c

/*
 * Copyright (C) 1984-2000  Mark Nudelman
 *
 * You may distribute under the terms of either the GNU General Public
 * License or the Less License, as specified in the README file.
 *
 * For more information about less, or for information on how to 
 * contact the author, see the README file.
 */


/*
 * High level routines dealing with the output to the screen.
 */

#include "less.h"
#if MSDOS_COMPILER==WIN32C
#include "windows.h"
#endif

public int errmsgs;     /* Count of messages displayed by error() */
public int need_clr;
public int final_attr;

extern int sigs;
extern int sc_width;
extern int so_s_width, so_e_width;
extern int screen_trashed;
extern int any_display;
extern int is_tty;

/*
 * Display the line which is in the line buffer.
 */
      public void
put_line()
{
      register int c;
      register int i;
      int a;
      int curr_attr;

      if (ABORT_SIGS())
      {
            /*
             * Don't output if a signal is pending.
             */
            screen_trashed = 1;
            return;
      }

      curr_attr = AT_NORMAL;

      for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
      {
            if (a != curr_attr)
            {
                  /*
                   * Changing attributes.
                   * Display the exit sequence for the old attribute
                   * and the enter sequence for the new one.
                   */
                  switch (curr_attr)
                  {
                  case AT_UNDERLINE:      ul_exit();  break;
                  case AT_BOLD:           bo_exit();  break;
                  case AT_BLINK:          bl_exit();  break;
                  case AT_STANDOUT: so_exit();  break;
                  }
                  switch (a)
                  {
                  case AT_UNDERLINE:      ul_enter(); break;
                  case AT_BOLD:           bo_enter(); break;
                  case AT_BLINK:          bl_enter(); break;
                  case AT_STANDOUT: so_enter(); break;
                  }
                  curr_attr = a;
            }
            if (curr_attr == AT_INVIS)
                  continue;
            if (c == '\b')
                  putbs();
            else
                  putchr(c);
      }

      switch (curr_attr)
      {
      case AT_UNDERLINE:      ul_exit();  break;
      case AT_BOLD:           bo_exit();  break;
      case AT_BLINK:          bl_exit();  break;
      case AT_STANDOUT: so_exit();  break;
      }
      final_attr = curr_attr;
}

static char obuf[OUTBUF_SIZE];
static char *ob = obuf;

/*
 * Flush buffered output.
 *
 * If we haven't displayed any file data yet,
 * output messages on error output (file descriptor 2),
 * otherwise output on standard output (file descriptor 1).
 *
 * This has the desirable effect of producing all
 * error messages on error output if standard output
 * is directed to a file.  It also does the same if
 * we never produce any real output; for example, if
 * the input file(s) cannot be opened.  If we do
 * eventually produce output, code in edit() makes
 * sure these messages can be seen before they are
 * overwritten or scrolled away.
 */
      public void
flush()
{
      register int n;
      register int fd;

      n = ob - obuf;
      if (n == 0)
            return;
#if MSDOS_COMPILER==WIN32C
      if (is_tty && any_display)
      {
            char *p;
            char *op;
            DWORD nwritten = 0;
            CONSOLE_SCREEN_BUFFER_INFO scr;
            DWORD nchars;
            COORD cpos;
            WORD nm_attr;
            int olen;
            extern HANDLE con_out;
            extern int nm_fg_color;
            extern int nm_bg_color;
#define     MAKEATTR(fg,bg)         ((WORD)((fg)|((bg)<<4)))

            *ob = '\0';
            olen = ob - obuf;
            /*
             * To avoid color problems, if we're scrolling the screen,
             * we write only up to the char that causes the scroll,
             * (a newline or a char in the last column), then fill 
             * the bottom line with the "normal" attribute, then 
             * write the rest.
             * When Windows scrolls, it takes the attributes for the 
             * new line from the first char of the (previously) 
             * bottom line.
             *
             * {{ This still doesn't work correctly in all cases! }}
             */
            nm_attr = MAKEATTR(nm_fg_color, nm_bg_color);
            for (op = obuf;  *op != '\0';  )
            {
                  GetConsoleScreenBufferInfo(con_out, &scr);
                  /* Find the next newline. */
                  p = strchr(op, '\n');
                  if (p == NULL &&
                      scr.dwCursorPosition.X + olen >= sc_width)
                  {
                        /*
                         * No newline, but writing in the 
                         * last column causes scrolling.
                         */
                        p = op + sc_width - scr.dwCursorPosition.X - 1;
                  }
                  if (scr.dwCursorPosition.Y != scr.srWindow.Bottom ||
                      p == NULL)
                  {
                        /* Write the entire buffer. */
                        WriteConsole(con_out, op, olen,
                                    &nwritten, NULL);
                        op += olen;
                  } else
                  {
                        /* Write only up to the scrolling char. */
                        WriteConsole(con_out, op, p - op + 1, 
                                    &nwritten, NULL);
                        cpos.X = 0;
                        cpos.Y = scr.dwCursorPosition.Y;
                        FillConsoleOutputAttribute(con_out, nm_attr,
                                    sc_width, cpos, &nchars);
                        olen -= p - op + 1;
                        op = p + 1;
                  }
            }
            ob = obuf;
            return;
      }
#else
#if MSDOS_COMPILER==MSOFTC
      if (is_tty && any_display)
      {
            *ob = '\0';
            _outtext(obuf);
            ob = obuf;
            return;
      }
#else
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
      if (is_tty && any_display)
      {
            *ob = '\0';
            cputs(obuf);
            ob = obuf;
            return;
      }
#endif
#endif
#endif
      fd = (any_display) ? 1 : 2;
      if (write(fd, obuf, n) != n)
            screen_trashed = 1;
      ob = obuf;
}

/*
 * Output a character.
 */
      public int
putchr(c)
      int c;
{
      if (need_clr)
      {
            need_clr = 0;
            clear_bot();
      }
#if MSDOS_COMPILER
      if (c == '\n' && is_tty)
      {
            /* remove_top(1); */
            putchr('\r');
      }
#else
#ifdef _OSK
      if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
            putchr(0x0A);
#endif
#endif
      /*
       * Some versions of flush() write to *ob, so we must flush
       * when we are still one char from the end of obuf.
       */
      if (ob >= &obuf[sizeof(obuf)-1])
            flush();
      *ob++ = c;
      return (c);
}

/*
 * Output a string.
 */
      public void
putstr(s)
      register char *s;
{
      while (*s != '\0')
            putchr(*s++);
}


/*
 * Output an integer in a given radix.
 */
      static int
iprintnum(num, radix)
      int num;
      int radix;
{
      register char *s;
      int r;
      int neg;
      char buf[10];

      neg = (num < 0);
      if (neg)
            num = -num;

      s = buf;
      do
      {
            *s++ = (num % radix) + '0';
      } while ((num /= radix) != 0);

      if (neg)
            *s++ = '-';
      r = s - buf;

      while (s > buf)
            putchr(*--s);
      return (r);
}

/*
 * This function implements printf-like functionality
 * using a more portable argument list mechanism than printf's.
 */
      static int
less_printf(fmt, parg)
      register char *fmt;
      PARG *parg;
{
      register char *s;
      register int n;
      register int col;

      col = 0;
      while (*fmt != '\0')
      {
            if (*fmt != '%')
            {
                  putchr(*fmt++);
                  col++;
            } else
            {
                  ++fmt;
                  switch (*fmt++) {
                  case 's':
                        s = parg->p_string;
                        parg++;
                        while (*s != '\0')
                        {
                              putchr(*s++);
                              col++;
                        }
                        break;
                  case 'd':
                        n = parg->p_int;
                        parg++;
                        col += iprintnum(n, 10);
                        break;
                  }
            }
      }
      return (col);
}

/*
 * Get a RETURN.
 * If some other non-trivial char is pressed, unget it, so it will
 * become the next command.
 */
      public void
get_return()
{
      int c;

#if ONLY_RETURN
      while ((c = getchr()) != '\n' && c != '\r')
            bell();
#else
      c = getchr();
      if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
            ungetcc(c);
#endif
}

/*
 * Output a message in the lower left corner of the screen
 * and wait for carriage return.
 */
      public void
error(fmt, parg)
      char *fmt;
      PARG *parg;
{
      int col = 0;
      static char return_to_continue[] = "  (press RETURN)";

      errmsgs++;

      if (any_display && is_tty)
      {
            clear_bot();
            so_enter();
            col += so_s_width;
      }

      col += less_printf(fmt, parg);

      if (!(any_display && is_tty))
      {
            putchr('\n');
            return;
      }

      putstr(return_to_continue);
      so_exit();
      col += sizeof(return_to_continue) + so_e_width;

      get_return();
      lower_left();

      if (col >= sc_width)
            /*
             * Printing the message has probably scrolled the screen.
             * {{ Unless the terminal doesn't have auto margins,
             *    in which case we just hammered on the right margin. }}
             */
            screen_trashed = 1;

      flush();
}

static char intr_to_abort[] = "... (interrupt to abort)";

/*
 * Output a message in the lower left corner of the screen
 * and don't wait for carriage return.
 * Usually used to warn that we are beginning a potentially
 * time-consuming operation.
 */
      public void
ierror(fmt, parg)
      char *fmt;
      PARG *parg;
{
      clear_bot();
      so_enter();
      (void) less_printf(fmt, parg);
      putstr(intr_to_abort);
      so_exit();
      flush();
      need_clr = 1;
}

/*
 * Output a message in the lower left corner of the screen
 * and return a single-character response.
 */
      public int
query(fmt, parg)
      char *fmt;
      PARG *parg;
{
      register int c;
      int col = 0;

      if (any_display && is_tty)
            clear_bot();

      (void) less_printf(fmt, parg);
      c = getchr();

      if (!(any_display && is_tty))
      {
            putchr('\n');
            return (c);
      }

      lower_left();
      if (col >= sc_width)
            screen_trashed = 1;
      flush();

      return (c);
}

Generated by  Doxygen 1.6.0   Back to index