Annotation of src/usr.bin/sudo/lbuf.c, Revision 1.5
1.1 millert 1: /*
1.3 millert 2: * Copyright (c) 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 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>
1.3 millert 44: #ifdef HAVE_TERMIOS_H
45: # include <termios.h>
46: #else
47: # ifdef HAVE_TERMIO_H
48: # include <termio.h>
49: # endif
50: #endif
1.1 millert 51:
52: #include "sudo.h"
53: #include "lbuf.h"
54:
1.5 ! naddy 55: #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
! 56: # define TIOCGWINSZ TIOCGSIZE
! 57: # define winsize ttysize
! 58: # define ws_col ts_cols
1.1 millert 59: #endif
60:
61: int
62: get_ttycols()
63: {
64: char *p;
65: int cols;
66: #ifdef TIOCGSIZE
1.5 ! naddy 67: struct winsize win;
1.1 millert 68:
1.5 ! naddy 69: if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) == 0 && win.ws_col != 0)
! 70: return((int)win.ws_col);
1.1 millert 71: #endif
72:
73: /* Fall back on $COLUMNS. */
74: if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
75: cols = 80;
76: return(cols);
77: }
78:
79: /*
80: * TODO: add support for embedded newlines in lbufs
81: */
82:
83: void
84: lbuf_init(lbuf, buf, indent, continuation)
85: struct lbuf *lbuf;
86: char *buf;
87: int indent;
88: int continuation;
89: {
90: lbuf->continuation = continuation;
91: lbuf->indent = indent;
92: lbuf->len = 0;
93: lbuf->size = 0;
94: lbuf->buf = NULL;
95: }
96:
97: void
98: lbuf_destroy(lbuf)
99: struct lbuf *lbuf;
100: {
101: efree(lbuf->buf);
102: lbuf->buf = NULL;
103: }
104:
105: /*
106: * Append strings to the buffer, expanding it as needed.
107: */
108: void
109: #ifdef __STDC__
110: lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
111: #else
1.2 millert 112: lbuf_append_quoted(lbuf, set, va_alist)
1.1 millert 113: struct lbuf *lbuf;
114: const char *set;
115: va_dcl
116: #endif
117: {
118: va_list ap;
119: int len = 0;
120: char *cp, *s;
121:
122: #ifdef __STDC__
123: va_start(ap, set);
124: #else
125: va_start(ap);
126: #endif
127: while ((s = va_arg(ap, char *)) != NULL) {
128: len += strlen(s);
129: for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++)
130: len++;
131: }
132: va_end(ap);
133:
134: /* Expand buffer as needed. */
135: if (lbuf->len + len >= lbuf->size) {
136: do {
137: lbuf->size += 256;
138: } while (lbuf->len + len >= lbuf->size);
139: lbuf->buf = erealloc(lbuf->buf, lbuf->size);
140: }
141:
142: #ifdef __STDC__
143: va_start(ap, set);
144: #else
145: va_start(ap);
146: #endif
147: /* Append each string. */
148: while ((s = va_arg(ap, char *)) != NULL) {
149: while ((cp = strpbrk(s, set)) != NULL) {
150: len = (int)(cp - s);
151: memcpy(lbuf->buf + lbuf->len, s, len);
152: lbuf->len += len;
153: lbuf->buf[lbuf->len++] = '\\';
154: lbuf->buf[lbuf->len++] = *cp;
155: s = cp + 1;
156: }
157: if (*s != '\0') {
158: len = strlen(s);
159: memcpy(lbuf->buf + lbuf->len, s, len);
160: lbuf->len += len;
161: }
162: }
163: lbuf->buf[lbuf->len] = '\0';
164: va_end(ap);
165: }
166:
167: /*
168: * Append strings to the buffer, expanding it as needed.
169: */
170: void
171: #ifdef __STDC__
172: lbuf_append(struct lbuf *lbuf, ...)
173: #else
174: lbuf_append(lbuf, va_alist)
175: struct lbuf *lbuf;
176: va_dcl
177: #endif
178: {
179: va_list ap;
180: int len = 0;
181: char *s;
182:
183: #ifdef __STDC__
184: va_start(ap, lbuf);
185: #else
186: va_start(ap);
187: #endif
188: while ((s = va_arg(ap, char *)) != NULL)
189: len += strlen(s);
190: va_end(ap);
191:
192: /* Expand buffer as needed. */
193: if (lbuf->len + len >= lbuf->size) {
194: do {
195: lbuf->size += 256;
196: } while (lbuf->len + len >= lbuf->size);
197: lbuf->buf = erealloc(lbuf->buf, lbuf->size);
198: }
199:
200: #ifdef __STDC__
201: va_start(ap, lbuf);
202: #else
203: va_start(ap);
204: #endif
205: /* Append each string. */
206: while ((s = va_arg(ap, char *)) != NULL) {
207: len = strlen(s);
208: memcpy(lbuf->buf + lbuf->len, s, len);
209: lbuf->len += len;
210: }
211: lbuf->buf[lbuf->len] = '\0';
212: va_end(ap);
213: }
214:
215: /*
216: * Print the buffer with word wrap based on the tty width.
217: * The lbuf is reset on return.
218: */
219: void
220: lbuf_print(lbuf)
221: struct lbuf *lbuf;
222: {
223: char *cp;
224: int i, have, contlen;
225: static int cols = -1;
226:
227: if (cols == -1)
228: cols = get_ttycols();
229: contlen = lbuf->continuation ? 2 : 0;
230:
231: /* For very small widths just give up... */
232: if (cols <= lbuf->indent + contlen + 20) {
233: puts(lbuf->buf);
234: goto done;
235: }
236:
237: /*
238: * Print the buffer, splitting the line as needed on a word
239: * boundary.
240: */
241: cp = lbuf->buf;
242: have = cols;
243: while (cp != NULL && *cp != '\0') {
244: char *ep = NULL;
245: int need = lbuf->len - (int)(cp - lbuf->buf);
246:
247: if (need > have) {
248: have -= contlen; /* subtract for continuation char */
249: if ((ep = memrchr(cp, ' ', have)) == NULL)
250: ep = memchr(cp + have, ' ', need - have);
251: if (ep != NULL)
252: need = (int)(ep - cp);
253: }
254: if (cp != lbuf->buf) {
255: /* indent continued lines */
256: for (i = 0; i < lbuf->indent; i++)
257: putchar(' ');
258: }
259: fwrite(cp, need, 1, stdout);
260: cp = ep;
261:
262: /*
263: * If there is more to print, reset have, incremement cp past
264: * the whitespace, and print a line continuaton char if needed.
265: */
266: if (cp != NULL) {
267: have = cols - lbuf->indent;
268: do {
269: cp++;
270: } while (isspace((unsigned char)*cp));
271: if (lbuf->continuation) {
272: putchar(' ');
273: putchar(lbuf->continuation);
274: }
275: }
276: putchar('\n');
277: }
278:
279: done:
280: lbuf->len = 0; /* reset the buffer for re-use. */
281: }