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