sos-code-article7/userland/stdarg.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;
}