[BACK]Return to lbuf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/lbuf.c, Revision 1.2

1.1       millert     1: /*
                      2:  * Copyright (c) 2007-2008 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 <sys/ioctl.h>
                     24: #include <stdio.h>
                     25: #ifdef STDC_HEADERS
                     26: # include <stdlib.h>
                     27: # include <stddef.h>
                     28: #else
                     29: # ifdef HAVE_STDLIB_H
                     30: #  include <stdlib.h>
                     31: # endif
                     32: #endif /* STDC_HEADERS */
                     33: #ifdef HAVE_STRING_H
                     34: # include <string.h>
                     35: #else
                     36: # ifdef HAVE_STRINGS_H
                     37: #  include <strings.h>
                     38: # endif
                     39: #endif /* HAVE_STRING_H */
                     40: #ifdef HAVE_UNISTD_H
                     41: # include <unistd.h>
                     42: #endif /* HAVE_UNISTD_H */
                     43: #include <ctype.h>
                     44:
                     45: #include "sudo.h"
                     46: #include "lbuf.h"
                     47:
                     48: #ifndef lint
1.2     ! millert    49: __unused static const char rcsid[] = "$Sudo: lbuf.c,v 1.7 2008/12/09 20:55:49 millert Exp $";
1.1       millert    50: #endif /* lint */
                     51:
                     52: #if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
                     53: # define TIOCGSIZE     TIOCGWINSZ
                     54: # define ttysize       winsize
                     55: # define ts_cols       ws_col
                     56: #endif
                     57:
                     58: int
                     59: get_ttycols()
                     60: {
                     61:     char *p;
                     62:     int cols;
                     63: #ifdef TIOCGSIZE
                     64:     struct ttysize win;
                     65:
                     66:     if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0)
                     67:        return((int)win.ts_cols);
                     68: #endif
                     69:
                     70:     /* Fall back on $COLUMNS. */
                     71:     if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
                     72:        cols = 80;
                     73:     return(cols);
                     74: }
                     75:
                     76: /*
                     77:  * TODO: add support for embedded newlines in lbufs
                     78:  */
                     79:
                     80: void
                     81: lbuf_init(lbuf, buf, indent, continuation)
                     82:     struct lbuf *lbuf;
                     83:     char *buf;
                     84:     int indent;
                     85:     int continuation;
                     86: {
                     87:     lbuf->continuation = continuation;
                     88:     lbuf->indent = indent;
                     89:     lbuf->len = 0;
                     90:     lbuf->size = 0;
                     91:     lbuf->buf = NULL;
                     92: }
                     93:
                     94: void
                     95: lbuf_destroy(lbuf)
                     96:     struct lbuf *lbuf;
                     97: {
                     98:     efree(lbuf->buf);
                     99:     lbuf->buf = NULL;
                    100: }
                    101:
                    102: /*
                    103:  * Append strings to the buffer, expanding it as needed.
                    104:  */
                    105: void
                    106: #ifdef __STDC__
                    107: lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
                    108: #else
