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