1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 18:57:35 +00:00

Enough compatibility work to make figlet build and run!

I ran out of steam writing library routines and imported two
BSD-licensed libc routines: sscanf() and getopt().

I will most likely rewrite them sooner or later. For now
I just wanted to see figlet running.
This commit is contained in:
Andreas Kling 2018-10-31 17:50:43 +01:00
parent 69c7a59e6f
commit 819ce91395
22 changed files with 714 additions and 36 deletions

View file

@ -17,6 +17,8 @@ LIBC_OBJS = \
utsname.o \
assert.o \
signal.o \
getopt.o \
scanf.o \
entry.o
OBJS = $(AK_OBJS) $(LIBC_OBJS)

View file

@ -6,7 +6,7 @@ __BEGIN_DECLS
void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func);
#define assert(expr) (static_cast<bool>(expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
#define assert(expr) ((expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
#define CRASH() do { asm volatile("ud2"); } while(0)
#define ASSERT assert
#define RELEASE_ASSERT assert

View file

@ -10,9 +10,14 @@ int errno;
FILE* stdin;
FILE* stdout;
FILE* stderr;
char** environ;
extern "C" void __malloc_init();
extern "C" int _start()
{
__malloc_init();
errno = 0;
__default_streams[0].fd = 0;
@ -26,12 +31,18 @@ extern "C" int _start()
StringImpl::initializeGlobals();
int status = 254;
int argc;
char** argv;
int rc = Syscall::invoke(Syscall::GetArguments, (dword)&argc, (dword)&argv);
int status = 254;
if (rc == 0)
status = main(argc, argv);
if (rc < 0)
goto epilogue;
rc = Syscall::invoke(Syscall::GetEnvironment, (dword)&environ);
if (rc < 0)
goto epilogue;
status = main(argc, argv);
epilogue:
Syscall::invoke(Syscall::PosixExit, status);
// Birger's birthday <3

109
LibC/getopt.cpp Normal file
View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <getopt.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
int getopt(int nargc, char* const nargv[], const char* ostr)
{
static const char* place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
ASSERT(nargv != NULL);
ASSERT(ostr != NULL);
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-' /* found "--" */
&& place[1] == '\0') {
++optind;
place = EMSG;
return -1;
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return -1;
if (!*place)
++optind;
if (opterr && *ostr != ':')
fprintf(stderr, "unknown option -- %c\n", optopt);
return BADCH;
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = (char*)place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return BADARG;
if (opterr)
fprintf(stderr, "option requires an argument -- %c\n", optopt);
return BADCH;
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return optopt; /* dump back option letter */
}

13
LibC/getopt.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
int getopt(int argc, char* const argv[], const char* optstring);
extern char* optarg;
extern int optind;
extern int opterr;
extern int optopt;
__END_DECLS

255
LibC/scanf.cpp Normal file
View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#define MAXLN 512
static const char* determineBase(const char* p, int& base)
{
if (p[0] == '0') {
switch (p[1]) {
case 'x':
base = 16;
break;
case 't':
case 'n':
base = 10;
break;
case 'o':
base = 8;
break;
default:
base = 10;
return p;
}
return p + 2;
}
base = 10;
return p;
}
static int _atob(unsigned long* vp, const char* p, int base)
{
unsigned long value, v1, v2;
char *q, tmp[20];
int digit;
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
base = 16;
p += 2;
}
if (base == 16 && (q = strchr(p, '.')) != 0) {
if (q - p > sizeof(tmp) - 1)
return 0;
strncpy(tmp, p, q - p);
tmp[q - p] = '\0';
if (!_atob(&v1, tmp, 16))
return 0;
++q;
if (strchr(q, '.'))
return 0;
if (!_atob(&v2, q, 16))
return 0;
*vp = (v1 << 16) + v2;
return 1;
}
value = *vp = 0;
for (; *p; p++) {
if (*p >= '0' && *p <= '9')
digit = *p - '0';
else if (*p >= 'a' && *p <= 'f')
digit = *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
digit = *p - 'A' + 10;
else
return 0;
if (digit >= base)
return 0;
value *= base;
value += digit;
}
*vp = value;
return 1;
}
int atob(unsigned int* vp, const char* p, int base)
{
unsigned long v;
if (base == 0)
p = determineBase(p, base);
if (_atob(&v, p, base)) {
*vp = v;
return 1;
}
return 0;
}
static int vfscanf(FILE*, const char*, va_list);
static int vsscanf(const char*, const char*, va_list);
#define ISSPACE " \t\n\r\f\v"
int scanf(const char* fmt, ...)
{
int count;
va_list ap;
va_start(ap, fmt);
count = vfscanf(stdin, fmt, ap);
va_end(ap);
return count;
}
int fscanf(FILE *fp, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(fp, fmt, ap);
va_end(ap);
return count;
}
int sscanf(const char *buf, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vsscanf(buf, fmt, ap);
va_end(ap);
return count;
}
static int vfscanf(FILE *fp, const char* fmt, va_list ap)
{
char buf[MAXLN + 1];
if (!fgets(buf, MAXLN, fp))
return -1;
int count = vsscanf(buf, fmt, ap);
return count;
}
static int vsscanf(const char *buf, const char *s, va_list ap)
{
int base;
char *t;
char tmp[MAXLN];
bool noassign = false;
bool lflag = false;
int count = 0;
int width = 0;
while (*s && *buf) {
while (isspace (*s))
s++;
if (*s == '%') {
s++;
for (; *s; s++) {
if (strchr ("dibouxcsefg%", *s))
break;
if (*s == '*')
noassign = true;
else if (*s == 'l' || *s == 'L')
lflag = true;
else if (*s >= '1' && *s <= '9') {
const char* tc;
for (tc = s; isdigit(*s); s++);
strncpy (tmp, tc, s - tc);
tmp[s - tc] = '\0';
atob ((dword*)&width, tmp, 10);
s--;
}
}
if (*s == 's') {
while (isspace(*buf))
buf++;
if (!width)
width = strcspn(buf, ISSPACE);
if (!noassign) {
strncpy(t = va_arg(ap, char*), buf, width);
t[width] = '\0';
}
buf += width;
} else if (*s == 'c') {
if (!width)
width = 1;
if (!noassign) {
strncpy(t = va_arg(ap, char*), buf, width);
t[width] = '\0';
}
buf += width;
} else if (strchr("dobxu", *s)) {
while (isspace(*buf))
buf++;
if (*s == 'd' || *s == 'u')
base = 10;
else if (*s == 'x')
base = 16;
else if (*s == 'o')
base = 8;
else if (*s == 'b')
base = 2;
if (!width) {
if (isspace(*(s + 1)) || *(s + 1) == 0)
width = strcspn(buf, ISSPACE);
else
width = strchr(buf, *(s + 1)) - buf;
}
strncpy(tmp, buf, width);
tmp[width] = '\0';
buf += width;
if (!noassign)
atob(va_arg(ap, dword*), tmp, base);
}
if (!noassign)
++count;
width = 0;
noassign = false;
lflag = false;
++s;
} else {
while (isspace(*buf))
buf++;
if (*s != *buf)
break;
else {
++s;
++buf;
}
}
}
return count;
}

