summaryrefslogtreecommitdiffstats
path: root/contrib/less/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/less/output.c')
-rw-r--r--contrib/less/output.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/contrib/less/output.c b/contrib/less/output.c
new file mode 100644
index 0000000..a9c3e9f
--- /dev/null
+++ b/contrib/less/output.c
@@ -0,0 +1,461 @@
+/*
+ * 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);
+}
OpenPOWER on IntegriCloud