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