View file

@ -4,15 +4,113 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <Kernel/Syscall.h>
#include <AK/printf.cpp>
extern "C" {
int fileno(FILE* stream)
{
return stream->fd;
}
int feof(FILE* stream)
{
return stream->eof;
}
char* fgets(char* buffer, int size, FILE* stream)
{
ssize_t nread = 0;
for (;;) {
if (nread >= size)
break;
char ch = fgetc(stream);
if (feof(stream))
break;
buffer[nread++] = ch;
if (!ch || ch == '\n')
break;
}
if (nread < size)
buffer[nread] = '\0';
return buffer;
}
int fgetc(FILE* stream)
{
char ch;
read(stream->fd, &ch, 1);
return ch;
}
int getc(FILE* stream)
{
return fgetc(stream);
}
int getchar()
{
return getc(stdin);
}
int fputc(int ch, FILE* stream)
{
write(stream->fd, &ch, 1);
return (byte)ch;
}
int putc(int ch, FILE* stream)
{
return fputc(ch, stream);
}
int putchar(int ch)
{
write(0, &ch, 1);
return (byte)ch;
return putc(ch, stdout);
}
void clearerr(FILE* stream)
{
stream->eof = false;
}
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
{
ssize_t nread = read(stream->fd, ptr, nmemb * size);
if (nread < 0)
return 0;
if (nread == 0)
stream->eof = true;
return nread;
}
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
{
ssize_t nwritten = write(stream->fd, ptr, nmemb * size);
if (nwritten < 0)
return 0;
return nwritten;
}
int fseek(FILE* stream, long offset, int whence)
{
off_t off = lseek(stream->fd, offset, whence);
if (off < 0)
return off;
return 0;
}
long ftell(FILE* stream)
{
return lseek(stream->fd, 0, SEEK_CUR);
}
void rewind(FILE* stream)
{
fseek(stream, 0, SEEK_SET);
}
static void sys_putch(char*&, char ch)
@ -65,5 +163,24 @@ void perror(const char* s)
printf("%s: %s\n", s, strerror(errno));
}
FILE* fopen(const char* pathname, const char* mode)
{
assert(!strcmp(mode, "r") || !strcmp(mode, "rb"));
int fd = open(pathname, O_RDONLY);
if (fd < 0)
return nullptr;
auto* fp = (FILE*)malloc(sizeof(FILE));
fp->fd = fd;
fp->eof = false;
return fp;
}
int fclose(FILE* stream)
{
int rc = close(stream->fd);
free(stream);
return rc;
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
@ -8,8 +9,13 @@ __BEGIN_DECLS
#define EOF (-1)
#endif
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
struct __STDIO_FILE {
int fd;
int eof;
};
typedef struct __STDIO_FILE FILE;
@ -18,11 +24,21 @@ extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr;
char* fgets(char* buffer, int size, FILE*);
int fileno(FILE*);
int fgetc(FILE*);
int getc(FILE*);
int getchar();
FILE* fopen(const char* pathname, const char* mode);
int fclose(FILE*);
size_t fread(void* ptr, size_t size, size_t nmemb, FILE*);
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE*);
int fprintf(FILE*, const char* fmt, ...);
int printf(const char* fmt, ...);
int sprintf(char* buffer, const char* fmt, ...);
int putchar(int ch);
void perror(const char*);
int sscanf (const char* buf, const char* fmt, ...);
__END_DECLS

