/* ** OSSP path - Filesystem Path Manipulation ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 The OSSP Project ** Copyright (c) 2002 Cable & Wireless Deutschland ** ** 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 #include #include #include #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: 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; }