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