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[] = "$Id: ex_print.c,v 10.25 2011/12/12 22:12:20 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 29 static 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 */ 39 int 40 ex_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 */ 57 int 58 ex_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 */ 75 int 76 ex_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 */ 91 int 92 ex_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 */ 146 int 147 ex_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 */ 167 int 168 ex_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 */ 202 static int 203 ex_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++) == '\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_LEN(sp, ch); 227 if (!repeatc && col + tlen < sp->cols) { 228 (void)ex_puts(sp, kp); 229 col += tlen; 230 } else 231 for (; tlen--; ++kp, ++col) { 232 if (col == sp->cols) { 233 col = 0; 234 (void)ex_puts(sp, "\n"); 235 } 236 (void)ex_printf(sp, 237 "%c", repeatc ? repeatc : *kp); 238 if (INTERRUPTED(sp)) 239 goto intr; 240 } 241 } 242 intr: *colp = col; 243 return (0); 244 } 245 246 /* 247 * ex_printf -- 248 * Ex's version of printf. 249 * 250 * PUBLIC: int ex_printf __P((SCR *, const char *, ...)); 251 */ 252 int 253 ex_printf( 254 SCR *sp, 255 const char *fmt, 256 ...) 257 { 258 EX_PRIVATE *exp; 259 va_list ap; 260 size_t n; 261 262 exp = EXP(sp); 263 264 va_start(ap, fmt); 265 exp->obp_len += n = vsnprintf(exp->obp + exp->obp_len, 266 sizeof(exp->obp) - exp->obp_len, fmt, ap); 267 va_end(ap); 268 269 /* Flush when reach a <newline> or half the buffer. */ 270 if (exp->obp[exp->obp_len - 1] == '\n' || 271 exp->obp_len > sizeof(exp->obp) / 2) 272 (void)ex_fflush(sp); 273 return (n); 274 } 275 276 /* 277 * ex_puts -- 278 * Ex's version of puts. 279 * 280 * PUBLIC: int ex_puts __P((SCR *, const char *)); 281 */ 282 int 283 ex_puts(SCR *sp, const char *str) 284 { 285 EX_PRIVATE *exp; 286 int doflush, n; 287 288 exp = EXP(sp); 289 290 /* Flush when reach a <newline> or the end of the buffer. */ 291 for (doflush = n = 0; *str != '\0'; ++n) { 292 if (exp->obp_len > sizeof(exp->obp)) 293 (void)ex_fflush(sp); 294 if ((exp->obp[exp->obp_len++] = *str++) == '\n') 295 doflush = 1; 296 } 297 if (doflush) 298 (void)ex_fflush(sp); 299 return (n); 300 } 301 302 /* 303 * ex_fflush -- 304 * Ex's version of fflush. 305 * 306 * PUBLIC: int ex_fflush __P((SCR *sp)); 307 */ 308 int 309 ex_fflush(SCR *sp) 310 { 311 EX_PRIVATE *exp; 312 313 exp = EXP(sp); 314 315 if (exp->obp_len != 0) { 316 sp->gp->scr_msg(sp, M_NONE, exp->obp, exp->obp_len); 317 exp->obp_len = 0; 318 } 319 return (0); 320 } 321