File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / common / lbuf.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:29:52 2012 UTC (11 years, 9 months ago) by misho
Branches: sudo, MAIN
CVS tags: HEAD
sudo

    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: #include "sudo_debug.h"
   51: 
   52: void
   53: lbuf_init(struct lbuf *lbuf, int (*output)(const char *),
   54:     int indent, const char *continuation, int cols)
   55: {
   56:     debug_decl(lbuf_init, SUDO_DEBUG_UTIL)
   57: 
   58:     lbuf->output = output;
   59:     lbuf->continuation = continuation;
   60:     lbuf->indent = indent;
   61:     lbuf->cols = cols;
   62:     lbuf->len = 0;
   63:     lbuf->size = 0;
   64:     lbuf->buf = NULL;
   65: 
   66:     debug_return;
   67: }
   68: 
   69: void
   70: lbuf_destroy(struct lbuf *lbuf)
   71: {
   72:     debug_decl(lbuf_destroy, SUDO_DEBUG_UTIL)
   73: 
   74:     efree(lbuf->buf);
   75:     lbuf->buf = NULL;
   76: 
   77:     debug_return;
   78: }
   79: 
   80: /*
   81:  * Parse the format and append strings, only %s and %% escapes are supported.
   82:  * Any characters in set are quoted with a backslash.
   83:  */
   84: void
   85: lbuf_append_quoted(struct lbuf *lbuf, const char *set, const char *fmt, ...)
   86: {
   87:     va_list ap;
   88:     int len;
   89:     char *cp, *s = NULL;
   90:     debug_decl(lbuf_append_quoted, SUDO_DEBUG_UTIL)
   91: 
   92:     va_start(ap, fmt);
   93:     while (*fmt != '\0') {
   94: 	len = 1;
   95: 	if (fmt[0] == '%' && fmt[1] == 's') {
   96: 	    s = va_arg(ap, char *);
   97: 	    len = strlen(s);
   98: 	}
   99: 	/* Assume worst case that all chars must be escaped. */
  100: 	if (lbuf->len + (len * 2) + 1 >= lbuf->size) {
  101: 	    do {
  102: 		lbuf->size += 256;
  103: 	    } while (lbuf->len + len + 1 >= lbuf->size);
  104: 	    lbuf->buf = erealloc(lbuf->buf, lbuf->size);
  105: 	}
  106: 	if (*fmt == '%') {
  107: 	    if (*(++fmt) == 's') {
  108: 		while ((cp = strpbrk(s, set)) != NULL) {
  109: 		    len = (int)(cp - s);
  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: 		    memcpy(lbuf->buf + lbuf->len, s, len);
  119: 		    lbuf->len += len;
  120: 		}
  121: 		fmt++;
  122: 		continue;
  123: 	    }
  124: 	}
  125: 	if (strchr(set, *fmt) != NULL)
  126: 	    lbuf->buf[lbuf->len++] = '\\';
  127: 	lbuf->buf[lbuf->len++] = *fmt++;
  128:     }
  129:     lbuf->buf[lbuf->len] = '\0';
  130:     va_end(ap);
  131: 
  132:     debug_return;
  133: }
  134: 
  135: /*
  136:  * Parse the format and append strings, only %s and %% escapes are supported.
  137:  */
  138: void
  139: lbuf_append(struct lbuf *lbuf, const char *fmt, ...)
  140: {
  141:     va_list ap;
  142:     int len;
  143:     char *s = NULL;
  144:     debug_decl(lbuf_append, SUDO_DEBUG_UTIL)
  145: 
  146:     va_start(ap, fmt);
  147:     while (*fmt != '\0') {
  148: 	len = 1;
  149: 	if (fmt[0] == '%' && fmt[1] == 's') {
  150: 	    s = va_arg(ap, char *);
  151: 	    len = strlen(s);
  152: 	}
  153: 	if (lbuf->len + len + 1 >= lbuf->size) {
  154: 	    do {
  155: 		lbuf->size += 256;
  156: 	    } while (lbuf->len + len + 1 >= lbuf->size);
  157: 	    lbuf->buf = erealloc(lbuf->buf, lbuf->size);
  158: 	}
  159: 	if (*fmt == '%') {
  160: 	    if (*(++fmt) == 's') {
  161: 		memcpy(lbuf->buf + lbuf->len, s, len);
  162: 		lbuf->len += len;
  163: 		fmt++;
  164: 		continue;
  165: 	    }
  166: 	}
  167: 	lbuf->buf[lbuf->len++] = *fmt++;
  168:     }
  169:     lbuf->buf[lbuf->len] = '\0';
  170:     va_end(ap);
  171: 
  172:     debug_return;
  173: }
  174: 
  175: static void
  176: lbuf_println(struct lbuf *lbuf, char *line, int len)
  177: {
  178:     char *cp, save;
  179:     int i, have, contlen;
  180:     debug_decl(lbuf_println, SUDO_DEBUG_UTIL)
  181: 
  182:     contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
  183: 
  184:     /*
  185:      * Print the buffer, splitting the line as needed on a word
  186:      * boundary.
  187:      */
  188:     cp = line;
  189:     have = lbuf->cols;
  190:     while (cp != NULL && *cp != '\0') {
  191: 	char *ep = NULL;
  192: 	int need = len - (int)(cp - line);
  193: 
  194: 	if (need > have) {
  195: 	    have -= contlen;		/* subtract for continuation char */
  196: 	    if ((ep = memrchr(cp, ' ', have)) == NULL)
  197: 		ep = memchr(cp + have, ' ', need - have);
  198: 	    if (ep != NULL)
  199: 		need = (int)(ep - cp);
  200: 	}
  201: 	if (cp != line) {
  202: 	    /* indent continued lines */
  203: 	    /* XXX - build up string instead? */
  204: 	    for (i = 0; i < lbuf->indent; i++)
  205: 		lbuf->output(" ");
  206: 	}
  207: 	/* NUL-terminate cp for the output function and restore afterwards */
  208: 	save = cp[need];
  209: 	cp[need] = '\0';
  210: 	lbuf->output(cp);
  211: 	cp[need] = save;
  212: 	cp = ep;
  213: 
  214: 	/*
  215: 	 * If there is more to print, reset have, incremement cp past
  216: 	 * the whitespace, and print a line continuaton char if needed.
  217: 	 */
  218: 	if (cp != NULL) {
  219: 	    have = lbuf->cols - lbuf->indent;
  220: 	    ep = line + len;
  221: 	    while (cp < ep && isblank((unsigned char)*cp)) {
  222: 		cp++;
  223: 	    }
  224: 	    if (contlen)
  225: 		lbuf->output(lbuf->continuation);
  226: 	}
  227: 	lbuf->output("\n");
  228:     }
  229: 
  230:     debug_return;
  231: }
  232: 
  233: /*
  234:  * Print the buffer with word wrap based on the tty width.
  235:  * The lbuf is reset on return.
  236:  */
  237: void
  238: lbuf_print(struct lbuf *lbuf)
  239: {
  240:     char *cp, *ep;
  241:     int len;
  242:     debug_decl(lbuf_print, SUDO_DEBUG_UTIL)
  243: 
  244:     if (lbuf->buf == NULL || lbuf->len == 0)
  245: 	goto done;
  246: 
  247:     /* For very small widths just give up... */
  248:     len = lbuf->continuation ? strlen(lbuf->continuation) : 0;
  249:     if (lbuf->cols <= lbuf->indent + len + 20) {
  250: 	if (lbuf->len > 0) {
  251: 	    lbuf->buf[lbuf->len] = '\0';
  252: 	    lbuf->output(lbuf->buf);
  253: 	    if (lbuf->buf[lbuf->len - 1] != '\n')
  254: 		lbuf->output("\n");
  255: 	}
  256: 	goto done;
  257:     }
  258: 
  259:     /* Print each line in the buffer */
  260:     for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) {
  261: 	if (*cp == '\n') {
  262: 	    lbuf->output("\n");
  263: 	    cp++;
  264: 	} else {
  265: 	    len = lbuf->len - (cp - lbuf->buf);
  266: 	    if ((ep = memchr(cp, '\n', len)) != NULL)
  267: 		len = (int)(ep - cp);
  268: 	    if (len)
  269: 		lbuf_println(lbuf, cp, len);
  270: 	    cp = ep ? ep + 1 : NULL;
  271: 	}
  272:     }
  273: 
  274: done:
  275:     lbuf->len = 0;		/* reset the buffer for re-use. */
  276: 
  277:     debug_return;
  278: }

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