RTL00ConsoleROM/lib/libc/libc.c
2016-09-26 17:55:41 +03:00

863 lines
22 KiB
C

#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#include <ctype.h>
#if defined (LIBC_GMTIME_R) || defined (LIBC_MKTIME)
#include <time.h>
#endif
#ifndef LIBC_FUNCTION_ATTRIBUTE
#define LIBC_FUNCTION_ATTRIBUTE
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTCHAR) || defined (LIBC_PUTC) || defined (LIBC_FPUTC) || defined (LIBC_PUTS) || defined (LIBC_FPUTS) || defined (LIBC_PRINTF) || defined (LIBC_FPRINTF) || defined (LIBC_WRITE)
#if defined (GCC_VERSION) || defined (__GNUC__)
ssize_t __attribute__((weak)) write_stdout(const void *buf __attribute__((unused)), size_t count){
return(count);
}
ssize_t __attribute__((weak, alias("write_stdout"))) write_stderr(const void *buf, size_t count);
// FILE *stdin = NULL;
FILE *stdout = write_stdout;
FILE *stderr = write_stderr;
#else
#warning no weak functions for stdio
FILE *stdout;
FILE *stderr;
#endif
#endif
#if defined (LIBC_ALL) || defined (LIBC_SNPRINTF) || defined (LIBC_VSNPRINTF)
struct _libc_snprintf_struct{
char *str;
size_t loc;
size_t maxlen;
}__attribute__((packed));
#endif
#if defined (LIBC_ALL) || defined (LIBC_SNPRINTF) || defined (LIBC_VSNPRINTF)
static int LIBC_FUNCTION_ATTRIBUTE _libc_cswrite(void *user, const void *buf, int count);
#endif
#if defined (LIBC_ALL) || defined (LIBC_PRINTF) || defined (LIBC_FPRINTF) || defined (LIBC_SNPRINTF) || defined (LIBC_VSNPRINTF)
typedef ssize_t(*stream_user_t)(void *user, const void *buf, size_t count);
#define _LIBC_PRINT_PAD_RIGHT 1
#define _LIBC_PRINT_PAD_ZERO 2
#define _LIBC_PRINT_BUF_LEN 32 // sellesse peavad kõik prinditavad numbrid ära mahtuma
typedef ssize_t(*stream_t)(const void *buf, size_t count);
static int LIBC_FUNCTION_ATTRIBUTE _libc_cvprintf(stream_t cb, void *user, const char *format, va_list ap);
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprints(stream_t cb, void *user, const char *string, int width, int pad);
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprinti(stream_t cb, void *user, int i, int b, int sg, int width, int pad, int letbase);
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprintl(stream_t cb, void *user, long long int i, int b, int sg, int width, int pad, int letbase);
static int LIBC_FUNCTION_ATTRIBUTE _libc_cwrite(stream_t cb, void *user, const void *buf, size_t count);
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTCHAR) || defined (LIBC_PRINTF)
int LIBC_FUNCTION_ATTRIBUTE putchar(int c){
return(fputc(c, stdout));
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTC)
int LIBC_FUNCTION_ATTRIBUTE putc(int c, FILE *stream){
return(fputc(c, stream));
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTCHAR) || defined (LIBC_PUTC) || defined (LIBC_FPUTC) || defined (LIBC_PRINTF) || defined (LIBC_FPRINTF)
int LIBC_FUNCTION_ATTRIBUTE fputc(int c, FILE *stream){
stream_t cb;
unsigned char _c;
cb = (stream_t)stream;
_c = c;
cb(&_c, 1);
return(c);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTS) || defined (LIBC_PRINTF)
int LIBC_FUNCTION_ATTRIBUTE puts(const char *s){
return(fputs(s, stdout));
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PUTS) || defined (LIBC_FPUTS) || defined (LIBC_PRINTF) || defined (LIBC_FPRINTF)
int LIBC_FUNCTION_ATTRIBUTE fputs(const char *s, FILE *stream){
stream_t cb;
int sl;
cb = (stream_t)stream;
for(sl = 0; s[sl]; sl++);
cb(s, sl);
cb("\n", 1);
return(sl);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PRINTF)
int LIBC_FUNCTION_ATTRIBUTE printf(const char *format, ...){
va_list ap;
int r;
va_start(ap, format);
r = _libc_cvprintf((stream_t)stdout, NULL, format, ap);
va_end(ap);
return(r);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_FPRINTF)
int LIBC_FUNCTION_ATTRIBUTE fprintf(FILE *stream, const char *format, ...){
va_list ap;
int r;
va_start(ap, format);
r = _libc_cvprintf((stream_t)stream, NULL, format, ap);
va_end(ap);
return(r);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_SNPRINTF)
int LIBC_FUNCTION_ATTRIBUTE snprintf(char *str, size_t size, const char *format, ...){
va_list ap;
int r;
struct _libc_snprintf_struct s;
s.str = str;
s.loc = 0;
s.maxlen = size;
va_start(ap, format);
r = _libc_cvprintf((stream_t)_libc_cswrite, &s, format, ap);
va_end(ap);
return(r);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_VSNPRINTF)
int LIBC_FUNCTION_ATTRIBUTE vsnprintf(char *str, size_t size, const char *format, va_list ap){
int r;
struct _libc_snprintf_struct s;
s.str = str;
s.loc = 0;
s.maxlen = size;
r = _libc_cvprintf((stream_t)_libc_cswrite, &s, format, ap);
return(r);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_SNPRINTF) || defined (LIBC_VSNPRINTF)
static int LIBC_FUNCTION_ATTRIBUTE _libc_cswrite(void *user, const void *buf, int count){
struct _libc_snprintf_struct *s;
int i;
s = (struct _libc_snprintf_struct *)user;
for(i = 0; (i < count) && (s->loc < s->maxlen); i++, s->loc++){
if((s->maxlen > 1) && (s->loc < (s->maxlen - 1)))s->str[s->loc] = ((char *)buf)[i];
}
if(s->maxlen){
if(s->loc < (s->maxlen - 1)){
s->str[s->loc] = 0;
}else{
s->str[s->maxlen - 1] = 0;
}
}
return(i);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_PRINTF) || defined (LIBC_FPRINTF) || defined (LIBC_SNPRINTF) || defined (LIBC_VSNPRINTF)
static int LIBC_FUNCTION_ATTRIBUTE _libc_cwrite(stream_t cb, void *user, const void *buf, size_t count){
stream_user_t cub;
if(user == NULL)return(cb(buf, count));
cub = (stream_user_t)cb;
return(cub(user, buf, count));
}
static int LIBC_FUNCTION_ATTRIBUTE _libc_cvprintf(stream_t cb, void *user, const char *format, va_list ap){
int width, pad, pc, l;
const char *s, *e;
char c;
pc = 0;
s = e = format;
for( ; *format != 0; format++){
e = format;
if(*format == '%'){
format++;
width = pad = 0;
if(*format == '\0')break;
if(*format == '%'){
pc += _libc_cwrite(cb, user, s, (e - s) + 1);
s = format + 1;
continue;
}
if(*format == '-'){
format++;
pad = _LIBC_PRINT_PAD_RIGHT;
}
while(*format == '0'){
format++;
pad |= _LIBC_PRINT_PAD_ZERO;
}
for( ; *format >= '0' && *format <= '9'; format++){
width *= 10;
width += *format - '0';
}
if(*format == 's'){
pc += _libc_cwrite(cb, user, s, (e - s));
s = va_arg(ap, char *);
pc += _libc_cprints(cb, user, s ? s : "(null)", width, pad);
s = format + 1;
continue;
}
l = 0;
while(*format == 'l'){
format++;
l++;
}
if(*format == 'd'){
pc += _libc_cwrite(cb, user, s, (e - s));
if(!l){
pc += _libc_cprinti(cb, user, va_arg(ap, int), 10, 1, width, pad, 'a');
}else if(l == 1){
pc += _libc_cprintl(cb, user, va_arg(ap, long int), 10, 1, width, pad, 'a');
}else{
pc += _libc_cprintl(cb, user, va_arg(ap, long long int), 10, 1, width, pad, 'a');
}
s = format + 1;
continue;
}
if(*format == 'b'){
pc += _libc_cwrite(cb, user, s, (e - s));
if(!l){
pc += _libc_cprinti(cb, user, va_arg(ap, unsigned int), 2, 0, width, pad, 'a');
}else if(l == 1){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long int), 2, 0, width, pad, 'a');
}else{
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long long int), 2, 0, width, pad, 'a');
}
s = format + 1;
continue;
}
if(*format == 'x'){
pc += _libc_cwrite(cb, user, s, (e - s));
if(!l){
pc += _libc_cprinti(cb, user, va_arg(ap, unsigned int), 16, 0, width, pad, 'a');
}else if(l == 1){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long int), 16, 0, width, pad, 'a');
}else{
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long long int), 16, 0, width, pad, 'a');
}
s = format + 1;
continue;
}
if(*format == 'X'){
pc += _libc_cwrite(cb, user, s, (e - s));
if(!l){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned int), 16, 0, width, pad, 'A');
}else if(l == 1){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long int), 16, 0, width, pad, 'A');
}else{
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long long int), 16, 0, width, pad, 'A');
}
s = format + 1;
continue;
}
if(*format == 'u'){
pc += _libc_cwrite(cb, user, s, (e - s));
if(!l){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned int), 10, 0, width, pad, 'a');
}else if(l == 1){
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long int), 10, 0, width, pad, 'a');
}else{
pc += _libc_cprintl(cb, user, va_arg(ap, unsigned long long int), 10, 0, width, pad, 'a');
}
s = format + 1;
continue;
}
if(*format == 'c'){
pc += _libc_cwrite(cb, user, s, (e - s));
c = va_arg(ap, int);
pc += _libc_cwrite(cb, user, &c, 1);
s = format + 1;
continue;
}
}
}
if(e >= s){
pc += _libc_cwrite(cb, user, s, (e - s) + 1);
}
return(pc);
}
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprints(stream_t cb, void *user, const char *string, int width, int pad){
int pc, sl, len;
const char *ptr;
char padchar;
pc = 0;
padchar = ' ';
if(width > 0){
len = 0;
for(ptr = string; *ptr; ++ptr) ++len;
if(len >= width)width = 0; else width -= len;
if(pad & _LIBC_PRINT_PAD_ZERO)padchar = '0';
}
if(!(pad & _LIBC_PRINT_PAD_RIGHT)){
for ( ; width > 0; width--){
pc += _libc_cwrite(cb, user, &padchar, 1);
}
}
for(sl = 0; string[sl]; sl++);
pc += _libc_cwrite(cb, user, string, sl);
for ( ; width > 0; --width) {
pc += _libc_cwrite(cb, user, &padchar, 1);
}
return(pc);
}
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprinti(stream_t cb, void *user, int i, int b, int sg, int width, int pad, int letbase){
char print_buf[_LIBC_PRINT_BUF_LEN], *s;
unsigned int u;
int t, neg, pc;
neg = pc = 0;
u = i;
if(i == 0){
print_buf[0] = '0';
print_buf[1] = '\0';
return(_libc_cprints(cb, user, print_buf, width, pad));
}
if(sg && (b == 10) && (i < 0)){
neg = 1;
u = -i;
}
s = print_buf + _LIBC_PRINT_BUF_LEN - 1;
*s = '\0';
while(u){
t = u % b;
if(t >= 10)t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if(neg){
if(width && (pad & _LIBC_PRINT_PAD_ZERO)){
pc += _libc_cwrite(cb, user, "-", 1);
width--;
}else{
*--s = '-';
}
}
return(pc + _libc_cprints(cb, user, s, width, pad));
}
// li -> i: workaround et oleks hetkel alati 4 baidine (unsigned long int)
// STM32 või ARM-C3 või vastav GCC ei oska 8 baidist arvu jagada
static int LIBC_FUNCTION_ATTRIBUTE _libc_cprintl(stream_t cb, void *user, long long int li, int b, int sg, int width, int pad, int letbase){
char print_buf[_LIBC_PRINT_BUF_LEN], *s;
unsigned long int u;
long int i;
int t, neg, pc;
neg = pc = 0;
i = li;
u = i;
if(i == 0){
print_buf[0] = '0';
print_buf[1] = '\0';
return(_libc_cprints(cb, user, print_buf, width, pad));
}
if(sg && (b == 10) && (i < 0)){
neg = 1;
u = -i;
}
s = print_buf + _LIBC_PRINT_BUF_LEN - 1;
*s = '\0';
while(u){
t = u % b;
if(t >= 10)t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if(neg){
if(width && (pad & _LIBC_PRINT_PAD_ZERO)){
pc += _libc_cwrite(cb, user, "-", 1);
width--;
}else{
*--s = '-';
}
}
return(pc + _libc_cprints(cb, user, s, width, pad));
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_WRITE)
ssize_t LIBC_FUNCTION_ATTRIBUTE write(int fd, const void *buf, size_t count){
stream_t cb;
if(fd == 1){
if(stdout != NULL){
cb = (stream_t)stdout;
return(cb(buf, count));
}
}else if(fd == 2){
if(stderr != NULL){
cb = (stream_t)stderr;
return(cb(buf, count));
}else if(stdout != NULL){
cb = (stream_t)stdout;
return(cb(buf, count));
}
}
return(0);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MEMCPY)
void LIBC_FUNCTION_ATTRIBUTE *memcpy(void *dest, const void *src, size_t n){
register char *_dest;
register const char *_src;
_dest = dest;
_src = src;
while(n-- > 0)*_dest++ = *_src++;
return(dest);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MEMMOVE)
void LIBC_FUNCTION_ATTRIBUTE *memmove(void *dest, const void *src, size_t n){
register char *_dest;
register const char *_src;
_dest = dest;
_src = src;
if(_src < _dest){ /* Moving from low mem to hi mem; start at end. */
for(_src += n, _dest += n; n; n--){
*--_dest = *--_src;
}
}else if(_src != _dest){ /* Moving from hi mem to low mem; start at beginning. */
for( ; n; n--){
*_dest++ = *_src++;
}
}
return(dest);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MEMCMP) || defined (LIBC_MEMMEM)
int LIBC_FUNCTION_ATTRIBUTE memcmp(const void *s1, const void *s2, size_t n){
register const unsigned char *str1;
register const unsigned char *str2;
str1 = (const unsigned char *)s1;
str2 = (const unsigned char *)s2;
while(n-- > 0){
if(*str1++ != *str2++)return str1[-1] < str2[-1] ? -1 : 1;
}
return(0);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MEMSET)
void LIBC_FUNCTION_ATTRIBUTE *memset(void *s, int c, size_t n){
register char *str = s;
while(n-- > 0)*str++ = c;
return(s);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MEMMEM)
void LIBC_FUNCTION_ATTRIBUTE *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen){
const char *begin;
const char *const last_possible = (const char *)haystack + haystacklen - needlelen;
if(needlelen == 0)return((void *)haystack);
if(haystacklen < needlelen)return(NULL);
for(begin = (const char *)haystack; begin <= last_possible; ++begin){
if(begin[0] == ((const char *)needle)[0] && !memcmp((const void *)&begin[1], (const void *)((const char *)needle + 1), needlelen - 1)){
return((void *)begin);
}
}
return(NULL);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRLEN)
size_t LIBC_FUNCTION_ATTRIBUTE strlen(const char *s){
register size_t n;
n = 0;
while(*s++)n++;
return(n);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRCHR)
char LIBC_FUNCTION_ATTRIBUTE *strchr(const char *s, int c){
for( ; *s != (char)c; s++)
if(*s == 0)return(0);
return((char *)s);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRSTR)
char LIBC_FUNCTION_ATTRIBUTE *strstr(const char *haystack, const char *needle){
register char *a, *b;
b = (char *)needle;
if(*b == 0)return((char *)haystack);
for( ; *haystack != 0; haystack += 1){
if(*haystack != *b)continue;
a = (char *)haystack;
while(1){
if(*b == 0)return((char *)haystack);
if(*a++ != *b++)break;
}
b = (char *)needle;
}
return(NULL);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRCMP)
int LIBC_FUNCTION_ATTRIBUTE strcmp(const char *s1, const char *s2){
for( ; *s1 == *s2; ++s1, ++s2)if(*s1 == 0)return(0);
return(*(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRNCMP)
int LIBC_FUNCTION_ATTRIBUTE strncmp(const char *s1, const char *s2, size_t n){
for( ; n > 0; s1++, s2++, n--){
if(*s1 == 0)return(0);
if(*s1 != *s2)return((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : 1);
}
return(0);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRCPY)
char LIBC_FUNCTION_ATTRIBUTE *strcpy(char *s1, const char *s2){
char *s;
s = s1;
while((*s++ = *s2++) != 0);
return(s1);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRNCPY)
char LIBC_FUNCTION_ATTRIBUTE *strncpy(char *s1, const char *s2, size_t n){
char *s;
s = s1;
if(n != 0){
do{
if((*s++ = *s2++) == 0){
while(--n != 0)*s++ = 0;
break;
}
}while(--n != 0);
}
return(s1);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRNCAT)
char LIBC_FUNCTION_ATTRIBUTE *strncat(char *s1, const char *s2, size_t n){
char *d = s1;
if (n != 0) {
while (*d != 0)d++;
do {
if ((*d = *s2++) == 0)break;
d++;
}
while (--n != 0);
*d = 0;
}
return s1;
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRCAT)
char LIBC_FUNCTION_ATTRIBUTE *strcat(char *s1, const char *s2){
char *d = s1;
while (*s1 != 0)s1++;
while ((*s1++ = *s2++) != '\0');
return d;
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRCASECMP)
int LIBC_FUNCTION_ATTRIBUTE strcasecmp(const char *s1, const char *s2){
for( ; tolower(*s1) == tolower(*s2); ++s1, ++s2)if(*s1 == 0)return(0);
return(tolower(*(unsigned char *)s1) < tolower(*(unsigned char *)s2) ? -1 : 1);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRNCASECMP)
int LIBC_FUNCTION_ATTRIBUTE strncasecmp(const char *s1, const char *s2, size_t n){
for( ; n > 0; s1++, s2++, n--){
if(*s1 == 0)return(0);
if(tolower(*s1) != tolower(*s2))return((tolower(*(unsigned char *)s1) < tolower(*(unsigned char *)s2)) ? -1 : 1);
}
return(0);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_ATOI)
int LIBC_FUNCTION_ATTRIBUTE atoi(const char *nptr){
register int num, neg;
register char c;
num = neg = 0;
c = *nptr;
while((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))c = *++nptr;
if(c == '-'){ /* get an optional sign */
neg = 1;
c = *++nptr;
}else if(c == '+'){
c = *++nptr;
}
while((c >= '0') && (c <= '9')){
num = (10 * num) + (c - '0');
c = *++nptr;
}
if(neg)return(0 - num);
return(num);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRTOL)
long int LIBC_FUNCTION_ATTRIBUTE strtol(const char *nptr, char **endptr, int base){
return(strtoll(nptr, endptr, base));
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRTOL) || defined (LIBC_STRTOLL)
long long int LIBC_FUNCTION_ATTRIBUTE strtoll(const char *nptr, char **endptr, int base){
long long int acc, cutoff;
int c, neg, any, cutlim;
const char *s;
s = nptr;
do{
c = (unsigned char)*s++;
}while(isspace(c));
if(c == '-'){
neg = 1;
c = *s++;
}else{
neg = 0;
if(c == '+')c = *s++;
}
if(((base == 0) || (base == 16)) && (c == '0') && ((*s == 'x') || (*s == 'X'))){
c = s[1];
s += 2;
base = 16;
}
if(base == 0)base = (c == '0') ? 8 : 10;
cutoff = neg ? LLONG_MIN : LLONG_MAX;
cutlim = (int)(cutoff % base);
cutoff /= base;
if(neg){
if(cutlim > 0){
cutlim -= base;
cutoff += 1;
}
cutlim = -cutlim;
}
for(acc = 0, any = 0; ; c = (unsigned char)*s++){
if(isdigit(c)){
c -= '0';
}else if(isalpha(c)){
c -= isupper(c) ? ('A' - 10) : ('a' - 10);
}else{
break;
}
if(c >= base)break;
if(any < 0)continue;
if(neg){
if((acc < cutoff) || ((acc == cutoff) && (c > cutlim))){
any = -1;
acc = LLONG_MIN;
// errno = ERANGE;
}else{
any = 1;
acc *= base;
acc -= c;
}
}else{
if((acc > cutoff) || ((acc == cutoff) && (c > cutlim))){
any = -1;
acc = LLONG_MAX;
// errno = ERANGE;
}else{
any = 1;
acc *= base;
acc += c;
}
}
}
if(endptr != 0)*endptr = (char *)(any ? (s - 1) : nptr);
return(acc);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_STRTOD)
#define _LIBC_HUGE_VAL (__builtin_huge_val())
#define _LIBC_DBL_MIN_EXP (__DBL_MIN_EXP__)
#define _LIBC_DBL_MAX_EXP (__DBL_MAX_EXP__)
double LIBC_FUNCTION_ATTRIBUTE strtod(const char *str, char **endptr){
double number, p10;
int exponent, negative, n, num_digits, num_decimals;
char *p;
p = (char *)str;
while(isspace(*p))p++;
negative = 0;
switch(*p){
case '-': negative = 1; // Fall through to increment position
case '+': p++;
}
number = 0.;
exponent = num_digits = num_decimals = 0;
while(isdigit(*p)){
number = number * 10. + (*p - '0');
p++;
num_digits++;
}
// Process decimal part
if(*p == '.'){
p++;
while(isdigit(*p)){
number = number * 10. + (*p - '0');
p++;
num_digits++;
num_decimals++;
}
exponent -= num_decimals;
}
if(num_digits == 0){
// errno = ERANGE;
return(0.0);
}
// Correct for sign
if(negative)number = -number;
// Process an exponent string
if(*p == 'e' || *p == 'E'){
// Handle optional sign
negative = 0;
switch(*++p){
case '-': negative = 1; // Fall through to increment pos
case '+': p++;
}
// Process string of digits
n = 0;
while(isdigit(*p)){
n = n * 10 + (*p - '0');
p++;
}
if(negative){
exponent -= n;
}else{
exponent += n;
}
}
if((exponent < _LIBC_DBL_MIN_EXP) || (exponent > _LIBC_DBL_MAX_EXP)){
// errno = ERANGE;
return(_LIBC_HUGE_VAL);
}
// Scale the result
p10 = 10.;
n = exponent;
if(n < 0)n = -n;
while(n){
if(n & 1){
if(exponent < 0){
number /= p10;
}else{
number *= p10;
}
}
n >>= 1;
p10 *= p10;
}
// if (number == _LIBC_HUGE_VAL)errno = ERANGE;
if(endptr)*endptr = p;
return(number);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_ABS)
int LIBC_FUNCTION_ATTRIBUTE abs(int j){
if(j < 0)return(-j);
return(j);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_ASSERT)
void LIBC_FUNCTION_ATTRIBUTE assert(int expression){
}
#endif
#if defined (LIBC_ALL) || defined(LIBC_ABORT)
void LIBC_FUNCTION_ATTRIBUTE abort(void){
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_GMTIME_R)
#define _LIBC_YEAR0 1900 /* the first year */
#define _LIBC_EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */
#define _LIBC_SECS_DAY (24L * 60L * 60L)
#define _LIBC_LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define _LIBC_YEARSIZE(year) (_LIBC_LEAPYEAR(year) ? 366 : 365)
static const int _ytab[2][12] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
struct tm * LIBC_FUNCTION_ATTRIBUTE gmtime_r(const time_t *timep, struct tm *result){
unsigned long dayclock, dayno;
int year;
year = _LIBC_EPOCH_YR;
dayclock = (unsigned long)*timep % _LIBC_SECS_DAY;
dayno = (unsigned long)*timep / _LIBC_SECS_DAY;
result->tm_sec = dayclock % 60;
result->tm_min = (dayclock % 3600) / 60;
result->tm_hour = dayclock / 3600;
result->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
while(dayno >= _LIBC_YEARSIZE(year)){
dayno -= _LIBC_YEARSIZE(year);
year++;
}
result->tm_year = year - _LIBC_YEAR0;
result->tm_yday = dayno;
result->tm_mon = 0;
while(dayno >= _ytab[_LIBC_LEAPYEAR(year)][result->tm_mon]){
dayno -= _ytab[_LIBC_LEAPYEAR(year)][result->tm_mon];
result->tm_mon++;
}
result->tm_mday = dayno + 1;
result->tm_isdst = 0;
return(result);
}
#endif
#if defined (LIBC_ALL) || defined (LIBC_MKTIME)
static const int m_to_d[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
time_t LIBC_FUNCTION_ATTRIBUTE mktime(struct tm *tm){
int month, year;
time_t result;
month = tm->tm_mon;
year = tm->tm_year + month / 12 + 1900;
month %= 12;
if(month < 0){
year -= 1;
month += 12;
}
result = (year - 1970) * 365 + (year - 1969) / 4 + m_to_d[month];
result = (year - 1970) * 365 + m_to_d[month];
if(month <= 1)year -= 1;
result += (year - 1968) / 4;
result -= (year - 1900) / 100;
result += (year - 1600) / 400;
result += tm->tm_mday;
result -= 1;
result *= 24;
result += tm->tm_hour;
result *= 60;
result += tm->tm_min;
result *= 60;
result += tm->tm_sec;
return(result);
}
#endif