WIP 2
This commit is contained in:
@ -14,6 +14,8 @@ SRCFILES := $(call GRABSRC, \
|
||||
sync \
|
||||
args \
|
||||
util \
|
||||
ubsan \
|
||||
write \
|
||||
)
|
||||
|
||||
CFLAGS += -isystem $(ROOT)/share -isystem $(ROOT)/ulib -isystem $(ROOT)/std/include \
|
||||
|
@ -2,10 +2,13 @@
|
||||
#include <stddef.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/processctl.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <errors.h>
|
||||
#include <dlmalloc/malloc.h>
|
||||
#include <uprintf.h>
|
||||
#include <log.h>
|
||||
#include <util/util.h>
|
||||
#include <devids.h>
|
||||
|
||||
extern void main(void);
|
||||
extern uint8_t _bss_start[];
|
||||
@ -18,24 +21,28 @@ void clearbss(void) {
|
||||
}
|
||||
}
|
||||
|
||||
char **_args;
|
||||
#define MAX_ARGS 15
|
||||
static char *_args[MAX_ARGS];
|
||||
|
||||
size_t _argslen;
|
||||
|
||||
char **args(void) {
|
||||
return _args;
|
||||
return (char **)_args;
|
||||
}
|
||||
|
||||
size_t argslen(void) {
|
||||
return _argslen;
|
||||
}
|
||||
|
||||
Dev_t termdev;
|
||||
|
||||
// ulib initialization goes here
|
||||
void _premain(void) {
|
||||
clearbss();
|
||||
|
||||
#define MAX_ARGS 30
|
||||
_args = (char **)dlmalloc(MAX_ARGS * sizeof(char *));
|
||||
for (size_t i = 0; i < MAX_ARGS; i++) {
|
||||
devctl(&termdev, DEVCTL_GET_HANDLE, (uint8_t *)DEV_TERMDEV, 0, 0);
|
||||
|
||||
for (size_t i = 0; i < ARRLEN(_args); i++) {
|
||||
_args[i] = dlmalloc(PROC_ARG_MAX);
|
||||
}
|
||||
|
||||
|
@ -5,35 +5,89 @@
|
||||
#include <string/conv.h>
|
||||
#include <string/string.h>
|
||||
#include <uprintf.h>
|
||||
#include <errors.h>
|
||||
|
||||
int32_t parse_args(char **argv, size_t argc, Arg *defs) {
|
||||
#define CONSUME_TK() i++
|
||||
|
||||
if (!argv || !defs) {
|
||||
return E_INVALIDARGUMENT;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
if (argv[i][0] == '-' && argv[i][1] != '\0') {
|
||||
char *optname = argv[i];
|
||||
char *arg = argv[i];
|
||||
if (!arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg[0] == '-' && arg[1] != '\0') {
|
||||
size_t j = 0;
|
||||
while (!defs[j].end) {
|
||||
Arg *def = &defs[j];
|
||||
if (string_strcmp(def->shortname, optname) == 0) {
|
||||
if (i < argc - 1) {
|
||||
switch (def->expected_value) {
|
||||
case ARG_STRING:
|
||||
*((char **)def->ptr) = argv[i+1];
|
||||
break;
|
||||
case ARG_BOOL:
|
||||
*((bool *)def->ptr) = string_strcmp(argv[i+1], "yes") == 0;
|
||||
break;
|
||||
case ARG_INT: {
|
||||
char *end;
|
||||
*((int32_t *)def->ptr) = string_conv_strtol(argv[i+1], &end, 10);
|
||||
} break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!def->shortname || !def->ptr) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string_strcmp(def->shortname, arg) == 0) {
|
||||
bool have_next = (i + 1) < argc && argv[i + 1] != NULL;
|
||||
char *nexttk = have_next ? argv[i + 1] : NULL;
|
||||
|
||||
if (nexttk && nexttk[0] == '-' && nexttk[1] != '\0') {
|
||||
have_next = false;
|
||||
nexttk = NULL;
|
||||
}
|
||||
|
||||
switch (def->expected_value) {
|
||||
case ARG_STRING:
|
||||
if (!have_next) {
|
||||
break;
|
||||
}
|
||||
*((char **)def->ptr) = nexttk;
|
||||
CONSUME_TK();
|
||||
break;
|
||||
case ARG_BOOL:
|
||||
if (!have_next) {
|
||||
*((bool *)def->ptr) = true;
|
||||
} else {
|
||||
if (string_strcmp(nexttk, "yes") == 0) {
|
||||
*((bool *)def->ptr) = true;
|
||||
CONSUME_TK();
|
||||
} else if (string_strcmp(nexttk, "no") == 0) {
|
||||
*((bool *)def->ptr) = false;
|
||||
CONSUME_TK();
|
||||
} else {
|
||||
*((bool *)def->ptr) = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ARG_INT:
|
||||
if (!have_next) {
|
||||
break;
|
||||
}
|
||||
char *endptr = NULL;
|
||||
long val = string_conv_strtol(nexttk, &endptr, 10);
|
||||
if (endptr == NULL) {
|
||||
break;
|
||||
}
|
||||
if (*endptr != '\0') {
|
||||
break;
|
||||
}
|
||||
*((int32_t *)def->ptr) = (int32_t)val;
|
||||
CONSUME_TK();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ARGP_OK;
|
||||
return E_OK;
|
||||
}
|
||||
|
@ -28,10 +28,6 @@ typedef struct {
|
||||
|
||||
#define ARG_END() ((Arg){ .end = true, })
|
||||
|
||||
enum {
|
||||
ARGP_OK = 0,
|
||||
};
|
||||
|
||||
int32_t parse_args(char **argv, size_t argc, Arg *defs);
|
||||
|
||||
#endif // ULIB_ARGS_H_
|
||||
|
15
ulib/assert.h
Normal file
15
ulib/assert.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef ULIB_ASSERT_H_
|
||||
#define ULIB_ASSERT_H_
|
||||
|
||||
#include <uprintf.h>
|
||||
#include <util/util.h>
|
||||
|
||||
#define ASSERT(X, fmt, ...) \
|
||||
do { \
|
||||
if (!(X)) { \
|
||||
uprintf("ASSERT %s:%d in %s "fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
quit(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif // ULIB_ASSERT_H_
|
8
ulib/devids.h
Normal file
8
ulib/devids.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef ULIB_DEVIDS_H_
|
||||
#define ULIB_DEVIDS_H_
|
||||
|
||||
enum {
|
||||
DEV_TERMDEV = 0x10,
|
||||
};
|
||||
|
||||
#endif // ULIB_DEVIDS_H_
|
@ -8,6 +8,7 @@
|
||||
#include <string/string.h>
|
||||
#include <sysdefs/mman.h>
|
||||
#include <system/system.h>
|
||||
#include <write/write.h>
|
||||
|
||||
#define USE_DL_PREFIX 1
|
||||
#define LACKS_SYS_TYPES_H 1
|
||||
@ -23,7 +24,7 @@
|
||||
#define LACKS_SCHED_H 1
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_MORECORE 0
|
||||
#define ABORT uprintf("dlmalloc: Aborting...\n")
|
||||
#define ABORT writefmt("dlmalloc: Aborting...\n")
|
||||
#define MALLOC_FAILURE_ACTION
|
||||
#define USE_LOCKS 2
|
||||
#define malloc_getpagesize 0x1000
|
||||
@ -61,8 +62,9 @@ static size_t _roundpage(size_t sz) {
|
||||
#define O_RDWR 0
|
||||
|
||||
#define EMUL_DEV_ZERO_FD 123
|
||||
#define EMUL_MAP_FAILED ((void *)-1)
|
||||
|
||||
int open(char *path, int flags) {
|
||||
int open(const char *path, int flags, ...) {
|
||||
return EMUL_DEV_ZERO_FD;
|
||||
}
|
||||
|
||||
@ -73,7 +75,7 @@ void *mmap(void *addr, size_t len, int prot, int flags, int fd, int off) {
|
||||
|
||||
int32_t err = mman_map(NULL, need, MMAN_MAP_PF_RW, 0, &outaddr);
|
||||
if (err != E_OK || outaddr == NULL) {
|
||||
return NULL;
|
||||
return EMUL_MAP_FAILED;
|
||||
}
|
||||
|
||||
if (fd == EMUL_DEV_ZERO_FD) {
|
||||
|
@ -53,14 +53,14 @@
|
||||
} while(0)
|
||||
|
||||
#define LL_FOREACH_SAFE(head, var, tmp) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
for (var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL) \
|
||||
)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX(head, var, tmp, idx) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL && ((idx) = 0, 1); \
|
||||
for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL), (idx)++)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX_LIMIT(head, var, tmp, idx, max) \
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define ULIB_LOG_H_
|
||||
|
||||
#include <uprintf.h>
|
||||
#include <write/write.h>
|
||||
|
||||
enum {
|
||||
LOG_ERR,
|
||||
@ -12,6 +13,6 @@ enum {
|
||||
|
||||
static const char *_LOG_STR[] = { "ERROR", "DEBUG", "INFO", "WARNING" };
|
||||
|
||||
#define LOG(mode, fmt, ...) uprintf("%s: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
|
||||
#define LOG(mode, fmt, ...) writefmt("{s}: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
|
||||
|
||||
#endif // ULIB_LOG_H_
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/ipcpipe.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <printf/printf.h>
|
||||
|
||||
extern Dev_t termdev;
|
||||
|
||||
void putchar_(char c) {
|
||||
char buf = c;
|
||||
ipcpipe(IPCPIPE_SELFPID, IPCPIPE_OUT, IPCPIPE_WRITE, (uint8_t *)&buf, sizeof(buf));
|
||||
devctl(&termdev, 0x00, (uint8_t *)&c, 1, 0);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stddef.h>
|
||||
#include <string/string.h>
|
||||
#include <dlmalloc/malloc.h>
|
||||
|
||||
size_t string_len(const char *s) {
|
||||
size_t l = 0;
|
||||
@ -130,3 +131,35 @@ int string_strncmp( const char * s1, const char * s2, size_t n )
|
||||
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
|
||||
}
|
||||
}
|
||||
|
||||
#define STRING_TOKENIZEALLOC_TOK_SIZE 0xff
|
||||
|
||||
char *string_tokenizealloc(char *s, char *delim) {
|
||||
static int curridx = 0;
|
||||
if (!s || !delim || !s[curridx]) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *w = (char *)dlmalloc(sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
|
||||
string_memset(w, 0, sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
|
||||
int i = curridx, k = 0, j = 0;
|
||||
|
||||
while (s[i] != '\0') {
|
||||
j = 0;
|
||||
while (delim[j] != '\0') {
|
||||
if (s[i] != delim[j]) {
|
||||
w[k] = s[i];
|
||||
} else {
|
||||
goto it;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
it: {
|
||||
w[i] = 0;
|
||||
curridx = i + 1;
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ size_t string_strspn(const char *s, const char *accept);
|
||||
char *string_strcpy(char *dest, const char *src);
|
||||
char *string_strchr(const char *s, int c);
|
||||
int string_strncmp(const char * s1, const char * s2, size_t n);
|
||||
char *string_tokenizealloc(char *s, char *delim);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdint.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
|
||||
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <sysdefs/ioctl.h>
|
||||
#include <sysdefs/processctl.h>
|
||||
#include <sysdefs/ipcpipe.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
void debugprint(const char *string) {
|
||||
@ -34,3 +35,7 @@ int32_t mman_unmap(uint8_t *addr) {
|
||||
int32_t schedrelease(void) {
|
||||
return syscall(SYS_SCHEDRELEASE, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra) {
|
||||
return syscall(SYS_DEVCTL, (uint64_t)devh, cmd, (uint64_t)buffer, (uint64_t)len, (uint64_t)extra, 0);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
|
||||
void debugprint(const char *string);
|
||||
int32_t ioctl(uint64_t ioh, uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3);
|
||||
@ -11,5 +12,6 @@ int32_t ipcpipe(uint64_t pid, uint64_t pipenum, uint64_t cmd, uint8_t *buffer, s
|
||||
int32_t mman_map(uint8_t *addr, size_t size, uint64_t prot, uint64_t flags, uint8_t **out);
|
||||
int32_t mman_unmap(uint8_t *addr);
|
||||
int32_t schedrelease(void);
|
||||
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra);
|
||||
|
||||
#endif // ULIB_SYSTEM_SYSTEM_H_
|
||||
|
224
ulib/ubsan/ubsan.c
Normal file
224
ulib/ubsan/ubsan.c
Normal file
@ -0,0 +1,224 @@
|
||||
// REFERENCES:
|
||||
// https://wiki.osdev.org/Undefined_Behavior_Sanitization
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
struct source_location {
|
||||
const char *file;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
|
||||
struct type_descriptor {
|
||||
uint16_t type_kind;
|
||||
uint16_t type_info;
|
||||
char *type_name;
|
||||
};
|
||||
|
||||
|
||||
struct type_mismatch_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned long alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
|
||||
struct type_mismatch_data_v1 {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned char alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
|
||||
struct overflow_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct shift_out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *lhs_type;
|
||||
struct type_descriptor *rhs_type;
|
||||
};
|
||||
|
||||
|
||||
struct out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *array_type;
|
||||
struct type_descriptor *index_type;
|
||||
};
|
||||
|
||||
|
||||
struct unreachable_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
struct vla_bound_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct invalid_value_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct nonnull_arg_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
struct nonnull_return_data {
|
||||
struct source_location loc;
|
||||
struct source_location attr_loc;
|
||||
};
|
||||
|
||||
|
||||
struct invalid_builtin_data {
|
||||
struct source_location loc;
|
||||
uint8_t kind;
|
||||
};
|
||||
|
||||
|
||||
struct pointer_overflow_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
static void ubsan_print(struct source_location *loc, const char *message)
|
||||
{
|
||||
uprintf("UBSAN error %s:%d:%d %s\n", loc->file, loc->line, loc->column, message);
|
||||
}
|
||||
|
||||
void __ubsan_handle_add_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "addition overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_sub_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "subtraction overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_mul_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "multiplication overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_divrem_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "division overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_negate_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "negation overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_pointer_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "pointer overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "shift out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "array out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "invalid load value");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, uintptr_t ptr)
|
||||
{
|
||||
if (ptr == (uintptr_t)NULL) {
|
||||
ubsan_print(&data->loc, "null pointer access");
|
||||
}
|
||||
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
|
||||
ubsan_print(&data->loc, "misaligned pointer is used");
|
||||
}
|
||||
else {
|
||||
ubsan_print(&data->loc, "insufficient space for an object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, uintptr_t ptr)
|
||||
{
|
||||
if (ptr == (uintptr_t)NULL) {
|
||||
ubsan_print(&data->loc, "null pointer access");
|
||||
}
|
||||
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
|
||||
ubsan_print(&data->loc, "misaligned pointer is used");
|
||||
}
|
||||
else {
|
||||
ubsan_print(&data->loc, "insufficient space for an object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "variable-length argument out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data, struct source_location *loc)
|
||||
{
|
||||
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "non-null argument is null");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "unreachable code reached");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "invalid builtin");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_missing_return(struct unreachable_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "missing return value");
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <uprintf.h>
|
||||
#include <linklist.h>
|
||||
#include <log.h>
|
||||
#include <assert.h>
|
||||
#include <write/write.h>
|
||||
|
||||
#include <errors.h>
|
||||
#include <sysdefs/ioctl.h>
|
||||
|
@ -5,11 +5,7 @@
|
||||
|
||||
#define ARRLEN(X) (sizeof((X))/sizeof((X)[0]))
|
||||
|
||||
#define ZERO(X) \
|
||||
({ \
|
||||
string_memset((X), 0, sizeof(*(X))); \
|
||||
*(X); \
|
||||
}) \
|
||||
#define ZERO(X) string_memset((X), 0, sizeof(*(X)))
|
||||
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
|
161
ulib/write/write.c
Normal file
161
ulib/write/write.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <write/write.h>
|
||||
|
||||
char *utoa(uintmax_t v, int base, bool uppercase) {
|
||||
if (base < 2 || base > 36) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
|
||||
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
size_t i = sizeof(buf) - 1;
|
||||
buf[i] = '\0';
|
||||
|
||||
if (v == 0) {
|
||||
buf[--i] = '0';
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
while (v != 0) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = digits[v % base];
|
||||
v /= base;
|
||||
}
|
||||
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
char *itoa(intmax_t v, int base, bool uppercase) {
|
||||
if (base < 2 || base > 36) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
|
||||
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
size_t i = sizeof(buf) - 1;
|
||||
buf[i] = '\0';
|
||||
|
||||
if (v == 0) {
|
||||
buf[--i] = '0';
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
bool neg = (v < 0);
|
||||
uintmax_t u;
|
||||
if (neg) {
|
||||
u = (uintmax_t)(-(v + 1)) + 1;
|
||||
} else {
|
||||
u = (uintmax_t)v;
|
||||
}
|
||||
|
||||
while (u != 0) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = digits[u % base];
|
||||
u /= base;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = '-';
|
||||
}
|
||||
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
#define FMTBUF_MAX 2048
|
||||
|
||||
extern Dev_t termdev;
|
||||
|
||||
enum {
|
||||
WRITE_FORMATMODE,
|
||||
WRITE_NORMALMODE,
|
||||
};
|
||||
|
||||
const char *convstr1 = "0123456789abcdef";
|
||||
const char *convstr2 = "0123456789ABCDEF";
|
||||
|
||||
void writefmt(char *fmt, ...) {
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
writevfmt(fmt, list);
|
||||
va_end(list);
|
||||
}
|
||||
|
||||
#define ITOA_BUF_SIZE 32
|
||||
|
||||
void writevsfmt(char *buf, char *fmt, va_list list) {
|
||||
size_t c = 0;
|
||||
int WRITE_STATE = WRITE_NORMALMODE;
|
||||
|
||||
for (size_t i = 0; fmt[i] != '\0'; i++) {
|
||||
if (WRITE_STATE == WRITE_NORMALMODE) {
|
||||
switch (fmt[i]) {
|
||||
case '{':
|
||||
WRITE_STATE = WRITE_FORMATMODE;
|
||||
break;
|
||||
default:
|
||||
buf[c++] = fmt[i];
|
||||
break;
|
||||
}
|
||||
} else if (WRITE_STATE == WRITE_FORMATMODE) {
|
||||
switch (fmt[i]) {
|
||||
case '}':
|
||||
WRITE_STATE = WRITE_NORMALMODE;
|
||||
break;
|
||||
case 's': {
|
||||
char *string = va_arg(list, char *);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'd': {
|
||||
int int1 = va_arg(list, int);
|
||||
char *string = itoa(int1, 10, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'x': {
|
||||
unsigned int int1 = va_arg(list, unsigned int);
|
||||
char *string = utoa(int1, 16, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'X': {
|
||||
unsigned int int1 = va_arg(list, unsigned int);
|
||||
char *string = utoa(int1, 16, true);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'p': {
|
||||
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
|
||||
char *string = utoa(ptr, 16, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'P': {
|
||||
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
|
||||
char *string = utoa(ptr, 16, true);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'c': {
|
||||
char c1 = (char)va_arg(list, char);
|
||||
buf[c++] = c1;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writevfmt(char *fmt, va_list list) {
|
||||
char buf[FMTBUF_MAX];
|
||||
writevsfmt(buf, fmt, list);
|
||||
devctl(&termdev, 0x00, buf, sizeof(buf), 0);
|
||||
}
|
10
ulib/write/write.h
Normal file
10
ulib/write/write.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef ULIB_WRITE_WRITE_H_
|
||||
#define ULIB_WRITE_WRITE_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void writefmt(char *fmt, ...);
|
||||
void writevfmt(char *fmt, va_list list);
|
||||
void writevsfmt(char *buf, char *fmt, va_list list);
|
||||
|
||||
#endif // ULIB_WRITE_WRITE_H_
|
Reference in New Issue
Block a user