1 /* $OpenBSD: ex_print.c,v 1.6 2002/02/19 19:39:39 millert Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1992, 1993, 1994, 1995, 1996 7 * Keith Bostic. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12 #include "config.h" 13 14 #ifndef lint 15 static const char sccsid[] = "@(#)ex_print.c 10.18 (Berkeley) 5/12/96"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/queue.h> 20 21 #include <bitstring.h> 22 #include <ctype.h> 23 #include <limits.h> 24 #include <stdarg.h> 25 #include <stdio.h> 26 #include <string.h> 27 28 #include "../common/common.h" 29 30 static int ex_prchars(SCR *, const char *, size_t *, size_t, u_int, int); 31 32 /* 33 * ex_list -- :[line [,line]] l[ist] [count] [flags] 34 * 35 * Display the addressed lines such that the output is unambiguous. 36 * 37 * PUBLIC: int ex_list(SCR *, EXCMD *); 38 */ 39 int 40 ex_list(sp, cmdp) 41 SCR *sp; 42 EXCMD *cmdp; 43 { 44 if (ex_print(sp, cmdp, 45 &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_LIST)) 46 return (1); 47 sp->lno = cmdp->addr2.lno; 48 sp->cno = cmdp->addr2.cno; 49 return (0); 50 } 51 52 /* 53 * ex_number -- :[line [,line]] nu[mber] [count] [flags] 54 * 55 * Display the addressed lines with a leading line number. 56 * 57 * PUBLIC: int ex_number(SCR *, EXCMD *); 58 */ 59 int 60 ex_number(sp, cmdp) 61 SCR *sp; 62 EXCMD *cmdp; 63 { 64 if (ex_print(sp, cmdp, 65 &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_HASH)) 66 return (1); 67 sp->lno = cmdp->addr2.lno; 68 sp->cno = cmdp->addr2.cno; 69 return (0); 70 } 71 72 /* 73 * ex_pr -- :[line [,line]] p[rint] [count] [flags] 74 * 75 * Display the addressed lines. 76 * 77 * PUBLIC: int ex_pr(SCR *, EXCMD *); 78 */ 79 int 80 ex_pr(sp, cmdp) 81 SCR *sp; 82 EXCMD *cmdp; 83 { 84 if (ex_print(sp, cmdp, &cmdp->addr1, &cmdp->addr2, cmdp->iflags)) 85 return (1); 86 sp->lno = cmdp->addr2.lno; 87 sp->cno = cmdp->addr2.cno; 88 return (0); 89 } 90 91 /* 92 * ex_print -- 93 * Print the selected lines. 94 * 95 * PUBLIC: int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t); 96 */ 97 int 98 ex_print(sp, cmdp, fp, tp, flags) 99 SCR *sp; 100 EXCMD *cmdp; 101 MARK *fp, *tp; 102 u_int32_t flags; 103 { 104 GS *gp; 105 recno_t from, to; 106 size_t col, len; 107 char *p, buf[10]; 108 109 NEEDFILE(sp, cmdp); 110 111 gp = sp->gp; 112 for (from = fp->lno, to = tp->lno; from <= to; ++from) { 113 col = 0; 114 115 /* 116 * Display the line number. The %6 format is specified 117 * by POSIX 1003.2, and is almost certainly large enough. 118 * Check, though, just in case. 119 */ 120 if (LF_ISSET(E_C_HASH)) { 121 if (from <= 999999) { 122 snprintf(buf, sizeof(buf), "%6ld ", from); 123 p = buf; 124 } else 125 p = "TOOBIG "; 126 if (ex_prchars(sp, p, &col, 8, 0, 0)) 127 return (1); 128 } 129 130 /* 131 * Display the line. The format for E_C_PRINT isn't very good, 132 * especially in handling end-of-line tabs, but they're almost 133 * backward compatible. 134 */ 135 if (db_get(sp, from, DBG_FATAL, &p, &len)) 136 return (1); 137 138 if (len == 0 && !LF_ISSET(E_C_LIST)) 139 (void)ex_puts(sp, "\n"); 140 else if (ex_ldisplay(sp, p, len, col, flags)) 141 return (1); 142 143 if (INTERRUPTED(sp)) 144 break; 145 } 146 return (0); 147 } 148 149 /* 150 * ex_ldisplay -- 151 * Display a line without any preceding number. 152 * 153 * PUBLIC: int ex_ldisplay(SCR *, const char *, size_t, size_t, u_int); 154 */ 155 int 156 ex_ldisplay(sp, p, len, col, flags) 157 SCR *sp; 158 const char *p; 159 size_t len, col; 160 u_int flags; 161 { 162 if (len > 0 && ex_prchars(sp, p, &col, len, LF_ISSET(E_C_LIST), 0)) 163 return (1); 164 if (!INTERRUPTED(sp) && LF_ISSET(E_C_LIST)) { 165 p = "$"; 166 if (ex_prchars(sp, p, &col, 1, LF_ISSET(E_C_LIST), 0)) 167 return (1); 168 } 169 if (!INTERRUPTED(sp)) 170 (void)ex_puts(sp, "\n"); 171 return (0); 172 } 173 174 /* 175 * ex_scprint -- 176 * Display a line for the substitute with confirmation routine. 177 * 178 * PUBLIC: int ex_scprint(SCR *, MARK *, MARK *); 179 */ 180 int 181 ex_scprint(sp, fp, tp) 182 SCR *sp; 183 MARK *fp, *tp; 184 { 185 const char *p; 186 size_t col, len; 187 188 col = 0; 189 if (O_ISSET(sp, O_NUMBER)) { 190 p = " "; 191 if (ex_prchars(sp, p, &col, 8, 0, 0)) 192 return (1); 193 } 194 195 if (db_get(sp, fp->lno, DBG_FATAL, (char **)&p, &len)) 196 return (1); 197 198 if (ex_prchars(sp, p, &col, fp->cno, 0, ' ')) 199 return (1); 200 p += fp->cno; 201 if (ex_prchars(sp, 202 p, &col, tp->cno == fp->cno ? 1 : tp->cno - fp->cno, 0, '^')) 203 return (1); 204 if (INTERRUPTED(sp)) 205 return (1); 206 p = "[ynq]"; /* XXX: should be msg_cat. */ 207 if (ex_prchars(sp, p, &col, 5, 0, 0)) 208 return (1); 209 (void)ex_fflush(sp); 210 return (0); 211 } 212 213 /* 214 * ex_prchars -- 215 * Local routine to dump characters to the screen. 216 */ 217 static int 218 ex_prchars(sp, p, colp, len, flags, repeatc) 219 SCR *sp; 220 const char *p; 221 size_t *colp, len; 222 u_int flags; 223 int repeatc; 224 { 225 CHAR_T ch, *kp; 226 GS *gp; 227 size_t col, tlen, ts; 228 229 if (O_ISSET(sp, O_LIST)) 230 LF_SET(E_C_LIST); 231 gp = sp->gp; 232 ts = O_VAL(sp, O_TABSTOP); 233 for (col = *colp; len--;) 234 if ((ch = *p++) == '\t' && !LF_ISSET(E_C_LIST)) 235 for (tlen = ts - col % ts; 236 col < sp->cols && tlen--; ++col) { 237 (void)ex_printf(sp, 238 "%c", repeatc ? repeatc : ' '); 239 if (INTERRUPTED(sp)) 240 goto intr; 241 } 242 else { 243 kp = KEY_NAME(sp, ch); 244 tlen = KEY_LEN(sp, ch); 245 if (!repeatc && col + tlen < sp->cols) { 246 (void)ex_puts(sp, kp); 247 col += tlen; 248 } else 249 for (; tlen--; ++kp, ++col) { 250 if (col == sp->cols) { 251 col = 0; 252 (void)ex_puts(sp, "\n"); 253 } 254 (void)ex_printf(sp, 255 "%c", repeatc ? repeatc : *kp); 256 if (INTERRUPTED(sp)) 257 goto intr; 258 } 259 } 260 intr: *colp = col; 261 return (0); 262 } 263 264 /* 265 * ex_printf -- 266 * Ex's version of printf. 267 * 268 * PUBLIC: int ex_printf(SCR *, const char *, ...); 269 */ 270 int 271 ex_printf(SCR *sp, const char *fmt, ...) 272 { 273 EX_PRIVATE *exp; 274 va_list ap; 275 size_t n; 276 277 exp = EXP(sp); 278 279 va_start(ap, fmt); 280 n = vsnprintf(exp->obp + exp->obp_len, 281 sizeof(exp->obp) - exp->obp_len, fmt, ap); 282 va_end(ap); 283 if (n >= sizeof(exp->obp) - exp->obp_len) 284 n = sizeof(exp->obp) - exp->obp_len - 1; 285 exp->obp_len += n; 286 287 /* Flush when reach a <newline> or half the buffer. */ 288 if (exp->obp[exp->obp_len - 1] == '\n' || 289 exp->obp_len > sizeof(exp->obp) / 2) 290 (void)ex_fflush(sp); 291 return (n); 292 } 293 294 /* 295 * ex_puts -- 296 * Ex's version of puts. 297 * 298 * PUBLIC: int ex_puts(SCR *, const char *); 299 */ 300 int 301 ex_puts(sp, str) 302 SCR *sp; 303 const char *str; 304 { 305 EX_PRIVATE *exp; 306 int doflush, n; 307 308 exp = EXP(sp); 309 310 /* Flush when reach a <newline> or the end of the buffer. */ 311 for (doflush = n = 0; *str != '\0'; ++n) { 312 if (exp->obp_len > sizeof(exp->obp)) 313 (void)ex_fflush(sp); 314 if ((exp->obp[exp->obp_len++] = *str++) == '\n') 315 doflush = 1; 316 } 317 if (doflush) 318 (void)ex_fflush(sp); 319 return (n); 320 } 321 322 /* 323 * ex_fflush -- 324 * Ex's version of fflush. 325 * 326 * PUBLIC: int ex_fflush(SCR *sp); 327 */ 328 int 329 ex_fflush(sp) 330 SCR *sp; 331 { 332 EX_PRIVATE *exp; 333 334 exp = EXP(sp); 335 336 if (exp->obp_len != 0) { 337 sp->gp->scr_msg(sp, M_NONE, exp->obp, exp->obp_len); 338 exp->obp_len = 0; 339 } 340 return (0); 341 } 342