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:
parent
63814ffebf
commit
04b9dc2d30
328 changed files with 36 additions and 36 deletions
94
Libraries/LibC/Makefile
Normal file
94
Libraries/LibC/Makefile
Normal 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
|
56
Libraries/LibC/SharedBuffer.cpp
Normal file
56
Libraries/LibC/SharedBuffer.cpp
Normal 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();
|
||||
}
|
||||
}
|
24
Libraries/LibC/SharedBuffer.h
Normal file
24
Libraries/LibC/SharedBuffer.h
Normal 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
3
Libraries/LibC/alloca.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#define alloca __builtin_alloca
|
59
Libraries/LibC/arpa/inet.cpp
Normal file
59
Libraries/LibC/arpa/inet.cpp
Normal 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;
|
||||
}
|
||||
}
|
42
Libraries/LibC/arpa/inet.h
Normal file
42
Libraries/LibC/arpa/inet.h
Normal 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
18
Libraries/LibC/assert.cpp
Normal 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
23
Libraries/LibC/assert.h
Normal 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
54
Libraries/LibC/crt0.cpp
Normal 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
9
Libraries/LibC/crti.S
Normal 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
7
Libraries/LibC/crtn.S
Normal file
|
@ -0,0 +1,7 @@
|
|||
.section .init
|
||||
pop %ebp
|
||||
ret
|
||||
|
||||
.section .fini
|
||||
pop %ebp
|
||||
ret
|
38
Libraries/LibC/ctype.cpp
Normal file
38
Libraries/LibC/ctype.cpp
Normal 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
49
Libraries/LibC/ctype.h
Normal 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
94
Libraries/LibC/dirent.cpp
Normal 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
30
Libraries/LibC/dirent.h
Normal 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
25
Libraries/LibC/dlfcn.cpp
Normal 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
17
Libraries/LibC/dlfcn.h
Normal 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
11
Libraries/LibC/endian.h
Normal 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
23
Libraries/LibC/errno.h
Normal 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
|
74
Libraries/LibC/errno_numbers.h
Normal file
74
Libraries/LibC/errno_numbers.h
Normal 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
17
Libraries/LibC/fcntl.cpp
Normal 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
72
Libraries/LibC/fcntl.h
Normal 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
13
Libraries/LibC/fd_set.h
Normal 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
0
Libraries/LibC/float.h
Normal file
107
Libraries/LibC/getopt.cpp
Normal file
107
Libraries/LibC/getopt.cpp
Normal 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
13
Libraries/LibC/getopt.h
Normal 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
141
Libraries/LibC/grp.cpp
Normal 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
23
Libraries/LibC/grp.h
Normal 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
13
Libraries/LibC/iconv.h
Normal 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
14
Libraries/LibC/install.sh
Executable 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
20
Libraries/LibC/inttypes.h
Normal 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
17
Libraries/LibC/ioctl.cpp
Normal 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
26
Libraries/LibC/limits.h
Normal 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
27
Libraries/LibC/locale.cpp
Normal 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
25
Libraries/LibC/locale.h
Normal 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
311
Libraries/LibC/malloc.cpp
Normal 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;
|
||||
}
|
||||
}
|
5
Libraries/LibC/mallocdefs.h
Normal file
5
Libraries/LibC/mallocdefs.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#define MALLOC_SCRUB_BYTE 0xdc
|
||||
#define FREE_SCRUB_BYTE 0xed
|
||||
|
1
Libraries/LibC/memory.h
Normal file
1
Libraries/LibC/memory.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include <string.h>
|
53
Libraries/LibC/mman.cpp
Normal file
53
Libraries/LibC/mman.cpp
Normal 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, ¶ms);
|
||||
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, ¶ms);
|
||||
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
28
Libraries/LibC/mman.h
Normal 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
11
Libraries/LibC/mntent.cpp
Normal 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
22
Libraries/LibC/mntent.h
Normal 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
181
Libraries/LibC/netdb.cpp
Normal 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
29
Libraries/LibC/netdb.h
Normal 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
|
14
Libraries/LibC/netinet/in.h
Normal file
14
Libraries/LibC/netinet/in.h
Normal 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
|
21
Libraries/LibC/netinet/ip_icmp.h
Normal file
21
Libraries/LibC/netinet/ip_icmp.h
Normal 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
12
Libraries/LibC/poll.cpp
Normal 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
22
Libraries/LibC/poll.h
Normal 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
75
Libraries/LibC/pthread.h
Normal 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
128
Libraries/LibC/pwd.cpp
Normal 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
24
Libraries/LibC/pwd.h
Normal 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
100
Libraries/LibC/qsort.cpp
Normal 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
218
Libraries/LibC/scanf.cpp
Normal 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
36
Libraries/LibC/sched.cpp
Normal 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
24
Libraries/LibC/sched.h
Normal 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
37
Libraries/LibC/serenity.h
Normal 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
31
Libraries/LibC/setjmp.S
Normal 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
25
Libraries/LibC/setjmp.h
Normal 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
163
Libraries/LibC/signal.cpp
Normal 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
52
Libraries/LibC/signal.h
Normal 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
|
35
Libraries/LibC/signal_numbers.h
Normal file
35
Libraries/LibC/signal_numbers.h
Normal 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
31
Libraries/LibC/stat.cpp
Normal 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
18
Libraries/LibC/stdarg.h
Normal 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
16
Libraries/LibC/stdbool.h
Normal 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
13
Libraries/LibC/stddef.h
Normal 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
107
Libraries/LibC/stdint.h
Normal 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
619
Libraries/LibC/stdio.cpp
Normal 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
103
Libraries/LibC/stdio.h
Normal 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
380
Libraries/LibC/stdlib.cpp
Normal 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
61
Libraries/LibC/stdlib.h
Normal 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
411
Libraries/LibC/string.cpp
Normal 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
38
Libraries/LibC/string.h
Normal 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
|
35
Libraries/LibC/strings.cpp
Normal file
35
Libraries/LibC/strings.cpp
Normal 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
11
Libraries/LibC/strings.h
Normal 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
|
24
Libraries/LibC/sys/cdefs.h
Normal file
24
Libraries/LibC/sys/cdefs.h
Normal 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
|
0
Libraries/LibC/sys/file.h
Normal file
0
Libraries/LibC/sys/file.h
Normal file
15
Libraries/LibC/sys/ioctl.h
Normal file
15
Libraries/LibC/sys/ioctl.h
Normal 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
|
14
Libraries/LibC/sys/ioctl_numbers.h
Normal file
14
Libraries/LibC/sys/ioctl_numbers.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
enum IOCtlNumber {
|
||||
TIOCGPGRP,
|
||||
TIOCSPGRP,
|
||||
TCGETS,
|
||||
TCSETS,
|
||||
TCSETSW,
|
||||
TCSETSF,
|
||||
TIOCGWINSZ,
|
||||
TIOCSCTTY,
|
||||
TIOCNOTTY,
|
||||
TIOCSWINSZ,
|
||||
};
|
1
Libraries/LibC/sys/mman.h
Normal file
1
Libraries/LibC/sys/mman.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include <mman.h>
|
4
Libraries/LibC/sys/param.h
Normal file
4
Libraries/LibC/sys/param.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
#include <endian.h>
|
||||
#include <limits.h>
|
32
Libraries/LibC/sys/resource.h
Normal file
32
Libraries/LibC/sys/resource.h
Normal 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
|
14
Libraries/LibC/sys/select.cpp
Normal file
14
Libraries/LibC/sys/select.cpp
Normal 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, ¶ms);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
}
|
12
Libraries/LibC/sys/select.h
Normal file
12
Libraries/LibC/sys/select.h
Normal 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
|
88
Libraries/LibC/sys/socket.cpp
Normal file
88
Libraries/LibC/sys/socket.cpp
Normal 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, ¶ms);
|
||||
__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, ¶ms);
|
||||
__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, ¶ms);
|
||||
__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, ¶ms);
|
||||
__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);
|
||||
}
|
||||
}
|
70
Libraries/LibC/sys/socket.h
Normal file
70
Libraries/LibC/sys/socket.h
Normal 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
26
Libraries/LibC/sys/stat.h
Normal 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
|
0
Libraries/LibC/sys/sysmacros.h
Normal file
0
Libraries/LibC/sys/sysmacros.h
Normal file
20
Libraries/LibC/sys/time.h
Normal file
20
Libraries/LibC/sys/time.h
Normal 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
|
17
Libraries/LibC/sys/times.h
Normal file
17
Libraries/LibC/sys/times.h
Normal 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
|
61
Libraries/LibC/sys/types.h
Normal file
61
Libraries/LibC/sys/types.h
Normal 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
|
12
Libraries/LibC/sys/uio.cpp
Normal file
12
Libraries/LibC/sys/uio.cpp
Normal 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
15
Libraries/LibC/sys/uio.h
Normal 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
13
Libraries/LibC/sys/un.h
Normal 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
|
19
Libraries/LibC/sys/utsname.h
Normal file
19
Libraries/LibC/sys/utsname.h
Normal 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
|
11
Libraries/LibC/sys/wait.cpp
Normal file
11
Libraries/LibC/sys/wait.cpp
Normal 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
21
Libraries/LibC/sys/wait.h
Normal 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
129
Libraries/LibC/termcap.cpp
Normal 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
18
Libraries/LibC/termcap.h
Normal 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
|
51
Libraries/LibC/termios.cpp
Normal file
51
Libraries/LibC/termios.cpp
Normal 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
204
Libraries/LibC/termios.h
Normal 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
Loading…
Add table
Add a link
Reference in a new issue