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>