Commit | Line | Data |
---|---|---|
77e25d77 WJ |
1 | /* |
2 | * High level routines dealing with the output to the screen. | |
3 | */ | |
4 | ||
5 | #include "less.h" | |
6 | ||
7 | public int errmsgs; /* Count of messages displayed by error() */ | |
8 | public int need_clr; | |
9 | ||
10 | extern int sigs; | |
11 | extern int sc_width; | |
12 | extern int so_s_width, so_e_width; | |
13 | extern int screen_trashed; | |
14 | extern int any_display; | |
15 | #if __MSDOS__ | |
16 | extern int output_mode; | |
17 | #endif | |
18 | ||
19 | /* | |
20 | * Display the line which is in the line buffer. | |
21 | */ | |
22 | public void | |
23 | put_line() | |
24 | { | |
25 | register int c; | |
26 | register int i; | |
27 | int a; | |
28 | int curr_attr; | |
29 | ||
30 | if (sigs) | |
31 | { | |
32 | /* | |
33 | * Don't output if a signal is pending. | |
34 | */ | |
35 | screen_trashed = 1; | |
36 | return; | |
37 | } | |
38 | ||
39 | curr_attr = NORMAL; | |
40 | ||
41 | for (i = 0; (c = gline(i, &a)) != '\0'; i++) | |
42 | { | |
43 | if (a != curr_attr) | |
44 | { | |
45 | /* | |
46 | * Changing attributes. | |
47 | * Display the exit sequence for the old attribute | |
48 | * and the enter sequence for the new one. | |
49 | */ | |
50 | switch (curr_attr) | |
51 | { | |
52 | case UNDERLINE: ul_exit(); break; | |
53 | case BOLD: bo_exit(); break; | |
54 | case BLINK: bl_exit(); break; | |
55 | } | |
56 | switch (a) | |
57 | { | |
58 | case UNDERLINE: ul_enter(); break; | |
59 | case BOLD: bo_enter(); break; | |
60 | case BLINK: bl_enter(); break; | |
61 | } | |
62 | curr_attr = a; | |
63 | } | |
64 | if (curr_attr == INVIS) | |
65 | continue; | |
66 | if (c == '\b') | |
67 | putbs(); | |
68 | else | |
69 | putchr(c); | |
70 | } | |
71 | } | |
72 | ||
73 | static char obuf[1024]; | |
74 | static char *ob = obuf; | |
75 | ||
76 | /* | |
77 | * Flush buffered output. | |
78 | * | |
79 | * If we haven't displayed any file data yet, | |
80 | * output messages on error output (file descriptor 2), | |
81 | * otherwise output on standard output (file descriptor 1). | |
82 | * | |
83 | * This has the desirable effect of producing all | |
84 | * error messages on error output if standard output | |
85 | * is directed to a file. It also does the same if | |
86 | * we never produce any real output; for example, if | |
87 | * the input file(s) cannot be opened. If we do | |
88 | * eventually produce output, code in edit() makes | |
89 | * sure these messages can be seen before they are | |
90 | * overwritten or scrolled away. | |
91 | */ | |
92 | public void | |
93 | flush() | |
94 | { | |
95 | register int n; | |
96 | register int fd; | |
97 | ||
98 | #if __MSDOS__ | |
99 | if (output_mode == 0) | |
100 | { | |
101 | *ob = '\0'; | |
102 | cputs(obuf); | |
103 | ob = obuf; | |
104 | return; | |
105 | } | |
106 | #endif | |
107 | n = ob - obuf; | |
108 | if (n == 0) | |
109 | return; | |
110 | fd = (any_display) ? 1 : 2; | |
111 | if (write(fd, obuf, n) != n) | |
112 | screen_trashed = 1; | |
113 | ob = obuf; | |
114 | } | |
115 | ||
116 | /* | |
117 | * Output a character. | |
118 | */ | |
119 | public void | |
120 | putchr(c) | |
121 | int c; | |
122 | { | |
123 | if (ob >= &obuf[sizeof(obuf)]) | |
124 | flush(); | |
125 | if (need_clr) | |
126 | { | |
127 | need_clr = 0; | |
128 | lower_left(); | |
129 | clear_eol(); | |
130 | } | |
131 | #if __MSDOS__ | |
132 | if (c == '\n') | |
133 | *ob++ = '\r'; | |
134 | #endif | |
135 | *ob++ = c; | |
136 | } | |
137 | ||
138 | /* | |
139 | * Output a string. | |
140 | */ | |
141 | public void | |
142 | putstr(s) | |
143 | register char *s; | |
144 | { | |
145 | while (*s != '\0') | |
146 | putchr(*s++); | |
147 | } | |
148 | ||
149 | ||
150 | /* | |
151 | * Output an integer in a given radix. | |
152 | */ | |
153 | static int | |
154 | iprintnum(num, radix) | |
155 | int num; | |
156 | int radix; | |
157 | { | |
158 | register char *s; | |
159 | int r; | |
160 | int neg; | |
161 | char buf[10]; | |
162 | ||
163 | if (neg = (num < 0)) | |
164 | num = -num; | |
165 | ||
166 | s = buf; | |
167 | do | |
168 | { | |
169 | *s++ = (num % radix) + '0'; | |
170 | } while ((num /= radix) != 0); | |
171 | ||
172 | if (neg) | |
173 | *s++ = '-'; | |
174 | r = s - buf; | |
175 | ||
176 | while (s > buf) | |
177 | putchr(*--s); | |
178 | return (r); | |
179 | } | |
180 | ||
181 | /* | |
182 | * This function implements printf-like functionality | |
183 | * using a more portable argument list mechanism than printf's. | |
184 | */ | |
185 | static int | |
186 | iprintf(fmt, parg) | |
187 | register char *fmt; | |
188 | PARG *parg; | |
189 | { | |
190 | register char *s; | |
191 | register int n; | |
192 | register int col; | |
193 | ||
194 | col = 0; | |
195 | while (*fmt != '\0') | |
196 | { | |
197 | if (*fmt != '%') | |
198 | { | |
199 | putchr(*fmt++); | |
200 | col++; | |
201 | } else | |
202 | { | |
203 | ++fmt; | |
204 | switch (*fmt++) { | |
205 | case 's': | |
206 | s = parg->p_string; | |
207 | parg++; | |
208 | while (*s != '\0') | |
209 | { | |
210 | putchr(*s++); | |
211 | col++; | |
212 | } | |
213 | break; | |
214 | case 'd': | |
215 | n = parg->p_int; | |
216 | parg++; | |
217 | col += iprintnum(n, 10); | |
218 | break; | |
219 | } | |
220 | } | |
221 | } | |
222 | return (col); | |
223 | } | |
224 | ||
225 | /* | |
226 | * Output a message in the lower left corner of the screen | |
227 | * and wait for carriage return. | |
228 | */ | |
229 | public void | |
230 | error(fmt, parg) | |
231 | char *fmt; | |
232 | PARG *parg; | |
233 | { | |
234 | int c; | |
235 | int col = 0; | |
236 | static char return_to_continue[] = " (press RETURN)"; | |
237 | ||
238 | errmsgs++; | |
239 | ||
240 | if (any_display) | |
241 | { | |
242 | lower_left(); | |
243 | clear_eol(); | |
244 | so_enter(); | |
245 | col += so_s_width; | |
246 | } | |
247 | ||
248 | col += iprintf(fmt, parg); | |
249 | ||
250 | if (!any_display) | |
251 | { | |
252 | putchr('\n'); | |
253 | return; | |
254 | } | |
255 | ||
256 | putstr(return_to_continue); | |
257 | so_exit(); | |
258 | col += sizeof(return_to_continue) + so_e_width; | |
259 | ||
260 | #if ONLY_RETURN | |
261 | while ((c = getchr()) != '\n' && c != '\r') | |
262 | bell(); | |
263 | #else | |
264 | c = getchr(); | |
265 | if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) | |
266 | ungetcc(c); | |
267 | #endif | |
268 | lower_left(); | |
269 | ||
270 | if (col >= sc_width) | |
271 | /* | |
272 | * Printing the message has probably scrolled the screen. | |
273 | * {{ Unless the terminal doesn't have auto margins, | |
274 | * in which case we just hammered on the right margin. }} | |
275 | */ | |
276 | screen_trashed = 1; | |
277 | ||
278 | flush(); | |
279 | } | |
280 | ||
281 | static char intr_to_abort[] = "... (interrupt to abort)"; | |
282 | ||
283 | /* | |
284 | * Output a message in the lower left corner of the screen | |
285 | * and don't wait for carriage return. | |
286 | * Usually used to warn that we are beginning a potentially | |
287 | * time-consuming operation. | |
288 | */ | |
289 | public void | |
290 | ierror(fmt, parg) | |
291 | char *fmt; | |
292 | PARG *parg; | |
293 | { | |
294 | lower_left(); | |
295 | clear_eol(); | |
296 | so_enter(); | |
297 | (void) iprintf(fmt, parg); | |
298 | putstr(intr_to_abort); | |
299 | so_exit(); | |
300 | flush(); | |
301 | need_clr = 1; | |
302 | } | |
303 | ||
304 | /* | |
305 | * Output a message in the lower left corner of the screen | |
306 | * and return a single-character response. | |
307 | */ | |
308 | public int | |
309 | query(fmt, parg) | |
310 | char *fmt; | |
311 | PARG *parg; | |
312 | { | |
313 | register int c; | |
314 | int col = 0; | |
315 | ||
316 | if (any_display) | |
317 | { | |
318 | lower_left(); | |
319 | clear_eol(); | |
320 | } | |
321 | ||
322 | (void) iprintf(fmt, parg); | |
323 | c = getchr(); | |
324 | ||
325 | if (!any_display) | |
326 | { | |
327 | putchr('\n'); | |
328 | return (c); | |
329 | } | |
330 | ||
331 | lower_left(); | |
332 | if (col >= sc_width) | |
333 | screen_trashed = 1; | |
334 | flush(); | |
335 | ||
336 | return (c); | |
337 | } |