Annotation of embedaddon/sudo/common/lbuf.c, revision 1.1.1.6

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

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