Admin Panel
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <math.h>
#include <float.h>
#include "stdio.h"
// a union to handle the
union _d_bits {
double d;
struct {
unsigned sign :1;
unsigned exp :11;
unsigned frac0 :20;
unsigned frac1 :32;
} b;
unsigned u;
};
#ifdef FULL_SPECIFIERS
extern unsigned char *__decimalpoint;
#endif
extern int __vwfprintf_total_size(FILE *stream, const wchar_t *fmt, va_list args);
/* a little macro to make life easier */
#define OUT(c) do { \
putc((c >> 24),stream); \
putc((c >> 16),stream); \
putc((c >> 8),stream); \
putc((c ),stream); \
outcount += 4; \
}while(0)
#define MINFLOATSIZE (DBL_DIG+3)
#define MININTSIZE (sizeof(unsigned long long)*CHAR_BIT/3+1)
#define MINPOINTSIZE (sizeof(void *)*CHAR_BIT/4+1)
#define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
(MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
(MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
/**
* '#'
* Used with o, exponent or X specifiers the value is preceeded with 0, 0x or 0X
* respectively for values different than zero.
* Used with a, A, e, E, f, F, g or G it forces the written output
* to contain a decimal point even if no more digits follow.
* By default, if no digits follow, no decimal point is written.
*/
#define ALTERNATEFLAG 1 /* '#' is set */
/**
* '0'
* Left-pads the number with zeroes (0) instead of spaces when padding is specified
* (see width sub-specifier).
*/
#define ZEROPADFLAG 2 /* '0' is set */
/**
* '-'
* Left-justify within the given field width;
* Right justification is the default (see width sub-specifier).
*/
#define LALIGNFLAG 4 /* '-' is set */
/**
* ' '
* If no sign is going to be written, a blank space is inserted before the value.
*/
#define BLANKFLAG 8 /* ' ' is set */
/**
* '+'
* Forces to preceed the result with a plus or minus sign (+ or -) even for positive numbers.
* By default, only negative numbers are preceded with a - sign.
*/
#define SIGNFLAG 16 /* '+' is set */
static const char flagc[] = { '#', '0', '-', ' ', '+' };
/**
* Set if an explicit precision is given.
*/
#define HAS_PRECI 32
extern unsigned __ulldivus(unsigned long long * llp, unsigned short n);
/**
* Differs from vfprintf such that it returns total number of bytes that
* would've been written if there were sufficient space in file.
* Required for vsnprintf
*/
int __vwfprintf_total_size(FILE *stream, const wchar_t *format, va_list args) {
size_t outcount = 0;
__STDIO_LOCK(stream);
// /* optimize unbuffered write-only files */
// if ((stream->_flags & (__SWO | __SNBF)) == (__SWO | __SNBF)) {
// return ___vfprintf_total_size(stream, format, args);
// }
while (*format) {
if (*format == '%') {
static const char lowertabel[] = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
static const char uppertabel[] = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
short width = 0;
unsigned short preci = 0x7fff;
short flags = 0; /* Specifications */
char type, subtype = 'i';
char buffer1[2]; /* Signs and that like */
char buffer[REQUIREDBUFFER]; /* The body */
char *buffer2 = buffer; /* So we can set this to any other strings */
size_t size1 = 0, size2 = 0; /* How many chars in buffer? */
const wchar_t *ptr = format + 1; /* pointer to format string */
unsigned short i, pad; /* Some temporary variables */
do /* read flags */
for (i = 0; i < sizeof(flagc); i++)
if (flagc[i] == *ptr) {
flags |= 1 << i;
ptr++;
break;
} while (i < sizeof(flagc));
if (*ptr == '*') /* read width from arguments */
{
signed int a;
ptr++;
a = va_arg(args, signed int);
if (a < 0) {
flags |= LALIGNFLAG;
width = -a;
} else
width = a;
} else {
while (isdigit(*ptr))
width = width * 10 + (*ptr++ - '0');
}
if (*ptr == '.') {
flags |= HAS_PRECI;
ptr++;
if (*ptr == '*') /* read precision from arguments */
{
signed int a;
ptr++;
a = va_arg(args, signed int);
if (a >= 0)
preci = a;
} else {
preci = 0;
while (isdigit(*ptr))
preci = preci * 10 + (*ptr++ - '0');
}
}
if (*ptr == 'h' || *ptr == 'l' || *ptr == 'L' || *ptr == 'j'
|| *ptr == 'z' || *ptr == 't') {
subtype = *ptr++;
if (*ptr == 'h' || *ptr == 'l')
++ptr, ++subtype;
} else
subtype = 0;
type = *ptr++;
switch (type) {
case 'd':
case 'i':
case 'o':
case 'p':
case 'u':
case 'x':
case 'X': {
unsigned long long v;
const char *tabel;
int base;
if (type == 'p') {
subtype = 'l'; /* This is written as %#lx */
type = 'x';
flags |= ALTERNATEFLAG;
}
if (type == 'd' || type == 'i') /* These are signed */
{
signed long long v2;
if (subtype == 'l')
v2 = va_arg(args, signed long);
else if (subtype == 'm' || subtype == 'j')
v2 = va_arg(args, signed long long);
else
v2 = va_arg(args, signed int);
if (subtype == 'h')
v2 &= 0xffff;
else if (subtype == 'i')
v2 &= 0xff;
if (v2 < 0 || (subtype == 'h' && (short)v2 < 0) || (subtype == 'i' && (char)v2 < 0)) {
buffer1[size1++] = '-';
v = -v2;
} else {
if (flags & SIGNFLAG)
buffer1[size1++] = '+';
else if (flags & BLANKFLAG)
buffer1[size1++] = ' ';
v = v2;
}
} else /* These are unsigned */
{
if (subtype == 'l')
v = va_arg(args, unsigned long);
else if (subtype == 'm' || subtype == 'j')
v = va_arg(args, unsigned long long);
else
v = va_arg(args, unsigned int);
if (subtype == 'h')
v &= 0xffff;
else if (subtype == 'i')
v &= 0xff;
if (flags & ALTERNATEFLAG) {
if (type == 'o') {
if (!preci || v)
buffer1[size1++] = '0';
} else if ((type == 'x' || type == 'X') && v) {
buffer1[size1++] = '0';
buffer1[size1++] = type;
}
}
}
buffer2 = &buffer[sizeof(buffer)]; /* Calculate body string */
base = type == 'x' || type == 'X' ? 16 : (type == 'o' ? 8 : 10);
tabel = type != 'X' ? lowertabel : uppertabel;
do {
*--buffer2 = tabel[__ulldivus(&v, base)];
size2++;
} while (v);
if (preci == 0x7fff) /* default */
preci = 0;
else
flags &= ~ZEROPADFLAG;
break;
}
case 'c':
if (subtype == 'l')
*buffer2 = va_arg(args, long);
else
*buffer2 = va_arg(args, int);
size2 = 1;
preci = 0;
break;
case 's':
buffer2 = va_arg(args, char *);
size2 = strlen(buffer2);
size2 = size2 <= preci ? size2 : preci;
preci = 0;
break;
#ifdef FULL_SPECIFIERS
case 'a':
case 'A':
case 'f':
case 'e':
case 'E':
case 'g':
case 'G': {
union _d_bits d;
short exponent = 0;
char sign = 0;
const char * infnan = 0;
char pad = (flags & ZEROPADFLAG) ? '0' : ' ';
if (type == 'f' || type == 'F')
type = 0;
d = va_arg(args, union _d_bits);
// check for negative number and set the sign char if necessary
if (d.b.sign) {
d.b.sign = 0;
sign = '-';
} else if (flags & SIGNFLAG)
sign = '+';
else if (flags & BLANKFLAG)
sign = ' ';
// check for inf/nan
if (d.b.exp == 0x7ff) {
if (d.b.frac0 || d.b.frac1) {
infnan = "NaN";
sign = 0;
} else {
infnan = "inf";
}
width -= 3;
}
{
short pos;
unsigned x, y;
// count of digts:
// f, F : all digits before dot, preci digits behind. = 1 + preci, add exponent if > 0
// e, E : one digit before dot, preci digits behind dot = 1 + preci
// g, G : preci digits total
int startPos = 1; // first digit
short stopPos; // behind last digit
short leading = 1; // digits until dot is inserted
short dotZero = 0; // insert zeroes after dot
short postZero = 0; // append zeroes at end
short killZero = 0; // kill trailing zeroes
// real number
if (!infnan) {
if (type != 'a' && type != 'A') {
if (preci == 0x7fff) /* old default */
preci = 6; /* new default */
stopPos = preci + 1;
// compute exponent - a tad slow but ok
if (d.u || d.b.frac1) {
if (d.d >= 1) {
while (d.d >= 10000000000) {
d.d *= 0.0000000001;
exponent += 10;
}
while (d.d >= 10) {
d.d *= 0.1;
++exponent;
}
} else {
while (d.d < 0.0000000001) {
d.d *= 10000000000;
exponent -= 10;
}
while (d.d < 1) {
d.d *= 10;
--exponent;
}
}
}
while ((int) d.d > 9) {
d.d /= 10;
++exponent;
}
// convert g into e or f
if (type == 'g' || type == 'G') {
int limit = preci + 4;
--preci;
if (preci >= exponent && exponent >= 0) {
type = 0;
preci -= exponent;
} else if (exponent < 0
&& limit + exponent + 1 > preci) {
type = 0;
preci -= exponent;
} else {
type = 'e';
}
stopPos = preci + 1;
if (!(flags & ALTERNATEFLAG))
killZero = 1;
}
// fill it with digits
buffer[0] = '0';
pos = 1;
if (type == 0) { // f, F
if (exponent >= 0) {
leading += exponent;
stopPos += exponent + 1;
} else {
dotZero = -exponent - 1;
buffer[1] = '0';
if (dotZero > preci) {
dotZero = preci;
buffer[2] = '0'; // mandatory - uninitialized values may break rounding
pos = 3;
} else
pos = 2;
stopPos -= dotZero - 1;
}
} else {
++stopPos; // add one for leading digit
}
if (stopPos >= REQUIREDBUFFER) {
postZero = stopPos - REQUIREDBUFFER + 1;
if (type == 0 && postZero > preci)
postZero = preci;
stopPos = REQUIREDBUFFER - 1;
}
// compute the digits + one more for rounding
for (; pos < stopPos; ++pos) {
int z = (int) d.d;
if (z) {
d.d = (d.d - z) * 10;
if (d.d <= -0.1) {
--z;
d.d += 10;
}
} else
d.d *= 10;
buffer[pos] = (char) ('0' + z);
}
// round up
if (d.d >= 5.) {
--pos;
for (; pos >= startPos; --pos) {
if (++buffer[pos] <= '9')
break;
buffer[pos] = '0';
}
// overflow
if (pos <= startPos) {
if (type != 0) {
if (pos < startPos) {
startPos = pos;
buffer[pos] = '1';
}
++exponent;
--stopPos;
} else if (type == 0) {
if (exponent < 0) {
if (dotZero > 0) {
startPos = 0;
--dotZero;
}
} else if (pos < startPos ){
startPos = pos;
buffer[pos] = '1';
++leading;
}
}
}
}
} else {
if (preci == 0x7fff) /* old default */
preci = 0; /* new default */
if (!(flags & HAS_PRECI)) killZero = 1;
// 'a' 'A'
OUT('0');
OUT(type + 'X' - 'A');
if (!d.b.exp) {
exponent = x = y = 0;
} else {
exponent = d.b.exp - 1023;
x = d.b.frac0;
y = d.b.frac1;
buffer[0] = '1';
startPos = 0;
if (HAS_PRECI)
++preci;
}
stopPos = 1;
{unsigned j; for (j = 16;j <= 28; j += 12) {
{int i; for (i = j; i >= 0; i -= 4) {
unsigned c = (x >> i) & 0xf;
x -= c << i;
if (c > 9)
c += type - 10;
else
c += '0';
buffer[stopPos++] = c;
if (!x && !y && stopPos >= preci)
break;
}}
if (!y && stopPos >= preci)
break;
x = y;
y = 0;
}}
type += 'P' - 'A';
}
// kill trailing zeroes
if (killZero != 0) {
int stop = stopPos - 1;
while (stop > startPos) {
if (buffer[stop] != '0')
break;
if (type == 0 && stop - startPos == exponent)
break;
--stop;
}
if (type != 0 && stop - startPos + 5 < width)
width = stop - startPos + preci + 5;
else if (type == 0) {
if (stop + 1 != stopPos
&& stop - startPos == exponent)
++width;
}
stopPos = stop + 1;
}
// calculate width
if (type != 0) {
// 1e+00
width -= 5 + stopPos - startPos + postZero;
if (exponent < -99) {
--width;
if (exponent < -999)
--width;
} else if (exponent > 99) {
--width;
if (exponent > 999)
--width;
}
} else {
// 123.456 -> exponent = 2, preci = 3
if (leading > stopPos - startPos)
width -= leading + dotZero + postZero;
else
width -= stopPos - startPos + dotZero
+ postZero;
}
// dot?
if (preci > 0 || (flags & ALTERNATEFLAG) != 0)
--width;
}
if (sign != 0)
--width;
// pad on left side
if ((flags & LALIGNFLAG) == 0)
while (--width >= 0)
OUT(pad);
// output sign if set
if (sign != 0)
OUT(sign);
if (infnan) {
// output inf/nan
OUT(infnan[0]);
OUT(infnan[1]);
OUT(infnan[2]);
} else {
// leading digits
while (leading-- > 0 && startPos < stopPos)
OUT(buffer[startPos++]);
// more leading digits than buffer size
while (leading-- >= 0)
OUT('0');
// output dot
if (startPos < stopPos || dotZero != 0 || postZero != 0
|| (flags & ALTERNATEFLAG) != 0)
OUT(__decimalpoint[0]);
// output zeroes behind dot not in buffer
while (dotZero-- > 0)
OUT('0');
// digits somewhere behind dot
for (; startPos < stopPos; ++startPos)
OUT(buffer[startPos]);
// output trailing zeroes not in buffer
while (postZero-- > 0)
OUT('0');
if (type != 0) {
int xout;
OUT(type);
if (exponent < 0) {
OUT('-');
exponent = -exponent;
} else
OUT('+');
--width;
xout = 0;
if (exponent > 999) {
int z = exponent / 1000;
OUT('0' + z);
exponent -= z * 1000;
--width;
xout = 1;
}
if (xout || exponent > 99) {
int z = exponent / 100;
OUT('0' + z);
exponent -= z * 100;
--width;
xout = 1;
}
if (xout || exponent > 9 || (type | 0x20) != 'p' ) {
int z = exponent / 10;
OUT('0' + z);
exponent -= z * 10;
--width;
}
OUT('0' + exponent);
--width;
}
}
// pad on right side
if ((flags & LALIGNFLAG) != 0)
while (--width >= 0)
OUT(' ');
/* Everything already done */
format = ptr;
continue;
}
}
#endif
case '%':
buffer2 = "%";
size2 = 1;
preci = 0;
break;
case 'n':
*va_arg(args, int *) = outcount;
width = preci = 0;
break;
default:
if (!type)
ptr--; /* We've gone too far - step one back */
buffer2 = (char *) format;
size2 = ptr - format;
width = preci = 0;
break;
}
if (flags & HAS_PRECI) {
if (size2 == 1 && !preci && buffer2[0] == '0')
size2 = 0;
}
pad = size1 + (size2 >= preci ? size2 : preci); /* Calculate the number of characters */
pad = pad >= width ? 0 : width - pad; /* and the number of resulting pad bytes */
if (flags & ZEROPADFLAG) /* print sign and that like */
for (i = 0; i < size1; i++)
OUT(buffer1[i]);
if (!(flags & LALIGNFLAG)) /* Pad left */
for (i = 0; i < pad; i++)
OUT(flags&ZEROPADFLAG?'0':' ');
if (!(flags & ZEROPADFLAG)) /* print sign if not zero padded */
for (i = 0; i < size1; i++)
OUT(buffer1[i]);
for (i = size2; i < preci; i++) /* extend to precision */
OUT('0');
for (i = 0; i < size2; i++) /* print body */
OUT(buffer2[i]);
if (flags & LALIGNFLAG) /* Pad right */
for (i = 0; i < pad; i++)
OUT(' ');
format = ptr;
} else
OUT(*format++);
}
__STDIO_UNLOCK(stream);
return outcount;
}
#ifdef TESTME
int main(int argc, char ** argv) {
double d;
printf("%-20.0f|\n", 0.0);
printf("%-20.0e\n", 0.0);
printf("%-20.1g\n", 0.0);
printf("%#20.0f\n", 0.0);
printf("%#20.0e\n", 0.0);
printf("%#20.1g\n", 0.0);
d = 1.2345678902468e-13;
for (int i = 0; i < 24; ++i) {
d *= 10;
printf("%20.7f\n", d);
}
d = 1.2345678902468e-13;
for (int i = 0; i < 24; ++i) {
d *= 10;
printf("%20.7g\n", d);
}
d = 1.2345678902468e-13;
for (int i = 0; i < 24; ++i) {
d *= 10;
printf("%20.7e\n", d);
}
return 0;
}
#endif