xref: /freebsd/contrib/nvi/ex/ex_print.c (revision 110d525ec6188f3c9dc4f54c4bc1cced2f7184cd)
1b8ba871bSPeter Wemm /*-
2b8ba871bSPeter Wemm  * Copyright (c) 1992, 1993, 1994
3b8ba871bSPeter Wemm  *	The Regents of the University of California.  All rights reserved.
4b8ba871bSPeter Wemm  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5b8ba871bSPeter Wemm  *	Keith Bostic.  All rights reserved.
6b8ba871bSPeter Wemm  *
7b8ba871bSPeter Wemm  * See the LICENSE file for redistribution information.
8b8ba871bSPeter Wemm  */
9b8ba871bSPeter Wemm 
10b8ba871bSPeter Wemm #include "config.h"
11b8ba871bSPeter Wemm 
12b8ba871bSPeter Wemm #include <sys/types.h>
13b8ba871bSPeter Wemm #include <sys/queue.h>
14f0957ccaSPeter Wemm #include <sys/time.h>
15b8ba871bSPeter Wemm 
16b8ba871bSPeter Wemm #include <bitstring.h>
17b8ba871bSPeter Wemm #include <ctype.h>
18b8ba871bSPeter Wemm #include <limits.h>
19f0957ccaSPeter Wemm #include <stdarg.h>
20b8ba871bSPeter Wemm #include <stdio.h>
21b8ba871bSPeter Wemm #include <string.h>
22b8ba871bSPeter Wemm 
23b8ba871bSPeter Wemm #include "../common/common.h"
24b8ba871bSPeter Wemm 
25c271fa92SBaptiste Daroussin static int ex_prchars(SCR *,
26c271fa92SBaptiste Daroussin     const CHAR_T *, size_t *, size_t, u_int, int);
27b8ba871bSPeter Wemm 
28b8ba871bSPeter Wemm /*
29b8ba871bSPeter Wemm  * ex_list -- :[line [,line]] l[ist] [count] [flags]
30b8ba871bSPeter Wemm  *
31b8ba871bSPeter Wemm  *	Display the addressed lines such that the output is unambiguous.
32b8ba871bSPeter Wemm  *
33c271fa92SBaptiste Daroussin  * PUBLIC: int ex_list(SCR *, EXCMD *);
34b8ba871bSPeter Wemm  */
35b8ba871bSPeter Wemm int
ex_list(SCR * sp,EXCMD * cmdp)36f0957ccaSPeter Wemm ex_list(SCR *sp, EXCMD *cmdp)
37b8ba871bSPeter Wemm {
38b8ba871bSPeter Wemm 	if (ex_print(sp, cmdp,
39b8ba871bSPeter Wemm 	    &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_LIST))
40b8ba871bSPeter Wemm 		return (1);
41b8ba871bSPeter Wemm 	sp->lno = cmdp->addr2.lno;
42b8ba871bSPeter Wemm 	sp->cno = cmdp->addr2.cno;
43b8ba871bSPeter Wemm 	return (0);
44b8ba871bSPeter Wemm }
45b8ba871bSPeter Wemm 
46b8ba871bSPeter Wemm /*
47b8ba871bSPeter Wemm  * ex_number -- :[line [,line]] nu[mber] [count] [flags]
48b8ba871bSPeter Wemm  *
49b8ba871bSPeter Wemm  *	Display the addressed lines with a leading line number.
50b8ba871bSPeter Wemm  *
51c271fa92SBaptiste Daroussin  * PUBLIC: int ex_number(SCR *, EXCMD *);
52b8ba871bSPeter Wemm  */
53b8ba871bSPeter Wemm int
ex_number(SCR * sp,EXCMD * cmdp)54f0957ccaSPeter Wemm ex_number(SCR *sp, EXCMD *cmdp)
55b8ba871bSPeter Wemm {
56b8ba871bSPeter Wemm 	if (ex_print(sp, cmdp,
57b8ba871bSPeter Wemm 	    &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_HASH))
58b8ba871bSPeter Wemm 		return (1);
59b8ba871bSPeter Wemm 	sp->lno = cmdp->addr2.lno;
60b8ba871bSPeter Wemm 	sp->cno = cmdp->addr2.cno;
61b8ba871bSPeter Wemm 	return (0);
62b8ba871bSPeter Wemm }
63b8ba871bSPeter Wemm 
64b8ba871bSPeter Wemm /*
65b8ba871bSPeter Wemm  * ex_pr -- :[line [,line]] p[rint] [count] [flags]
66b8ba871bSPeter Wemm  *
67b8ba871bSPeter Wemm  *	Display the addressed lines.
68b8ba871bSPeter Wemm  *
69c271fa92SBaptiste Daroussin  * PUBLIC: int ex_pr(SCR *, EXCMD *);
70b8ba871bSPeter Wemm  */
71b8ba871bSPeter Wemm int
ex_pr(SCR * sp,EXCMD * cmdp)72f0957ccaSPeter Wemm ex_pr(SCR *sp, EXCMD *cmdp)
73b8ba871bSPeter Wemm {
74b8ba871bSPeter Wemm 	if (ex_print(sp, cmdp, &cmdp->addr1, &cmdp->addr2, cmdp->iflags))
75b8ba871bSPeter Wemm 		return (1);
76b8ba871bSPeter Wemm 	sp->lno = cmdp->addr2.lno;
77b8ba871bSPeter Wemm 	sp->cno = cmdp->addr2.cno;
78b8ba871bSPeter Wemm 	return (0);
79b8ba871bSPeter Wemm }
80b8ba871bSPeter Wemm 
81b8ba871bSPeter Wemm /*
82b8ba871bSPeter Wemm  * ex_print --
83b8ba871bSPeter Wemm  *	Print the selected lines.
84b8ba871bSPeter Wemm  *
85c271fa92SBaptiste Daroussin  * PUBLIC: int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t);
86b8ba871bSPeter Wemm  */
87b8ba871bSPeter Wemm int
ex_print(SCR * sp,EXCMD * cmdp,MARK * fp,MARK * tp,u_int32_t flags)88f0957ccaSPeter Wemm ex_print(SCR *sp, EXCMD *cmdp, MARK *fp, MARK *tp, u_int32_t flags)
89b8ba871bSPeter Wemm {
90b8ba871bSPeter Wemm 	GS *gp;
91b8ba871bSPeter Wemm 	recno_t from, to;
92b8ba871bSPeter Wemm 	size_t col, len;
93f0957ccaSPeter Wemm 	CHAR_T *p;
94f0957ccaSPeter Wemm 	CHAR_T buf[10];
95b8ba871bSPeter Wemm 
96b8ba871bSPeter Wemm 	NEEDFILE(sp, cmdp);
97b8ba871bSPeter Wemm 
98b8ba871bSPeter Wemm 	gp = sp->gp;
99b8ba871bSPeter Wemm 	for (from = fp->lno, to = tp->lno; from <= to; ++from) {
100b8ba871bSPeter Wemm 		col = 0;
101b8ba871bSPeter Wemm 
102b8ba871bSPeter Wemm 		/*
103b8ba871bSPeter Wemm 		 * Display the line number.  The %6 format is specified
104b8ba871bSPeter Wemm 		 * by POSIX 1003.2, and is almost certainly large enough.
105b8ba871bSPeter Wemm 		 * Check, though, just in case.
106b8ba871bSPeter Wemm 		 */
107b8ba871bSPeter Wemm 		if (LF_ISSET(E_C_HASH)) {
108b8ba871bSPeter Wemm 			if (from <= 999999) {
109f0957ccaSPeter Wemm 				SPRINTF(buf, SIZE(buf), L("%6u  "), from);
110b8ba871bSPeter Wemm 				p = buf;
111b8ba871bSPeter Wemm 			} else
112f0957ccaSPeter Wemm 				p = L("TOOBIG  ");
113b8ba871bSPeter Wemm 			if (ex_prchars(sp, p, &col, 8, 0, 0))
114b8ba871bSPeter Wemm 				return (1);
115b8ba871bSPeter Wemm 		}
116b8ba871bSPeter Wemm 
117b8ba871bSPeter Wemm 		/*
118b8ba871bSPeter Wemm 		 * Display the line.  The format for E_C_PRINT isn't very good,
119b8ba871bSPeter Wemm 		 * especially in handling end-of-line tabs, but they're almost
120b8ba871bSPeter Wemm 		 * backward compatible.
121b8ba871bSPeter Wemm 		 */
122b8ba871bSPeter Wemm 		if (db_get(sp, from, DBG_FATAL, &p, &len))
123b8ba871bSPeter Wemm 			return (1);
124b8ba871bSPeter Wemm 
125b8ba871bSPeter Wemm 		if (len == 0 && !LF_ISSET(E_C_LIST))
126b8ba871bSPeter Wemm 			(void)ex_puts(sp, "\n");
127b8ba871bSPeter Wemm 		else if (ex_ldisplay(sp, p, len, col, flags))
128b8ba871bSPeter Wemm 			return (1);
129b8ba871bSPeter Wemm 
130b8ba871bSPeter Wemm 		if (INTERRUPTED(sp))
131b8ba871bSPeter Wemm 			break;
132b8ba871bSPeter Wemm 	}
133b8ba871bSPeter Wemm 	return (0);
134b8ba871bSPeter Wemm }
135b8ba871bSPeter Wemm 
136b8ba871bSPeter Wemm /*
137b8ba871bSPeter Wemm  * ex_ldisplay --
138b8ba871bSPeter Wemm  *	Display a line without any preceding number.
139b8ba871bSPeter Wemm  *
140c271fa92SBaptiste Daroussin  * PUBLIC: int ex_ldisplay(SCR *, const CHAR_T *, size_t, size_t, u_int);
141b8ba871bSPeter Wemm  */
142b8ba871bSPeter Wemm int
ex_ldisplay(SCR * sp,const CHAR_T * p,size_t len,size_t col,u_int flags)143f0957ccaSPeter Wemm ex_ldisplay(SCR *sp, const CHAR_T *p, size_t len, size_t col, u_int flags)
144b8ba871bSPeter Wemm {
145b8ba871bSPeter Wemm 	if (len > 0 && ex_prchars(sp, p, &col, len, LF_ISSET(E_C_LIST), 0))
146b8ba871bSPeter Wemm 		return (1);
147b8ba871bSPeter Wemm 	if (!INTERRUPTED(sp) && LF_ISSET(E_C_LIST)) {
148f0957ccaSPeter Wemm 		p = L("$");
149b8ba871bSPeter Wemm 		if (ex_prchars(sp, p, &col, 1, LF_ISSET(E_C_LIST), 0))
150b8ba871bSPeter Wemm 			return (1);
151b8ba871bSPeter Wemm 	}
152b8ba871bSPeter Wemm 	if (!INTERRUPTED(sp))
153b8ba871bSPeter Wemm 		(void)ex_puts(sp, "\n");
154b8ba871bSPeter Wemm 	return (0);
155b8ba871bSPeter Wemm }
156b8ba871bSPeter Wemm 
157b8ba871bSPeter Wemm /*
158b8ba871bSPeter Wemm  * ex_scprint --
159b8ba871bSPeter Wemm  *	Display a line for the substitute with confirmation routine.
160b8ba871bSPeter Wemm  *
161c271fa92SBaptiste Daroussin  * PUBLIC: int ex_scprint(SCR *, MARK *, MARK *);
162b8ba871bSPeter Wemm  */
163b8ba871bSPeter Wemm int
ex_scprint(SCR * sp,MARK * fp,MARK * tp)164f0957ccaSPeter Wemm ex_scprint(SCR *sp, MARK *fp, MARK *tp)
165b8ba871bSPeter Wemm {
166f0957ccaSPeter Wemm 	CHAR_T *p;
167b8ba871bSPeter Wemm 	size_t col, len;
168b8ba871bSPeter Wemm 
169b8ba871bSPeter Wemm 	col = 0;
170b8ba871bSPeter Wemm 	if (O_ISSET(sp, O_NUMBER)) {
171f0957ccaSPeter Wemm 		p = L("        ");
172b8ba871bSPeter Wemm 		if (ex_prchars(sp, p, &col, 8, 0, 0))
173b8ba871bSPeter Wemm 			return (1);
174b8ba871bSPeter Wemm 	}
175b8ba871bSPeter Wemm 
176f0957ccaSPeter Wemm 	if (db_get(sp, fp->lno, DBG_FATAL, &p, &len))
177b8ba871bSPeter Wemm 		return (1);
178b8ba871bSPeter Wemm 
179b8ba871bSPeter Wemm 	if (ex_prchars(sp, p, &col, fp->cno, 0, ' '))
180b8ba871bSPeter Wemm 		return (1);
181b8ba871bSPeter Wemm 	p += fp->cno;
182b8ba871bSPeter Wemm 	if (ex_prchars(sp,
183b8ba871bSPeter Wemm 	    p, &col, tp->cno == fp->cno ? 1 : tp->cno - fp->cno, 0, '^'))
184b8ba871bSPeter Wemm 		return (1);
185b8ba871bSPeter Wemm 	if (INTERRUPTED(sp))
186b8ba871bSPeter Wemm 		return (1);
187f0957ccaSPeter Wemm 	p = L("[ynq]");		/* XXX: should be msg_cat. */
188b8ba871bSPeter Wemm 	if (ex_prchars(sp, p, &col, 5, 0, 0))
189b8ba871bSPeter Wemm 		return (1);
190b8ba871bSPeter Wemm 	(void)ex_fflush(sp);
191b8ba871bSPeter Wemm 	return (0);
192b8ba871bSPeter Wemm }
193b8ba871bSPeter Wemm 
194b8ba871bSPeter Wemm /*
195b8ba871bSPeter Wemm  * ex_prchars --
196b8ba871bSPeter Wemm  *	Local routine to dump characters to the screen.
197b8ba871bSPeter Wemm  */
198b8ba871bSPeter Wemm static int
ex_prchars(SCR * sp,const CHAR_T * p,size_t * colp,size_t len,u_int flags,int repeatc)199f0957ccaSPeter Wemm ex_prchars(SCR *sp, const CHAR_T *p, size_t *colp, size_t len,
200f0957ccaSPeter Wemm 	    u_int flags, int repeatc)
201b8ba871bSPeter Wemm {
202f0957ccaSPeter Wemm 	CHAR_T ch;
203f0957ccaSPeter Wemm 	char *kp;
204b8ba871bSPeter Wemm 	GS *gp;
205b8ba871bSPeter Wemm 	size_t col, tlen, ts;
206b8ba871bSPeter Wemm 
207b8ba871bSPeter Wemm 	if (O_ISSET(sp, O_LIST))
208b8ba871bSPeter Wemm 		LF_SET(E_C_LIST);
209b8ba871bSPeter Wemm 	gp = sp->gp;
210b8ba871bSPeter Wemm 	ts = O_VAL(sp, O_TABSTOP);
211b8ba871bSPeter Wemm 	for (col = *colp; len--;)
212*110d525eSBaptiste Daroussin 		if ((ch = *p++) == '\t' && !LF_ISSET(E_C_LIST))
213b8ba871bSPeter Wemm 			for (tlen = ts - col % ts;
214b8ba871bSPeter Wemm 			    col < sp->cols && tlen--; ++col) {
215b8ba871bSPeter Wemm 				(void)ex_printf(sp,
216b8ba871bSPeter Wemm 				    "%c", repeatc ? repeatc : ' ');
217b8ba871bSPeter Wemm 				if (INTERRUPTED(sp))
218b8ba871bSPeter Wemm 					goto intr;
219b8ba871bSPeter Wemm 			}
220b8ba871bSPeter Wemm 		else {
221b8ba871bSPeter Wemm 			kp = KEY_NAME(sp, ch);
2229d9df6f4SPeter Wemm 			tlen = KEY_COL(sp, ch);
2239d9df6f4SPeter Wemm 
2249d9df6f4SPeter Wemm 			/*
2259d9df6f4SPeter Wemm 			 * Start a new line if the last character does not fit
2269d9df6f4SPeter Wemm 			 * into the current line.  The implicit new lines are
2279d9df6f4SPeter Wemm 			 * not interruptible.
2289d9df6f4SPeter Wemm 			 */
2299d9df6f4SPeter Wemm 			if (col + tlen > sp->cols) {
230b8ba871bSPeter Wemm 				col = 0;
231b8ba871bSPeter Wemm 				(void)ex_puts(sp, "\n");
232b8ba871bSPeter Wemm 			}
2339d9df6f4SPeter Wemm 
2349d9df6f4SPeter Wemm 			col += tlen;
2359d9df6f4SPeter Wemm 			if (!repeatc) {
2369d9df6f4SPeter Wemm 				(void)ex_puts(sp, kp);
237b8ba871bSPeter Wemm 				if (INTERRUPTED(sp))
238b8ba871bSPeter Wemm 					goto intr;
2399d9df6f4SPeter Wemm 			} else while (tlen--) {
2409d9df6f4SPeter Wemm 				(void)ex_printf(sp, "%c", repeatc);
2419d9df6f4SPeter Wemm 				if (INTERRUPTED(sp))
2429d9df6f4SPeter Wemm 					goto intr;
2439d9df6f4SPeter Wemm 			}
2449d9df6f4SPeter Wemm 			if (col == sp->cols) {
2459d9df6f4SPeter Wemm 				col = 0;
2469d9df6f4SPeter Wemm 				(void)ex_puts(sp, "\n");
247b8ba871bSPeter Wemm 			}
248b8ba871bSPeter Wemm 		}
249b8ba871bSPeter Wemm intr:	*colp = col;
250b8ba871bSPeter Wemm 	return (0);
251b8ba871bSPeter Wemm }
252b8ba871bSPeter Wemm 
253b8ba871bSPeter Wemm /*
254b8ba871bSPeter Wemm  * ex_printf --
255b8ba871bSPeter Wemm  *	Ex's version of printf.
256b8ba871bSPeter Wemm  *
257c271fa92SBaptiste Daroussin  * PUBLIC: int ex_printf(SCR *, const char *, ...);
258b8ba871bSPeter Wemm  */
259b8ba871bSPeter Wemm int
ex_printf(SCR * sp,const char * fmt,...)260f0957ccaSPeter Wemm ex_printf(
261f0957ccaSPeter Wemm 	SCR *sp,
262f0957ccaSPeter Wemm 	const char *fmt,
263f0957ccaSPeter Wemm 	...)
264b8ba871bSPeter Wemm {
265b8ba871bSPeter Wemm 	EX_PRIVATE *exp;
266b8ba871bSPeter Wemm 	va_list ap;
267b8ba871bSPeter Wemm 	size_t n;
268b8ba871bSPeter Wemm 
269b8ba871bSPeter Wemm 	exp = EXP(sp);
270b8ba871bSPeter Wemm 
271b8ba871bSPeter Wemm 	va_start(ap, fmt);
272b8ba871bSPeter Wemm 	exp->obp_len += n = vsnprintf(exp->obp + exp->obp_len,
273b8ba871bSPeter Wemm 	    sizeof(exp->obp) - exp->obp_len, fmt, ap);
274b8ba871bSPeter Wemm 	va_end(ap);
275b8ba871bSPeter Wemm 
276b8ba871bSPeter Wemm 	/* Flush when reach a <newline> or half the buffer. */
277b8ba871bSPeter Wemm 	if (exp->obp[exp->obp_len - 1] == '\n' ||
278b8ba871bSPeter Wemm 	    exp->obp_len > sizeof(exp->obp) / 2)
279b8ba871bSPeter Wemm 		(void)ex_fflush(sp);
280b8ba871bSPeter Wemm 	return (n);
281b8ba871bSPeter Wemm }
282b8ba871bSPeter Wemm 
283b8ba871bSPeter Wemm /*
284b8ba871bSPeter Wemm  * ex_puts --
285b8ba871bSPeter Wemm  *	Ex's version of puts.
286b8ba871bSPeter Wemm  *
287c271fa92SBaptiste Daroussin  * PUBLIC: int ex_puts(SCR *, const char *);
288b8ba871bSPeter Wemm  */
289b8ba871bSPeter Wemm int
ex_puts(SCR * sp,const char * str)290f0957ccaSPeter Wemm ex_puts(SCR *sp, const char *str)
291b8ba871bSPeter Wemm {
292b8ba871bSPeter Wemm 	EX_PRIVATE *exp;
293b8ba871bSPeter Wemm 	int doflush, n;
294b8ba871bSPeter Wemm 
295b8ba871bSPeter Wemm 	exp = EXP(sp);
296b8ba871bSPeter Wemm 
297b8ba871bSPeter Wemm 	/* Flush when reach a <newline> or the end of the buffer. */
298b8ba871bSPeter Wemm 	for (doflush = n = 0; *str != '\0'; ++n) {
299b8ba871bSPeter Wemm 		if (exp->obp_len > sizeof(exp->obp))
300b8ba871bSPeter Wemm 			(void)ex_fflush(sp);
301b8ba871bSPeter Wemm 		if ((exp->obp[exp->obp_len++] = *str++) == '\n')
302b8ba871bSPeter Wemm 			doflush = 1;
303b8ba871bSPeter Wemm 	}
304b8ba871bSPeter Wemm 	if (doflush)
305b8ba871bSPeter Wemm 		(void)ex_fflush(sp);
306b8ba871bSPeter Wemm 	return (n);
307b8ba871bSPeter Wemm }
308b8ba871bSPeter Wemm 
309b8ba871bSPeter Wemm /*
310b8ba871bSPeter Wemm  * ex_fflush --
311b8ba871bSPeter Wemm  *	Ex's version of fflush.
312b8ba871bSPeter Wemm  *
313c271fa92SBaptiste Daroussin  * PUBLIC: int ex_fflush(SCR *sp);
314b8ba871bSPeter Wemm  */
315b8ba871bSPeter Wemm int
ex_fflush(SCR * sp)316f0957ccaSPeter Wemm ex_fflush(SCR *sp)
317b8ba871bSPeter Wemm {
318b8ba871bSPeter Wemm 	EX_PRIVATE *exp;
319b8ba871bSPeter Wemm 
320b8ba871bSPeter Wemm 	exp = EXP(sp);
321b8ba871bSPeter Wemm 
322b8ba871bSPeter Wemm 	if (exp->obp_len != 0) {
323b8ba871bSPeter Wemm 		sp->gp->scr_msg(sp, M_NONE, exp->obp, exp->obp_len);
324b8ba871bSPeter Wemm 		exp->obp_len = 0;
325b8ba871bSPeter Wemm 	}
326b8ba871bSPeter Wemm 	return (0);
327b8ba871bSPeter Wemm }
328