Home | History | Annotate | Line # | Download | only in ex
      1 /*	$NetBSD: ex_print.c,v 1.6 2017/12/01 18:39:49 rin 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.6 2017/12/01 18:39:49 rin 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("%6u  "), 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 *, ...)) __printflike(2, 3);
    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