View file

@ -1,32 +1,50 @@
#include "stdlib.h"
#include "mman.h"
#include "stdio.h"
#include <stdlib.h>
#include <mman.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <alloca.h>
#include <Kernel/Syscall.h>
#include <AK/Assertions.h>
extern "C" {
// FIXME: This is a temporary malloc() implementation. It never frees anything,
// and you can't allocate more than 128 kB total.
static const size_t mallocBudget = 131072;
static byte* nextptr = nullptr;
static byte* endptr = nullptr;
void __malloc_init()
{
nextptr = (byte*)mmap(nullptr, mallocBudget);
endptr = nextptr + mallocBudget;
int rc = set_mmap_name(nextptr, mallocBudget, "malloc");
if (rc < 0)
perror("set_mmap_name failed");
}
void* malloc(size_t size)
{
if (size > 4096) {
if ((nextptr + size) > endptr) {
volatile char* crashme = (char*)0xc007d00d;
*crashme = 0;
}
void* ptr = mmap(nullptr, 4096);
if (ptr) {
int rc = set_mmap_name(ptr, 4096, "malloc");
if (rc < 0) {
perror("set_mmap_name failed");
}
}
return ptr;
byte* ret = nextptr;
nextptr += size;
nextptr += 16;
nextptr = (byte*)((dword)nextptr & 0xfffffff0);
return ret;
}
void free(void* ptr)
{
if (!ptr)
return;
#if 0
munmap(ptr, 4096);
#endif
}
void* calloc(size_t nmemb, size_t)
@ -52,5 +70,41 @@ void abort()
exit(253);
}
char* getenv(const char* name)
{
for (size_t i = 0; environ[i]; ++i) {
const char* decl = environ[i];
char* eq = strchr(decl, '=');
if (!eq)
continue;
size_t varLength = eq - decl;
char* var = (char*)alloca(varLength + 1);
memcpy(var, decl, varLength);
var[varLength] = '\0';
if (!strcmp(var, name)) {
char* value = eq + 1;
return value;
}
}
return nullptr;
}
int atoi(const char* str)
{
ssize_t len = strlen(str);
int value = 0;
bool isNegative = false;
for (size_t i = 0; i < len; ++i) {
if (i == 0 && str[0] == '-') {
isNegative = true;
continue;
}
if (str[i] < '0' || str[i] > '9')
return 0;
value = value * 10;
value += str[i] - '0';
}
return isNegative ? -value : value;
}
}

