xref: /minix/external/bsd/nvi/dist/ex/ex_print.c (revision ebfedea0)
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