File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / common / lbuf.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>