man pages get built in the build- directories
[debian/sudo] / lbuf.c
1 /*
2  * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
16  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  */
18
19 #include <config.h>
20
21 #include <sys/types.h>
22 #include <sys/param.h>
23 #include <sys/ioctl.h>
24 #include <stdio.h>
25 #ifdef STDC_HEADERS
26 # include <stdlib.h>
27 # include <stddef.h>
28 #else
29 # ifdef HAVE_STDLIB_H
30 #  include <stdlib.h>
31 # endif
32 #endif /* STDC_HEADERS */
33 #ifdef HAVE_STRING_H
34 # include <string.h>
35 #else
36 # ifdef HAVE_STRINGS_H
37 #  include <strings.h>
38 # endif
39 #endif /* HAVE_STRING_H */
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 #include <ctype.h>
44
45 #include "sudo.h"
46 #include "lbuf.h"
47
48 #ifndef lint
49 __unused static const char rcsid[] = "$Sudo: lbuf.c,v 1.7 2008/12/09 20:55:49 millert Exp $";
50 #endif /* lint */
51
52 #if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
53 # define TIOCGSIZE      TIOCGWINSZ
54 # define ttysize        winsize
55 # define ts_cols        ws_col
56 #endif
57
58 int
59 get_ttycols()
60 {
61     char *p;
62     int cols;
63 #ifdef TIOCGSIZE
64     struct ttysize win;
65
66     if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0)
67         return((int)win.ts_cols);
68 #endif
69
70     /* Fall back on $COLUMNS. */
71     if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
72         cols = 80;
73     return(cols);
74 }
75
76 /*
77  * TODO: add support for embedded newlines in lbufs
78  */
79
80 void
81 lbuf_init(lbuf, buf, indent, continuation)
82     struct lbuf *lbuf;
83     char *buf;
84     int indent;
85     int continuation;
86 {
87     lbuf->continuation = continuation;
88     lbuf->indent = indent;
89     lbuf->len = 0;
90     lbuf->size = 0;
91     lbuf->buf = NULL;
92 }
93
94 void
95 lbuf_destroy(lbuf)
96     struct lbuf *lbuf;
97 {
98     efree(lbuf->buf);
99     lbuf->buf = NULL;
100 }
101
102 /*
103  * Append strings to the buffer, expanding it as needed.
104  */
105 void
106 #ifdef __STDC__
107 lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
108 #else
109 lbuf_append_quoted(lbuf, set, va_alist)
110         struct lbuf *lbuf;
111         const char *set;
112         va_dcl
113 #endif
114 {
115     va_list ap;
116     int len = 0;
117     char *cp, *s;
118
119 #ifdef __STDC__
120     va_start(ap, set);
121 #else
122     va_start(ap);
123 #endif
124     while ((s = va_arg(ap, char *)) != NULL) {
125         len += strlen(s);
126         for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++)
127             len++;
128     }
129     va_end(ap);
130
131     /* Expand buffer as needed. */
132     if (lbuf->len + len >= lbuf->size) {
133         do {
134             lbuf->size += 256;
135         } while (lbuf->len + len >= lbuf->size);
136         lbuf->buf = erealloc(lbuf->buf, lbuf->size);
137     }
138
139 #ifdef __STDC__
140     va_start(ap, set);
141 #else
142     va_start(ap);
143 #endif
144     /* Append each string. */
145     while ((s = va_arg(ap, char *)) != NULL) {
146         while ((cp = strpbrk(s, set)) != NULL) {
147             len = (int)(cp - s);
148             memcpy(lbuf->buf + lbuf->len, s, len);
149             lbuf->len += len;
150             lbuf->buf[lbuf->len++] = '\\';
151             lbuf->buf[lbuf->len++] = *cp;
152             s = cp + 1;
153         }
154         if (*s != '\0') {
155             len = strlen(s);
156             memcpy(lbuf->buf + lbuf->len, s, len);
157             lbuf->len += len;
158         }
159     }
160     lbuf->buf[lbuf->len] = '\0';
161     va_end(ap);
162 }
163
164 /*
165  * Append strings to the buffer, expanding it as needed.
166  */
167 void
168 #ifdef __STDC__
169 lbuf_append(struct lbuf *lbuf, ...)
170 #else
171 lbuf_append(lbuf, va_alist)
172         struct lbuf *lbuf;
173         va_dcl
174 #endif
175 {
176     va_list ap;
177     int len = 0;
178     char *s;
179
180 #ifdef __STDC__
181     va_start(ap, lbuf);
182 #else
183     va_start(ap);
184 #endif
185     while ((s = va_arg(ap, char *)) != NULL)
186         len += strlen(s);
187     va_end(ap);
188
189     /* Expand buffer as needed. */
190     if (lbuf->len + len >= lbuf->size) {
191         do {
192             lbuf->size += 256;
193         } while (lbuf->len + len >= lbuf->size);
194         lbuf->buf = erealloc(lbuf->buf, lbuf->size);
195     }
196
197 #ifdef __STDC__
198     va_start(ap, lbuf);
199 #else
200     va_start(ap);
201 #endif
202     /* Append each string. */
203     while ((s = va_arg(ap, char *)) != NULL) {
204         len = strlen(s);
205         memcpy(lbuf->buf + lbuf->len, s, len);
206         lbuf->len += len;
207     }
208     lbuf->buf[lbuf->len] = '\0';
209     va_end(ap);
210 }
211
212 /*
213  * Print the buffer with word wrap based on the tty width.
214  * The lbuf is reset on return.
215  */
216 void
217 lbuf_print(lbuf)
218     struct lbuf *lbuf;
219 {
220     char *cp;
221     int i, have, contlen;
222     static int cols = -1;
223
224     if (cols == -1)
225         cols = get_ttycols();
226     contlen = lbuf->continuation ? 2 : 0;
227
228     /* For very small widths just give up... */
229     if (cols <= lbuf->indent + contlen + 20) {
230         puts(lbuf->buf);
231         goto done;
232     }
233
234     /*
235      * Print the buffer, splitting the line as needed on a word
236      * boundary.
237      */
238     cp = lbuf->buf;
239     have = cols;
240     while (cp != NULL && *cp != '\0') {
241         char *ep = NULL;
242         int need = lbuf->len - (int)(cp - lbuf->buf);
243
244         if (need > have) {
245             have -= contlen;            /* subtract for continuation char */
246             if ((ep = memrchr(cp, ' ', have)) == NULL)
247                 ep = memchr(cp + have, ' ', need - have);
248             if (ep != NULL)
249                 need = (int)(ep - cp);
250         }
251         if (cp != lbuf->buf) {
252             /* indent continued lines */
253             for (i = 0; i < lbuf->indent; i++)
254                 putchar(' ');
255         }
256         fwrite(cp, need, 1, stdout);
257         cp = ep;
258
259         /*
260          * If there is more to print, reset have, incremement cp past
261          * the whitespace, and print a line continuaton char if needed.
262          */
263         if (cp != NULL) {
264             have = cols - lbuf->indent;
265             do {
266                 cp++;
267             } while (isspace((unsigned char)*cp));
268             if (lbuf->continuation) {
269                 putchar(' ');
270                 putchar(lbuf->continuation);
271             }
272         }
273         putchar('\n');
274     }
275
276 done:
277     lbuf->len = 0;              /* reset the buffer for re-use. */
278 }