/*
* 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 <matthias.andree@gmx.de>.
* 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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/** 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
syntax highlighted by Code2HTML, v. 0.9.1