]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/less/output.c
This commit was generated by cvs2svn to compensate for changes in r102528,
[FreeBSD/FreeBSD.git] / contrib / less / output.c
1 /*
2  * Copyright (C) 1984-2000  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
25 extern int sigs;
26 extern int sc_width;
27 extern int so_s_width, so_e_width;
28 extern int screen_trashed;
29 extern int any_display;
30 extern int is_tty;
31
32 /*
33  * Display the line which is in the line buffer.
34  */
35         public void
36 put_line()
37 {
38         register int c;
39         register int i;
40         int a;
41         int curr_attr;
42
43         if (ABORT_SIGS())
44         {
45                 /*
46                  * Don't output if a signal is pending.
47                  */
48                 screen_trashed = 1;
49                 return;
50         }
51
52         curr_attr = AT_NORMAL;
53
54         for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
55         {
56                 if (a != curr_attr)
57                 {
58                         /*
59                          * Changing attributes.
60                          * Display the exit sequence for the old attribute
61                          * and the enter sequence for the new one.
62                          */
63                         switch (curr_attr)
64                         {
65                         case AT_UNDERLINE:      ul_exit();      break;
66                         case AT_BOLD:           bo_exit();      break;
67                         case AT_BLINK:          bl_exit();      break;
68                         case AT_STANDOUT:       so_exit();      break;
69                         }
70                         switch (a)
71                         {
72                         case AT_UNDERLINE:      ul_enter();     break;
73                         case AT_BOLD:           bo_enter();     break;
74                         case AT_BLINK:          bl_enter();     break;
75                         case AT_STANDOUT:       so_enter();     break;
76                         }
77                         curr_attr = a;
78                 }
79                 if (curr_attr == AT_INVIS)
80                         continue;
81                 if (c == '\b')
82                         putbs();
83                 else
84                         putchr(c);
85         }
86
87         switch (curr_attr)
88         {
89         case AT_UNDERLINE:      ul_exit();      break;
90         case AT_BOLD:           bo_exit();      break;
91         case AT_BLINK:          bl_exit();      break;
92         case AT_STANDOUT:       so_exit();      break;
93         }
94         final_attr = curr_attr;
95 }
96
97 static char obuf[OUTBUF_SIZE];
98 static char *ob = obuf;
99
100 /*
101  * Flush buffered output.
102  *
103  * If we haven't displayed any file data yet,
104  * output messages on error output (file descriptor 2),
105  * otherwise output on standard output (file descriptor 1).
106  *
107  * This has the desirable effect of producing all
108  * error messages on error output if standard output
109  * is directed to a file.  It also does the same if
110  * we never produce any real output; for example, if
111  * the input file(s) cannot be opened.  If we do
112  * eventually produce output, code in edit() makes
113  * sure these messages can be seen before they are
114  * overwritten or scrolled away.
115  */
116         public void
117 flush()
118 {
119         register int n;
120         register int fd;
121
122         n = ob - obuf;
123         if (n == 0)
124                 return;
125 #if MSDOS_COMPILER==WIN32C
126         if (is_tty && any_display)
127         {
128                 char *op;
129                 DWORD nwritten = 0;
130                 CONSOLE_SCREEN_BUFFER_INFO scr;
131                 int row;
132                 int col;
133                 int olen;
134                 extern HANDLE con_out;
135
136                 olen = ob - obuf;
137                 /*
138                  * There is a bug in Win32 WriteConsole() if we're
139                  * writing in the last cell with a different color.
140                  * To avoid color problems in the bottom line,
141                  * we scroll the screen manually, before writing.
142                  */
143                 GetConsoleScreenBufferInfo(con_out, &scr);
144                 col = scr.dwCursorPosition.X;
145                 row = scr.dwCursorPosition.Y;
146                 for (op = obuf;  op < obuf + olen;  op++)
147                 {
148                         if (*op == '\n')
149                         {
150                                 col = 0;
151                                 row++;
152                         } else
153                         {
154                                 col++;
155                                 if (col >= sc_width)
156                                 {
157                                         col = 0;
158                                         row++;
159                                 }
160                         }
161                 }
162                 if (row > scr.srWindow.Bottom)
163                         win32_scroll_up(row - scr.srWindow.Bottom);
164                 WriteConsole(con_out, obuf, olen, &nwritten, NULL);
165                 ob = obuf;
166                 return;
167         }
168 #else
169 #if MSDOS_COMPILER==MSOFTC
170         if (is_tty && any_display)
171         {
172                 *ob = '\0';
173                 _outtext(obuf);
174                 ob = obuf;
175                 return;
176         }
177 #else
178 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
179         if (is_tty && any_display)
180         {
181                 *ob = '\0';
182                 cputs(obuf);
183                 ob = obuf;
184                 return;
185         }
186 #endif
187 #endif
188 #endif
189         fd = (any_display) ? 1 : 2;
190         if (write(fd, obuf, n) != n)
191                 screen_trashed = 1;
192         ob = obuf;
193 }
194
195 /*
196  * Output a character.
197  */
198         public int
199 putchr(c)
200         int c;
201 {
202         if (need_clr)
203         {
204                 need_clr = 0;
205                 clear_bot();
206         }
207 #if MSDOS_COMPILER
208         if (c == '\n' && is_tty)
209         {
210                 /* remove_top(1); */
211                 putchr('\r');
212         }
213 #else
214 #ifdef _OSK
215         if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
216                 putchr(0x0A);
217 #endif
218 #endif
219         /*
220          * Some versions of flush() write to *ob, so we must flush
221          * when we are still one char from the end of obuf.
222          */
223         if (ob >= &obuf[sizeof(obuf)-1])
224                 flush();
225         *ob++ = c;
226         return (c);
227 }
228
229 /*
230  * Output a string.
231  */
232         public void
233 putstr(s)
234         register char *s;
235 {
236         while (*s != '\0')
237                 putchr(*s++);
238 }
239
240
241 /*
242  * Output an integer in a given radix.
243  */
244         static int
245 iprintnum(num, radix)
246         int num;
247         int radix;
248 {
249         register char *s;
250         int r;
251         int neg;
252         char buf[INT_STRLEN_BOUND(num)];
253
254         neg = (num < 0);
255         if (neg)
256                 num = -num;
257
258         s = buf;
259         do
260         {
261                 *s++ = (num % radix) + '0';
262         } while ((num /= radix) != 0);
263
264         if (neg)
265                 *s++ = '-';
266         r = s - buf;
267
268         while (s > buf)
269                 putchr(*--s);
270         return (r);
271 }
272
273 /*
274  * This function implements printf-like functionality
275  * using a more portable argument list mechanism than printf's.
276  */
277         static int
278 less_printf(fmt, parg)
279         register char *fmt;
280         PARG *parg;
281 {
282         register char *s;
283         register int n;
284         register int col;
285
286         col = 0;
287         while (*fmt != '\0')
288         {
289                 if (*fmt != '%')
290                 {
291                         putchr(*fmt++);
292                         col++;
293                 } else
294                 {
295                         ++fmt;
296                         switch (*fmt++) {
297                         case 's':
298                                 s = parg->p_string;
299                                 parg++;
300                                 while (*s != '\0')
301                                 {
302                                         putchr(*s++);
303                                         col++;
304                                 }
305                                 break;
306                         case 'd':
307                                 n = parg->p_int;
308                                 parg++;
309                                 col += iprintnum(n, 10);
310                                 break;
311                         }
312                 }
313         }
314         return (col);
315 }
316
317 /*
318  * Get a RETURN.
319  * If some other non-trivial char is pressed, unget it, so it will
320  * become the next command.
321  */
322         public void
323 get_return()
324 {
325         int c;
326
327 #if ONLY_RETURN
328         while ((c = getchr()) != '\n' && c != '\r')
329                 bell();
330 #else
331         c = getchr();
332         if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
333                 ungetcc(c);
334 #endif
335 }
336
337 /*
338  * Output a message in the lower left corner of the screen
339  * and wait for carriage return.
340  */
341         public void
342 error(fmt, parg)
343         char *fmt;
344         PARG *parg;
345 {
346         int col = 0;
347         static char return_to_continue[] = "  (press RETURN)";
348
349         errmsgs++;
350
351         if (any_display && is_tty)
352         {
353                 clear_bot();
354                 so_enter();
355                 col += so_s_width;
356         }
357
358         col += less_printf(fmt, parg);
359
360         if (!(any_display && is_tty))
361         {
362                 putchr('\n');
363                 return;
364         }
365
366         putstr(return_to_continue);
367         so_exit();
368         col += sizeof(return_to_continue) + so_e_width;
369
370         get_return();
371         lower_left();
372
373         if (col >= sc_width)
374                 /*
375                  * Printing the message has probably scrolled the screen.
376                  * {{ Unless the terminal doesn't have auto margins,
377                  *    in which case we just hammered on the right margin. }}
378                  */
379                 screen_trashed = 1;
380
381         flush();
382 }
383
384 static char intr_to_abort[] = "... (interrupt to abort)";
385
386 /*
387  * Output a message in the lower left corner of the screen
388  * and don't wait for carriage return.
389  * Usually used to warn that we are beginning a potentially
390  * time-consuming operation.
391  */
392         public void
393 ierror(fmt, parg)
394         char *fmt;
395         PARG *parg;
396 {
397         clear_bot();
398         so_enter();
399         (void) less_printf(fmt, parg);
400         putstr(intr_to_abort);
401         so_exit();
402         flush();
403         need_clr = 1;
404 }
405
406 /*
407  * Output a message in the lower left corner of the screen
408  * and return a single-character response.
409  */
410         public int
411 query(fmt, parg)
412         char *fmt;
413         PARG *parg;
414 {
415         register int c;
416         int col = 0;
417
418         if (any_display && is_tty)
419                 clear_bot();
420
421         (void) less_printf(fmt, parg);
422         c = getchr();
423
424         if (!(any_display && is_tty))
425         {
426                 putchr('\n');
427                 return (c);
428         }
429
430         lower_left();
431         if (col >= sc_width)
432                 screen_trashed = 1;
433         flush();
434
435         return (c);
436 }