OSSP CVS Repository

ossp - ossp-pkg/path/path_util.c 1.3
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/path/path_util.c 1.3
/*
**  OSSP path - Filesystem Path Manipulation
**  Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP path, a filesystem path manipulation library
**  which can be found at http://www.ossp.org/pkg/lib/path/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  path_util.c: utility functions
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "path.h"
#include "path_util.h"

/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */
int path_mvxprintf(int (*output)(void *ctx, const char *buffer, size_t bufsize), void *ctx, const char *format, va_list ap)
{
    /* sufficient integer buffer: <available-bits> x log_10(2) + safety */
    char ibuf[((sizeof(int)*8)/3)+10];
    char libuf[((sizeof(long)*8)/3)+10];
    char *cp;
    char c;
    int d;
    long ld;
    int n;
    int bytes;
    int islong;

    if (format == NULL || ap == NULL)
        return -1;
    bytes = 0;
    while (*format != '\0') {
        if (*format == '%') {
            c = *(format+1);
            islong = 0;
            if (c == 'l') {
                islong = 1;
                format++;
                c = *(format+1);
            }
            if (c == '%') {
                /* expand "%%" */
                cp = &c;
                n = sizeof(char);
            }
            else if (c == 'c') {
                /* expand "%c" */
                c = (char)va_arg(ap, int);
                cp = &c;
                n = sizeof(char);
            }
            else if (c == 's') {
                /* expand "%s" */
                if ((cp = (char *)va_arg(ap, char *)) == NULL)
                    cp = "(null)";
                n = strlen(cp);
            }
            else if (c == 'd') {
                /* expand "%d" */
                if (islong) {
                    ld = (long)va_arg(ap, long);
#ifdef HAVE_SNPRINTF
                    snprintf(libuf, sizeof(libuf), "%ld", ld); /* explicitly secure */
#else
                    sprintf(libuf, "%ld", ld);                 /* implicitly secure */
#endif
                    cp = libuf;
                }
                else {
                    d = (int)va_arg(ap, int);
#ifdef HAVE_SNPRINTF
                    snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */
#else
                    sprintf(ibuf, "%d", d);                /* implicitly secure */
#endif
                    cp = ibuf;
                }
                n = strlen(cp);
            }
            else {
                /* any other "%X" */
                cp = (char *)format;
                n  = 2;
            }
            format += 2;
        }
        else {
            /* plain text */
            cp = (char *)format;
            if ((format = strchr(cp, '%')) == NULL)
                format = strchr(cp, '\0');
            n = format - cp;
        }
        /* perform output operation */
        if (output != NULL)
            if ((n = output(ctx, cp, n)) == -1)
                break;
        bytes += n;
    }
    return bytes;
}

/* output callback function context for path_mvsnprintf() */
typedef struct {
    char *bufptr;
    size_t buflen;
} path_mvsnprintf_cb_t;

/* output callback function for path_mvsnprintf() */
static int path_mvsnprintf_cb(void *_ctx, const char *buffer, size_t bufsize)
{
    path_mvsnprintf_cb_t *ctx = (path_mvsnprintf_cb_t *)_ctx;

    if (bufsize > ctx->buflen)
        return -1;
    memcpy(ctx->bufptr, buffer, bufsize);
    ctx->bufptr += bufsize;
    ctx->buflen -= bufsize;
    return bufsize;
}

/* minimal vsnprintf(3) variant which supports %{c,s,d} only */
int path_mvsnprintf(char *buffer, size_t bufsize, const char *format, va_list ap)
{
    int n;
    path_mvsnprintf_cb_t ctx;

    if (format == NULL || ap == NULL)
        return -1;
    if (buffer != NULL && bufsize == 0)
        return -1;
    if (buffer == NULL)
        /* just determine output length */
        n = path_mvxprintf(NULL, NULL, format, ap);
    else {
        /* perform real output */
        ctx.bufptr = buffer;
        ctx.buflen = bufsize;
        n = path_mvxprintf(path_mvsnprintf_cb, &ctx, format, ap);
        if (n != -1 && ctx.buflen == 0)
            n = -1;
        if (n != -1)
            *(ctx.bufptr) = '\0';
    }
    return n;
}

/* minimal snprintf(3) variant which supports %{c,s,d} only */
int path_msnprintf(char *buffer, size_t bufsize, const char *format, ...)
{
    int chars;
    va_list ap;

    /* pass through to va_list based variant */
    va_start(ap, format);
    chars = path_mvsnprintf(buffer, bufsize, format, ap);
    va_end(ap);

    return chars;
}

/* minimal vasnprintf(3) variant which supports %{c,s,d} only */
char *path_mvasnprintf(const char *format, va_list ap)
{
    char *buffer;
    size_t bufsize;
    va_list apbak;

    apbak = ap;
    if ((bufsize = path_mvsnprintf(NULL, -1, format, ap)) == -1)
        return NULL;
    if ((buffer = malloc(bufsize+1)) == NULL)
        return NULL;
    ap = apbak;
    if ((bufsize = path_mvsnprintf(buffer, bufsize, format, ap)) == -1) {
        free(buffer);
        return NULL;
    }
    return buffer;
}

/* minimal asnprintf(3) variant which supports %{c,s,d} only */
char *path_masnprintf(const char *format, ...)
{
    char *buffer;
    va_list ap;

    /* pass through to va_list based variant */
    va_start(ap, format);
    buffer = path_mvasnprintf(format, ap);
    va_end(ap);

    return buffer;
}


CVSTrac 2.0.1