/* * poor man's snprintf() - for systems which don't have their own * * This version of snprintf() currently supports only %s, %c, %d, %u, * %ld, %lu, %li, %i. It supports the 0, + and width modifiers only for decimal * output (%[l]{d|u|i}). * * Copyright (c) Cornelius Krasel 2000. * Modified by Matthias Andree . * Modifications (C)opyright 2002 - 2003. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "leafnode.h" #ifndef HAVE_WORKING_SNPRINTF #include #include #include #include /** format unsigned value u into p */ static void fmtu(char *p, unsigned long u) { unsigned int len = 0; unsigned long i = u, ni; unsigned char b[22]; do { ni = i / 10; b[len++] = i - 10*ni; i = ni; } while (i); while (len) { *p++ = "0123456789"[b[--len]]; } *p = '\0'; } /** format signed value s into p, prefix asign if its nonzero and the * value is positive. asign is usually '+' or ' '. */ static inline void fmts(char *p, long s, char asign) { if (s < 0) { *p++ = '-'; fmtu(p, -s); } else { if (asign) *p++ = asign; fmtu(p, s); } } int ln_vsnprintf(char *str, size_t n, const char *format, va_list ap) { const char *p; char *q; int flag = 0; size_t width = 0; char fill = ' '; int lflag = 0; /* checking for longs */ int asign = 0; /* always show sign */ size_t i = 1; /* because the terminating \0 also counts */ size_t len, olen; char buf[30]; /* buffer for converting longs and ints */ char *s; char c; p = format; q = str; while (p && *p) { if ((*p == '%') && !flag) { /* swallow the %, switch to % mode and initialize */ lflag = 0; flag = 1; asign = 0; /* can be 0, '+' or later ' ' (' ' is unimplemented) */ fill = ' '; width = 0; p++; } else if (flag) { /* % mode */ switch (*p) { case 's': case 'm': { if (*p == 's') s = va_arg(ap, char *); else s = strerror(errno); olen = len = strlen(s); if (len > (n - i)) len = n - i; *q = '\0'; strncat(q, s, len); p++; q += len; i += olen; flag = 0; break; } case 'u':{ unsigned long u; if (lflag) { u = va_arg(ap, unsigned long); } else { u = (unsigned long)va_arg(ap, unsigned int); } fmtu(buf, u); goto printdec; } case 'd': case 'i': { long l; if (lflag) { l = va_arg(ap, long); } else { l = (long)va_arg(ap, int); } fmts(buf, l, asign); printdec: olen = len = strlen(buf); if (width) { int off = !!asign; if (len < width) { switch (fill) { case ' ': memmove(buf + width - len, buf, len + 1); memset(buf, fill, width - len); break; case '0': memmove(buf + off + width - len, buf + off, len + 1 - off); memset(buf + off, fill, width - len); break; default: abort(); } } olen = len = strlen(buf); } if (len > (n - i)) len = n - i; *q = '\0'; strncat(q, buf, len); q += len; i += olen; flag = 0; p++; break; } case 'l':{ /* next argument will be long */ lflag = 1; p++; break; } case 'c':{ c = va_arg(ap, int); flag = 0; if (i < n) *q++ = c; i++; p++; break; } case '%':{ flag = 0; if (i < n) *q++ = *p++; i++; break; } case '0': if (fill == ' ' && width == 0) fill='0'; else width *= 10; p++; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': width = width * 10 + *p - '0'; p++; break; case '+': asign = '+'; p++; break; default: abort(); break; } } else { if (i < n) { *q++ = *p; } p++; i++; } } va_end(ap); *q = '\0'; return (i - 1); } int ln_snprintf(char *str, size_t n, const char *format, ...) { int r; va_list ap; va_start(ap, format); r = ln_vsnprintf(str, n, format, ap); va_end(ap); return r; } #endif