658 lines
12 KiB
C
658 lines
12 KiB
C
/*
|
|
* libcaca Colour ASCII-Art library
|
|
* Copyright (c) 2006 Sam Hocevar <sam@hocevar.net>
|
|
* 2009 Jean-Yves Lamoureux <jylam@lnxscene.org>
|
|
* All Rights Reserved
|
|
*
|
|
* This library is free software. It comes without any warranty, to
|
|
* the extent permitted by applicable law. You can redistribute it
|
|
* and/or modify it under the terms of the Do What the Fuck You Want
|
|
* to Public License, Version 2, as published by Sam Hocevar. See
|
|
* http://www.wtfpl.net/ for more details.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "caca_types.h"
|
|
|
|
#include "klibc.h"
|
|
#include "drivers/timer.h"
|
|
#include "kernel.h"
|
|
|
|
|
|
void htoa(unsigned int value, char s[]);
|
|
|
|
#define IS_DIGIT(x) (x>='0' && x<='9')
|
|
#define IS_ALPHA(x) (x>='A' && x<='z')
|
|
#define IS_UPPER(x) (x>='A' && x<='Z')
|
|
#define IS_LOWER(x) (x>='a' && x<='z')
|
|
#define UPPER(x) (IS_LOWER(x)?(x+('A'-'a')):x)
|
|
#define LOWER(x) (IS_UPPER(x)?(x-('a'-'A')):x)
|
|
|
|
/* Our default seed for random number generator */
|
|
static int seed = 0x68743284;
|
|
|
|
/* Our memory mapping */
|
|
static uint32_t *freemem = (uint32_t *) 0x00200000;
|
|
int kX = 0;
|
|
int kY = 0;
|
|
|
|
void scroll(void)
|
|
{
|
|
unsigned char *video, *tmp;
|
|
|
|
for (video = (unsigned char *)0xB8000; video < (unsigned char *)0xB8FA0;
|
|
video++)
|
|
{
|
|
tmp = (unsigned char *)(video + 1 * 160);
|
|
|
|
if (tmp < (unsigned char *)0xB8FA0)
|
|
*video = *tmp;
|
|
else
|
|
*video = 0;
|
|
}
|
|
|
|
kY -= 1;
|
|
if (kY < 0)
|
|
kY = 0;
|
|
}
|
|
|
|
void putcar(unsigned char c)
|
|
{
|
|
unsigned char *video;
|
|
|
|
if (c == 10)
|
|
{
|
|
kX = 0;
|
|
kY++;
|
|
}
|
|
else
|
|
{
|
|
video = (unsigned char *)(0xB8000 + 2 * kX + 160 * kY);
|
|
*video = c;
|
|
*(video + 1) = 0x07;
|
|
|
|
kX++;
|
|
if (kX > 79)
|
|
{
|
|
kX = 0;
|
|
kY++;
|
|
}
|
|
if (kY >= 24)
|
|
{
|
|
scroll();
|
|
}
|
|
}
|
|
}
|
|
|
|
void print(char *str)
|
|
{
|
|
char const *ptr = str;
|
|
while (*ptr)
|
|
{
|
|
putcar(*ptr++);
|
|
}
|
|
}
|
|
|
|
void clearscreen(void)
|
|
{
|
|
int x, y;
|
|
kX = 0;
|
|
kY = 0;
|
|
for (y = 0; y < 25; y++)
|
|
for (x = 0; x < 80; x++)
|
|
{
|
|
putcar(' ');
|
|
}
|
|
kX = 0;
|
|
kY = 0;
|
|
}
|
|
|
|
/* stdlib.h functions */
|
|
void *malloc(size_t size)
|
|
{
|
|
uint32_t *p = freemem;
|
|
if (!size)
|
|
return NULL;
|
|
size = (size + 0x7) / 4;
|
|
*p = size;
|
|
freemem += size + 1;
|
|
return p + 1;
|
|
}
|
|
|
|
void free(void *ptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void *realloc(void *ptr, size_t size)
|
|
{
|
|
uint32_t oldsize;
|
|
void *p;
|
|
|
|
if (!size)
|
|
return NULL;
|
|
|
|
if (!ptr)
|
|
oldsize = 0;
|
|
else
|
|
{
|
|
oldsize = ((uint32_t *) ptr)[-1];
|
|
if (oldsize >= size)
|
|
return ptr;
|
|
}
|
|
|
|
p = malloc(size);
|
|
memcpy(p, ptr, oldsize);
|
|
return p;
|
|
}
|
|
|
|
char *getenv(const char *name)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int getpid(void)
|
|
{
|
|
return 0x1337;
|
|
}
|
|
|
|
void srand(unsigned int s)
|
|
{
|
|
seed = rand();
|
|
}
|
|
|
|
int time(void *dummy)
|
|
{
|
|
return rand();
|
|
}
|
|
|
|
int rand(void)
|
|
{
|
|
seed = (seed * 0x7f32ba17) ^ 0xf893a735;
|
|
return seed % RAND_MAX;
|
|
}
|
|
|
|
int abs(int j)
|
|
{
|
|
if (j < 0)
|
|
return -j;
|
|
return j;
|
|
}
|
|
|
|
void exit(int status)
|
|
{
|
|
/* FIXME: reboot? */
|
|
while (1);
|
|
}
|
|
|
|
int atexit(void (*function) (void))
|
|
{
|
|
/* FIXME: register function */
|
|
return 0;
|
|
}
|
|
|
|
/* string.h functions */
|
|
void *memset(void *s, int c, size_t n)
|
|
{
|
|
uint8_t *ptr = s;
|
|
|
|
while (n--)
|
|
*ptr++ = c;
|
|
|
|
return s;
|
|
}
|
|
|
|
void *memcpy(void *dest, const void *src, size_t n)
|
|
{
|
|
uint8_t *destptr = dest;
|
|
uint8_t const *srcptr = src;
|
|
|
|
while (n--)
|
|
*destptr++ = *srcptr++;
|
|
|
|
return dest;
|
|
}
|
|
|
|
void *memmove(void *dest, const void *src, size_t n)
|
|
{
|
|
memcpy(freemem, src, n);
|
|
memcpy(dest, freemem, n);
|
|
return dest;
|
|
}
|
|
|
|
size_t strlen(const char *s)
|
|
{
|
|
int len = 0;
|
|
|
|
while (*s++)
|
|
len++;
|
|
|
|
return len;
|
|
}
|
|
|
|
int strcmp(const char *s1, const char *s2)
|
|
{
|
|
while (*s1 && *s1 == *s2)
|
|
{
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return (int)*s1 - (int)*s2;
|
|
}
|
|
|
|
int strcasecmp(const char *s1, const char *s2)
|
|
{
|
|
while (*s1 && *s2 && UPPER(*s1) == UPPER(*s2))
|
|
{
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return (int)UPPER(*s1) - (int)UPPER(*s2);
|
|
}
|
|
|
|
int memcmp(const void *_s1, const void *_s2, size_t n)
|
|
{
|
|
uint8_t const *s1 = _s1, *s2 = _s2;
|
|
|
|
while (n--)
|
|
{
|
|
if (*s1 != *s2)
|
|
return (int)*s1 - (int)*s2;
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *strdup(const char *s)
|
|
{
|
|
char *new;
|
|
unsigned int len = strlen(s);
|
|
|
|
new = malloc(len + 1);
|
|
memcpy(new, s, len + 1);
|
|
|
|
return new;
|
|
}
|
|
|
|
char *strchr(const char *s, int c)
|
|
{
|
|
do
|
|
if (*s == c)
|
|
return (char *)(intptr_t) s;
|
|
while (*s++);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* stdarg.h functions */
|
|
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
/* stdio.h functions */
|
|
FILE *fopen(const char *path, const char *mode)
|
|
{
|
|
/* FIXME */
|
|
return NULL;
|
|
}
|
|
|
|
int feof(FILE * stream)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
char *fgets(char *s, int size, FILE * stream)
|
|
{
|
|
/* FIXME */
|
|
return NULL;
|
|
}
|
|
|
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE * stream)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int fclose(FILE * fp)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
int printf(const char *fmt, ...)
|
|
{
|
|
char str[200];
|
|
char tmp[100];
|
|
args_list args;
|
|
args_start(args, fmt);
|
|
|
|
char *s;
|
|
int ptr = 0;
|
|
int i = 0;
|
|
|
|
for (; fmt[i]; ++i)
|
|
{
|
|
if ((fmt[i] != '%') && (fmt[i] != '\\'))
|
|
{
|
|
str[ptr++] = fmt[i];
|
|
continue;
|
|
}
|
|
else if (fmt[i] == '\\')
|
|
{
|
|
switch (fmt[++i])
|
|
{
|
|
case 'a':
|
|
str[ptr++] = '\a';
|
|
break;
|
|
case 'b':
|
|
str[ptr++] = '\b';
|
|
break;
|
|
case 't':
|
|
str[ptr++] = '\t';
|
|
break;
|
|
case 'n':
|
|
str[ptr++] = '\n';
|
|
break;
|
|
case 'r':
|
|
str[ptr++] = '\r';
|
|
break;
|
|
case '\\':
|
|
str[ptr++] = '\\';
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
switch (fmt[++i])
|
|
{
|
|
case 's':
|
|
s = (char *)args_next(args, char *);
|
|
while (*s)
|
|
str[ptr++] = *s++;
|
|
break;
|
|
case 'c':
|
|
str[ptr++] = (char)args_next(args, int);
|
|
break;
|
|
case 'p':
|
|
case 'x':
|
|
htoa((unsigned long)args_next(args, unsigned long), tmp);
|
|
memcpy(&str[ptr], tmp, strlen(tmp));
|
|
ptr += strlen(tmp);
|
|
break;
|
|
case 'd':
|
|
itoa((unsigned long)args_next(args, unsigned long), tmp);
|
|
memcpy(&str[ptr], tmp, strlen(tmp));
|
|
ptr += strlen(tmp);
|
|
break;
|
|
case '%':
|
|
str[ptr++] = '%';
|
|
break;
|
|
default:
|
|
str[ptr++] = fmt[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
str[ptr] = '\0';
|
|
args_end(args);
|
|
|
|
print(str);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fprintf(FILE * stream, const char *format, ...)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
int fflush(FILE * stream)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
int sprintf(char *str, const char *fmt, ...)
|
|
{
|
|
char tmp[100];
|
|
args_list args;
|
|
args_start(args, fmt);
|
|
|
|
char *s;
|
|
int ptr = 0;
|
|
int i = 0;
|
|
|
|
for (; fmt[i]; ++i)
|
|
{
|
|
if ((fmt[i] != '%') && (fmt[i] != '\\'))
|
|
{
|
|
str[ptr++] = fmt[i];
|
|
continue;
|
|
}
|
|
else if (fmt[i] == '\\')
|
|
{
|
|
switch (fmt[++i])
|
|
{
|
|
case 'a':
|
|
str[ptr++] = '\a';
|
|
break;
|
|
case 'b':
|
|
str[ptr++] = '\b';
|
|
break;
|
|
case 't':
|
|
str[ptr++] = '\t';
|
|
break;
|
|
case 'n':
|
|
str[ptr++] = '\n';
|
|
break;
|
|
case 'r':
|
|
str[ptr++] = '\r';
|
|
break;
|
|
case '\\':
|
|
str[ptr++] = '\\';
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
switch (fmt[++i])
|
|
{
|
|
case 's':
|
|
s = (char *)args_next(args, char *);
|
|
while (*s)
|
|
str[ptr++] = *s++;
|
|
break;
|
|
case 'c':
|
|
str[ptr++] = (char)args_next(args, int);
|
|
break;
|
|
case 'p':
|
|
case 'x':
|
|
htoa((unsigned long)args_next(args, unsigned long), tmp);
|
|
memcpy(&str[ptr], tmp, strlen(tmp));
|
|
ptr += strlen(tmp);
|
|
break;
|
|
case 'd':
|
|
itoa((unsigned long)args_next(args, unsigned long), tmp);
|
|
memcpy(&str[ptr], tmp, strlen(tmp));
|
|
ptr += strlen(tmp);
|
|
break;
|
|
case '%':
|
|
str[ptr++] = '%';
|
|
break;
|
|
default:
|
|
str[ptr++] = fmt[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
str[ptr] = '\0';
|
|
args_end(args);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sscanf(const char *str, const char *format, ...)
|
|
{
|
|
/* FIXME */
|
|
return 0;
|
|
}
|
|
|
|
/* unistd.h functions */
|
|
void usleep(unsigned long usec)
|
|
{
|
|
u32 start = ticks;
|
|
signed int diff = 0;
|
|
|
|
while (1)
|
|
{
|
|
diff = (signed int)(ticks - start);
|
|
if (diff >= (signed int)(usec / 20))
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sleep(unsigned long sec)
|
|
{
|
|
usleep(sec * 1000);
|
|
}
|
|
|
|
|
|
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
|
{
|
|
static int usec = 0;
|
|
static int sec = 0;
|
|
|
|
/* FIXME */
|
|
usec += 10000;
|
|
if (usec > 1000000)
|
|
{
|
|
sec++;
|
|
usec -= 1000000;
|
|
}
|
|
|
|
tv->tv_sec = sec;
|
|
tv->tv_usec = usec;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* math.h functions */
|
|
double cos(double x)
|
|
{
|
|
double ret = 0.0;
|
|
#ifdef HAVE_FSIN_FCOS
|
|
asm volatile ("fcos":"=t" (ret):"0"(x));
|
|
#else
|
|
double x2;
|
|
double num = 1.0;
|
|
double fact = 1.0;
|
|
int i;
|
|
|
|
x = x - ((double)(int)(x / (2 * M_PI))) * (2 * M_PI);
|
|
x2 = x * x;
|
|
|
|
/* cos(x) = 1/0! - x^2/2! + x^4/4! - x^6/6! ... */
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
ret += num / fact;
|
|
num *= -x2;
|
|
fact *= (2 * i + 1) * (2 * i + 2);
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
double sin(double x)
|
|
{
|
|
double ret = 0.0;
|
|
#ifdef HAVE_FSIN_FCOS
|
|
asm volatile ("fsin":"=t" (ret):"0"(x));
|
|
#else
|
|
double x2;
|
|
double num;
|
|
double fact = 1.0;
|
|
int i;
|
|
|
|
x = x - ((double)(int)(x / (2 * M_PI))) * (2 * M_PI);
|
|
x2 = x * x;
|
|
num = x;
|
|
|
|
/* sin(x) = x/1! - x^3/3! + x^5/5! - x^7/7! ... */
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
ret += num / fact;
|
|
num *= -x2;
|
|
fact *= (2 * i + 2) * (2 * i + 3);
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
double sqrt(double x)
|
|
{
|
|
double ret = x;
|
|
int i;
|
|
|
|
/* This is Newton's method */
|
|
for (i = 0; i < 10; i++)
|
|
ret = (ret * ret + x) / (ret * 2.0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* reverse: reverse string s in place */
|
|
void reverse(char s[])
|
|
{
|
|
int i, j;
|
|
char c;
|
|
|
|
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
|
|
{
|
|
c = s[i];
|
|
s[i] = s[j];
|
|
s[j] = c;
|
|
}
|
|
}
|
|
|
|
|
|
/* itoa implementation, by Kernighan and Ritchie's The C Programming Language */
|
|
void itoa(int n, char s[])
|
|
{
|
|
int i, sign;
|
|
|
|
if ((sign = n) < 0) /* record sign */
|
|
n = -n; /* make n positive */
|
|
i = 0;
|
|
do
|
|
{ /* generate digits in reverse order */
|
|
s[i++] = n % 10 + '0'; /* get next digit */
|
|
}
|
|
while ((n /= 10) > 0); /* delete it */
|
|
if (sign < 0)
|
|
s[i++] = '-';
|
|
s[i] = '\0';
|
|
reverse(s);
|
|
}
|
|
|
|
void htoa(unsigned int value, char s[])
|
|
{
|
|
int i = 8;
|
|
int ptr = 0;
|
|
while (i-- > 0)
|
|
{
|
|
s[ptr++] = "0123456789abcdef"[(value >> (i * 4)) & 0xf];
|
|
}
|
|
s[ptr] = 0;
|
|
}
|
|
|
|
|
|
/* errno.h stuff */
|
|
int errno = 0;
|