xref: /minix/external/bsd/nvi/dist/ex/ex_print.c (revision 0a6a1f1d)
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
ex_list(SCR * sp,EXCMD * cmdp)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
ex_number(SCR * sp,EXCMD * cmdp)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
ex_pr(SCR * sp,EXCMD * cmdp)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
ex_print(SCR * sp,EXCMD * cmdp,MARK * fp,MARK * tp,u_int32_t flags)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
ex_ldisplay(SCR * sp,const CHAR_T * p,size_t len,size_t col,u_int flags)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
ex_scprint(SCR * sp,MARK * fp,MARK * tp)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
ex_prchars(SCR * sp,const CHAR_T * p,size_t * colp,size_t len,u_int flags,int repeatc)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__
ex_printf(SCR * sp,const char * fmt,...)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
ex_puts(SCR * sp,const char * str)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
ex_fflush(SCR * sp)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