File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / common / lbuf.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:56:33 2013 UTC (10 years, 8 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, HEAD
v 1.8.8

    1: /*
    2:  * Copyright (c) 2007-2013 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 <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 "fatal.h"
   48: #include "lbuf.h"
   49: #include "sudo_debug.h"
   50: 
   51: void
   52: lbuf_init(struct lbuf *lbuf, int (*output)(const char *),
   53:     int indent, const char *continuation, int cols)
   54: {
   55:     debug_decl(lbuf_init, SUDO_DEBUG_UTIL)
   56: 
   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;
   64: 
   65:     debug_return;
   66: }
   67: 
   68: void
   69: lbuf_destroy(struct lbuf *lbuf)
   70: {
   71:     debug_decl(lbuf_destroy, SUDO_DEBUG_UTIL)
   72: 
   73:     efree(lbuf->buf);
   74:     lbuf->buf = NULL;
   75: 
   76:     debug_return;
   77: }
   78: 
   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: 
   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;
   99:     char *cp, *s;
  100:     debug_decl(lbuf_append_quoted, SUDO_DEBUG_UTIL)
  101: 
  102:     va_start(ap, fmt);
  103:     while (*fmt != '\0') {
  104: 	if (fmt[0] == '%' && fmt[1] == 's') {
  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;
  115: 	    }
  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;
  124: 	}
  125: 	lbuf_expand(lbuf, 2);
  126: 	if (strchr(set, *fmt) != NULL)
  127: 	    lbuf->buf[lbuf->len++] = '\\';
  128: 	lbuf->buf[lbuf->len++] = *fmt++;
  129:     }
  130: done:
  131:     if (lbuf->size != 0)
  132: 	lbuf->buf[lbuf->len] = '\0';
  133:     va_end(ap);
  134: 
  135:     debug_return;
  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;
  146:     char *s;
  147:     debug_decl(lbuf_append, SUDO_DEBUG_UTIL)
  148: 
  149:     va_start(ap, fmt);
  150:     while (*fmt != '\0') {
  151: 	if (fmt[0] == '%' && fmt[1] == 's') {
  152: 	    if ((s = va_arg(ap, char *)) == NULL)
  153: 		goto done;
  154: 	    len = strlen(s);
  155: 	    lbuf_expand(lbuf, len);
  156: 	    memcpy(lbuf->buf + lbuf->len, s, len);
  157: 	    lbuf->len += len;
  158: 	    fmt += 2;
  159: 	    continue;
  160: 	}
  161: 	lbuf_expand(lbuf, 1);
  162: 	lbuf->buf[lbuf->len++] = *fmt++;
  163:     }
  164: done:
  165:     if (lbuf->size != 0)
  166: 	lbuf->buf[lbuf->len] = '\0';
  167:     va_end(ap);
  168: 
  169:     debug_return;
  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;
  177:     debug_decl(lbuf_println, SUDO_DEBUG_UTIL)
  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:     }
  226: 
  227:     debug_return;
  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;
  239:     debug_decl(lbuf_print, SUDO_DEBUG_UTIL)
  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) {
  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: 	}
  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. */
  273: 
  274:     debug_return;
  275: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>