1 1.8 tsutsui /* $NetBSD: output.c,v 1.8 2009/01/24 13:58:21 tsutsui Exp $ */ 2 1.3 perry 3 1.1 cjs /* 4 1.7 agc * Copyright (c) 1988 Mark Nudelman 5 1.1 cjs * Copyright (c) 1988, 1993 6 1.1 cjs * The Regents of the University of California. All rights reserved. 7 1.1 cjs * 8 1.1 cjs * Redistribution and use in source and binary forms, with or without 9 1.1 cjs * modification, are permitted provided that the following conditions 10 1.1 cjs * are met: 11 1.1 cjs * 1. Redistributions of source code must retain the above copyright 12 1.1 cjs * notice, this list of conditions and the following disclaimer. 13 1.1 cjs * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 cjs * notice, this list of conditions and the following disclaimer in the 15 1.1 cjs * documentation and/or other materials provided with the distribution. 16 1.6 agc * 3. Neither the name of the University nor the names of its contributors 17 1.6 agc * may be used to endorse or promote products derived from this software 18 1.6 agc * without specific prior written permission. 19 1.6 agc * 20 1.6 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.6 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.6 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.6 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.6 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.6 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.6 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.6 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.6 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.6 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.6 agc * SUCH DAMAGE. 31 1.6 agc */ 32 1.6 agc 33 1.4 christos #include <sys/cdefs.h> 34 1.1 cjs #ifndef lint 35 1.4 christos #if 0 36 1.1 cjs static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 4/27/95"; 37 1.4 christos #else 38 1.8 tsutsui __RCSID("$NetBSD: output.c,v 1.8 2009/01/24 13:58:21 tsutsui Exp $"); 39 1.4 christos #endif 40 1.1 cjs #endif /* not lint */ 41 1.1 cjs 42 1.1 cjs /* 43 1.1 cjs * High level routines dealing with the output to the screen. 44 1.1 cjs */ 45 1.1 cjs 46 1.1 cjs #include <stdio.h> 47 1.2 cjs #include <string.h> 48 1.4 christos #include <unistd.h> 49 1.4 christos #include <stdlib.h> 50 1.4 christos 51 1.4 christos #include "less.h" 52 1.4 christos #include "extern.h" 53 1.1 cjs 54 1.1 cjs int errmsgs; /* Count of messages displayed by error() */ 55 1.1 cjs 56 1.1 cjs /* display the line which is in the line buffer. */ 57 1.4 christos void 58 1.1 cjs put_line() 59 1.1 cjs { 60 1.4 christos char *p; 61 1.4 christos int c; 62 1.4 christos int column; 63 1.1 cjs 64 1.1 cjs if (sigs) 65 1.1 cjs { 66 1.1 cjs /* 67 1.1 cjs * Don't output if a signal is pending. 68 1.1 cjs */ 69 1.1 cjs screen_trashed = 1; 70 1.1 cjs return; 71 1.1 cjs } 72 1.1 cjs 73 1.1 cjs if (line == NULL) 74 1.1 cjs line = ""; 75 1.1 cjs 76 1.1 cjs column = 0; 77 1.1 cjs for (p = line; *p != '\0'; p++) 78 1.1 cjs { 79 1.1 cjs switch (c = *p) 80 1.1 cjs { 81 1.1 cjs case UL_CHAR: 82 1.1 cjs ul_enter(); 83 1.1 cjs column += ul_width +1; 84 1.1 cjs break; 85 1.1 cjs case UE_CHAR: 86 1.1 cjs ul_exit(); 87 1.1 cjs column += ue_width; 88 1.1 cjs break; 89 1.1 cjs case BO_CHAR: 90 1.1 cjs bo_enter(); 91 1.1 cjs column += bo_width +1; 92 1.1 cjs break; 93 1.1 cjs case BE_CHAR: 94 1.1 cjs bo_exit(); 95 1.1 cjs column += be_width; 96 1.1 cjs break; 97 1.1 cjs case '\t': 98 1.1 cjs do 99 1.1 cjs { 100 1.1 cjs putchr(' '); 101 1.1 cjs column++; 102 1.1 cjs } while ((column % tabstop) != 0); 103 1.1 cjs break; 104 1.1 cjs case '\b': 105 1.1 cjs putbs(); 106 1.1 cjs column--; 107 1.1 cjs break; 108 1.1 cjs default: 109 1.1 cjs if (c & 0200) 110 1.1 cjs { 111 1.1 cjs /* 112 1.1 cjs * Control characters arrive here as the 113 1.1 cjs * normal character [CARAT_CHAR(c)] with 114 1.1 cjs * the 0200 bit set. See pappend(). 115 1.1 cjs */ 116 1.1 cjs putchr('^'); 117 1.1 cjs putchr(c & 0177); 118 1.1 cjs column += 2; 119 1.1 cjs } else 120 1.1 cjs { 121 1.1 cjs putchr(c); 122 1.1 cjs column++; 123 1.1 cjs } 124 1.1 cjs } 125 1.1 cjs } 126 1.1 cjs if (column < sc_width || !auto_wrap || ignaw) 127 1.1 cjs putchr('\n'); 128 1.1 cjs } 129 1.1 cjs 130 1.1 cjs static char obuf[1024]; 131 1.1 cjs static char *ob = obuf; 132 1.1 cjs 133 1.1 cjs /* 134 1.1 cjs * Flush buffered output. 135 1.1 cjs */ 136 1.4 christos void 137 1.1 cjs flush() 138 1.1 cjs { 139 1.4 christos int n; 140 1.1 cjs 141 1.1 cjs n = ob - obuf; 142 1.1 cjs if (n == 0) 143 1.1 cjs return; 144 1.1 cjs if (write(1, obuf, n) != n) 145 1.1 cjs screen_trashed = 1; 146 1.1 cjs ob = obuf; 147 1.1 cjs } 148 1.1 cjs 149 1.1 cjs /* 150 1.1 cjs * Purge any pending output. 151 1.1 cjs */ 152 1.4 christos void 153 1.1 cjs purge() 154 1.1 cjs { 155 1.1 cjs 156 1.1 cjs ob = obuf; 157 1.1 cjs } 158 1.1 cjs 159 1.1 cjs /* 160 1.1 cjs * Output a character. 161 1.1 cjs */ 162 1.5 dan int 163 1.1 cjs putchr(c) 164 1.1 cjs int c; 165 1.1 cjs { 166 1.1 cjs if (ob >= &obuf[sizeof(obuf)]) 167 1.1 cjs flush(); 168 1.1 cjs *ob++ = c; 169 1.8 tsutsui return c; 170 1.1 cjs } 171 1.1 cjs 172 1.1 cjs /* 173 1.1 cjs * Output a string. 174 1.1 cjs */ 175 1.4 christos void 176 1.1 cjs putstr(s) 177 1.4 christos char *s; 178 1.1 cjs { 179 1.1 cjs while (*s != '\0') 180 1.1 cjs putchr(*s++); 181 1.1 cjs } 182 1.1 cjs 183 1.1 cjs int cmdstack; 184 1.1 cjs static char return_to_continue[] = "(press RETURN)"; 185 1.1 cjs 186 1.1 cjs /* 187 1.1 cjs * Output a message in the lower left corner of the screen 188 1.1 cjs * and wait for carriage return. 189 1.1 cjs */ 190 1.4 christos void 191 1.1 cjs error(s) 192 1.1 cjs char *s; 193 1.1 cjs { 194 1.1 cjs int ch; 195 1.1 cjs 196 1.1 cjs ++errmsgs; 197 1.1 cjs if (!any_display) { 198 1.1 cjs /* 199 1.1 cjs * Nothing has been displayed yet. Output this message on 200 1.1 cjs * error output (file descriptor 2) and don't wait for a 201 1.1 cjs * keystroke to continue. 202 1.1 cjs * 203 1.1 cjs * This has the desirable effect of producing all error 204 1.1 cjs * messages on error output if standard output is directed 205 1.1 cjs * to a file. It also does the same if we never produce 206 1.1 cjs * any real output; for example, if the input file(s) cannot 207 1.1 cjs * be opened. If we do eventually produce output, code in 208 1.1 cjs * edit() makes sure these messages can be seen before they 209 1.1 cjs * are overwritten or scrolled away. 210 1.1 cjs */ 211 1.1 cjs if (s != NULL) { 212 1.1 cjs (void)write(2, s, strlen(s)); 213 1.1 cjs (void)write(2, "\n", 1); 214 1.1 cjs } 215 1.1 cjs return; 216 1.1 cjs } 217 1.1 cjs 218 1.1 cjs lower_left(); 219 1.1 cjs clear_eol(); 220 1.1 cjs so_enter(); 221 1.1 cjs if (s != NULL) { 222 1.1 cjs putstr(s); 223 1.1 cjs putstr(" "); 224 1.1 cjs } 225 1.1 cjs putstr(return_to_continue); 226 1.1 cjs so_exit(); 227 1.1 cjs 228 1.1 cjs if ((ch = getchr()) != '\n') { 229 1.1 cjs if (ch == 'q') 230 1.1 cjs quit(); 231 1.1 cjs cmdstack = ch; 232 1.1 cjs } 233 1.1 cjs lower_left(); 234 1.1 cjs 235 1.1 cjs if ((s != NULL ? strlen(s) : 0) + sizeof(return_to_continue) + 236 1.1 cjs so_width + se_width + 1 > sc_width) 237 1.1 cjs /* 238 1.1 cjs * Printing the message has probably scrolled the screen. 239 1.1 cjs * {{ Unless the terminal doesn't have auto margins, 240 1.1 cjs * in which case we just hammered on the right margin. }} 241 1.1 cjs */ 242 1.1 cjs repaint(); 243 1.1 cjs flush(); 244 1.1 cjs } 245 1.1 cjs 246 1.1 cjs static char intr_to_abort[] = "... (interrupt to abort)"; 247 1.1 cjs 248 1.4 christos void 249 1.1 cjs ierror(s) 250 1.1 cjs char *s; 251 1.1 cjs { 252 1.1 cjs lower_left(); 253 1.1 cjs clear_eol(); 254 1.1 cjs so_enter(); 255 1.1 cjs putstr(s); 256 1.1 cjs putstr(intr_to_abort); 257 1.1 cjs so_exit(); 258 1.1 cjs flush(); 259 1.1 cjs } 260