1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 21:47:45 +00:00

Libraries: Create top level directory for libraries.

Things were getting a little crowded in the project root, so this patch
moves the Lib*/ directories into Libraries/.
This commit is contained in:
Andreas Kling 2019-07-04 16:16:50 +02:00
parent 63814ffebf
commit 04b9dc2d30
328 changed files with 36 additions and 36 deletions

94
Libraries/LibC/Makefile Normal file
View file

@ -0,0 +1,94 @@
include ../../Makefile.common
AK_OBJS = \
../../AK/StringImpl.o \
../../AK/String.o \
../../AK/StringView.o \
../../AK/StringBuilder.o \
../../AK/FileSystemPath.o \
../../AK/StdLibExtras.o \
../../AK/JsonValue.o \
../../AK/JsonArray.o \
../../AK/JsonObject.o \
../../AK/JsonParser.o \
../../AK/LogStream.o \
../../AK/MappedFile.o
LIBC_OBJS = \
SharedBuffer.o \
stdio.o \
unistd.o \
string.o \
strings.o \
mman.o \
dirent.o \
malloc.o \
stdlib.o \
time.o \
utsname.o \
assert.o \
signal.o \
getopt.o \
scanf.o \
pwd.o \
grp.o \
times.o \
termcap.o \
stat.o \
mntent.o \
ctype.o \
fcntl.o \
termios.o \
ulimit.o \
qsort.o \
ioctl.o \
utime.o \
sys/select.o \
sys/socket.o \
sys/wait.o \
sys/uio.o \
poll.o \
locale.o \
arpa/inet.o \
netdb.o \
sched.o \
dlfcn.o
ASM_OBJS = setjmp.ao crti.ao crtn.ao
CPP_OBJS = $(AK_OBJS) $(WIDGETS_OBJS) $(LIBC_OBJS)
LIBRARY = libc.a
DEFINES += -DUSERLAND -DSERENITY_LIBC_BUILD
all: $(LIBRARY) startfiles
startfiles:
@echo "CXX crt0.o"; $(CXX) $(CXXFLAGS) -o crt0.o -c crt0.cpp
cp crti.ao crti.o
cp crtn.ao crtn.o
$(LIBRARY): $(CPP_OBJS) $(ASM_OBJS)
@echo "LIB $@"; $(AR) rcs $@ $(CPP_OBJS) $(ASM_OBJS)
.cpp.o:
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
%.ao: %.S
@echo "AS $@"; $(AS) -o $@ $<
-include $(OBJS:%.o=%.d)
clean:
@echo "CLEAN"; rm -f $(LIBRARY) $(CPP_OBJS) $(ASM_OBJS) *.d
install: $(LIBRARY) startfiles
mkdir -p ../Root/usr/include
mkdir -p ../Root/usr/lib
# Copy headers
rsync -r -a --include '*/' --include '*.h' --exclude '*' . ../Root/usr/include
# Install the library
cp $(LIBRARY) ../Root/usr/lib
cp crt0.o ../Root/usr/lib/
cp crti.ao ../Root/usr/lib/crti.o
cp crtn.ao ../Root/usr/lib/crtn.o

View file

@ -0,0 +1,56 @@
#include <AK/kmalloc.h>
#include <SharedBuffer.h>
#include <stdio.h>
#include <unistd.h>
RefPtr<SharedBuffer> SharedBuffer::create(pid_t peer, int size)
{
void* data;
int shared_buffer_id = create_shared_buffer(peer, size, &data);
if (shared_buffer_id < 0) {
perror("create_shared_buffer");
return nullptr;
}
return adopt(*new SharedBuffer(shared_buffer_id, size, data));
}
RefPtr<SharedBuffer> SharedBuffer::create_from_shared_buffer_id(int shared_buffer_id)
{
void* data = get_shared_buffer(shared_buffer_id);
if (data == (void*)-1) {
perror("get_shared_buffer");
return nullptr;
}
int size = get_shared_buffer_size(shared_buffer_id);
if (size < 0) {
perror("get_shared_buffer_size");
return nullptr;
}
return adopt(*new SharedBuffer(shared_buffer_id, size, data));
}
SharedBuffer::SharedBuffer(int shared_buffer_id, int size, void* data)
: m_shared_buffer_id(shared_buffer_id)
, m_size(size)
, m_data(data)
{
}
SharedBuffer::~SharedBuffer()
{
if (m_shared_buffer_id >= 0) {
int rc = release_shared_buffer(m_shared_buffer_id);
if (rc < 0) {
perror("release_shared_buffer");
}
}
}
void SharedBuffer::seal()
{
int rc = seal_shared_buffer(m_shared_buffer_id);
if (rc < 0) {
perror("seal_shared_buffer");
ASSERT_NOT_REACHED();
}
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <AK/RefPtr.h>
#include <AK/RefCounted.h>
class SharedBuffer : public RefCounted<SharedBuffer> {
public:
static RefPtr<SharedBuffer> create(pid_t peer, int);
static RefPtr<SharedBuffer> create_from_shared_buffer_id(int);
~SharedBuffer();
int shared_buffer_id() const { return m_shared_buffer_id; }
void seal();
int size() const { return m_size; }
void* data() { return m_data; }
const void* data() const { return m_data; }
private:
SharedBuffer(int shared_buffer_id, int size, void*);
int m_shared_buffer_id { -1 };
int m_size { 0 };
void* m_data;
};

3
Libraries/LibC/alloca.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
#define alloca __builtin_alloca

View file

@ -0,0 +1,59 @@
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
extern "C" {
const char* inet_ntop(int af, const void* src, char* dst, socklen_t len)
{
if (af != AF_INET) {
errno = EAFNOSUPPORT;
return nullptr;
}
auto* bytes = (const unsigned char*)src;
snprintf(dst, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]);
return (const char*)dst;
}
int inet_pton(int af, const char* src, void* dst)
{
if (af != AF_INET) {
errno = EAFNOSUPPORT;
return -1;
}
unsigned a;
unsigned b;
unsigned c;
unsigned d;
int count = sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d);
if (count != 4) {
errno = EINVAL;
return 0;
}
union {
struct {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
};
uint32_t l;
} u;
u.a = a;
u.b = b;
u.c = c;
u.d = d;
*(uint32_t*)dst = u.l;
return 1;
}
in_addr_t inet_addr(const char* str)
{
in_addr_t tmp;
int rc = inet_pton(AF_INET, str, &tmp);
if (rc < 0)
return INADDR_NONE;
return tmp;
}
}

View file

@ -0,0 +1,42 @@
#pragma once
#include <endian.h>
#include <sys/cdefs.h>
#include <sys/socket.h>
__BEGIN_DECLS
#define INET_ADDRSTRLEN 16
const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
int inet_pton(int af, const char* src, void* dst);
inline uint16_t htons(uint16_t value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
return __builtin_bswap16(value);
#else
return value;
#endif
}
inline uint16_t ntohs(uint16_t value)
{
return htons(value);
}
inline uint32_t htonl(uint32_t value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
return __builtin_bswap32(value);
#else
return value;
#endif
}
inline uint32_t ntohl(uint32_t value)
{
return htonl(value);
}
__END_DECLS

18
Libraries/LibC/assert.cpp Normal file
View file

@ -0,0 +1,18 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" {
#ifdef DEBUG
void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func)
{
dbgprintf("USERSPACE(%d) ASSERTION FAILED: %s\n%s:%u in %s\n", getpid(), msg, file, line, func);
fprintf(stderr, "ASSERTION FAILED: %s\n%s:%u in %s\n", msg, file, line, func);
abort();
for (;;)
;
}
#endif
}

23
Libraries/LibC/assert.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
#ifdef DEBUG
__attribute__((noreturn)) void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func);
# define assert(expr) ((expr) ? (void)0 : __assertion_failed(# expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
# define ASSERT_NOT_REACHED() assert(false)
#else
# define assert(expr)
# define ASSERT_NOT_REACHED() CRASH()
#endif
#define CRASH() \
do { \
asm volatile("ud2"); \
} while (0)
#define ASSERT assert
#define RELEASE_ASSERT assert
__END_DECLS

54
Libraries/LibC/crt0.cpp Normal file
View file

@ -0,0 +1,54 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern "C" {
int main(int, char**);
int errno;
char** environ;
bool __environ_is_malloced;
void __libc_init()
{
void __malloc_init();
__malloc_init();
void __stdio_init();
__stdio_init();
}
int _start(int argc, char** argv, char** env)
{
environ = env;
__environ_is_malloced = false;
__libc_init();
extern void _init();
_init();
extern void (*__init_array_start[])(int, char**, char**) __attribute__((visibility("hidden")));
extern void (*__init_array_end[])(int, char**, char**) __attribute__((visibility("hidden")));
const size_t size = __init_array_end - __init_array_start;
for (size_t i = 0; i < size; i++)
(*__init_array_start[i])(argc, argv, env);
int status = main(argc, argv);
exit(status);
return 20150614;
}
[[noreturn]] void __cxa_pure_virtual()
{
ASSERT_NOT_REACHED();
}
void __cxa_atexit()
{
}
}

9
Libraries/LibC/crti.S Normal file
View file

@ -0,0 +1,9 @@
.global _init
.section .init
_init:
push %ebp
.global _fini
.section .fini
_fini:
push %ebp

7
Libraries/LibC/crtn.S Normal file
View file

@ -0,0 +1,7 @@
.section .init
pop %ebp
ret
.section .fini
pop %ebp
ret

38
Libraries/LibC/ctype.cpp Normal file
View file

@ -0,0 +1,38 @@
#include <ctype.h>
#include <string.h>
extern "C" {
const char _ctype_[256] = {
_C, _C, _C, _C, _C, _C, _C, _C,
_C, _C | _S, _C | _S, _C | _S, _C | _S, _C | _S, _C, _C,
_C, _C, _C, _C, _C, _C, _C, _C,
_C, _C, _C, _C, _C, _C, _C, _C,
(char)(_S | _B), _P, _P, _P, _P, _P, _P, _P,
_P, _P, _P, _P, _P, _P, _P, _P,
_N, _N, _N, _N, _N, _N, _N, _N,
_N, _N, _P, _P, _P, _P, _P, _P,
_P, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U,
_U, _U, _U, _U, _U, _U, _U, _U,
_U, _U, _U, _U, _U, _U, _U, _U,
_U, _U, _U, _P, _P, _P, _P, _P,
_P, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L,
_L, _L, _L, _L, _L, _L, _L, _L,
_L, _L, _L, _L, _L, _L, _L, _L,
_L, _L, _L, _P, _P, _P, _P, _C
};
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
return c | 0x20;
return c;
}
int toupper(int c)
{
if (c >= 'a' && c <= 'z')
return c & ~0x20;
return c;
}
}

49
Libraries/LibC/ctype.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
#include <string.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Do what newlib does to appease GCC's --with-newlib option. */
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _X 0100
#define _B 0200
extern const char _ctype_[256];
int tolower(int);
int toupper(int);
int isalnum(int);
int isalpha(int);
int iscntrl(int);
int isdigit(int);
int isxdigit(int);
int isspace(int);
int ispunct(int);
int isprint(int);
int isgraph(int);
int islower(int);
int isupper(int);
#define isalnum(c) (_ctype_[(int)(c)] & (_U | _L | _N))
#define isalpha(c) (_ctype_[(int)(c)] & (_U | _L))
#define iscntrl(c) (_ctype_[(int)(c)] & (_C))
#define isdigit(c) (_ctype_[(int)(c)] & (_N))
#define isxdigit(c) (_ctype_[(int)(c)] & (_N | _X))
#define isspace(c) (_ctype_[(int)(c)] & (_S))
#define ispunct(c) (_ctype_[(int)(c)] & (_P))
#define isprint(c) (_ctype_[(int)(c)] & (_P | _U | _L | _N | _B))
#define isgraph(c) (_ctype_[(int)(c)] & (_P | _U | _L | _N))
#define islower(c) ((_ctype_[(int)(c)] & (_U | _L)) == _L)
#define isupper(c) ((_ctype_[(int)(c)] & (_U | _L)) == _U)
#define isascii(c) ((unsigned)c <= 127)
#define toascii(c) ((c)&127)
__END_DECLS

94
Libraries/LibC/dirent.cpp Normal file
View file

@ -0,0 +1,94 @@
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <Kernel/Syscall.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
extern "C" {
DIR* opendir(const char* name)
{
int fd = open(name, O_RDONLY | O_DIRECTORY);
if (fd == -1)
return nullptr;
DIR* dirp = (DIR*)malloc(sizeof(DIR));
dirp->fd = fd;
dirp->buffer = nullptr;
dirp->buffer_size = 0;
dirp->nextptr = nullptr;
return dirp;
}
int closedir(DIR* dirp)
{
if (!dirp || dirp->fd == -1)
return -EBADF;
if (dirp->buffer)
free(dirp->buffer);
int rc = close(dirp->fd);
if (rc == 0)
dirp->fd = -1;
free(dirp);
return rc;
}
struct [[gnu::packed]] sys_dirent
{
ino_t ino;
u8 file_type;
size_t namelen;
char name[];
size_t total_size()
{
return sizeof(ino_t) + sizeof(u8) + sizeof(size_t) + sizeof(char) * namelen;
}
};
dirent* readdir(DIR* dirp)
{
if (!dirp)
return nullptr;
if (dirp->fd == -1)
return nullptr;
if (!dirp->buffer) {
struct stat st;
int rc = fstat(dirp->fd, &st);
if (rc < 0)
return nullptr;
size_t size_to_allocate = max(st.st_size, 4096);
dirp->buffer = (char*)malloc(size_to_allocate);
ssize_t nread = syscall(SC_get_dir_entries, dirp->fd, dirp->buffer, size_to_allocate);
dirp->buffer_size = nread;
dirp->nextptr = dirp->buffer;
}
if (dirp->nextptr >= (dirp->buffer + dirp->buffer_size))
return nullptr;
auto* sys_ent = (sys_dirent*)dirp->nextptr;
dirp->cur_ent.d_ino = sys_ent->ino;
dirp->cur_ent.d_type = sys_ent->file_type;
dirp->cur_ent.d_off = 0;
dirp->cur_ent.d_reclen = sys_ent->total_size();
for (size_t i = 0; i < sys_ent->namelen; ++i)
dirp->cur_ent.d_name[i] = sys_ent->name[i];
// FIXME: I think this null termination behavior is not supposed to be here.
dirp->cur_ent.d_name[sys_ent->namelen] = '\0';
dirp->nextptr += sys_ent->total_size();
return &dirp->cur_ent;
}
int dirfd(DIR* dirp)
{
ASSERT(dirp);
return dirp->fd;
}
}

30
Libraries/LibC/dirent.h Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
struct __DIR {
int fd;
struct dirent cur_ent;
char* buffer;
size_t buffer_size;
char* nextptr;
};
typedef struct __DIR DIR;
DIR* opendir(const char* name);
int closedir(DIR*);
struct dirent* readdir(DIR*);
int dirfd(DIR*);
__END_DECLS

25
Libraries/LibC/dlfcn.cpp Normal file
View file