1.2     ! millert   109: lbuf_append_quoted(lbuf, set, va_alist)
1.1       millert   110:        struct lbuf *lbuf;
                    111:        const char *set;
                    112:        va_dcl
                    113: #endif
                    114: {
                    115:     va_list ap;
                    116:     int len = 0;
                    117:     char *cp, *s;
                    118:
                    119: #ifdef __STDC__
                    120:     va_start(ap, set);
                    121: #else
                    122:     va_start(ap);
                    123: #endif
                    124:     while ((s = va_arg(ap, char *)) != NULL) {
                    125:        len += strlen(s);
                    126:        for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++)
                    127:            len++;
                    128:     }
                    129:     va_end(ap);
                    130:
                    131:     /* Expand buffer as needed. */
                    132:     if (lbuf->len + len >= lbuf->size) {
                    133:        do {
                    134:            lbuf->size += 256;
                    135:        } while (lbuf->len + len >= lbuf->size);
                    136:        lbuf->buf = erealloc(lbuf->buf, lbuf->size);
                    137:     }
                    138:
                    139: #ifdef __STDC__
                    140:     va_start(ap, set);
                    141: #else
                    142:     va_start(ap);
                    143: #endif
                    144:     /* Append each string. */
                    145:     while ((s = va_arg(ap, char *)) != NULL) {
                    146:        while ((cp = strpbrk(s, set)) != NULL) {
                    147:            len = (int)(cp - s);
                    148:            memcpy(lbuf->buf + lbuf->len, s, len);
                    149:            lbuf->len += len;
                    150:            lbuf->buf[lbuf->len++] = '\\';
                    151:            lbuf->buf[lbuf->len++] = *cp;
                    152:            s = cp + 1;
                    153:        }
                    154:        if (*s != '\0') {
                    155:            len = strlen(s);
                    156:            memcpy(lbuf->buf + lbuf->len, s, len);
                    157:            lbuf->len += len;
                    158:        }
                    159:     }
                    160:     lbuf->buf[lbuf->len] = '\0';
                    161:     va_end(ap);
                    162: }
                    163:
                    164: /*
                    165:  * Append strings to the buffer, expanding it as needed.
                    166:  */
                    167: void
                    168: #ifdef __STDC__
                    169: lbuf_append(struct lbuf *lbuf, ...)
                    170: #else
                    171: lbuf_append(lbuf, va_alist)
                    172:        struct lbuf *lbuf;
                    173:        va_dcl
                    174: #endif
                    175: {
                    176:     va_list ap;
                    177:     int len = 0;
                    178:     char *s;
                    179:
                    180: #ifdef __STDC__
                    181:     va_start(ap, lbuf);
                    182: #else
                    183:     va_start(ap);
                    184: #endif
                    185:     while ((s = va_arg(ap, char *)) != NULL)
                    186:        len += strlen(s);
                    187:     va_end(ap);
                    188:
                    189:     /* Expand buffer as needed. */
                    190:     if (lbuf->len + len >= lbuf->size) {
                    191:        do {
                    192:            lbuf->size += 256;
                    193:        } while (lbuf->len + len >= lbuf->size);
                    194:        lbuf->buf = erealloc(lbuf->buf, lbuf->size);
                    195:     }
                    196:
                    197: #ifdef __STDC__
                    198:     va_start(ap, lbuf);
                    199: #else
                    200:     va_start(ap);
                    201: #endif
                    202:     /* Append each string. */
                    203:     while ((s = va_arg(ap, char *)) != NULL) {
                    204:        len = strlen(s);
                    205:        memcpy(lbuf->buf + lbuf->len, s, len);
                    206:        lbuf->len += len;
                    207:     }
                    208:     lbuf->buf[lbuf->len] = '\0';
                    209:     va_end(ap);
                    210: }
                    211:
                    212: /*
                    213:  * Print the buffer with word wrap based on the tty width.
                    214:  * The lbuf is reset on return.
                    215:  */
                    216: void
                    217: lbuf_print(lbuf)
                    218:     struct lbuf *lbuf;
                    219: {
                    220:     char *cp;
                    221:     int i, have, contlen;
                    222:     static int cols = -1;
                    223:
                    224:     if (cols == -1)
                    225:        cols = get_ttycols();
                    226:     contlen = lbuf->continuation ? 2 : 0;
                    227:
                    228:     /* For very small widths just give up... */
                    229:     if (cols <= lbuf->indent + contlen + 20) {
                    230:        puts(lbuf->buf);
                    231:        goto done;
                    232:     }
                    233:
                    234:     /*
                    235:      * Print the buffer, splitting the line as needed on a word
                    236:      * boundary.
                    237:      */
                    238:     cp = lbuf->buf;
                    239:     have = cols;
                    240:     while (cp != NULL && *cp != '\0') {
                    241:        char *ep = NULL;
                    242:        int need = lbuf->len - (int)(cp - lbuf->buf);
                    243:
                    244:        if (need > have) {
                    245:            have -= contlen;            /* subtract for continuation char */
                    246:            if ((ep = memrchr(cp, ' ', have)) == NULL)
                    247:                ep = memchr(cp + have, ' ', need - have);
                    248:            if (ep != NULL)
                    249:                need = (int)(ep - cp);
                    250:        }
                    251:        if (cp != lbuf->buf) {
                    252:            /* indent continued lines */
                    253:            for (i = 0; i < lbuf->indent; i++)
                    254:                putchar(' ');
                    255:        }
                    256:        fwrite(cp, need, 1, stdout);
                    257:        cp = ep;
                    258:
                    259:        /*
                    260:         * If there is more to print, reset have, incremement cp past
                    261:         * the whitespace, and print a line continuaton char if needed.
                    262:         */
                    263:        if (cp != NULL) {
                    264:            have = cols - lbuf->indent;
                    265:            do {
                    266:                cp++;
                    267:            } while (isspace((unsigned char)*cp));
                    268:            if (lbuf->continuation) {
                    269:                putchar(' ');
                    270:                putchar(lbuf->continuation);
                    271:            }
                    272:        }
                    273:        putchar('\n');
                    274:     }
                    275:
                    276: done:
                    277:     lbuf->len = 0;             /* reset the buffer for re-use. */
                    278: }