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