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