@ -0,0 +1,25 @@
#include <assert.h>
#include <dlfcn.h>
extern "C" {
int dlclose(void*)
{
ASSERT_NOT_REACHED();
}
char* dlerror()
{
ASSERT_NOT_REACHED();
}
void* dlopen(const char*, int)
{
ASSERT_NOT_REACHED();
}
void* dlsym(void*, const char*)
{
ASSERT_NOT_REACHED();
}
}

17
Libraries/LibC/dlfcn.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
#define RTLD_LAZY 1
#define RTLD_NOW 2
#define RTLD_GLOBAL 3
#define RTLD_LOCAL 4
int dlclose(void*);
char* dlerror();
void* dlopen(const char*, int);
void* dlsym(void*, const char*);
__END_DECLS

11
Libraries/LibC/endian.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#define BYTE_ORDER LITTLE_ENDIAN
__END_DECLS

23
Libraries/LibC/errno.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <errno_numbers.h>
#include <sys/cdefs.h>
#define __RETURN_WITH_ERRNO(rc, good_ret, bad_ret) \
do { \
if (rc < 0) { \
errno = -rc; \
return (bad_ret); \
} else { \
errno = 0; \
return (good_ret); \
} \
} while (0)
__BEGIN_DECLS
extern const char* sys_errlist[];
extern int sys_nerr;
extern int errno;
__END_DECLS

View file

@ -0,0 +1,74 @@
#pragma once
#define ESUCCESS 0
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define ERANGE 33
#define ENAMETOOLONG 34
#define ELOOP 35
#define EOVERFLOW 36
#define EOPNOTSUPP 37
#define ENOSYS 38
#define ENOTIMPL 39
#define EAFNOSUPPORT 40
#define ENOTSOCK 41
#define EADDRINUSE 42
#define EWHYTHO 43
#define ENOTEMPTY 44
#define EDOM 45
#define ECONNREFUSED 46
#define EADDRNOTAVAIL 47
#define EISCONN 48
#define ECONNABORTED 49
#define EALREADY 50
#define ECONNRESET 51
#define EDESTADDRREQ 52
#define EHOSTUNREACH 53
#define EILSEQ 54
#define EMSGSIZE 55
#define ENETDOWN 56
#define ENETUNREACH 57
#define ENETRESET 58
#define ENOBUFS 59
#define ENOLCK 60
#define ENOMSG 61
#define ENOPROTOOPT 62
#define ENOTCONN 63
#define EWOULDBLOCK 64
#define EPROTONOSUPPORT 65
#define EDEADLK 66
#define ETIMEDOUT 67
#define EPROTOTYPE 68
#define EINPROGRESS 69
#define ENOTHREAD 70
#define EMAXERRNO 71