View file

@ -9,7 +9,8 @@ void* malloc(size_t);
void free(void*);
void* calloc(size_t nmemb, size_t);
void* realloc(void *ptr, size_t);
char* getenv(const char* name);
int atoi(const char*);
void exit(int status);
void abort();

View file

@ -4,6 +4,40 @@
extern "C" {
void* memset(void* dest, int c, size_t n)
{
byte* bdest = (byte*)dest;
for (; n; --n)
*(bdest++) = c;
return dest;
}
size_t strspn(const char* s, const char* accept)
{
const char* p = s;
cont:
char ch = *p++;
char ac;
for (const char* ap = accept; (ac = *ap++) != '\0';) {
if (ac == ch)
goto cont;
}
return p - 1 - s;
}
size_t strcspn(const char* s, const char* reject)
{
for (auto* p = s;;) {
char c = *p++;
auto* rp = reject;
char rc;
do {
if ((rc = *rp++) == c)
return p - 1 - s;
} while(rc);
}
}
size_t strlen(const char* str)
{
size_t len = 0;
@ -62,11 +96,22 @@ char* strchr(const char* str, int c)
if (!str)
return nullptr;
char* ptr = (char*)str;
while (*ptr != c)
while (*ptr && *ptr != c)
++ptr;
return ptr;
}
char* strrchr(const char* str, int ch)
{
char *last = nullptr;
char c;
for (; (c = *str); ++str) {
if (c == ch)
last = (char*)str;
}
return last;
}
char* strcat(char *dest, const char *src)
{
size_t destLength = strlen(dest);

View file

@ -9,11 +9,15 @@ size_t strlen(const char*);
int strcmp(const char*, const char*);
int memcmp(const void*, const void*, size_t);
void memcpy(void*, const void*, size_t);
void* memset(void*, int, size_t);
char* strcpy(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t);
char* strchr(const char*, int c);
char* strrchr(const char*, int c);
char* strcat(char *dest, const char *src);
char* strncat(char *dest, const char *src, size_t);
size_t strspn(const char*, const char* accept);
size_t strcspn(const char*, const char* reject);
const char* strerror(int errnum);
__END_DECLS

View file

@ -105,5 +105,11 @@ ssize_t readlink(const char* path, char* buffer, size_t size)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
off_t lseek(int fd, off_t offset, int whence)
{
int rc = Syscall::invoke(Syscall::PosixLseek, (dword)fd, (dword)offset, (dword)whence);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

View file

@ -5,6 +5,8 @@
__BEGIN_DECLS
extern char** environ;
uid_t getuid();
gid_t getgid();
pid_t getpid();
@ -22,6 +24,7 @@ int gethostname(char*, size_t);
ssize_t readlink(const char* path, char* buffer, size_t);
char* ttyname(int fd);
int ttyname_r(int fd, char* buffer, size_t);
off_t lseek(int fd, off_t, int whence);
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WTERMSIG(status) ((status) & 0x7f)