xref: /original-bsd/usr.bin/more/output.c (revision 048a349a)
1 /*
2  * Copyright (c) 1988 Mark Nudleman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that the above copyright notice and this paragraph are
8  * duplicated in all such forms and that any documentation,
9  * advertising materials, and other materials related to such
10  * distribution and use acknowledge that the software was developed
11  * by Mark Nudleman and the University of California, Berkeley.  The
12  * name of Mark Nudleman or the
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #ifndef lint
21 static char sccsid[] = "@(#)output.c	5.4 (Berkeley) 07/25/88";
22 #endif /* not lint */
23 
24 /*
25  * High level routines dealing with the output to the screen.
26  */
27 
28 #include "less.h"
29 
30 public int errmsgs;	/* Count of messages displayed by error() */
31 
32 extern int sigs;
33 extern int sc_width, sc_height;
34 extern int ul_width, ue_width;
35 extern int so_width, se_width;
36 extern int bo_width, be_width;
37 extern int tabstop;
38 extern int twiddle;
39 extern int screen_trashed;
40 extern int any_display;
41 extern char *line;
42 extern char *first_cmd;
43 
44 /*
45  * Display the line which is in the line buffer.
46  */
47 	public void
48 put_line()
49 {
50 	register char *p;
51 	register int c;
52 	register int column;
53 	extern int auto_wrap, ignaw;
54 
55 	if (sigs)
56 	{
57 		/*
58 		 * Don't output if a signal is pending.
59 		 */
60 		screen_trashed = 1;
61 		return;
62 	}
63 
64 	if (line == NULL)
65 		line = (twiddle) ? "~" : "";
66 
67 	column = 0;
68 	for (p = line;  *p != '\0';  p++)
69 	{
70 		switch (c = *p)
71 		{
72 		case UL_CHAR:
73 			ul_enter();
74 			column += ul_width;
75 			break;
76 		case UE_CHAR:
77 			ul_exit();
78 			column += ue_width;
79 			break;
80 		case BO_CHAR:
81 			bo_enter();
82 			column += bo_width;
83 			break;
84 		case BE_CHAR:
85 			bo_exit();
86 			column += be_width;
87 			break;
88 		case '\t':
89 			do
90 			{
91 				putchr(' ');
92 				column++;
93 			} while ((column % tabstop) != 0);
94 			break;
95 		case '\b':
96 			putbs();
97 			column--;
98 			break;
99 		default:
100 			if (c & 0200)
101 			{
102 				/*
103 				 * Control characters arrive here as the
104 				 * normal character [carat_char(c)] with
105 				 * the 0200 bit set.  See pappend().
106 				 */
107 				putchr('^');
108 				putchr(c & 0177);
109 				column += 2;
110 			} else
111 			{
112 				putchr(c);
113 				column++;
114 			}
115 		}
116 	}
117 	if (column < sc_width || !auto_wrap || ignaw)
118 		putchr('\n');
119 }
120 
121 /*
122  * Is a given character a "control" character?
123  * {{ ASCII DEPENDENT }}
124  */
125 	public int
126 control_char(c)
127 	int c;
128 {
129 	return (c < ' ' || c == '\177');
130 }
131 
132 /*
133  * Return the printable character used to identify a control character
134  * (printed after a carat; e.g. '\3' => "^C").
135  * {{ ASCII DEPENDENT }}
136  */
137 	public int
138 carat_char(c)
139 	int c;
140 {
141 	return ((c == '\177') ? '?' : (c | 0100));
142 }
143 
144 
145 static char obuf[1024];
146 static char *ob = obuf;
147 
148 /*
149  * Flush buffered output.
150  */
151 	public void
152 flush()
153 {
154 	register int n;
155 
156 	n = ob - obuf;
157 	if (n == 0)
158 		return;
159 	if (write(1, obuf, n) != n)
160 		screen_trashed = 1;
161 	ob = obuf;
162 }
163 
164 /*
165  * Output a character.
166  */
167 	public void
168 putchr(c)
169 	int c;
170 {
171 	if (ob >= &obuf[sizeof(obuf)])
172 		flush();
173 	*ob++ = c;
174 }
175 
176 /*
177  * Output a string.
178  */
179 	public void
180 putstr(s)
181 	register char *s;
182 {
183 	while (*s != '\0')
184 		putchr(*s++);
185 }
186 
187 /*
188  * Output a message in the lower left corner of the screen
189  * and wait for carriage return.
190  */
191 
192 static char return_to_continue[] = "  (press RETURN)";
193 
194 	public void
195 error(s)
196 	char *s;
197 {
198 	register int c;
199 	static char buf[2];
200 
201 	errmsgs++;
202 	if (!any_display)
203 	{
204 		/*
205 		 * Nothing has been displayed yet.
206 		 * Output this message on error output (file
207 		 * descriptor 2) and don't wait for a keystroke
208 		 * to continue.
209 		 *
210 		 * This has the desirable effect of producing all
211 		 * error messages on error output if standard output
212 		 * is directed to a file.  It also does the same if
213 		 * we never produce any real output; for example, if
214 		 * the input file(s) cannot be opened.  If we do
215 		 * eventually produce output, code in edit() makes
216 		 * sure these messages can be seen before they are
217 		 * overwritten or scrolled away.
218 		 */
219 		write(2, s, strlen(s));
220 		write(2, "\n", 1);
221 		return;
222 	}
223 
224 	lower_left();
225 	clear_eol();
226 	so_enter();
227 	putstr(s);
228 	putstr(return_to_continue);
229 	so_exit();
230 
231 	c = getchr();
232 	if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
233 	{
234 		buf[0] = c;
235 		first_cmd = buf;
236 	}
237 	lower_left();
238 
239 	if (strlen(s) + sizeof(return_to_continue) +
240 		so_width + se_width + 1 > sc_width)
241 		/*
242 		 * Printing the message has probably scrolled the screen.
243 		 * {{ Unless the terminal doesn't have auto margins,
244 		 *    in which case we just hammered on the right margin. }}
245 		 */
246 		repaint();
247 
248 	flush();
249 }
250 
251 static char intr_to_abort[] = "... (interrupt to abort)";
252 
253 	public void
254 ierror(s)
255 	char *s;
256 {
257 
258 	lower_left();
259 	clear_eol();
260 	so_enter();
261 	putstr(s);
262 	putstr(intr_to_abort);
263 	so_exit();
264 	flush();
265 }
266