ossp-pkg/path/path_util.c
/*
** 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;
}