17
Libraries/LibC/fcntl.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
extern "C" {
int fcntl(int fd, int cmd, ...)
{
va_list ap;
va_start(ap, cmd);
u32 extra_arg = va_arg(ap, u32);
int rc = syscall(SC_fcntl, fd, cmd, extra_arg);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

72
Libraries/LibC/fcntl.h Normal file
View file

@ -0,0 +1,72 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
#define F_DUPFD 0
#define F_GETFD 1
#define F_SETFD 2
#define F_GETFL 3
#define F_SETFL 4
#define FD_CLOEXEC 1
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 0100
#define O_EXCL 0200
#define O_NOCTTY 0400
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_DIRECTORY 00200000
#define O_NOFOLLOW 00400000
#define O_CLOEXEC 02000000
#define S_IFMT 0170000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFIFO 0010000
#define S_IFLNK 0120000
#define S_IFSOCK 0140000
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
#define S_IRUSR 0400
#define S_IWUSR 0200
#define S_IXUSR 0100
#define S_IRGRP 0040
#define S_IWGRP 0020
#define S_IXGRP 0010
#define S_IROTH 0004
#define S_IWOTH 0002
#define S_IXOTH 0001
#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
#define S_IRWXG (S_IRWXU >> 3)
#define S_IRWXO (S_IRWXG >> 3)
int fcntl(int fd, int cmd, ...);
#define F_RDLCK 0
#define F_WRLCK 1
#define F_UNLCK 2
#define F_SETLKW 7
struct flock {
short l_type;
short l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
__END_DECLS

13
Libraries/LibC/fd_set.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#define FD_SETSIZE 64
#define FD_ZERO(set) memset((set), 0, sizeof(fd_set));
#define FD_CLR(fd, set) ((set)->bits[(fd / 8)] &= ~(1 << (fd) % 8))
#define FD_SET(fd, set) ((set)->bits[(fd / 8)] |= (1 << (fd) % 8))
#define FD_ISSET(fd, set) ((set)->bits[(fd / 8)] & (1 << (fd) % 8))
struct __fd_set {
unsigned char bits[FD_SETSIZE / 8];
};
typedef struct __fd_set fd_set;

0
Libraries/LibC/float.h Normal file
View file

107
Libraries/LibC/getopt.cpp Normal file
View file

@ -0,0 +1,107 @@
/*
* 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 = const_cast<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
Libraries/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

141
Libraries/LibC/grp.cpp Normal file
View file

@ -0,0 +1,141 @@
#include <AK/AKString.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
extern "C" {
#define GRDB_STR_MAX_LEN 256
struct group_with_strings : public group {
char name_buffer[GRDB_STR_MAX_LEN];
char passwd_buffer[GRDB_STR_MAX_LEN];
char* members[32];
char members_buffer[32][32];
};
static FILE* __grdb_stream = nullptr;
static unsigned __grdb_line_number = 0;
static struct group_with_strings* __grdb_entry = nullptr;
void setgrent()
{
__grdb_line_number = 0;
if (__grdb_stream) {
rewind(__grdb_stream);
} else {
__grdb_stream = fopen("/etc/group", "r");
if (!__grdb_stream) {
perror("open /etc/group");
}
assert(__grdb_stream);
__grdb_entry = (struct group_with_strings*)mmap_with_name(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "setgrent");
}
}
void endgrent()
{
__grdb_line_number = 0;
if (__grdb_stream) {
fclose(__grdb_stream);
__grdb_stream = nullptr;
}
if (__grdb_entry) {
munmap(__grdb_entry, getpagesize());
__grdb_entry = nullptr;
}
}
struct group* getgrgid(gid_t gid)
{
setgrent();
while (auto* gr = getgrent()) {
if (gr->gr_gid == gid)
return gr;
}
return nullptr;
}
struct group* getgrnam(const char* name)
{
setgrent();
while (auto* gr = getgrent()) {
if (!strcmp(gr->gr_name, name))
return gr;
}
return nullptr;
}
struct group* getgrent()
{
if (!__grdb_stream)
setgrent();
assert(__grdb_stream);
if (feof(__grdb_stream))
return nullptr;
next_entry:
char buffer[1024];
++__grdb_line_number;
char* s = fgets(buffer, sizeof(buffer), __grdb_stream);
if (!s)
return nullptr;
assert(__grdb_stream);
if (feof(__grdb_stream))
return nullptr;
String line(s, Chomp);
auto parts = line.split(':');
if (parts.size() != 4) {
fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %u parts\n", __grdb_line_number, line.characters(), parts.size());
goto next_entry;
}
auto& e_name = parts[0];
auto& e_passwd = parts[1];
auto& e_gid_string = parts[2];
auto& e_members_string = parts[3];
bool ok;
gid_t e_gid = e_gid_string.to_uint(ok);
if (!ok) {
fprintf(stderr, "getgrent(): Malformed GID on line %u\n", __grdb_line_number);
goto next_entry;
}
auto members = e_members_string.split(',');
__grdb_entry->gr_gid = e_gid;
__grdb_entry->gr_name = __grdb_entry->name_buffer;
__grdb_entry->gr_passwd = __grdb_entry->passwd_buffer;
for (ssize_t i = 0; i < members.size(); ++i) {
__grdb_entry->members[i] = __grdb_entry->members_buffer[i];
strcpy(__grdb_entry->members_buffer[i], members[i].characters());
}
__grdb_entry->members[members.size()] = nullptr;
__grdb_entry->gr_mem = __grdb_entry->members;
strncpy(__grdb_entry->name_buffer, e_name.characters(), GRDB_STR_MAX_LEN);
strncpy(__grdb_entry->passwd_buffer, e_passwd.characters(), GRDB_STR_MAX_LEN);
return __grdb_entry;
}
int initgroups(const char* user, gid_t extra_gid)
{
size_t count = 0;
gid_t gids[32];
bool extra_gid_added = false;
setgrent();
while (auto* gr = getgrent()) {
for (auto* mem = gr->gr_mem; *mem; ++mem) {
if (!strcmp(*mem, user)) {
gids[count++] = gr->gr_gid;
if (gr->gr_gid == extra_gid)
extra_gid_added = true;
break;
}
}
}
endgrent();
if (!extra_gid_added)
gids[count++] = extra_gid;
return setgroups(count, gids);
}
}

23
Libraries/LibC/grp.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct group {
char* gr_name;
char* gr_passwd;
gid_t gr_gid;
char** gr_mem;
};
struct group* getgrent();
void setgrent();
void endgrent();
struct group* getgrnam(const char* name);
struct group* getgrgid(gid_t);
int initgroups(const char* user, gid_t);
__END_DECLS

13
Libraries/LibC/iconv.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef void* iconv_t;
extern iconv_t iconv_open(const char* tocode, const char* fromcode);
extern size_t iconv(iconv_t, char** inbuf, size_t* inbytesleft, char** outbuf, size_t* outbytesleft);
extern int iconv_close(iconv_t);
__END_DECLS

14
Libraries/LibC/install.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
mkdir -p ../Root/usr/include/sys/
mkdir -p ../Root/usr/include/netinet/
mkdir -p ../Root/usr/include/arpa/
mkdir -p ../Root/usr/lib/
cp *.h ../Root/usr/include/
cp sys/*.h ../Root/usr/include/sys/
cp arpa/*.h ../Root/usr/include/arpa/
cp netinet/*.h ../Root/usr/include/netinet/
cp libc.a ../Root/usr/lib/
cp crt0.o ../Root/usr/lib/
cp crti.ao ../Root/usr/lib/crti.o
cp crtn.ao ../Root/usr/lib/crtn.o

20
Libraries/LibC/inttypes.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 "lld"
#define PRIi8 "d"
#define PRIi16 "d"
#define PRIi32 "d"
#define PRIi64 "lld"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 "llu"
#define PRIx8 "b"
#define PRIx16 "w"
#define PRIx32 "x"
#define PRIx64 "llx"

17
Libraries/LibC/ioctl.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/ioctl.h>
extern "C" {
int ioctl(int fd, unsigned request, ...)
{
va_list ap;
va_start(ap, request);
unsigned arg = va_arg(ap, unsigned);
int rc = syscall(SC_ioctl, fd, request, arg);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

26
Libraries/LibC/limits.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
#define PAGE_SIZE 4096
#define PATH_MAX 4096
#define INT_MAX INT32_MAX
#define INT_MIN INT32_MIN
#define UINT_MAX UINT32_MAX
#define UINT_MIN UINT32_MIN
#define CHAR_BIT 8
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#define LONG_MAX 2147483647L
#define LONG_MIN (-LONG_MAX - 1L)
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#define MB_LEN_MAX 16

27
Libraries/LibC/locale.cpp Normal file
View file

@ -0,0 +1,27 @@
#include <assert.h>
#include <locale.h>
#include <stdio.h>
extern "C" {
static char default_decimal_point[] = ".";
static char default_thousands_sep[] = ",";
static char default_grouping[] = "\x03\x03";
static struct lconv default_locale = {
default_decimal_point,
default_thousands_sep,
default_grouping,
};
char* setlocale(int category, const char* locale)
{
dbgprintf("FIXME(LibC): setlocale(%d, %s)\n", category, locale);
return nullptr;
}
struct lconv* localeconv()
{
return &default_locale;
}
}

25
Libraries/LibC/locale.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
enum {
LC_ALL,
LC_NUMERIC,
LC_CTYPE,
LC_COLLATE,
LC_TIME,
LC_MONETARY,
};
struct lconv {
char* decimal_point;
char* thousands_sep;
char* grouping;
};
struct lconv* localeconv();
char* setlocale(int category, const char* locale);
__END_DECLS

311
Libraries/LibC/malloc.cpp Normal file
View file

@ -0,0 +1,311 @@
#include <AK/Bitmap.h>
#include <AK/InlineLinkedList.h>
#include <AK/Vector.h>
#include <assert.h>
#include <mallocdefs.h>
#include <serenity.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
// FIXME: Thread safety.
//#define MALLOC_DEBUG
#define RECYCLE_BIG_ALLOCATIONS
#define MAGIC_PAGE_HEADER 0x42657274
#define MAGIC_BIGALLOC_HEADER 0x42697267
#define PAGE_ROUND_UP(x) ((((size_t)(x)) + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)))
static const int number_of_chunked_blocks_to_keep_around_per_size_class = 32;
static const int number_of_big_blocks_to_keep_around_per_size_class = 8;
static bool s_log_malloc = false;
static bool s_scrub_malloc = true;
static bool s_scrub_free = true;
static unsigned short size_classes[] = { 8, 16, 32, 64, 128, 252, 508, 1016, 2036, 0 };
static constexpr size_t num_size_classes = sizeof(size_classes) / sizeof(unsigned short);
struct CommonHeader {
size_t m_magic;
size_t m_size;
};
struct BigAllocationBlock : public CommonHeader {
BigAllocationBlock(size_t size)
{
m_magic = MAGIC_BIGALLOC_HEADER;
m_size = size;
}
unsigned char* m_slot[0];
};
struct FreelistEntry {
FreelistEntry* next;
};
struct ChunkedBlock : public CommonHeader
, public InlineLinkedListNode<ChunkedBlock> {
ChunkedBlock(size_t bytes_per_chunk)
{
m_magic = MAGIC_PAGE_HEADER;
m_size = bytes_per_chunk;
m_free_chunks = chunk_capacity();
m_freelist = (FreelistEntry*)chunk(0);
for (size_t i = 0; i < chunk_capacity(); ++i) {
auto* entry = (FreelistEntry*)chunk(i);
if (i != chunk_capacity() - 1)
entry->next = (FreelistEntry*)chunk(i + 1);
else
entry->next = nullptr;
}
}
ChunkedBlock* m_prev { nullptr };
ChunkedBlock* m_next { nullptr };
FreelistEntry* m_freelist { nullptr };
unsigned short m_free_chunks { 0 };
unsigned char m_slot[0];
void* chunk(int index)
{
return &m_slot[index * m_size];
}
bool is_full() const { return m_free_chunks == 0; }
size_t bytes_per_chunk() const { return m_size; }
size_t free_chunks() const { return m_free_chunks; }
size_t used_chunks() const { return chunk_capacity() - m_free_chunks; }
size_t chunk_capacity() const { return (PAGE_SIZE - sizeof(ChunkedBlock)) / m_size; }
};
struct Allocator {
size_t size { 0 };
size_t block_count { 0 };
InlineLinkedList<ChunkedBlock> usable_blocks;
InlineLinkedList<ChunkedBlock> full_blocks;
};
struct BigAllocator {
Vector<BigAllocationBlock*, number_of_big_blocks_to_keep_around_per_size_class> blocks;
};
static Allocator g_allocators[num_size_classes];
static BigAllocator g_big_allocators[1];
static Allocator* allocator_for_size(size_t size, size_t& good_size)
{
for (int i = 0; size_classes[i]; ++i) {
if (size <= size_classes[i]) {
good_size = size_classes[i];
return &g_allocators[i];
}
}
good_size = PAGE_ROUND_UP(size);
return nullptr;
}
static BigAllocator* big_allocator_for_size(size_t size)
{
if (size == 4096)
return &g_big_allocators[0];
return nullptr;
}
extern "C" {
size_t malloc_good_size(size_t size)
{
for (int i = 0; size_classes[i]; ++i) {
if (size < size_classes[i])
return size_classes[i];
}
return PAGE_ROUND_UP(size);
}
static void* os_alloc(size_t size, const char* name)
{
return mmap_with_name(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, name);
}
static void os_free(void* ptr, size_t size)
{
int rc = munmap(ptr, size);
assert(rc == 0);
}
void* malloc(size_t size)
{
if (s_log_malloc)
dbgprintf("LibC: malloc(%u)\n", size);
if (!size)
return nullptr;
size_t good_size;
auto* allocator = allocator_for_size(size, good_size);
if (!allocator) {
size_t real_size = PAGE_ROUND_UP(sizeof(BigAllocationBlock) + size);
#ifdef RECYCLE_BIG_ALLOCATIONS
if (auto* allocator = big_allocator_for_size(real_size)) {
if (!allocator->blocks.is_empty()) {
auto* block = allocator->blocks.take_last();
return &block->m_slot[0];
}
}
#endif
auto* block = (BigAllocationBlock*)os_alloc(real_size, "malloc: BigAllocationBlock");
new (block) BigAllocationBlock(real_size);
return &block->m_slot[0];
}
ChunkedBlock* block = nullptr;
for (block = allocator->usable_blocks.head(); block; block = block->next()) {
if (block->free_chunks())
break;
}
if (!block) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "malloc: ChunkedBlock(%zu)", good_size);
block = (ChunkedBlock*)os_alloc(PAGE_SIZE, buffer);
new (block) ChunkedBlock(good_size);
allocator->usable_blocks.append(block);
++allocator->block_count;
}
--block->m_free_chunks;
void* ptr = block->m_freelist;
block->m_freelist = block->m_freelist->next;
if (block->is_full()) {
#ifdef MALLOC_DEBUG
dbgprintf("Block %p is now full in size class %u\n", block, good_size);
#endif
allocator->usable_blocks.remove(block);
allocator->full_blocks.append(block);
}
#ifdef MALLOC_DEBUG
dbgprintf("LibC: allocated %p (chunk %d in block %p, size %u)\n", ptr, index, block, block->bytes_per_chunk());
#endif
if (s_scrub_malloc)
memset(ptr, MALLOC_SCRUB_BYTE, block->m_size);
return ptr;
}
void free(void* ptr)
{
if (!ptr)
return;
void* page_base = (void*)((uintptr_t)ptr & (uintptr_t)~0xfff);
size_t magic = *(size_t*)page_base;
if (magic == MAGIC_BIGALLOC_HEADER) {
auto* block = (BigAllocationBlock*)page_base;
#ifdef RECYCLE_BIG_ALLOCATIONS
if (auto* allocator = big_allocator_for_size(block->m_size)) {
if (allocator->blocks.size() < number_of_big_blocks_to_keep_around_per_size_class) {
allocator->blocks.append(block);
return;
}
}
#endif
os_free(block, block->m_size);
return;
}
assert(magic == MAGIC_PAGE_HEADER);
auto* block = (ChunkedBlock*)page_base;
#ifdef MALLOC_DEBUG
dbgprintf("LibC: freeing %p in allocator %p (size=%u, used=%u)\n", ptr, page, page->bytes_per_chunk(), page->used_chunks());
#endif
if (s_scrub_free)
memset(ptr, FREE_SCRUB_BYTE, block->bytes_per_chunk());
auto* entry = (FreelistEntry*)ptr;
entry->next = block->m_freelist;
block->m_freelist = entry;
if (block->is_full()) {
size_t good_size;
auto* allocator = allocator_for_size(block->m_size, good_size);
#ifdef MALLOC_DEBUG
dbgprintf("Block %p no longer full in size class %u\n", block, good_size);
#endif
allocator->full_blocks.remove(block);
allocator->usable_blocks.prepend(block);
}
++block->m_free_chunks;
if (!block->used_chunks()) {
size_t good_size;
auto* allocator = allocator_for_size(block->m_size, good_size);
if (allocator->block_count < number_of_chunked_blocks_to_keep_around_per_size_class) {
#ifdef MALLOC_DEBUG
dbgprintf("Keeping block %p around for size class %u\n", block, good_size);
#endif
if (allocator->usable_blocks.tail() != block) {
#ifdef MALLOC_DEBUG
dbgprintf("Moving block %p to tail of list for size class %u\n", block, good_size);
#endif
allocator->usable_blocks.remove(block);
allocator->usable_blocks.append(block);
}
return;
}
#ifdef MALLOC_DEBUG
dbgprintf("Releasing block %p for size class %u\n", block, good_size);
#endif
allocator->usable_blocks.remove(block);
--allocator->block_count;
os_free(block, PAGE_SIZE);
}
}
void* calloc(size_t count, size_t size)
{
size_t new_size = count * size;
auto* ptr = malloc(new_size);
memset(ptr, 0, new_size);
return ptr;
}
size_t malloc_size(void* ptr)
{
if (!ptr)
return 0;
void* page_base = (void*)((uintptr_t)ptr & (uintptr_t)~0xfff);
auto* header = (const CommonHeader*)page_base;
auto size = header->m_size;
if (header->m_magic == MAGIC_BIGALLOC_HEADER)
size -= sizeof(CommonHeader);
return size;
}
void* realloc(void* ptr, size_t size)
{
if (!ptr)
return malloc(size);
auto existing_allocation_size = malloc_size(ptr);
if (size <= existing_allocation_size)
return ptr;
auto* new_ptr = malloc(size);
memcpy(new_ptr, ptr, min(existing_allocation_size, size));
free(ptr);
return new_ptr;
}
void __malloc_init()
{
if (getenv("LIBC_NOSCRUB_MALLOC"))
s_scrub_malloc = false;
if (getenv("LIBC_NOSCRUB_FREE"))
s_scrub_free = false;
if (getenv("LIBC_LOG_MALLOC"))
s_log_malloc = true;
}
}

View file

@ -0,0 +1,5 @@
#pragma once
#define MALLOC_SCRUB_BYTE 0xdc
#define FREE_SCRUB_BYTE 0xed

1
Libraries/LibC/memory.h Normal file
View file

@ -0,0 +1 @@
#include <string.h>

53
Libraries/LibC/mman.cpp Normal file
View file

@ -0,0 +1,53 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <mman.h>
#include <stdio.h>
extern "C" {
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset)
{
Syscall::SC_mmap_params params { (u32)addr, size, prot, flags, fd, offset, nullptr };
int rc = syscall(SC_mmap, &params);
if (rc < 0 && -rc < EMAXERRNO) {
errno = -rc;
return (void*)-1;
}
return (void*)rc;
}
void* mmap_with_name(void* addr, size_t size, int prot, int flags, int fd, off_t offset, const char* name)
{
Syscall::SC_mmap_params params { (u32)addr, size, prot, flags, fd, offset, name };
int rc = syscall(SC_mmap, &params);
if (rc < 0 && -rc < EMAXERRNO) {
errno = -rc;
return (void*)-1;
}
return (void*)rc;
}
int munmap(void* addr, size_t size)
{
int rc = syscall(SC_munmap, addr, size);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int set_mmap_name(void* addr, size_t size, const char* name)
{
int rc = syscall(SC_set_mmap_name, addr, size, name);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int shm_open(const char* name, int flags, mode_t mode)
{
int rc = syscall(SC_shm_open, name, flags, mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int shm_unlink(const char* name)
{
int rc = syscall(SC_unlink, name);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

28
Libraries/LibC/mman.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define PROT_NONE 0x0
#define MAP_FAILED ((void*)-1)
__BEGIN_DECLS
void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t);
void* mmap_with_name(void* addr, size_t, int prot, int flags, int fd, off_t, const char* name);
int munmap(void*, size_t);
int set_mmap_name(void*, size_t, const char*);
int shm_open(const char* name, int flags, mode_t);
int shm_unlink(const char* name);
__END_DECLS

11
Libraries/LibC/mntent.cpp Normal file
View file

@ -0,0 +1,11 @@
#include <assert.h>
#include <mntent.h>
extern "C" {
struct mntent* getmntent(FILE*)
{
ASSERT_NOT_REACHED();
return nullptr;
}
}

22
Libraries/LibC/mntent.h Normal file
View file

@ -0,0 +1,22 @@
#pragma once
#include <stdio.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
#define MOUNTED "/etc/mtab"
#define MNTTAB "/etc/fstab"
struct mntent {
char* mnt_fsname;
char* mnt_dir;
char* mnt_type;
char* mnt_opts;
int mnt_freq;
int mnt_passno;
};
struct mntent* getmntent(FILE* stream);
__END_DECLS

181
Libraries/LibC/netdb.cpp Normal file
View file

@ -0,0 +1,181 @@
#include <AK/AKString.h>
#include <AK/Assertions.h>
#include <AK/ScopeGuard.h>
#include <Kernel/Net/IPv4.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
extern "C" {
static hostent __gethostbyname_buffer;
static char __gethostbyname_name_buffer[512];
static in_addr_t __gethostbyname_address;
static in_addr_t* __gethostbyname_address_list_buffer[2];
static hostent __gethostbyaddr_buffer;
static char __gethostbyaddr_name_buffer[512];
static in_addr_t* __gethostbyaddr_address_list_buffer[2];
static int connect_to_lookup_server()
{
int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
perror("socket");
return -1;
}
sockaddr_un address;
address.sun_family = AF_LOCAL;
strcpy(address.sun_path, "/tmp/.LookupServer-socket");
int retries = 3;
int rc = 0;
while (retries) {
rc = connect(fd, (const sockaddr*)&address, sizeof(address));
if (rc == 0)
break;
--retries;
sleep(1);
}
if (rc < 0) {
close(fd);
return -1;
}
return fd;
}
hostent* gethostbyname(const char* name)
{
unsigned a;
unsigned b;
unsigned c;
unsigned d;
int count = sscanf(name, "%u.%u.%u.%u", &a, &b, &c, &d);
if (count == 4 && a < 256 && b < 256 && c < 256 && d < 256) {
sprintf(__gethostbyname_name_buffer, "%u.%u.%u.%u", a, b, c, d);
__gethostbyname_buffer.h_name = __gethostbyname_name_buffer;
__gethostbyname_buffer.h_aliases = nullptr;
__gethostbyname_buffer.h_addrtype = AF_INET;
new (&__gethostbyname_address) IPv4Address(a, b, c, d);
__gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
__gethostbyname_address_list_buffer[1] = nullptr;
__gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
__gethostbyname_buffer.h_length = 4;
return &__gethostbyname_buffer;
}
int fd = connect_to_lookup_server();
if (fd < 0)
return nullptr;
auto close_fd_on_exit = ScopeGuard([fd] {
dbgprintf("closing fd\n");
close(fd);
});
auto line = String::format("L%s\n", name);
int nsent = write(fd, line.characters(), line.length());
if (nsent < 0) {
perror("write");
return nullptr;
}
ASSERT(nsent == line.length());
char buffer[1024];
int nrecv = read(fd, buffer, sizeof(buffer) - 1);
if (nrecv < 0) {
perror("recv");
return nullptr;
}
buffer[nrecv] = '\0';
if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1))
return nullptr;
int rc = inet_pton(AF_INET, buffer, &__gethostbyname_address);
if (rc <= 0)
return nullptr;
strncpy(__gethostbyname_name_buffer, name, strlen(name));
__gethostbyname_buffer.h_name = __gethostbyname_name_buffer;
__gethostbyname_buffer.h_aliases = nullptr;
__gethostbyname_buffer.h_addrtype = AF_INET;
__gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
__gethostbyname_address_list_buffer[1] = nullptr;
__gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
__gethostbyname_buffer.h_length = 4;
return &__gethostbyname_buffer;
}
hostent* gethostbyaddr(const void* addr, socklen_t addr_size, int type)
{
if (type != AF_INET) {
errno = EAFNOSUPPORT;
return nullptr;
}
if (addr_size < sizeof(in_addr)) {
errno = EINVAL;
return nullptr;
}
int fd = connect_to_lookup_server();
if (fd < 0)
return nullptr;
auto close_fd_on_exit = ScopeGuard([fd] {
close(fd);
});
IPv4Address ipv4_address((const u8*)&((const in_addr*)addr)->s_addr);
auto line = String::format("R%d.%d.%d.%d.in-addr.arpa\n",
ipv4_address[3],
ipv4_address[2],
ipv4_address[1],
ipv4_address[0]);
int nsent = write(fd, line.characters(), line.length());
if (nsent < 0) {
perror("write");
return nullptr;
}
ASSERT(nsent == line.length());
char buffer[1024];
int nrecv = read(fd, buffer, sizeof(buffer) - 1);
if (nrecv < 0) {
perror("recv");
return nullptr;
}
if (nrecv > 1) {
// Strip newline.
buffer[nrecv - 1] = '\0';
}
buffer[nrecv] = '\0';
if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1))
return nullptr;
strncpy(__gethostbyaddr_name_buffer, buffer, max(sizeof(__gethostbyaddr_name_buffer), (size_t)nrecv));
__gethostbyaddr_buffer.h_name = __gethostbyaddr_name_buffer;
__gethostbyaddr_buffer.h_aliases = nullptr;
__gethostbyaddr_buffer.h_addrtype = AF_INET;
// FIXME: Should we populate the hostent's address list here with a sockaddr_in for the provided host?
__gethostbyaddr_address_list_buffer[0] = nullptr;
__gethostbyaddr_buffer.h_addr_list = (char**)__gethostbyaddr_address_list_buffer;
__gethostbyaddr_buffer.h_length = 4;
return &__gethostbyaddr_buffer;
}
}

29
Libraries/LibC/netdb.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct hostent {
char* h_name;
char** h_aliases;
int h_addrtype;
int h_length;
char** h_addr_list;
#define h_addr h_addr_list[0]
};
struct hostent* gethostbyname(const char*);
struct hostent* gethostbyaddr(const void* addr, socklen_t len, int type);
struct servent {
char* s_name;
char** s_aliases;
int s_port;
char* s_proto;
};
struct servent* getservbyname(const char* name, const char* protocol);
__END_DECLS

View file

@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef uint32_t in_addr_t;
in_addr_t inet_addr(const char*);
#define INADDR_ANY ((in_addr_t)0)
#define INADDR_NONE ((in_addr_t)-1)
__END_DECLS

View file

@ -0,0 +1,21 @@
#pragma once
#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
struct icmphdr {
uint8_t type;
uint8_t code;
uint16_t checksum;
union {
struct {
uint16_t id;
uint16_t sequence;
} echo;
uint32_t gateway;
} un;
};
__END_DECLS

12
Libraries/LibC/poll.cpp Normal file
View file

@ -0,0 +1,12 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <poll.h>
extern "C" {
int poll(struct pollfd* fds, int nfds, int timeout)
{
int rc = syscall(SC_poll, fds, nfds, timeout);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

22
Libraries/LibC/poll.h Normal file
View file

@ -0,0 +1,22 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
#define POLLIN (1u << 0)
#define POLLPRI (1u << 2)
#define POLLOUT (1u << 3)
#define POLLERR (1u << 4)
#define POLLHUP (1u << 5)
#define POLLNVAL (1u << 6)
struct pollfd {
int fd;
short events;
short revents;
};
int poll(struct pollfd* fds, int nfds, int timeout);
__END_DECLS

75
Libraries/LibC/pthread.h Normal file
View file

@ -0,0 +1,75 @@
#pragma once
#include <sched.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef void* pthread_t;
typedef void* pthread_key_t;
typedef void* pthread_once_t;
typedef void* pthread_mutex_t;
typedef void* pthread_attr_t;
typedef void* pthread_mutexattr_t;
typedef void* pthread_cond_t;
typedef void* pthread_spinlock_t;
typedef void* pthread_condattr_t;
int pthread_create(pthread_t, pthread_attr_t*, void* (*)(void*), void*);
void pthread_exit(void*);
int pthread_kill(pthread_t, int);
void pthread_cleanup_push(void (*)(void*), void*);
void pthread_cleanup_pop(int);
int pthread_join(pthread_t, void**);
int pthread_mutex_lock(pthread_mutex_t*);
int pthread_mutex_trylock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread_mutex_t*);
int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*);
int pthread_mutex_destroy(pthread_mutex_t*);
int pthread_attr_init(pthread_attr_t*);
int pthread_attr_destroy(pthread_attr_t*);
int pthread_once(pthread_once_t*, void (*)(void));
#define PTHREAD_ONCE_INIT 0
pthread_once_t once_control = PTHREAD_ONCE_INIT;
void* pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void* value);
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_RECURSIVE 1
#define PTHREAD_MUTEX_INITIALIZER 0
#define PTHREAD_COND_INITIALIZER 0
int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
int pthread_cond_broadcast(pthread_cond_t*);
int pthread_cond_init(pthread_cond_t*, const pthread_condattr_t*);
int pthread_cond_signal(pthread_cond_t*);
int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
int pthread_condattr_destroy(pthread_condattr_t*);
int pthread_cancel(pthread_t);
void pthread_cleanup_push(void (*)(void*), void*);
void pthread_cleanup_pop(int);
int pthread_cond_broadcast(pthread_cond_t*);
int pthread_cond_destroy(pthread_cond_t*);
int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, const struct timespec*);
int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
int pthread_condattr_destroy(pthread_condattr_t*);
void pthread_testcancel(void);
int pthread_spin_destroy(pthread_spinlock_t*);
int pthread_spin_init(pthread_spinlock_t*, int);
int pthread_spin_lock(pthread_spinlock_t*);
int pthread_spin_trylock(pthread_spinlock_t*);
int pthread_spin_unlock(pthread_spinlock_t*);
int pthread_cond_destroy(pthread_cond_t*);
pthread_t pthread_self(void);
int pthread_detach(pthread_t);
int pthread_equal(pthread_t, pthread_t);
void pthread_exit(void*);
int pthread_mutexattr_init(pthread_mutexattr_t*);
int pthread_mutexattr_settype(pthread_mutexattr_t*, int);
int pthread_mutexattr_destroy(pthread_mutexattr_t*);
__END_DECLS

128
Libraries/LibC/pwd.cpp Normal file
View file

@ -0,0 +1,128 @@
#include <AK/AKString.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
extern "C" {
#define PWDB_STR_MAX_LEN 256
struct passwd_with_strings : public passwd {
char name_buffer[PWDB_STR_MAX_LEN];
char passwd_buffer[PWDB_STR_MAX_LEN];
char gecos_buffer[PWDB_STR_MAX_LEN];
char dir_buffer[PWDB_STR_MAX_LEN];
char shell_buffer[PWDB_STR_MAX_LEN];
};
static FILE* __pwdb_stream = nullptr;
static unsigned __pwdb_line_number = 0;
static struct passwd_with_strings* __pwdb_entry = nullptr;
void setpwent()
{
__pwdb_line_number = 0;
if (__pwdb_stream) {
rewind(__pwdb_stream);
} else {
__pwdb_stream = fopen("/etc/passwd", "r");
if (!__pwdb_stream) {
perror("open /etc/passwd");
}
assert(__pwdb_stream);
__pwdb_entry = (struct passwd_with_strings*)mmap_with_name(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "setpwent");
}
}
void endpwent()
{
__pwdb_line_number = 0;
if (__pwdb_stream) {
fclose(__pwdb_stream);
__pwdb_stream = nullptr;
}
if (__pwdb_entry) {
munmap(__pwdb_entry, getpagesize());
__pwdb_entry = nullptr;
}
}
struct passwd* getpwuid(uid_t uid)
{
setpwent();
while (auto* pw = getpwent()) {
if (pw->pw_uid == uid)
return pw;
}
return nullptr;
}
struct passwd* getpwnam(const char* name)
{
setpwent();
while (auto* pw = getpwent()) {
if (!strcmp(pw->pw_name, name))
return pw;
}
return nullptr;
}
struct passwd* getpwent()
{
if (!__pwdb_stream)
setpwent();
assert(__pwdb_stream);
if (feof(__pwdb_stream))
return nullptr;
next_entry:
char buffer[1024];
++__pwdb_line_number;
char* s = fgets(buffer, sizeof(buffer), __pwdb_stream);
if (!s)
return nullptr;
assert(__pwdb_stream);
if (feof(__pwdb_stream))
return nullptr;
String line(s, Chomp);
auto parts = line.split(':');
if (parts.size() != 7) {
fprintf(stderr, "getpwent(): Malformed entry on line %u\n", __pwdb_line_number);
goto next_entry;
}
auto& e_name = parts[0];
auto& e_passwd = parts[1];
auto& e_uid_string = parts[2];
auto& e_gid_string = parts[3];
auto& e_gecos = parts[4];
auto& e_dir = parts[5];
auto& e_shell = parts[6];
bool ok;
uid_t e_uid = e_uid_string.to_uint(ok);
if (!ok) {
fprintf(stderr, "getpwent(): Malformed UID on line %u\n", __pwdb_line_number);
goto next_entry;
}
gid_t e_gid = e_gid_string.to_uint(ok);
if (!ok) {
fprintf(stderr, "getpwent(): Malformed GID on line %u\n", __pwdb_line_number);
goto next_entry;
}
__pwdb_entry->pw_uid = e_uid;
__pwdb_entry->pw_gid = e_gid;
__pwdb_entry->pw_name = __pwdb_entry->name_buffer;
__pwdb_entry->pw_passwd = __pwdb_entry->passwd_buffer;
__pwdb_entry->pw_gecos = __pwdb_entry->gecos_buffer;
__pwdb_entry->pw_dir = __pwdb_entry->dir_buffer;
__pwdb_entry->pw_shell = __pwdb_entry->shell_buffer;
strncpy(__pwdb_entry->name_buffer, e_name.characters(), PWDB_STR_MAX_LEN);
strncpy(__pwdb_entry->passwd_buffer, e_passwd.characters(), PWDB_STR_MAX_LEN);
strncpy(__pwdb_entry->gecos_buffer, e_gecos.characters(), PWDB_STR_MAX_LEN);
strncpy(__pwdb_entry->dir_buffer, e_dir.characters(), PWDB_STR_MAX_LEN);
strncpy(__pwdb_entry->shell_buffer, e_shell.characters(), PWDB_STR_MAX_LEN);
return __pwdb_entry;
}
}

24
Libraries/LibC/pwd.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct passwd {
char* pw_name;
char* pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
char* pw_gecos;
char* pw_dir;
char* pw_shell;
};
struct passwd* getpwent();
void setpwent();
void endpwent();
struct passwd* getpwnam(const char* name);
struct passwd* getpwuid(uid_t);
__END_DECLS

100
Libraries/LibC/qsort.cpp Normal file
View file

@ -0,0 +1,100 @@
/*-
* Copyright (c) 1980, 1983, 1990 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)qsort.c 5.9 (Berkeley) 2/23/91";
#endif /* LIBC_SCCS and not lint */
#include <stdlib.h>
#include <sys/types.h>
static void insertion_sort(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
static void insertion_sort_r(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg);
void qsort(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
{
if (nmemb <= 1)
return;
insertion_sort(bot, nmemb, size, compar);
}
void qsort_r(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg)
{
if (nmemb <= 1)
return;
insertion_sort_r(bot, nmemb, size, compar, arg);
}
void insertion_sort(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
{
int cnt;
unsigned char ch;
char *s1, *s2, *t1, *t2, *top;
top = (char*)bot + nmemb * size;
for (t1 = (char*)bot + size; t1 < top;) {
for (t2 = t1; (t2 -= size) >= bot && compar(t1, t2) < 0;)
;
if (t1 != (t2 += size)) {
for (cnt = size; cnt--; ++t1) {
ch = *t1;
for (s1 = s2 = t1; (s2 -= size) >= t2; s1 = s2)
*s1 = *s2;
*s1 = ch;
}
} else
t1 += size;
}
}
void insertion_sort_r(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg)
{
int cnt;
unsigned char ch;
char *s1, *s2, *t1, *t2, *top;
top = (char*)bot + nmemb * size;
for (t1 = (char*)bot + size; t1 < top;) {
for (t2 = t1; (t2 -= size) >= bot && compar(t1, t2, arg) < 0;)
;
if (t1 != (t2 += size)) {
for (cnt = size; cnt--; ++t1) {
ch = *t1;
for (s1 = s2 = t1; (s2 -= size) >= t2; s1 = s2)
*s1 = *s2;
*s1 = ch;
}
} else
t1 += size;
}
}

218
Libraries/LibC/scanf.cpp Normal file
View file

@ -0,0 +1,218 @@
/*
* 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 <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
static const char* determine_base(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 > (int)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 = determine_base(p, base);
if (_atob(&v, p, base)) {
*vp = v;
return 1;
}
return 0;
}
#define ISSPACE " \t\n\r\f\v"
int vsscanf(const char* buf, const char* s, va_list ap)
{
int base = 10;
char* t;
char tmp[BUFSIZ];
bool noassign = 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 >= '1' && *s <= '9') {
const char* tc;
for (tc = s; isdigit(*s); s++)
;
strncpy(tmp, tc, s - tc);
tmp[s - tc] = '\0';
atob((uint32_t*)&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 {
auto* p = strchr(buf, *(s + 1));
if (p)
width = p - buf;
else {
noassign = true;
width = 0;
}
}
}
strncpy(tmp, buf, width);
tmp[width] = '\0';
buf += width;
if (!noassign) {
if (!atob(va_arg(ap, uint32_t*), tmp, base))
noassign = true;
}
}
if (!noassign)
++count;
width = 0;
noassign = false;
++s;
} else {
while (isspace(*buf))
buf++;
if (*s != *buf)
break;
else {
++s;
++buf;
}
}
}
return count;
}

36
Libraries/LibC/sched.cpp Normal file
View file

@ -0,0 +1,36 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <sched.h>
extern "C" {
int sched_yield()
{
int rc = syscall(SC_yield);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int sched_get_priority_min(int policy)
{
(void)policy;
return 0; // Idle
}
int sched_get_priority_max(int policy)
{
(void)policy;
return 3; // High
}
int sched_setparam(pid_t pid, const struct sched_param* param)
{
int rc = syscall(SC_sched_setparam, pid, param);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int sched_getparam(pid_t pid, struct sched_param* param)
{
int rc = syscall(SC_sched_getparam, pid, param);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

24
Libraries/LibC/sched.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
int sched_yield();
struct sched_param {
int sched_priority;
};
#define SCHED_FIFO 0
#define SCHED_RR 1
#define SCHED_OTHER 2
#define SCHED_BATCH 3
int sched_get_priority_min(int policy);
int sched_get_priority_max(int policy);
int sched_setparam(pid_t pid, const struct sched_param* param);
int sched_getparam(pid_t pid, struct sched_param* param);
__END_DECLS

37
Libraries/LibC/serenity.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include <stdio.h>
#include <unistd.h>
#ifdef __cplusplus
struct Stopwatch {
union SplitQword {
struct {
uint32_t lsw;
uint32_t msw;
};
uint64_t qw { 0 };
};
public:
Stopwatch(const char* name)
: m_name(name)
{
read_tsc(&m_start.lsw, &m_start.msw);
}
~Stopwatch()
{
SplitQword end;
read_tsc(&end.lsw, &end.msw);
uint64_t diff = end.qw - m_start.qw;
dbgprintf("Stopwatch(%s): %Q ticks\n", m_name, diff);
}
private:
const char* m_name { nullptr };
SplitQword m_start;
};
#endif // __cplusplus

31
Libraries/LibC/setjmp.S Normal file
View file

@ -0,0 +1,31 @@
.global setjmp
setjmp:
mov 4(%esp), %eax
mov %ebx, 0(%eax)
mov %esi, 4(%eax)
mov %edi, 8(%eax)
mov %ebp, 12(%eax)
lea 4(%esp), %ecx
mov %ecx, 16(%eax)
mov (%esp), %ecx
mov %ecx, 20(%eax)
xor %eax, %eax
ret
.global longjmp
longjmp:
mov 4(%esp), %edx
mov 8(%esp), %eax
mov 0(%edx), %ebx
mov 4(%edx), %esi
mov 8(%edx), %edi
mov 12(%edx), %ebp
mov 16(%edx), %ecx
mov %ecx, %esp
mov 20(%edx), %ecx
test %eax, %eax
jnz .nonzero
mov 1, %eax
.nonzero:
jmp *%ecx

25
Libraries/LibC/setjmp.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct __jmp_buf {
uint32_t regs[6];
bool did_save_signal_mask;
sigset_t saved_signal_mask;
};
typedef struct __jmp_buf jmp_buf[1];
int setjmp(jmp_buf);
void longjmp(jmp_buf, int val);
int sigsetjmp(jmp_buf, int savesigs);
void siglongjmp(jmp_buf, int val);
__END_DECLS

163
Libraries/LibC/signal.cpp Normal file
View file

@ -0,0 +1,163 @@
#include <Kernel/Syscall.h>
#include <assert.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
extern "C" {
int kill(pid_t pid, int sig)
{
int rc = syscall(SC_kill, pid, sig);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int killpg(int pgrp, int sig)
{
int rc = syscall(SC_killpg, pgrp, sig);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int raise(int sig)
{
// FIXME: Support multi-threaded programs.
return kill(getpid(), sig);
}
sighandler_t signal(int signum, sighandler_t handler)
{
struct sigaction new_act;
struct sigaction old_act;
new_act.sa_handler = handler;
new_act.sa_flags = 0;
new_act.sa_mask = 0;
int rc = sigaction(signum, &new_act, &old_act);
if (rc < 0)
return SIG_ERR;
return old_act.sa_handler;
}
int sigaction(int signum, const struct sigaction* act, struct sigaction* old_act)
{
int rc = syscall(SC_sigaction, signum, act, old_act);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int sigemptyset(sigset_t* set)
{
*set = 0;
return 0;
}
int sigfillset(sigset_t* set)
{
*set = 0xffffffff;
return 0;
}
int sigaddset(sigset_t* set, int sig)
{
if (sig < 1 || sig > 32) {
errno = EINVAL;
return -1;
}
*set |= 1 << (sig);
return 0;
}
int sigdelset(sigset_t* set, int sig)
{
if (sig < 1 || sig > 32) {
errno = EINVAL;
return -1;
}
*set &= ~(1 << (sig));
return 0;
}
int sigismember(const sigset_t* set, int sig)
{
if (sig < 1 || sig > 32) {
errno = EINVAL;
return -1;
}
if (*set & (1 << (sig)))
return 1;
return 0;
}
int sigprocmask(int how, const sigset_t* set, sigset_t* old_set)
{
int rc = syscall(SC_sigprocmask, how, set, old_set);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int sigpending(sigset_t* set)
{
int rc = syscall(SC_sigpending, set);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
const char* sys_siglist[NSIG] = {
"Invalid signal number",
"Hangup",
"Interrupt",
"Quit",
"Illegal instruction",
"Trap",
"Aborted",
"Bus error",
"Division by zero",
"Killed",
"User signal 1",
"Segmentation violation",
"User signal 2",
"Broken pipe",
"Alarm clock",
"Terminated",
"Stack fault",
"Child exited",
"Continued",
"Stopped (signal)",
"Stopped",
"Stopped (tty input)",
"Stopped (tty output)",
"Urgent I/O condition)",
"CPU limit exceeded",
"File size limit exceeded",
"Virtual timer expired",
"Profiling timer expired",
"Window changed",
"I/O possible",
"Power failure",
"Bad system call",
};
int sigsetjmp(jmp_buf env, int savesigs)
{
if (savesigs) {
int rc = sigprocmask(0, nullptr, &env->saved_signal_mask);
assert(rc == 0);
env->did_save_signal_mask = true;
} else {
env->did_save_signal_mask = false;
}
return setjmp(env);
}
void siglongjmp(jmp_buf env, int val)
{
if (env->did_save_signal_mask) {
int rc = sigprocmask(SIG_SETMASK, &env->saved_signal_mask, nullptr);
assert(rc == 0);
}
longjmp(env, val);
}
int sigsuspend(const sigset_t*)
{
dbgprintf("FIXME: Implement sigsuspend()\n");
ASSERT_NOT_REACHED();
}
}

52
Libraries/LibC/signal.h Normal file
View file

@ -0,0 +1,52 @@
#pragma once
#include <signal_numbers.h>
#include <sys/types.h>
__BEGIN_DECLS
typedef void (*__sighandler_t)(int);
typedef __sighandler_t sighandler_t;
typedef uint32_t sigset_t;
typedef void siginfo_t;
typedef uint32_t sig_atomic_t;
struct sigaction {
union {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t*, void*);
};
sigset_t sa_mask;
int sa_flags;
};
int kill(pid_t, int sig);
int killpg(int pgrp, int sig);
sighandler_t signal(int sig, sighandler_t);
int sigaction(int sig, const struct sigaction* act, struct sigaction* old_act);
int sigemptyset(sigset_t*);
int sigfillset(sigset_t*);
int sigaddset(sigset_t*, int sig);
int sigdelset(sigset_t*, int sig);
int sigismember(const sigset_t*, int sig);
int sigprocmask(int how, const sigset_t* set, sigset_t* old_set);
int sigpending(sigset_t*);
int sigsuspend(const sigset_t*);
int raise(int sig);
extern const char* sys_siglist[NSIG];
#define SIG_DFL ((__sighandler_t)0)
#define SIG_ERR ((__sighandler_t)-1)
#define SIG_IGN ((__sighandler_t)1)
#define SA_NOCLDSTOP 1
#define SA_NOCLDWAIT 2
#define SA_SIGINFO 4
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
__END_DECLS

View file

@ -0,0 +1,35 @@
#pragma once
#define SIGINVAL 0
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPWR 30
#define SIGSYS 31
#define NSIG 32

31
Libraries/LibC/stat.cpp Normal file
View file

@ -0,0 +1,31 @@
#include <Kernel/Syscall.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
extern "C" {
mode_t umask(mode_t mask)
{
return syscall(SC_umask, mask);
}
int mkdir(const char* pathname, mode_t mode)
{
int rc = syscall(SC_mkdir, pathname, mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int chmod(const char* pathname, mode_t mode)
{
int rc = syscall(SC_chmod, pathname, mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int fchmod(int fd, mode_t mode)
{
int rc = syscall(SC_fchmod, fd, mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

18
Libraries/LibC/stdarg.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#ifdef KERNEL
# define __BEGIN_DECLS
# define __END_DECLS
#else
# include <sys/cdefs.h>
#endif
__BEGIN_DECLS
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
__END_DECLS

16
Libraries/LibC/stdbool.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#ifndef __cplusplus
# include <sys/cdefs.h>
__BEGIN_DECLS
# define bool _Bool
# define true 1
# define false 0
# define __bool_true_false_are_Defined 1
__END_DECLS
#endif

13
Libraries/LibC/stddef.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
#ifdef __cplusplus
# define NULL nullptr
#else
# define NULL ((void*)0)
#endif
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;

107
Libraries/LibC/stdint.h Normal file
View file

@ -0,0 +1,107 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef __UINT64_TYPE__ uint64_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __INT64_TYPE__ int64_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT8_TYPE__ int8_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
#define __int8_t_defined 1
#define __uint8_t_defined 1
#define __int16_t_defined 1
#define __uint16_t_defined 1
#define __int32_t_defined 1
#define __uint32_t_defined 1
#define __int64_t_defined 1
#define __uint64_t_defined 1
typedef __PTRDIFF_TYPE__ uintptr_t;
typedef __PTRDIFF_TYPE__ intptr_t;
typedef __UINTMAX_TYPE__ uintmax_t;
#define UINTMAX_MAX __UINTMAX_MAX__
#define UINTMAX_MIN __UINTMAX_MIN__
typedef __INTMAX_TYPE__ intmax_t;
#define INTMAX_MAX __INTMAX_MAX__
#define INTMAX_MIN (-INTMAX_MAX - 1)
#define INT8_MIN (-128)
#define INT16_MIN (-32767 - 1)
#define INT32_MIN (-2147483647 - 1)
#define INT64_MIN (-9223372036854775807LL - 1LL)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX (9223372036854775807LL)
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX (18446744073709551615ULL)
#define INTPTR_MAX INT32_MAX
#define INTPTR_MIN INT32_MIN
#define UINTPTR_MAX UINT32_MAX
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define INT64_C(x) x##LL
#define UINT64_C(x) x##ULL
__END_DECLS

619
Libraries/LibC/stdio.cpp Normal file
View file

@ -0,0 +1,619 @@
#include <AK/PrintfImplementation.h>
#include <AK/StdLibExtras.h>
#include <AK/ValueRestorer.h>
#include <Kernel/Syscall.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
extern "C" {
static FILE __default_streams[4];
FILE* stdin;
FILE* stdout;
FILE* stderr;
FILE* stddbg;
void init_FILE(FILE& fp, int fd, int mode)
{
fp.fd = fd;
fp.buffer = fp.default_buffer;
fp.buffer_size = BUFSIZ;
fp.mode = mode;
}
static FILE* make_FILE(int fd)
{
auto* fp = (FILE*)malloc(sizeof(FILE));
memset(fp, 0, sizeof(FILE));
init_FILE(*fp, fd, isatty(fd));
return fp;
}
void __stdio_init()
{
stdin = &__default_streams[0];
stdout = &__default_streams[1];
stderr = &__default_streams[2];
stddbg = &__default_streams[3];
init_FILE(*stdin, 0, isatty(0) ? _IOLBF : _IOFBF);
init_FILE(*stdout, 1, isatty(1) ? _IOLBF : _IOFBF);
init_FILE(*stderr, 2, _IONBF);
int fd = open("/dev/debuglog", O_WRONLY | O_CLOEXEC);
if (fd < 0) {
perror("open /dev/debuglog");
ASSERT_NOT_REACHED();
}
init_FILE(*stddbg, fd, _IOLBF);
}
int setvbuf(FILE* stream, char* buf, int mode, size_t size)
{
if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
errno = EINVAL;
return -1;
}
stream->mode = mode;
if (buf) {
stream->buffer = buf;
stream->buffer_size = size;
} else {
stream->buffer = stream->default_buffer;
stream->buffer_size = BUFSIZ;
}
stream->buffer_index = 0;
return 0;
}
void setbuf(FILE* stream, char* buf)
{
setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
}
void setlinebuf(FILE* stream)
{
setvbuf(stream, nullptr, _IOLBF, 0);
}
int fileno(FILE* stream)
{
assert(stream);
return stream->fd;
}
int feof(FILE* stream)
{
assert(stream);
return stream->eof;
}
int fflush(FILE* stream)
{
// FIXME: fflush(NULL) should flush all open output streams.
ASSERT(stream);
if (!stream->buffer_index)
return 0;
int rc = write(stream->fd, stream->buffer, stream->buffer_index);
stream->buffer_index = 0;
stream->error = 0;
stream->eof = 0;
if (rc < 0) {
stream->error = errno;
return EOF;
}
return 0;
}
char* fgets(char* buffer, int size, FILE* stream)
{
assert(stream);
ssize_t nread = 0;
for (;;) {
if (nread >= size)
break;
int ch = fgetc(stream);
if (ch == EOF) {
if (nread == 0)
return nullptr;
break;
}
buffer[nread++] = ch;
if (!ch || ch == '\n')
break;
}
if (nread < size)
buffer[nread] = '\0';
return buffer;
}
int fgetc(FILE* stream)
{
assert(stream);
char ch;
size_t nread = fread(&ch, sizeof(char), 1, stream);
if (nread <= 0) {
stream->eof = nread == 0;
stream->error = errno;
return EOF;
}
return ch;
}
int getc(FILE* stream)
{
return fgetc(stream);
}
int getchar()
{
return getc(stdin);
}
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
{
char *ptr, *eptr;
if (*lineptr == nullptr || *n == 0) {
*n = BUFSIZ;
if ((*lineptr = static_cast<char*>(malloc(*n))) == nullptr) {
return -1;
}
}
for (ptr = *lineptr, eptr = *lineptr + *n;;) {
int c = fgetc(stream);
if (c == -1) {
if (feof(stream)) {
return ptr == *lineptr ? -1 : ptr - *lineptr;
} else {
return -1;
}
}
*ptr++ = c;
if (c == delim) {
*ptr = '\0';
return ptr - *lineptr;
}
if (ptr + 2 >= eptr) {
char *nbuf;
size_t nbuf_sz = *n * 2;
ssize_t d = ptr - *lineptr;
if ((nbuf = static_cast<char*>(realloc(*lineptr, nbuf_sz))) == nullptr) {
return -1;
}
*lineptr = nbuf;
*n = nbuf_sz;
eptr = nbuf + nbuf_sz;
ptr = nbuf + d;
}
}
}
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
return getdelim(lineptr, n, '\n', stream);
}
int ungetc(int c, FILE* stream)
{
ASSERT(stream);
if (stream->have_ungotten)
return EOF;
stream->have_ungotten = true;
stream->ungotten = c;
stream->eof = false;
return c;
}
int fputc(int ch, FILE* stream)
{
assert(stream);
assert(stream->buffer_index < stream->buffer_size);
stream->buffer[stream->buffer_index++] = ch;
if (stream->buffer_index >= stream->buffer_size)
fflush(stream);
else if (stream->mode == _IONBF || (stream->mode == _IOLBF && ch == '\n'))
fflush(stream);
if (stream->eof || stream->error)
return EOF;
return (u8)ch;
}
int putc(int ch, FILE* stream)
{
return fputc(ch, stream);
}
int putchar(int ch)
{
return putc(ch, stdout);
}
int fputs(const char* s, FILE* stream)
{
for (; *s; ++s) {
int rc = putc(*s, stream);
if (rc == EOF)
return EOF;
}
return 1;
}
int puts(const char* s)
{
int rc = fputs(s, stdout);
if (rc == EOF)
return EOF;
return fputc('\n', stdout);
}
void clearerr(FILE* stream)
{
assert(stream);
stream->eof = false;
stream->error = 0;
}
int ferror(FILE* stream)
{
return stream->error;
}
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
{
assert(stream);
if (!size)
return 0;
ssize_t nread = 0;
if (stream->have_ungotten) {
// FIXME: Support ungotten character even if size != 1.
ASSERT(size == 1);
((char*)ptr)[0] = stream->ungotten;
stream->have_ungotten = false;
--nmemb;
if (!nmemb)
return 1;
ptr = &((char*)ptr)[1];
++nread;
}
ssize_t rc = read(stream->fd, ptr, nmemb * size);
if (rc < 0) {
stream->error = errno;
return 0;
}
if (rc == 0)
stream->eof = true;
nread += rc;
return nread / size;
}
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
{
assert(stream);
auto* bytes = (const u8*)ptr;
ssize_t nwritten = 0;
for (size_t i = 0; i < (size * nmemb); ++i) {
int rc = fputc(bytes[i], stream);
if (rc == EOF)
break;
++nwritten;
}
return nwritten / size;
}
int fseek(FILE* stream, long offset, int whence)
{
assert(stream);
fflush(stream);
off_t off = lseek(stream->fd, offset, whence);
if (off < 0)
return off;
stream->eof = false;
stream->error = 0;
stream->have_ungotten = false;
stream->ungotten = 0;
return 0;
}
long ftell(FILE* stream)
{
assert(stream);
fflush(stream);
return lseek(stream->fd, 0, SEEK_CUR);
}
void rewind(FILE* stream)
{
fseek(stream, 0, SEEK_SET);
}
int dbgprintf(const char* fmt, ...)
{
// if this fails, you're printing too early.
ASSERT(stddbg);
int errno_backup = errno;
va_list ap;
va_start(ap, fmt);
int ret = vfprintf(stddbg, fmt, ap);
va_end(ap);
errno = errno_backup;
return ret;
}
static void stdout_putch(char*&, char ch)
{
putchar(ch);
}
static FILE* __current_stream = nullptr;
static void stream_putch(char*&, char ch)
{
fputc(ch, __current_stream);
}
int vfprintf(FILE* stream, const char* fmt, va_list ap)
{
__current_stream = stream;
return printf_internal(stream_putch, nullptr, fmt, ap);
}
int fprintf(FILE* stream, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vfprintf(stream, fmt, ap);
va_end(ap);
return ret;
}
int vprintf(const char* fmt, va_list ap)
{
return printf_internal(stdout_putch, nullptr, fmt, ap);
}
int printf(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
static void buffer_putch(char*& bufptr, char ch)
{
*bufptr++ = ch;
}
int vsprintf(char* buffer, const char* fmt, va_list ap)
{
int ret = printf_internal(buffer_putch, buffer, fmt, ap);
buffer[ret] = '\0';
return ret;
}
int sprintf(char* buffer, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vsprintf(buffer, fmt, ap);
buffer[ret] = '\0';
va_end(ap);
return ret;
}
static size_t __vsnprintf_space_remaining;
static void sized_buffer_putch(char*& bufptr, char ch)
{
if (__vsnprintf_space_remaining) {
*bufptr++ = ch;
--__vsnprintf_space_remaining;
}
}
int vsnprintf(char* buffer, size_t size, const char* fmt, va_list ap)
{
__vsnprintf_space_remaining = size;
int ret = printf_internal(sized_buffer_putch, buffer, fmt, ap);
buffer[ret] = '\0';
return ret;
}
int snprintf(char* buffer, size_t size, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vsnprintf(buffer, size, fmt, ap);
buffer[ret] = '\0';
va_end(ap);
return ret;
}
void perror(const char* s)
{
fprintf(stderr, "%s: %s\n", s, strerror(errno));
}
FILE* fopen(const char* pathname, const char* mode)
{
int flags = 0;
if (!strcmp(mode, "r") || !strcmp(mode, "rb"))
flags = O_RDONLY;
else if (!strcmp(mode, "r+") || !strcmp(mode, "rb+"))
flags = O_RDWR;
else if (!strcmp(mode, "w") || !strcmp(mode, "wb"))
flags = O_WRONLY | O_CREAT | O_TRUNC;
else if (!strcmp(mode, "w+") || !strcmp(mode, "wb+"))
flags = O_RDWR | O_CREAT | O_TRUNC;
else {
fprintf(stderr, "FIXME(LibC): fopen('%s', '%s')\n", pathname, mode);
ASSERT_NOT_REACHED();
}
int fd = open(pathname, flags, 0666);
if (fd < 0)
return nullptr;
return make_FILE(fd);
}
FILE* freopen(const char* pathname, const char* mode, FILE* stream)
{
(void)pathname;
(void)mode;
(void)stream;
ASSERT_NOT_REACHED();
}
FILE* fdopen(int fd, const char* mode)
{
UNUSED_PARAM(mode);
// FIXME: Verify that the mode matches how fd is already open.
if (fd < 0)
return nullptr;
return make_FILE(fd);
}
int fclose(FILE* stream)
{
fflush(stream);
int rc = close(stream->fd);
if (stream != &__default_streams[0] && stream != &__default_streams[1] && stream != &__default_streams[2] && stream != &__default_streams[3])
free(stream);
return rc;
}
int rename(const char* oldpath, const char* newpath)
{
int rc = syscall(SC_rename, oldpath, newpath);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
char* tmpnam(char*)
{
ASSERT_NOT_REACHED();
}
FILE* popen(const char* command, const char* type)
{
if (!type || (*type != 'r' && *type != 'w')) {
errno = EINVAL;
return nullptr;
}
int pipe_fds[2];
int rc = pipe(pipe_fds);
if (rc < 0) {
ValueRestorer restorer(errno);
perror("pipe");
return nullptr;
}
pid_t child_pid = fork();
if (!child_pid) {
if (*type == 'r') {
int rc = dup2(pipe_fds[1], STDOUT_FILENO);
if (rc < 0) {
perror("dup2");
exit(1);
}
close(pipe_fds[0]);
close(pipe_fds[1]);
} else if (*type == 'w') {
int rc = dup2(pipe_fds[0], STDIN_FILENO);
if (rc < 0) {
perror("dup2");
exit(1);
}
close(pipe_fds[0]);
close(pipe_fds[1]);
}
int rc = execl("/bin/sh", "sh", "-c", command, nullptr);
if (rc < 0)
perror("execl");
exit(1);
}
FILE* fp = nullptr;
if (*type == 'r') {
fp = make_FILE(pipe_fds[0]);
close(pipe_fds[1]);
} else if (*type == 'w') {
fp = make_FILE(pipe_fds[1]);
close(pipe_fds[0]);
}
fp->popen_child = child_pid;
return fp;
}
int pclose(FILE* fp)
{
ASSERT(fp);
ASSERT(fp->popen_child != 0);
int wstatus = 0;
int rc = waitpid(fp->popen_child, &wstatus, 0);
if (rc < 0)
return rc;
return wstatus;
}
int remove(const char* pathname)
{
int rc = unlink(pathname);
if (rc < 0 && errno != EISDIR)
return -1;
return rmdir(pathname);
}
int scanf(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(stdin, fmt, ap);
va_end(ap);
return count;
}
int fscanf(FILE* stream, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(stream, fmt, ap);
va_end(ap);
return count;
}
int sscanf(const char* buffer, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vsscanf(buffer, fmt, ap);
va_end(ap);
return count;
}
int vfscanf(FILE* stream, const char* fmt, va_list ap)
{
char buffer[BUFSIZ];
if (!fgets(buffer, sizeof(buffer) - 1, stream))
return -1;
return vsscanf(buffer, fmt, ap);
}
FILE* tmpfile()
{
dbgprintf("FIXME: Implement tmpfile()\n");
ASSERT_NOT_REACHED();
}
}

103
Libraries/LibC/stdio.h Normal file
View file

@ -0,0 +1,103 @@
#pragma once
#define _STDIO_H // Make GMP believe we exist.
#include <limits.h>
#include <stdarg.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#define BUFSIZ 1024
__BEGIN_DECLS
#ifndef EOF
# define EOF (-1)
#endif
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define _IOFBF 0
#define _IOLBF 1
#define _IONBF 2
#define L_tmpnam 256
struct __STDIO_FILE {
int fd;
int eof;
int error;
int mode;
pid_t popen_child;
char* buffer;
size_t buffer_size;
size_t buffer_index;
int have_ungotten;
char ungotten;
char default_buffer[BUFSIZ];
};
typedef struct __STDIO_FILE FILE;
extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr;
extern FILE* stddbg;
typedef size_t fpos_t;
int fseek(FILE*, long offset, int whence);
int fgetpos(FILE*, fpos_t*);
int fsetpos(FILE*, const fpos_t*);
long ftell(FILE*);
char* fgets(char* buffer, int size, FILE*);
int fputc(int ch, FILE*);
int fileno(FILE*);
int fgetc(FILE*);
int getc(FILE*);
int getchar();
ssize_t getdelim(char**, size_t*, int, FILE*);
ssize_t getline(char**, size_t*, FILE*);
int ungetc(int c, FILE*);
int remove(const char* pathname);
FILE* fdopen(int fd, const char* mode);
FILE* fopen(const char* pathname, const char* mode);
FILE* freopen(const char* pathname, const char* mode, FILE*);
int fclose(FILE*);
void rewind(FILE*);
void clearerr(FILE*);
int ferror(FILE*);
int feof(FILE*);
int fflush(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 vprintf(const char* fmt, va_list);
int vfprintf(FILE*, const char* fmt, va_list);
int vsprintf(char* buffer, const char* fmt, va_list);
int vsnprintf(char* buffer, size_t, const char* fmt, va_list);
int fprintf(FILE*, const char* fmt, ...);
int printf(const char* fmt, ...);
int dbgprintf(const char* fmt, ...);
int sprintf(char* buffer, const char* fmt, ...);
int snprintf(char* buffer, size_t, const char* fmt, ...);
int putchar(int ch);
int putc(int ch, FILE*);
int puts(const char*);
int fputs(const char*, FILE*);
void perror(const char*);
int scanf(const char* fmt, ...);
int sscanf(const char* str, const char* fmt, ...);
int fscanf(FILE*, const char* fmt, ...);
int vfscanf(FILE*, const char*, va_list);
int vsscanf(const char*, const char*, va_list);
int setvbuf(FILE*, char* buf, int mode, size_t);
void setbuf(FILE*, char* buf);
void setlinebuf(FILE*);
int rename(const char* oldpath, const char* newpath);
FILE* tmpfile();
char* tmpnam(char*);
FILE* popen(const char* command, const char* type);
int pclose(FILE*);
__END_DECLS

380
Libraries/LibC/stdlib.cpp Normal file
View file

@ -0,0 +1,380 @@
#include <AK/AKString.h>
#include <AK/Assertions.h>
#include <AK/HashMap.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <Kernel/Syscall.h>
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
extern "C" {
typedef void (*__atexit_handler)();
static int __atexit_handler_count = 0;
static __atexit_handler __atexit_handlers[32];
void exit(int status)
{
for (int i = 0; i < __atexit_handler_count; ++i)
__atexit_handlers[i]();
extern void _fini();
_fini();
fflush(stdout);
fflush(stderr);
_exit(status);
ASSERT_NOT_REACHED();
}
int atexit(void (*handler)())
{
ASSERT(__atexit_handler_count < 32);
__atexit_handlers[__atexit_handler_count++] = handler;
return 0;
}
void abort()
{
raise(SIGABRT);
ASSERT_NOT_REACHED();
}
static HashTable<const char*> s_malloced_environment_variables;
static void free_environment_variable_if_needed(const char* var)
{
if (!s_malloced_environment_variables.contains(var))
return;
free(const_cast<char*>(var));
s_malloced_environment_variables.remove(var);
}
char* getenv(const char* name)
{
size_t vl = strlen(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;
if (vl != varLength)
continue;
if (strncmp(decl, name, varLength) == 0) {
return eq + 1;
}
}
return nullptr;
}
int unsetenv(const char* name)
{
auto new_var_len = strlen(name);
size_t environ_size = 0;
int skip = -1;
for (; environ[environ_size]; ++environ_size) {
char* old_var = environ[environ_size];
char* old_eq = strchr(old_var, '=');
ASSERT(old_eq);
size_t old_var_len = old_eq - old_var;
if (new_var_len != old_var_len)
continue; // can't match
if (strncmp(name, old_var, new_var_len) == 0)
skip = environ_size;
}
if (skip == -1)
return 0; // not found: no failure.
// Shuffle the existing array down by one.
memmove(&environ[skip], &environ[skip + 1], ((environ_size - 1) - skip) * sizeof(environ[0]));
environ[environ_size - 1] = nullptr;
free_environment_variable_if_needed(name);
return 0;
}
int setenv(const char* name, const char* value, int overwrite)
{
if (!overwrite && !getenv(name))
return 0;
auto length = strlen(name) + strlen(value) + 2;
auto* var = (char*)malloc(length);
snprintf(var, length, "%s=%s", name, value);
s_malloced_environment_variables.set(var);
return putenv(var);
}
int putenv(char* new_var)
{
char* new_eq = strchr(new_var, '=');
if (!new_eq)
return unsetenv(new_var);
auto new_var_len = new_eq - new_var;
int environ_size = 0;
for (; environ[environ_size]; ++environ_size) {
char* old_var = environ[environ_size];
char* old_eq = strchr(old_var, '=');
ASSERT(old_eq);
auto old_var_len = old_eq - old_var;
if (new_var_len != old_var_len)
continue; // can't match
if (strncmp(new_var, old_var, new_var_len) == 0) {
free_environment_variable_if_needed(old_var);
environ[environ_size] = new_var;
return 0;
}
}
// At this point, we need to append the new var.
// 2 here: one for the new var, one for the sentinel value.
char** new_environ = (char**)malloc((environ_size + 2) * sizeof(char*));
if (new_environ == nullptr) {
errno = ENOMEM;
return -1;
}
for (int i = 0; environ[i]; ++i) {
new_environ[i] = environ[i];
}
new_environ[environ_size] = new_var;
new_environ[environ_size + 1] = nullptr;
// swap new and old
// note that the initial environ is not heap allocated!
extern bool __environ_is_malloced;
if (__environ_is_malloced)
free(environ);
__environ_is_malloced = true;
environ = new_environ;
return 0;
}
double strtod(const char* str, char** endptr)
{
(void)str;
(void)endptr;
dbgprintf("LibC: strtod: '%s'\n", str);
ASSERT_NOT_REACHED();
}
float strtof(const char* str, char** endptr)
{
(void)str;
(void)endptr;
dbgprintf("LibC: strtof: '%s'\n", str);
ASSERT_NOT_REACHED();
}
double atof(const char* str)
{
dbgprintf("LibC: atof: '%s'\n", str);
ASSERT_NOT_REACHED();
}
int atoi(const char* str)
{
size_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 value;
value = value * 10;
value += str[i] - '0';
}
return isNegative ? -value : value;
}
long atol(const char* str)
{
static_assert(sizeof(int) == sizeof(long));
return atoi(str);
}
long long atoll(const char* str)
{
dbgprintf("FIXME(Libc): atoll('%s') passing through to atol()\n", str);
return atol(str);
}
static char ptsname_buf[32];
char* ptsname(int fd)
{
if (ptsname_r(fd, ptsname_buf, sizeof(ptsname_buf)) < 0)
return nullptr;
return ptsname_buf;
}
int ptsname_r(int fd, char* buffer, size_t size)
{
int rc = syscall(SC_ptsname_r, fd, buffer, size);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
static unsigned long s_next_rand = 1;
int rand()
{
s_next_rand = s_next_rand * 1103515245 + 12345;
return ((unsigned)(s_next_rand / ((RAND_MAX + 1) * 2)) % (RAND_MAX + 1));
}
void srand(unsigned seed)
{
s_next_rand = seed;
}
int abs(int i)
{
return i < 0 ? -i : i;
}
long int random()
{
return rand();
}
void srandom(unsigned seed)
{
srand(seed);
}
int system(const char* command)
{
auto child = fork();
if (!child) {
int rc = execl("/bin/sh", "sh", "-c", command, nullptr);
if (rc < 0)
perror("execl");
exit(0);
}
int wstatus;
waitpid(child, &wstatus, 0);
return WEXITSTATUS(wstatus);
}
char* mktemp(char* pattern)
{
int length = strlen(pattern);
// FIXME: Check for an invalid template pattern and return EINVAL.
if (length < 6) {
pattern[0] = '\0';
errno = EINVAL;
return pattern;
}
int start = length - 6;
static constexpr char random_characters[] = "abcdefghijklmnopqrstuvwxyz0123456789";
for (int attempt = 0; attempt < 100; ++attempt) {
for (int i = 0; i < 6; ++i)
pattern[start + i] = random_characters[(rand() % sizeof(random_characters))];
struct stat st;
int rc = lstat(pattern, &st);
if (rc < 0 && errno == ENOENT)
return pattern;
}
pattern[0] = '\0';
errno = EEXIST;
return pattern;
}
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
{
dbgprintf("FIXME(LibC): bsearch(%p, %p, %u, %u, %p)\n", key, base, nmemb, size, compar);
ASSERT_NOT_REACHED();
}
div_t div(int numerator, int denominator)
{
div_t result;
result.quot = numerator / denominator;
result.rem = numerator % denominator;
return result;
}
ldiv_t ldiv(long numerator, long denominator)
{
ldiv_t result;
result.quot = numerator / denominator;
result.rem = numerator % denominator;
return result;
}
size_t mbstowcs(wchar_t*, const char*, size_t)
{
ASSERT_NOT_REACHED();
}
long strtol(const char* str, char** endptr, int base)
{
int sign = 1;
while (isspace(*str))
str++;
if (*str == '-' || *str == '+') {
if (*str == '-')
sign = -1;
str++;
}
if (base == 0 || base == 16) {
if (base == 0)
base = 10;
if (*str == '0') {
str++;
if (*str == 'X' || *str == 'x') {
str++;
base = 16;
} else if (base != 16) {
base = 8;
}
}
}
const char* estr = str + strlen(str) - 1;
long track = 1;
long num = 0;
while (estr >= str) {
if ((*estr >= '0' && *estr <= '9') || (base > 10 && (*estr >= 'A' && *estr <= 'Z'))) {
int digit_value = *estr - '0';
if (*estr >= 'A' && *estr <= 'Z')
digit_value = 10 + (*estr - 'A');
num += (track *= base) / base * digit_value;
} else {
if (endptr != NULL)
*endptr = const_cast<char*>(estr);
return 0;
};
estr--;
}
return num * sign;
}
unsigned long strtoul(const char* str, char** endptr, int base)
{
auto value = strtol(str, endptr, base);
ASSERT(value >= 0);
return value;
}
}

61
Libraries/LibC/stdlib.h Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define MB_CUR_MAX 1
__attribute__((malloc)) __attribute__((alloc_size(1))) void* malloc(size_t);
__attribute__((malloc)) __attribute__((alloc_size(1, 2))) void* calloc(size_t nmemb, size_t);
size_t malloc_size(void*);
void free(void*);
void* realloc(void* ptr, size_t);
char* getenv(const char* name);
int putenv(char*);
int unsetenv(const char*);
int setenv(const char* name, const char* value, int overwrite);
int atoi(const char*);
long atol(const char*);
long long atoll(const char*);
double strtod(const char*, char** endptr);
float strtof(const char*, char** endptr);
long strtol(const char*, char** endptr, int base);
unsigned long strtoul(const char*, char** endptr, int base);
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
void qsort_r(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg);
int atexit(void (*function)());
__attribute__((noreturn)) void exit(int status);
__attribute__((noreturn)) void abort();
char* ptsname(int fd);
int ptsname_r(int fd, char* buffer, size_t);
int abs(int);
long labs(long);
double atof(const char*);
int system(const char* command);
char* mktemp(char*);
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
#define RAND_MAX 32767
int rand();
void srand(unsigned seed);
long int random();
void srandom(unsigned seed);
typedef struct {
int quot;
int rem;
} div_t;
div_t div(int, int);
typedef struct {
long quot;
long rem;
} ldiv_t;
ldiv_t ldiv(long, long);
__END_DECLS

411
Libraries/LibC/string.cpp Normal file
View file

@ -0,0 +1,411 @@
#include "ctype.h"
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" {
void bzero(void* dest, size_t n)
{
memset(dest, 0, n);
}
void bcopy(const void* src, void* dest, size_t n)
{
memmove(dest, src, n);
}
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;
while (*(str++))
++len;
return len;
}
char* strdup(const char* str)
{
size_t len = strlen(str);
char* new_str = (char*)malloc(len + 1);
strcpy(new_str, str);
return new_str;
}
char* strndup(const char* str, size_t maxlen)
{
size_t len = min(strlen(str), maxlen);
char* new_str = (char*)malloc(len + 1);
memcpy(new_str, str, len);
new_str[len] = 0;
return new_str;
}
int strcmp(const char* s1, const char* s2)
{
while (*s1 == *s2++)
if (*s1++ == 0)
return 0;
return *(const unsigned char*)s1 - *(const unsigned char*)--s2;
}
int strncmp(const char* s1, const char* s2, size_t n)
{
if (!n)
return 0;
do {
if (*s1 != *s2++)
return *(const unsigned char*)s1 - *(const unsigned char*)--s2;
if (*s1++ == 0)
break;
} while (--n);
return 0;
}
int strcasecmp(const char* s1, const char* s2)
{
int c1, c2;
for (;;) {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
if (c1 == 0 || c1 != c2) {
return c1 - c2;
}
}
}
int strncasecmp(const char* s1, const char* s2, size_t n)
{
if (n == 0) {
return 0;
}
while (n-- != 0 && tolower(*s1) == tolower(*s2)) {
if (n == 0 || *s1 == '\0' || *s2 == '\0') {
break;
}
s1++;
s2++;
}
return tolower(*s1) - tolower(*s2);
}
int memcmp(const void* v1, const void* v2, size_t n)
{
auto* s1 = (const uint8_t*)v1;
auto* s2 = (const uint8_t*)v2;
while (n-- > 0) {
if (*s1++ != *s2++)
return s1[-1] < s2[-1] ? -1 : 1;
}
return 0;
}
void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
{
if (n >= 1024)
return mmx_memcpy(dest_ptr, src_ptr, n);
u32 dest = (u32)dest_ptr;
u32 src = (u32)src_ptr;
// FIXME: Support starting at an unaligned address.
if (!(dest & 0x3) && !(src & 0x3) && n >= 12) {
size_t u32s = n / sizeof(u32);
asm volatile(
"rep movsl\n"
: "=S"(src), "=D"(dest)
: "S"(src), "D"(dest), "c"(u32s)
: "memory");
n -= u32s * sizeof(u32);
if (n == 0)
return dest_ptr;
}
asm volatile(
"rep movsb\n" ::"S"(src), "D"(dest), "c"(n)
: "memory");
return dest_ptr;
}
void* memset(void* dest_ptr, int c, size_t n)
{
u32 dest = (u32)dest_ptr;
// FIXME: Support starting at an unaligned address.
if (!(dest & 0x3) && n >= 12) {
size_t u32s = n / sizeof(u32);
u32 expanded_c = (u8)c;
expanded_c |= expanded_c << 8;
expanded_c |= expanded_c << 16;
asm volatile(
"rep stosl\n"
: "=D"(dest)
: "D"(dest), "c"(u32s), "a"(expanded_c)
: "memory");
n -= u32s * sizeof(u32);
if (n == 0)
return dest_ptr;
}
asm volatile(
"rep stosb\n"
: "=D"(dest), "=c"(n)
: "0"(dest), "1"(n), "a"(c)
: "memory");
return dest_ptr;
}
void* memmove(void* dest, const void* src, size_t n)
{
if (dest < src)
return memcpy(dest, src, n);
u8* pd = (u8*)dest;
const u8* ps = (const u8*)src;
for (pd += n, ps += n; n--;)
*--pd = *--ps;
return dest;
}
char* strcpy(char* dest, const char* src)
{
char* originalDest = dest;
while ((*dest++ = *src++) != '\0')
;
return originalDest;
}
char* strncpy(char* dest, const char* src, size_t n)
{
size_t i;
for (i = 0; i < n && src[i] != '\0'; ++i)
dest[i] = src[i];
for (; i < n; ++i)
dest[i] = '\0';
return dest;
}
char* strchr(const char* str, int c)
{
char ch = c;
for (;; ++str) {
if (*str == ch)
return const_cast<char*>(str);
if (!*str)
return nullptr;
}
}
void* memchr(const void* ptr, int c, size_t size)
{
char ch = c;
auto* cptr = (const char*)ptr;
for (size_t i = 0; i < size; ++i) {
if (cptr[i] == ch)
return const_cast<char*>(cptr + i);
}
return nullptr;
}
char* strrchr(const char* str, int ch)
{
char* last = nullptr;
char c;
for (; (c = *str); ++str) {
if (c == ch)
last = const_cast<char*>(str);
}
return last;
}
char* strcat(char* dest, const char* src)
{
size_t dest_length = strlen(dest);
size_t i;
for (i = 0; src[i] != '\0'; i++)
dest[dest_length + i] = src[i];
dest[dest_length + i] = '\0';
return dest;
}
char* strncat(char* dest, const char* src, size_t n)
{
size_t dest_length = strlen(dest);
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++)
dest[dest_length + i] = src[i];
dest[dest_length + i] = '\0';
return dest;
}
const char* sys_errlist[] = {
"Success (not an error)",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted syscall",
"I/O error",
"No such device or address",
"Argument list too long",
"Exec format error",
"Bad fd number",
"No child processes",
"Try again",
"Out of memory",
"Permission denied",
"Bad address",
"Block device required",
"Device or resource busy",
"File already exists",
"Cross-device link",
"No such device",
"Not a directory",
"Is a directory",
"Invalid argument",
"File table overflow",
"Too many open files",
"Not a TTY",
"Text file busy",
"File too large",
"No space left on device",
"Illegal seek",
"Read-only filesystem",
"Too many links",
"Broken pipe",
"Range error",
"Name too long",
"Too many symlinks",
"Overflow",
"Operation not supported",
"No such syscall",
"Not implemented",
"Address family not supported",
"Not a socket",
"Address in use",
"Failed without setting an error code (bug!)",
"Directory not empty",
"Math argument out of domain",
"Connection refused",
"Address not available",
"Already connected",
"Connection aborted",
"Connection already in progress",
"Connection reset",
"Desination address required",
"Host unreachable",
"Illegal byte sequence",
"Message size",
"Network down",
"Network unreachable",
"Network reset",
"No buffer space",
"No lock available",
"No message",
"No protocol option",
"Not connected",
"Operation would block",
"Protocol not supported",
"Resource deadlock would occur",
"Timed out",
"Wrong protocol type",
"Operation in progress",
"No such thread",
"The highest errno +1 :^)",
};
int sys_nerr = EMAXERRNO;
char* strerror(int errnum)
{
if (errnum >= EMAXERRNO) {
printf("strerror() missing string for errnum=%d\n", errnum);
return const_cast<char*>("Unknown error");
}
return const_cast<char*>(sys_errlist[errnum]);
}
char* strsignal(int signum)
{
if (signum >= NSIG) {
printf("strsignal() missing string for signum=%d\n", signum);
return const_cast<char*>("Unknown signal");
}
return const_cast<char*>(sys_siglist[signum]);
}
char* strstr(const char* haystack, const char* needle)
{
char nch;
char hch;
if ((nch = *needle++) != 0) {
size_t len = strlen(needle);
do {
do {
if ((hch = *haystack++) == 0)
return nullptr;
} while (hch != nch);
} while (strncmp(haystack, needle, len) != 0);
--haystack;
}
return const_cast<char*>(haystack);
}
char* strpbrk(const char* s, const char* accept)
{
while (*s)
if (strchr(accept, *s++))
return const_cast<char*>(--s);
return nullptr;
}
char* strtok(char* str, const char* delim)
{
(void)str;
(void)delim;
ASSERT_NOT_REACHED();
}
int strcoll(const char* s1, const char* s2)
{
return strcmp(s1, s2);
}
size_t strxfrm(char* dest, const char* src, size_t n)
{
size_t i;
for (i = 0; i < n && src[i] != '\0'; ++i)
dest[i] = src[i];
for (; i < n; ++i)
dest[i] = '\0';
return i;
}
}

38
Libraries/LibC/string.h Normal file
View file

@ -0,0 +1,38 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
size_t strlen(const char*);
int strcmp(const char*, const char*);
int strncmp(const char*, const char*, size_t);
int strcasecmp(const char*, const char*);
int strncasecmp(const char*, const char*, size_t);
int memcmp(const void*, const void*, size_t);
void* memcpy(void*, const void*, size_t);
void* memmove(void*, const void*, size_t);
void* memchr(const void*, int c, size_t);
void bzero(void*, size_t);
void bcopy(const void*, void*, size_t);
void* memset(void*, int, size_t);
char* strdup(const char*);
char* strndup(const char*, 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* strstr(const char* haystack, const char* needle);
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);
char* strerror(int errnum);
char* strsignal(int signum);
char* strpbrk(const char*, const char* accept);
char* strtok(char* str, const char* delim);
int strcoll(const char* s1, const char* s2);
size_t strxfrm(char* dest, const char* src, size_t n);
__END_DECLS

View file

@ -0,0 +1,35 @@
#include <assert.h>
#include <ctype.h>
#include <strings.h>
extern "C" {
static char foldcase(char ch)
{
if (isalpha(ch))
return tolower(ch);
return ch;
}
int strcasecmp(const char* s1, const char* s2)
{
for (; foldcase(*s1) == foldcase(*s2); ++s1, ++s2) {
if (*s1 == 0)
return 0;
}
return foldcase(*(const unsigned char*)s1) < foldcase(*(const unsigned char*)s2) ? -1 : 1;
}
int strncasecmp(const char* s1, const char* s2, size_t n)
{
if (!n)
return 0;
do {
if (foldcase(*s1) != foldcase(*s2++))
return foldcase(*(const unsigned char*)s1) - foldcase(*(const unsigned char*)--s2);
if (*s1++ == 0)
break;
} while (--n);
return 0;
}
}

11
Libraries/LibC/strings.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
int strcasecmp(const char*, const char*);
int strncasecmp(const char*, const char*, size_t);
__END_DECLS

View file

@ -0,0 +1,24 @@
#pragma once
#define _POSIX_VERSION 200809L
#ifndef ALWAYS_INLINE
# define ALWAYS_INLINE inline __attribute__((always_inline))
#endif
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
#undef __P
#define __P(a) a
#define offsetof(type, member) __builtin_offsetof(type, member)
#ifdef __cplusplus
//extern "C" int main(int, char**);
#endif

View file

View file

@ -0,0 +1,15 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/ioctl_numbers.h>
__BEGIN_DECLS
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
};
int ioctl(int fd, unsigned request, ...);
__END_DECLS

View file

@ -0,0 +1,14 @@
#pragma once
enum IOCtlNumber {
TIOCGPGRP,
TIOCSPGRP,
TCGETS,
TCSETS,
TCSETSW,
TCSETSF,
TIOCGWINSZ,
TIOCSCTTY,
TIOCNOTTY,
TIOCSWINSZ,
};

View file

@ -0,0 +1 @@
#include <mman.h>

View file

@ -0,0 +1,4 @@
#pragma once
#include <endian.h>
#include <limits.h>

View file

@ -0,0 +1,32 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/time.h>
__BEGIN_DECLS
struct rusage {
struct timeval ru_utime;
struct timeval ru_stime;
long ru_maxrss;
long ru_ixrss;
long ru_idrss;
long ru_isrss;
long ru_minflt;
long ru_majflt;
long ru_nswap;
long ru_inblock;
long ru_oublock;
long ru_msgsnd;
long ru_msgrcv;
long ru_nsignals;
long ru_nvcsw;
long ru_nivcsw;
};
#define RUSAGE_SELF 1
#define RUSAGE_CHILDREN 2
int getrusage(int who, struct rusage* usage);
__END_DECLS

View file

@ -0,0 +1,14 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <stdio.h>
#include <sys/select.h>
extern "C" {
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout)
{
Syscall::SC_select_params params { nfds, readfds, writefds, exceptfds, timeout };
int rc = syscall(SC_select, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

View file

@ -0,0 +1,12 @@
#pragma once
#include <fd_set.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
__END_DECLS

View file

@ -0,0 +1,88 @@
#include <AK/Assertions.h>
#include <Kernel/Syscall.h>
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
extern "C" {
int socket(int domain, int type, int protocol)
{
int rc = syscall(SC_socket, domain, type, protocol);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int bind(int sockfd, const sockaddr* addr, socklen_t addrlen)
{
int rc = syscall(SC_bind, sockfd, addr, addrlen);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int listen(int sockfd, int backlog)
{
int rc = syscall(SC_listen, sockfd, backlog);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int accept(int sockfd, sockaddr* addr, socklen_t* addrlen)
{
int rc = syscall(SC_accept, sockfd, addr, addrlen);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int connect(int sockfd, const sockaddr* addr, socklen_t addrlen)
{
int rc = syscall(SC_connect, sockfd, addr, addrlen);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
ssize_t sendto(int sockfd, const void* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
{
Syscall::SC_sendto_params params { sockfd, data, data_length, flags, addr, addr_length };
int rc = syscall(SC_sendto, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
ssize_t send(int sockfd, const void* data, size_t data_length, int flags)
{
return sendto(sockfd, data, data_length, flags, nullptr, 0);
}
ssize_t recvfrom(int sockfd, void* buffer, size_t buffer_length, int flags, struct sockaddr* addr, socklen_t* addr_length)
{
Syscall::SC_recvfrom_params params { sockfd, buffer, buffer_length, flags, addr, addr_length };
int rc = syscall(SC_recvfrom, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
ssize_t recv(int sockfd, void* buffer, size_t buffer_length, int flags)
{
return recvfrom(sockfd, buffer, buffer_length, flags, nullptr, nullptr);
}
int getsockopt(int sockfd, int level, int option, void* value, socklen_t* value_size)
{
Syscall::SC_getsockopt_params params { sockfd, level, option, value, value_size };
int rc = syscall(SC_getsockopt, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int setsockopt(int sockfd, int level, int option, const void* value, socklen_t value_size)
{
Syscall::SC_setsockopt_params params { sockfd, level, option, value, value_size };
int rc = syscall(SC_setsockopt, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
{
int rc = syscall(SC_getsockname, sockfd, addr, addrlen);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
{
int rc = syscall(SC_getpeername, sockfd, addr, addrlen);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

View file

@ -0,0 +1,70 @@
#pragma once
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/un.h>
__BEGIN_DECLS
#define AF_MASK 0xff
#define AF_UNSPEC 0
#define AF_LOCAL 1
#define AF_UNIX AF_LOCAL
#define AF_INET 2
#define PF_LOCAL AF_LOCAL
#define PF_UNIX PF_LOCAL
#define PF_INET AF_INET
#define SOCK_TYPE_MASK 0xff
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define SOCK_NONBLOCK 04000
#define SOCK_CLOEXEC 02000000
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define MSG_DONTWAIT 0x40
struct sockaddr {
uint16_t sa_family;
char sa_data[14];
};
struct in_addr {
uint32_t s_addr;
};
struct sockaddr_in {
uint16_t sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
#define SOL_SOCKET 1
#define SOMAXCONN 128
#define SO_RCVTIMEO 1
#define SO_SNDTIMEO 2
#define SO_KEEPALIVE 3
#define SO_ERROR 4
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr* addr, socklen_t);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr*, socklen_t*);
int connect(int sockfd, const struct sockaddr*, socklen_t);
ssize_t send(int sockfd, const void*, size_t, int flags);
ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
ssize_t recv(int sockfd, void*, size_t, int flags);
ssize_t recvfrom(int sockfd, void*, size_t, int flags, struct sockaddr*, socklen_t*);
int getsockopt(int sockfd, int level, int option, void*, socklen_t*);
int setsockopt(int sockfd, int level, int option, const void*, socklen_t);
int getsockname(int sockfd, struct sockaddr*, socklen_t*);
int getpeername(int sockfd, struct sockaddr*, socklen_t*);
__END_DECLS

26
Libraries/LibC/sys/stat.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <fcntl.h>
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)
mode_t umask(mode_t);
int chmod(const char* pathname, mode_t);
int fchmod(int fd, mode_t);
int mkdir(const char* pathname, mode_t);
inline dev_t makedev(unsigned int major, unsigned int minor) { return (minor & 0xffu) | (major << 8u) | ((minor & ~0xffu) << 12u); }
inline unsigned int major(dev_t dev) { return (dev & 0xfff00u) >> 8u; }
inline unsigned int minor(dev_t dev) { return (dev & 0xffu) | ((dev >> 12u) & 0xfff00u); }
__END_DECLS

View file

20
Libraries/LibC/sys/time.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
int gettimeofday(struct timeval* __restrict__, void* __restrict__) __attribute__((nonnull(1)));
__END_DECLS

View file

@ -0,0 +1,17 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
clock_t times(struct tms*);
__END_DECLS

View file

@ -0,0 +1,61 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef int __pid_t;
#define pid_t __pid_t
typedef int __ssize_t;
#define ssize_t __ssize_t
typedef __WINT_TYPE__ wint_t;
typedef uint32_t ino_t;
typedef int32_t off_t;
typedef uint32_t dev_t;
typedef uint16_t mode_t;
typedef uint32_t nlink_t;
typedef uint32_t blksize_t;
typedef uint32_t blkcnt_t;
typedef uint32_t time_t;
typedef uint32_t useconds_t;
typedef int32_t suseconds_t;
typedef uint32_t clock_t;
#define __socklen_t_defined
#define __socklen_t uint32_t
typedef __socklen_t socklen_t;
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
struct utimbuf {
time_t actime;
time_t modtime;
};
__END_DECLS

View file

@ -0,0 +1,12 @@
#include <Kernel/Syscall.h>
#include <errno.h>
#include <sys/uio.h>
extern "C" {
ssize_t writev(int fd, const struct iovec* iov, int iov_count)
{
int rc = syscall(SC_writev, fd, iov, iov_count);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

15
Libraries/LibC/sys/uio.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
struct iovec {
void* iov_base;
size_t iov_len;
};
ssize_t writev(int fd, const struct iovec*, int iov_count);
__END_DECLS

13
Libraries/LibC/sys/un.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
#define UNIX_PATH_MAX 108
struct sockaddr_un {
uint16_t sun_family;
char sun_path[UNIX_PATH_MAX];
};
__END_DECLS

View file

@ -0,0 +1,19 @@
#pragma once
#include <sys/cdefs.h>
#define UTSNAME_ENTRY_LEN 65
__BEGIN_DECLS
struct utsname {
char sysname[UTSNAME_ENTRY_LEN];
char nodename[UTSNAME_ENTRY_LEN];
char release[UTSNAME_ENTRY_LEN];
char version[UTSNAME_ENTRY_LEN];
char machine[UTSNAME_ENTRY_LEN];
};
int uname(struct utsname*);
__END_DECLS

View file

@ -0,0 +1,11 @@
#include <assert.h>
#include <sys/wait.h>
#include <unistd.h>
extern "C" {
pid_t wait(int* wstatus)
{
return waitpid(-1, wstatus, 0);
}
}

21
Libraries/LibC/sys/wait.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
#define WEXITSTATUS(status) (((status)&0xff00) >> 8)
#define WTERMSIG(status) ((status)&0x7f)
#define WIFEXITED(status) (WTERMSIG(status) == 0)
#define WIFSIGNALED(status) (((char)(((status)&0x7f) + 1) >> 1) > 0)
#define WNOHANG 1
#define WUNTRACED 2
#define WSTOPPED WUNTRACED
#define WEXITED 4
#define WCONTINUED 8
pid_t wait(int* wstatus);
__END_DECLS

129
Libraries/LibC/termcap.cpp Normal file
View file

@ -0,0 +1,129 @@
#include <AK/AKString.h>
#include <AK/HashMap.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <termcap.h>
//#define TERMCAP_DEBUG
extern "C" {
char PC;
char* UP;
char* BC;
int tgetent(char* bp, const char* name)
{
(void)bp;
(void)name;
#ifdef TERMCAP_DEBUG
fprintf(stderr, "tgetent: bp=%p, name='%s'\n", bp, name);
#endif
PC = '\0';
BC = const_cast<char*>("\033[D");
UP = const_cast<char*>("\033[A");
return 1;
}
static HashMap<String, const char*>* caps = nullptr;
void ensure_caps()
{
if (caps)
return;
caps = new HashMap<String, const char*>;
caps->set("DC", "\033[%p1%dP");
caps->set("IC", "\033[%p1%d@");
caps->set("ce", "\033[K");
caps->set("cl", "\033[H\033[J");
caps->set("cr", "\015");
caps->set("dc", "\033[P");
caps->set("ei", "");
caps->set("ic", "");
caps->set("im", "");
caps->set("kd", "\033[B");
caps->set("kl", "\033[D");
caps->set("kr", "\033[C");
caps->set("ku", "\033[A");
caps->set("ks", "");
caps->set("ke", "");
caps->set("le", "\033[D");
caps->set("mm", "");
caps->set("mo", "");
caps->set("pc", "");
caps->set("up", "\033[A");
caps->set("vb", "");
caps->set("am", "");
caps->set("@7", "");
caps->set("kH", "");
caps->set("kI", "\033[L");
caps->set("kh", "\033[H");
caps->set("vs", "");
caps->set("ve", "");
caps->set("E3", "");
caps->set("kD", "");
caps->set("nd", "\033[C");
caps->set("co", "80");
caps->set("li", "25");
}
char* tgetstr(const char* id, char** area)
{
ensure_caps();
#ifdef TERMCAP_DEBUG
fprintf(stderr, "tgetstr: id='%s'\n", id);
#endif
auto it = caps->find(id);
if (it != caps->end()) {
char* ret = *area;
const char* val = (*it).value;
strcpy(*area, val);
*area += strlen(val) + 1;
return ret;
}
fprintf(stderr, "tgetstr: missing cap id='%s'\n", id);
return nullptr;
}
int tgetflag(const char* id)
{
(void)id;
#ifdef TERMCAP_DEBUG
fprintf(stderr, "tgetflag: '%s'\n", id);
#endif
auto it = caps->find(id);
if (it != caps->end())
return 1;
return 0;
}
int tgetnum(const char* id)
{
#ifdef TERMCAP_DEBUG
fprintf(stderr, "tgetnum: '%s'\n", id);
#endif
auto it = caps->find(id);
if (it != caps->end())
return atoi((*it).value);
ASSERT_NOT_REACHED();
}
char* tgoto(const char* cap, int col, int row)
{
(void)cap;
(void)col;
(void)row;
ASSERT_NOT_REACHED();
}
int tputs(const char* str, int affcnt, int (*putc)(int))
{
(void)affcnt;
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i)
putc(str[i]);
return 0;
}
}

18
Libraries/LibC/termcap.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#include <sys/cdefs.h>
__BEGIN_DECLS
extern char PC;
extern char* UP;
extern char* BC;
int tgetent(char* bp, const char* name);
int tgetflag(const char* id);
int tgetnum(const char* id);
char* tgetstr(const char* id, char** area);
char* tgoto(const char* cap, int col, int row);
int tputs(const char* str, int affcnt, int (*putc)(int));
__END_DECLS

View file

@ -0,0 +1,51 @@
#include <Kernel/Syscall.h>
#include <assert.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <termios.h>
extern "C" {
int tcgetattr(int fd, struct termios* t)
{
return ioctl(fd, TCGETS, t);
}
int tcsetattr(int fd, int optional_actions, const struct termios* t)
{
switch (optional_actions) {
case TCSANOW:
return ioctl(fd, TCSETS, t);
case TCSADRAIN:
return ioctl(fd, TCSETSW, t);
case TCSAFLUSH:
return ioctl(fd, TCSETSF, t);
}
errno = EINVAL;
return -1;
}
int tcflow(int fd, int action)
{
(void)fd;
(void)action;
ASSERT_NOT_REACHED();
}
int tcflush(int fd, int queue_selector)
{
(void)fd;
(void)queue_selector;
ASSERT_NOT_REACHED();
}
speed_t cfgetispeed(const struct termios* tp)
{
return tp->c_ispeed;
}
speed_t cfgetospeed(const struct termios* tp)
{
return tp->c_ospeed;
}
}

204
Libraries/LibC/termios.h Normal file
View file

@ -0,0 +1,204 @@
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
#define NCCS 32
typedef uint32_t tcflag_t;
typedef uint8_t cc_t;
typedef uint32_t speed_t;
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_cc[NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
int tcgetattr(int fd, struct termios*);
int tcsetattr(int fd, int optional_actions, const struct termios*);
int tcflow(int fd, int action);
int tcflush(int fd, int queue_selector);
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
/* c_iflag bits */
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IUCLC 0001000
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */
#define OPOST 0000001
#define OLCUC 0000002
#define ONLCR 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 0000100
#define OFDEL 0000200
#if defined __USE_MISC || defined __USE_XOPEN
# define NLDLY 0000400
# define NL0 0000000
# define NL1 0000400
# define CRDLY 0003000
# define CR0 0000000
# define CR1 0001000
# define CR2 0002000
# define CR3 0003000
# define TABDLY 0014000
# define TAB0 0000000
# define TAB1 0004000
# define TAB2 0010000
# define TAB3 0014000
# define BSDLY 0020000
# define BS0 0000000
# define BS1 0020000
# define FFDLY 0100000
# define FF0 0000000
# define FF1 0100000
#endif
#define VTDLY 0040000
#define VT0 0000000
#define VT1 0040000
#ifdef __USE_MISC
# define XTABS 0014000
#endif
/* c_cflag bit meaning */
#ifdef __USE_MISC
# define CBAUD 0010017
#endif
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#ifdef __USE_MISC
# define EXTA B19200
# define EXTB B38400
#endif
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#ifdef __USE_MISC
# define CBAUDEX 0010000
#endif
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
#define __MAX_BAUD B4000000
#ifdef __USE_MISC
# define CIBAUD 002003600000 /* input baud rate (not used) */
# define CMSPAR 010000000000 /* mark or space (stick) parity */
# define CRTSCTS 020000000000 /* flow control */
#endif
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
#if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
# define XCASE 0000004
#endif
#define ECHO 0000010
#define ECHOE 0000020
#define ECHOK 0000040
#define ECHONL 0000100
#define NOFLSH 0000200
#define TOSTOP 0000400
#ifdef __USE_MISC
# define ECHOCTL 0001000
# define ECHOPRT 0002000
# define ECHOKE 0004000
# define FLUSHO 0010000
# define PENDIN 0040000
#endif
#define IEXTEN 0100000
#ifdef __USE_MISC
# define EXTPROC 0200000
#endif
/* tcflow() and TCXONC use these */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/* tcsetattr uses these */
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
__END_DECLS

Some files were not shown because too many files have changed in this diff Show more