245 lines
5.0 KiB
C
245 lines
5.0 KiB
C
/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf)
|
|
Copyright (C) 2003 The KOS Team
|
|
Copyright (C) 1999 Free Software Foundation
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
USA.
|
|
*/
|
|
#include <string.h>
|
|
|
|
#include "stdarg.h"
|
|
|
|
|
|
/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to
|
|
them for having kindly allowed me to do so. */
|
|
int vsnprintf(char *buff, size_t len, const char * format, va_list ap)
|
|
{
|
|
int i, result;
|
|
int fmt_modifiers = 0;
|
|
int prefix_long = 0;
|
|
int prefix_long_long = 0;
|
|
|
|
if (!buff || !format || (len < 0))
|
|
return -1;
|
|
|
|
#define PUTCHAR(thechar) \
|
|
do { \
|
|
if (result < len-1) \
|
|
*buff++ = (thechar); \
|
|
result++; \
|
|
} while (0)
|
|
|
|
result = 0;
|
|
for(i=0 ; format[i] != '\0' ; i++)
|
|
{
|
|
if (!fmt_modifiers && (format[i] != '%'))
|
|
{
|
|
PUTCHAR(format[i]);
|
|
continue;
|
|
}
|
|
|
|
switch (format[i])
|
|
{
|
|
case '%':
|
|
if (fmt_modifiers)
|
|
{
|
|
PUTCHAR('%');
|
|
fmt_modifiers = 0;
|
|
break;
|
|
}
|
|
|
|
fmt_modifiers = 1;
|
|
prefix_long = 0;
|
|
prefix_long_long = 0;
|
|
break;
|
|
|
|
case 'l':
|
|
if (prefix_long)
|
|
prefix_long_long = 1;
|
|
else
|
|
prefix_long = 1;
|
|
break;
|
|
|
|
case 'u':
|
|
{
|
|
if (! prefix_long_long)
|
|
{
|
|
unsigned int integer = va_arg(ap,unsigned int);
|
|
int cpt2 = 0;
|
|
char buff_int[16];
|
|
|
|
do {
|
|
int m10 = integer%10;
|
|
buff_int[cpt2++]=(char)('0'+ m10);
|
|
integer=integer/10;
|
|
} while(integer!=0);
|
|
|
|
for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--)
|
|
PUTCHAR(buff_int[cpt2]);
|
|
}
|
|
else
|
|
{
|
|
unsigned long long int integer
|
|
= va_arg(ap,unsigned long long int);
|
|
int cpt2 = 0;
|
|
char buff_int[32];
|
|
|
|
do {
|
|
int m10 = integer%10;
|
|
buff_int[cpt2++]=(char)('0'+ m10);
|
|
integer=integer/10;
|
|
} while(integer!=0);
|
|
|
|
for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--)
|
|
PUTCHAR(buff_int[cpt2]);
|
|
}
|
|
}
|
|
fmt_modifiers = 0;
|
|
break;
|
|
|
|
case 'i':
|
|
case 'd':
|
|
{
|
|
if (! prefix_long_long)
|
|
{
|
|
int integer = va_arg(ap,int);
|
|
int cpt2 = 0;
|
|
char buff_int[16];
|
|
|
|
if (integer<0)
|
|
PUTCHAR('-');
|
|
/* Ne fait pas integer = -integer ici parce que INT_MIN
|
|
n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */
|
|
|
|
do {
|
|
int m10 = integer%10;
|
|
m10 = (m10 < 0)? -m10:m10;
|
|
buff_int[cpt2++]=(char)('0'+ m10);
|
|
integer=integer/10;
|
|
} while(integer!=0);
|
|
|
|
for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--)
|
|
PUTCHAR(buff_int[cpt2]);
|
|
}
|
|
else
|
|
{
|
|
long long int integer = va_arg(ap,long long int);
|
|
int cpt2 = 0;
|
|
char buff_int[32];
|
|
|
|
if (integer<0)
|
|
PUTCHAR('-');
|
|
/* Ne fait pas integer = -integer ici parce que INT_MIN
|
|
n'a pas d'equivalent positif (int = [-2^63, 2^63-1]) */
|
|
|
|
do {
|
|
int m10 = integer%10;
|
|
m10 = (m10 < 0)? -m10:m10;
|
|
buff_int[cpt2++]=(char)('0'+ m10);
|
|
integer=integer/10;
|
|
} while(integer!=0);
|
|
|
|
for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--)
|
|
PUTCHAR(buff_int[cpt2]);
|
|
}
|
|
}
|
|
fmt_modifiers = 0;
|
|
break;
|
|
|
|
case 'c':
|
|
{
|
|
int value = va_arg(ap,int);
|
|
PUTCHAR((char)value);
|
|
fmt_modifiers = 0;
|
|
break;
|
|
}
|
|
|
|
case 's':
|
|
{
|
|
char *string = va_arg(ap,char *);
|
|
if (! string)
|
|
string = "(null)";
|
|
for( ; *string != '\0' ; string++)
|
|
PUTCHAR(*string);
|
|
fmt_modifiers = 0;
|
|
break;
|
|
}
|
|
|
|
case 'p':
|
|
PUTCHAR('0');
|
|
PUTCHAR('x');
|
|
case 'x':
|
|
{
|
|
unsigned long long int hexa;
|
|
unsigned long long int nb;
|
|
int i, had_nonzero = 0;
|
|
|
|
if (prefix_long_long)
|
|
hexa = va_arg(ap,unsigned long long int);
|
|
else
|
|
hexa = va_arg(ap,unsigned int);
|
|
|
|
for(i=0 ; i < 16 ; i++)
|
|
{
|
|
nb = (unsigned long long int)(hexa << (i*4));
|
|
nb = (nb >> 60) & 0xf;
|
|
// Skip the leading zeros
|
|
if (nb == 0)
|
|
{
|
|
if (had_nonzero)
|
|
PUTCHAR('0');
|
|
}
|
|
else
|
|
{
|
|
had_nonzero = 1;
|
|
if (nb < 10)
|
|
PUTCHAR('0'+nb);
|
|
else
|
|
PUTCHAR('a'+(nb-10));
|
|
}
|
|
}
|
|
if (! had_nonzero)
|
|
PUTCHAR('0');
|
|
}
|
|
fmt_modifiers = 0;
|
|
break;
|
|
|
|
default:
|
|
PUTCHAR('%');
|
|
if (prefix_long)
|
|
PUTCHAR('l');
|
|
if (prefix_long_long)
|
|
PUTCHAR('l');
|
|
PUTCHAR(format[i]);
|
|
fmt_modifiers = 0;
|
|
}
|
|
}
|
|
|
|
*buff = '\0';
|
|
return result;
|
|
}
|
|
|
|
|
|
int snprintf(char * buff, size_t len, const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
len = vsnprintf(buff, len, format, ap);
|
|
va_end(ap);
|
|
|
|
return len;
|
|
}
|