"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "less-424/output.c" of archive less-424.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * Copyright (C) 1984-2008  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 public int at_prompt;
   25 
   26 extern int sigs;
   27 extern int sc_width;
   28 extern int so_s_width, so_e_width;
   29 extern int screen_trashed;
   30 extern int any_display;
   31 extern int is_tty;
   32 extern int oldbot;
   33 
   34 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
   35 extern int ctldisp;
   36 extern int nm_fg_color, nm_bg_color;
   37 extern int bo_fg_color, bo_bg_color;
   38 extern int ul_fg_color, ul_bg_color;
   39 extern int so_fg_color, so_bg_color;
   40 extern int bl_fg_color, bl_bg_color;
   41 #endif
   42 
   43 /*
   44  * Display the line which is in the line buffer.
   45  */
   46 	public void
   47 put_line()
   48 {
   49 	register int c;
   50 	register int i;
   51 	int a;
   52 
   53 	if (ABORT_SIGS())
   54 	{
   55 		/*
   56 		 * Don't output if a signal is pending.
   57 		 */
   58 		screen_trashed = 1;
   59 		return;
   60 	}
   61 
   62 	final_attr = AT_NORMAL;
   63 
   64 	for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
   65 	{
   66 		at_switch(a);
   67 		final_attr = a;
   68 		if (c == '\b')
   69 			putbs();
   70 		else
   71 			putchr(c);
   72 	}
   73 
   74 	at_exit();
   75 }
   76 
   77 static char obuf[OUTBUF_SIZE];
   78 static char *ob = obuf;
   79 
   80 /*
   81  * Flush buffered output.
   82  *
   83  * If we haven't displayed any file data yet,
   84  * output messages on error output (file descriptor 2),
   85  * otherwise output on standard output (file descriptor 1).
   86  *
   87  * This has the desirable effect of producing all
   88  * error messages on error output if standard output
   89  * is directed to a file.  It also does the same if
   90  * we never produce any real output; for example, if
   91  * the input file(s) cannot be opened.  If we do
   92  * eventually produce output, code in edit() makes
   93  * sure these messages can be seen before they are
   94  * overwritten or scrolled away.
   95  */
   96 	public void
   97 flush()
   98 {
   99 	register int n;
  100 	register int fd;
  101 
  102 	n = ob - obuf;
  103 	if (n == 0)
  104 		return;
  105 
  106 #if MSDOS_COMPILER==MSOFTC
  107 	if (is_tty && any_display)
  108 	{
  109 		*ob = '\0';
  110 		_outtext(obuf);
  111 		ob = obuf;
  112 		return;
  113 	}
  114 #else
  115 #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  116 	if (is_tty && any_display)
  117 	{
  118 		*ob = '\0';
  119 		if (ctldisp != OPT_ONPLUS)
  120 			WIN32textout(obuf, ob - obuf);
  121 		else
  122 		{
  123 			/*
  124 			 * Look for SGR escape sequences, and convert them
  125 			 * to color commands.  Replace bold, underline,
  126 			 * and italic escapes into colors specified via
  127 			 * the -D command-line option.
  128 			 */
  129 			char *anchor, *p, *p_next;
  130 			unsigned char fg, bg;
  131 #if MSDOS_COMPILER==WIN32C
  132 			/* Screen colors used by 3x and 4x SGR commands. */
  133 			static unsigned char screen_color[] = {
  134 				0, /* BLACK */
  135 				FOREGROUND_RED,
  136 				FOREGROUND_GREEN,
  137 				FOREGROUND_RED|FOREGROUND_GREEN,
  138 				FOREGROUND_BLUE,
  139 				FOREGROUND_BLUE|FOREGROUND_RED,
  140 				FOREGROUND_BLUE|FOREGROUND_GREEN,
  141 				FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED
  142 			};
  143 #else
  144 			static enum COLORS screen_color[] = {
  145 				BLACK, RED, GREEN, BROWN,
  146 				BLUE, MAGENTA, CYAN, LIGHTGRAY
  147 			};
  148 #endif
  149 
  150 			for (anchor = p_next = obuf;
  151 			     (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
  152 			{
  153 				p = p_next;
  154 				if (p[1] == '[')  /* "ESC-[" sequence */
  155 				{
  156 					if (p > anchor)
  157 					{
  158 						/*
  159 						 * If some chars seen since
  160 						 * the last escape sequence,
  161 						 * write them out to the screen.
  162 						 */
  163 						WIN32textout(anchor, p-anchor);
  164 						anchor = p;
  165 					}
  166 					p += 2;  /* Skip the "ESC-[" */
  167 					if (is_ansi_end(*p))
  168 					{
  169 						/*
  170 						 * Handle null escape sequence
  171 						 * "ESC[m", which restores
  172 						 * the normal color.
  173 						 */
  174 						p++;
  175 						anchor = p_next = p;
  176 						WIN32setcolors(nm_fg_color, nm_bg_color);
  177 						continue;
  178 					}
  179 					p_next = p;
  180 
  181 					/*
  182 					 * Select foreground/background colors
  183 					 * based on the escape sequence.
  184 					 */
  185 					fg = nm_fg_color;
  186 					bg = nm_bg_color;
  187 					while (!is_ansi_end(*p))
  188 					{
  189 						char *q;
  190 						long code = strtol(p, &q, 10);
  191 
  192 						if (*q == '\0')
  193 						{
  194 							/*
  195 							 * Incomplete sequence.
  196 							 * Leave it unprocessed
  197 							 * in the buffer.
  198 							 */
  199 							int slop = q - anchor;
  200 							/* {{ strcpy args overlap! }} */
  201 							strcpy(obuf, anchor);
  202 							ob = &obuf[slop];
  203 							return;
  204 						}
  205 
  206 						if (q == p ||
  207 						    code > 49 || code < 0 ||
  208 						    (!is_ansi_end(*q) && *q != ';'))
  209 						{
  210 							p_next = q;
  211 							break;
  212 						}
  213 						if (*q == ';')
  214 							q++;
  215 
  216 						switch (code)
  217 						{
  218 						default:
  219 						/* case 0:  all attrs off */
  220 						/* case 22: bold off */
  221 						/* case 23: italic off */
  222 						/* case 24: underline off */
  223 						/* case 27: inverse off */
  224 							fg = nm_fg_color;
  225 							bg = nm_bg_color;
  226 							break;
  227 						case 1:	/* bold on */
  228 							fg = bo_fg_color;
  229 							bg = bo_bg_color;
  230 							break;
  231 						case 3:	/* italic on */
  232 						case 7: /* inverse on */
  233 							fg = so_fg_color;
  234 							bg = so_bg_color;
  235 							break;
  236 						case 4:	/* underline on */
  237 							fg = ul_fg_color;
  238 							bg = ul_bg_color;
  239 							break;
  240 						case 5: /* slow blink on */
  241 						case 6: /* fast blink on */
  242 							fg = bl_fg_color;
  243 							bg = bl_bg_color;
  244 							break;
  245 						case 8:	/* concealed on */
  246 							fg = (bg & 7) | 8;
  247 							break;
  248 						case 30: case 31: case 32:
  249 						case 33: case 34: case 35:
  250 						case 36: case 37:
  251 							fg = (fg & 8) | (screen_color[code - 30]);
  252 							break;
  253 						case 39: /* default fg */
  254 							fg = nm_fg_color;
  255 							break;
  256 						case 40: case 41: case 42:
  257 						case 43: case 44: case 45:
  258 						case 46: case 47:
  259 							bg = (bg & 8) | (screen_color[code - 40]);
  260 							break;
  261 						case 49: /* default fg */
  262 							bg = nm_bg_color;
  263 							break;
  264 						}
  265 						p = q;
  266 					}
  267 					if (!is_ansi_end(*p) || p == p_next)
  268 						break;
  269 					fg &= 0xf;
  270 					bg &= 0xf;
  271 					WIN32setcolors(fg, bg);
  272 					p_next = anchor = p + 1;
  273 				} else
  274 					p_next++;
  275 			}
  276 
  277 			/* Output what's left in the buffer.  */
  278 			WIN32textout(anchor, ob - anchor);
  279 		}
  280 		ob = obuf;
  281 		return;
  282 	}
  283 #endif
  284 #endif
  285 	fd = (any_display) ? 1 : 2;
  286 	if (write(fd, obuf, n) != n)
  287 		screen_trashed = 1;
  288 	ob = obuf;
  289 }
  290 
  291 /*
  292  * Output a character.
  293  */
  294 	public int
  295 putchr(c)
  296 	int c;
  297 {
  298 #if 0 /* fake UTF-8 output for testing */
  299 	extern int utf_mode;
  300 	if (utf_mode)
  301 	{
  302 		static char ubuf[MAX_UTF_CHAR_LEN];
  303 		static int ubuf_len = 0;
  304 		static int ubuf_index = 0;
  305 		if (ubuf_len == 0)
  306 		{
  307 			ubuf_len = utf_len(c);
  308 			ubuf_index = 0;
  309 		}
  310 		ubuf[ubuf_index++] = c;
  311 		if (ubuf_index < ubuf_len)
  312 			return c;
  313 		c = get_wchar(ubuf) & 0xFF;
  314 		ubuf_len = 0;
  315 	}
  316 #endif
  317 	if (need_clr)
  318 	{
  319 		need_clr = 0;
  320 		clear_bot();
  321 	}
  322 #if MSDOS_COMPILER
  323 	if (c == '\n' && is_tty)
  324 	{
  325 		/* remove_top(1); */
  326 		putchr('\r');
  327 	}
  328 #else
  329 #ifdef _OSK
  330 	if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
  331 		putchr(0x0A);
  332 #endif
  333 #endif
  334 	/*
  335 	 * Some versions of flush() write to *ob, so we must flush
  336 	 * when we are still one char from the end of obuf.
  337 	 */
  338 	if (ob >= &obuf[sizeof(obuf)-1])
  339 		flush();
  340 	*ob++ = c;
  341 	at_prompt = 0;
  342 	return (c);
  343 }
  344 
  345 /*
  346  * Output a string.
  347  */
  348 	public void
  349 putstr(s)
  350 	register char *s;
  351 {
  352 	while (*s != '\0')
  353 		putchr(*s++);
  354 }
  355 
  356 
  357 /*
  358  * Convert an integral type to a string.
  359  */
  360 #define TYPE_TO_A_FUNC(funcname, type) \
  361 void funcname(num, buf) \
  362 	type num; \
  363 	char *buf; \
  364 { \
  365 	int neg = (num < 0); \
  366 	char tbuf[INT_STRLEN_BOUND(num)+2]; \
  367 	register char *s = tbuf + sizeof(tbuf); \
  368 	if (neg) num = -num; \
  369 	*--s = '\0'; \
  370 	do { \
  371 		*--s = (num % 10) + '0'; \
  372 	} while ((num /= 10) != 0); \
  373 	if (neg) *--s = '-'; \
  374 	strcpy(buf, s); \
  375 }
  376 
  377 TYPE_TO_A_FUNC(postoa, POSITION)
  378 TYPE_TO_A_FUNC(linenumtoa, LINENUM)
  379 TYPE_TO_A_FUNC(inttoa, int)
  380 
  381 /*
  382  * Output an integer in a given radix.
  383  */
  384 	static int
  385 iprint_int(num)
  386 	int num;
  387 {
  388 	char buf[INT_STRLEN_BOUND(num)];
  389 
  390 	inttoa(num, buf);
  391 	putstr(buf);
  392 	return (strlen(buf));
  393 }
  394 
  395 /*
  396  * Output a line number in a given radix.
  397  */
  398 	static int
  399 iprint_linenum(num)
  400 	LINENUM num;
  401 {
  402 	char buf[INT_STRLEN_BOUND(num)];
  403 
  404 	linenumtoa(num, buf);
  405 	putstr(buf);
  406 	return (strlen(buf));
  407 }
  408 
  409 /*
  410  * This function implements printf-like functionality
  411  * using a more portable argument list mechanism than printf's.
  412  */
  413 	static int
  414 less_printf(fmt, parg)
  415 	register char *fmt;
  416 	PARG *parg;
  417 {
  418 	register char *s;
  419 	register int col;
  420 
  421 	col = 0;
  422 	while (*fmt != '\0')
  423 	{
  424 		if (*fmt != '%')
  425 		{
  426 			putchr(*fmt++);
  427 			col++;
  428 		} else
  429 		{
  430 			++fmt;
  431 			switch (*fmt++)
  432 			{
  433 			case 's':
  434 				s = parg->p_string;
  435 				parg++;
  436 				while (*s != '\0')
  437 				{
  438 					putchr(*s++);
  439 					col++;
  440 				}
  441 				break;
  442 			case 'd':
  443 				col += iprint_int(parg->p_int);
  444 				parg++;
  445 				break;
  446 			case 'n':
  447 				col += iprint_linenum(parg->p_linenum);
  448 				parg++;
  449 				break;
  450 			}
  451 		}
  452 	}
  453 	return (col);
  454 }
  455 
  456 /*
  457  * Get a RETURN.
  458  * If some other non-trivial char is pressed, unget it, so it will
  459  * become the next command.
  460  */
  461 	public void
  462 get_return()
  463 {
  464 	int c;
  465 
  466 #if ONLY_RETURN
  467 	while ((c = getchr()) != '\n' && c != '\r')
  468 		bell();
  469 #else
  470 	c = getchr();
  471 	if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
  472 		ungetcc(c);
  473 #endif
  474 }
  475 
  476 /*
  477  * Output a message in the lower left corner of the screen
  478  * and wait for carriage return.
  479  */
  480 	public void
  481 error(fmt, parg)
  482 	char *fmt;
  483 	PARG *parg;
  484 {
  485 	int col = 0;
  486 	static char return_to_continue[] = "  (press RETURN)";
  487 
  488 	errmsgs++;
  489 
  490 	if (any_display && is_tty)
  491 	{
  492 		if (!oldbot)
  493 			squish_check();
  494 		at_exit();
  495 		clear_bot();
  496 		at_enter(AT_STANDOUT);
  497 		col += so_s_width;
  498 	}
  499 
  500 	col += less_printf(fmt, parg);
  501 
  502 	if (!(any_display && is_tty))
  503 	{
  504 		putchr('\n');
  505 		return;
  506 	}
  507 
  508 	putstr(return_to_continue);
  509 	at_exit();
  510 	col += sizeof(return_to_continue) + so_e_width;
  511 
  512 	get_return();
  513 	lower_left();
  514 
  515 	if (col >= sc_width)
  516 		/*
  517 		 * Printing the message has probably scrolled the screen.
  518 		 * {{ Unless the terminal doesn't have auto margins,
  519 		 *    in which case we just hammered on the right margin. }}
  520 		 */
  521 		screen_trashed = 1;
  522 
  523 	flush();
  524 }
  525 
  526 static char intr_to_abort[] = "... (interrupt to abort)";
  527 
  528 /*
  529  * Output a message in the lower left corner of the screen
  530  * and don't wait for carriage return.
  531  * Usually used to warn that we are beginning a potentially
  532  * time-consuming operation.
  533  */
  534 	public void
  535 ierror(fmt, parg)
  536 	char *fmt;
  537 	PARG *parg;
  538 {
  539 	at_exit();
  540 	clear_bot();
  541 	at_enter(AT_STANDOUT);
  542 	(void) less_printf(fmt, parg);
  543 	putstr(intr_to_abort);
  544 	at_exit();
  545 	flush();
  546 	need_clr = 1;
  547 }
  548 
  549 /*
  550  * Output a message in the lower left corner of the screen
  551  * and return a single-character response.
  552  */
  553 	public int
  554 query(fmt, parg)
  555 	char *fmt;
  556 	PARG *parg;
  557 {
  558 	register int c;
  559 	int col = 0;
  560 
  561 	if (any_display && is_tty)
  562 		clear_bot();
  563 
  564 	(void) less_printf(fmt, parg);
  565 	c = getchr();
  566 
  567 	if (!(any_display && is_tty))
  568 	{
  569 		putchr('\n');
  570 		return (c);
  571 	}
  572 
  573 	lower_left();
  574 	if (col >= sc_width)
  575 		screen_trashed = 1;
  576 	flush();
  577 
  578 	return (c);
  579 }