Annotation of src/usr.bin/sudo/lbuf.c, Revision 1.2
1.1 millert 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
1.2 ! millert 49: __unused static const char rcsid[] = "$Sudo: lbuf.c,v 1.7 2008/12/09 20:55:49 millert Exp $";
1.1 millert 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
1.2 ! millert 109: lbuf_append_quoted(lbuf, set, va_alist)
1.1 millert 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: }