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