xref: /dragonfly/contrib/nvi2/ex/ex_print.c (revision 07bc39c2f4bbca56f12568e06d89da17f2eeb965)
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
ex_list(SCR * sp,EXCMD * cmdp)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
ex_number(SCR * sp,EXCMD * cmdp)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
ex_pr(SCR * sp,EXCMD * cmdp)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
ex_print(SCR * sp,EXCMD * cmdp,MARK * fp,MARK * tp,u_int32_t flags)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
ex_ldisplay(SCR * sp,const CHAR_T * p,size_t len,size_t col,u_int flags)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
ex_scprint(SCR * sp,MARK * fp,MARK * tp)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
ex_prchars(SCR * sp,const CHAR_T * p,size_t * colp,size_t len,u_int flags,int repeatc)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
ex_printf(SCR * sp,const char * fmt,...)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
ex_puts(SCR * sp,const char * str)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
ex_fflush(SCR * sp)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 }
328