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