Annotation of embedaddon/sudo/common/lbuf.c, revision 1.1.1.4
1.1 misho 1: /*
1.1.1.4 ! misho 2: * Copyright (c) 2007-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 misho 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 <stdio.h>
23: #ifdef STDC_HEADERS
24: # include <stdlib.h>
25: # include <stddef.h>
26: #else
27: # ifdef HAVE_STDLIB_H
28: # include <stdlib.h>
29: # endif
30: #endif /* STDC_HEADERS */
31: #ifdef HAVE_STRING_H
32: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
33: # include <memory.h>
34: # endif
35: # include <string.h>
36: #endif /* HAVE_STRING_H */
37: #ifdef HAVE_STRINGS_H
38: # include <strings.h>
39: #endif /* HAVE_STRINGS_H */
40: #ifdef HAVE_UNISTD_H
41: # include <unistd.h>
42: #endif /* HAVE_UNISTD_H */
43: #include <ctype.h>
44:
45: #include "missing.h"
46: #include "alloc.h"
47: #include "error.h"
48: #include "lbuf.h"
1.1.1.2 misho 49: #include "sudo_debug.h"
1.1 misho 50:
51: void
52: lbuf_init(struct lbuf *lbuf, int (*output)(const char *),
53: int indent, const char *continuation, int cols)
54: {
1.1.1.2 misho 55: debug_decl(lbuf_init, SUDO_DEBUG_UTIL)
56:
1.1 misho 57: lbuf->output = output;
58: lbuf->continuation = continuation;
59: lbuf->indent = indent;
60: lbuf->cols = cols;
61: lbuf->len = 0;
62: lbuf->size = 0;
63: lbuf->buf = NULL;
1.1.1.2 misho 64:
65: debug_return;
1.1 misho 66: }
67:
68: void
69: lbuf_destroy(struct lbuf *lbuf)
70: {
1.1.1.2 misho 71: debug_decl(lbuf_destroy, SUDO_DEBUG_UTIL)
72:
1.1 misho 73: efree(lbuf->buf);
74: lbuf->buf = NULL;
1.1.1.2 misho 75:
76: debug_return;
1.1 misho 77: }
78:
1.1.1.4 ! misho 79: static void
! 80: lbuf_expand(struct lbuf *lbuf, size_t extra)
! 81: {
! 82: if (lbuf->len + extra + 1 >= lbuf->size) {
! 83: do {
! 84: lbuf->size += 256;
! 85: } while (lbuf->len + extra + 1 >= lbuf->size);
! 86: lbuf->buf = erealloc(lbuf->buf, lbuf->size);
! 87: }
! 88: }
! 89:
1.1 misho 90: /*
91: * Parse the format and append strings, only %s and %% escapes are supported.
92: * Any characters in set are quoted with a backslash.
93: */
94: void
95: lbuf_append_quoted(struct lbuf *lbuf, const char *set, const char *fmt, ...)
96: {
97: va_list ap;
98: int len;
1.1.1.4 ! misho 99: char *cp, *s;
1.1.1.2 misho 100: debug_decl(lbuf_append_quoted, SUDO_DEBUG_UTIL)
1.1 misho 101:
102: va_start(ap, fmt);
103: while (*fmt != '\0') {
104: if (fmt[0] == '%' && fmt[1] == 's') {
1.1.1.4 ! misho 105: if ((s = va_arg(ap, char *)) == NULL)
! 106: goto done;
! 107: while ((cp = strpbrk(s, set)) != NULL) {
! 108: len = (int)(cp - s);
! 109: lbuf_expand(lbuf, len + 2);
! 110: memcpy(lbuf->buf + lbuf->len, s, len);
! 111: lbuf->len += len;
! 112: lbuf->buf[lbuf->len++] = '\\';
! 113: lbuf->buf[lbuf->len++] = *cp;
! 114: s = cp + 1;
1.1 misho 115: }
1.1.1.4 ! misho 116: if (*s != '\0') {
! 117: len = strlen(s);
! 118: lbuf_expand(lbuf, len);
! 119: memcpy(lbuf->buf + lbuf->len, s, len);
! 120: lbuf->len += len;
! 121: }
! 122: fmt += 2;
! 123: continue;
1.1 misho 124: }
1.1.1.4 ! misho 125: lbuf_expand(lbuf, 2);
1.1 misho 126: if (strchr(set, *fmt) != NULL)
127: lbuf->buf[lbuf->len++] = '\\';
128: lbuf->buf[lbuf->len++] = *fmt++;
129: }
1.1.1.4 ! misho 130: done:
! 131: if (lbuf->size != 0)
! 132: lbuf->buf[lbuf->len] = '\0';
1.1 misho 133: va_end(ap);
1.1.1.2 misho 134:
135: debug_return;
1.1 misho 136: }
137:
138: /*
139: * Parse the format and append strings, only %s and %% escapes are supported.
140: */
141: void
142: lbuf_append(struct lbuf *lbuf, const char *fmt, ...)
143: {
144: va_list ap;
145: int len;
1.1.1.4 ! misho 146: char *s;
1.1.1.2 misho 147: debug_decl(lbuf_append, SUDO_DEBUG_UTIL)
1.1 misho 148:
149: va_start(ap, fmt);
150: while (*fmt != '\0') {
151: if (fmt[0] == '%' && fmt[1] == 's') {
1.1.1.4 ! misho 152: if ((s = va_arg(ap, char *)) == NULL)
! 153: goto done;
1.1 misho 154: len = strlen(s);
1.1.1.4 ! misho 155: lbuf_expand(lbuf, len);
! 156: memcpy(lbuf->buf + lbuf->len, s, len);
! 157: lbuf->len += len;
! 158: fmt += 2;
! 159: continue;
1.1 misho 160: }
1.1.1.4 ! misho 161: lbuf_expand(lbuf, 1);
1.1 misho 162: lbuf->buf[lbuf->len++] = *fmt++;
163: }
1.1.1.4 ! misho 164: done:
! 165: if (lbuf->size != 0)
! 166: lbuf->buf[lbuf->len] = '\0';
1.1 misho 167: va_end(ap);
1.1.1.2 misho 168:
169: debug_return;
1.1 misho 170: }
171:
172: static void
173: lbuf_println(struct lbuf *lbuf, char *line, int len)
174: {
175: char *cp, save;
176: int i, have, contlen;
1.1.1.2 misho 177: debug_decl(lbuf_println, SUDO_DEBUG_UTIL)
1.1 misho 178:
179: contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
180:
181: /*
182: * Print the buffer, splitting the line as needed on a word
183: * boundary.
184: */
185: cp = line;
186: have = lbuf->cols;
187: while (cp != NULL && *cp != '\0') {
188: char *ep = NULL;
189: int need = len - (int)(cp - line);
190:
191: if (need > have) {
192: have -= contlen; /* subtract for continuation char */
193: if ((ep = memrchr(cp, ' ', have)) == NULL)
194: ep = memchr(cp + have, ' ', need - have);
195: if (ep != NULL)
196: need = (int)(ep - cp);
197: }
198: if (cp != line) {
199: /* indent continued lines */
200: /* XXX - build up string instead? */
201: for (i = 0; i < lbuf->indent; i++)
202: lbuf->output(" ");
203: }
204: /* NUL-terminate cp for the output function and restore afterwards */
205: save = cp[need];
206: cp[need] = '\0';
207: lbuf->output(cp);
208: cp[need] = save;
209: cp = ep;
210:
211: /*
212: * If there is more to print, reset have, incremement cp past
213: * the whitespace, and print a line continuaton char if needed.
214: */
215: if (cp != NULL) {
216: have = lbuf->cols - lbuf->indent;
217: ep = line + len;
218: while (cp < ep && isblank((unsigned char)*cp)) {
219: cp++;
220: }
221: if (contlen)
222: lbuf->output(lbuf->continuation);
223: }
224: lbuf->output("\n");
225: }
1.1.1.2 misho 226:
227: debug_return;
1.1 misho 228: }
229:
230: /*
231: * Print the buffer with word wrap based on the tty width.
232: * The lbuf is reset on return.
233: */
234: void
235: lbuf_print(struct lbuf *lbuf)
236: {
237: char *cp, *ep;
238: int len;
1.1.1.2 misho 239: debug_decl(lbuf_print, SUDO_DEBUG_UTIL)
1.1 misho 240:
241: if (lbuf->buf == NULL || lbuf->len == 0)
242: goto done;
243:
244: /* For very small widths just give up... */
245: len = lbuf->continuation ? strlen(lbuf->continuation) : 0;
246: if (lbuf->cols <= lbuf->indent + len + 20) {
1.1.1.3 misho 247: if (lbuf->len > 0) {
248: lbuf->buf[lbuf->len] = '\0';
249: lbuf->output(lbuf->buf);
250: if (lbuf->buf[lbuf->len - 1] != '\n')
251: lbuf->output("\n");
252: }
1.1 misho 253: goto done;
254: }
255:
256: /* Print each line in the buffer */
257: for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) {
258: if (*cp == '\n') {
259: lbuf->output("\n");
260: cp++;
261: } else {
262: len = lbuf->len - (cp - lbuf->buf);
263: if ((ep = memchr(cp, '\n', len)) != NULL)
264: len = (int)(ep - cp);
265: if (len)
266: lbuf_println(lbuf, cp, len);
267: cp = ep ? ep + 1 : NULL;
268: }
269: }
270:
271: done:
272: lbuf->len = 0; /* reset the buffer for re-use. */
1.1.1.2 misho 273:
274: debug_return;
1.1 misho 275: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>