From e6891b39cceb6d0a7e6933ec8b5ae8538f9d3d3a Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sat, 13 Sep 2025 15:43:31 +0200 Subject: [PATCH] Parsing commandline arguments --- kernel/syscall/processctl.c | 4 +- ulib/Makefile | 4 +- ulib/args.h | 7 -- ulib/args/args.c | 32 ++++++++ ulib/args/args.h | 33 ++++++++ ulib/log.h | 17 ++++ ulib/machine/limits.h | 25 ++++++ ulib/std/limits.h | 6 ++ ulib/std/stdlib.h | 17 ++++ ulib/std/string.h | 17 ++++ ulib/string/char.h | 17 ++++ ulib/string/conv.c | 159 ++++++++++++++++++++++++++++++++++++ ulib/string/conv.h | 7 ++ ulib/string/string.c | 19 +++++ ulib/string/string.h | 4 +- user/Makefile.inc | 3 +- user/init/main.c | 58 +++++-------- user/tb/main.c | 78 ++++++++++++++++-- 18 files changed, 448 insertions(+), 59 deletions(-) delete mode 100644 ulib/args.h create mode 100644 ulib/args/args.c create mode 100644 ulib/args/args.h create mode 100644 ulib/log.h create mode 100644 ulib/machine/limits.h create mode 100644 ulib/std/limits.h create mode 100644 ulib/std/stdlib.h create mode 100644 ulib/std/string.h create mode 100644 ulib/string/char.h create mode 100644 ulib/string/conv.c create mode 100644 ulib/string/conv.h diff --git a/kernel/syscall/processctl.c b/kernel/syscall/processctl.c index 0fab511..0785379 100644 --- a/kernel/syscall/processctl.c +++ b/kernel/syscall/processctl.c @@ -61,9 +61,9 @@ int32_t SYSCALL5(sys_processctl, pid1, cmd1, arg1, arg2, arg3) { } size_t argslen = arg3; - char **args = (char **)arg2; + char *(*args)[] = (char *(*)[])arg2; for (size_t i = 0; i < argslen; i++) { - PROC_ARG(newproc, args[i]); + PROC_ARG(newproc, (*args)[i]); } proc_register(newproc); diff --git a/ulib/Makefile b/ulib/Makefile index b6d7f07..b58c73b 100644 --- a/ulib/Makefile +++ b/ulib/Makefile @@ -12,10 +12,12 @@ SRCFILES := $(call GRABSRC, \ printf \ dlmalloc \ sync \ + args \ ) CFLAGS += -isystem $(ROOT)/share -isystem $(ROOT)/ulib -isystem $(ROOT)/std/include \ - -DPRINTF_INCLUDE_CONFIG_H=1 -DLACKS_STRING_H=1 -include $(ROOT)/ulib/string/string.h + -isystem $(ROOT)/ulib/std -DPRINTF_INCLUDE_CONFIG_H=1 \ + -DULIB_FLOAT_SUPPORT=0 ASFILES := $(call GET_ASFILES, $(SRCFILES)) CFILES := $(call GET_CFILES, $(SRCFILES)) diff --git a/ulib/args.h b/ulib/args.h deleted file mode 100644 index e82ad0c..0000000 --- a/ulib/args.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ULIB_ARGS_H_ -#define ULIB_ARGS_H_ - -char **args(void); -size_t argslen(void); - -#endif // ULIB_ARGS_H_ diff --git a/ulib/args/args.c b/ulib/args/args.c new file mode 100644 index 0000000..89c4da9 --- /dev/null +++ b/ulib/args/args.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include +#include + +int32_t parse_args(char **argv, size_t argc, Arg *defs) { + for (size_t i = 0; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] != '\0') { + char *optname = argv[i]; + 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; + } + i++; + } + } + j++; + } + } + } + + return ARGP_OK; +} diff --git a/ulib/args/args.h b/ulib/args/args.h new file mode 100644 index 0000000..38db4f9 --- /dev/null +++ b/ulib/args/args.h @@ -0,0 +1,33 @@ +#ifndef ULIB_ARGS_H_ +#define ULIB_ARGS_H_ + +#include +#include +#include + +char **args(void); +size_t argslen(void); + +typedef struct { + char *shortname; + enum { ARG_STRING } expected_value; + void *ptr; + bool end; +} Arg; + +#define ARG(sn, ev, p) ((Arg){ \ + .shortname = (sn), \ + .expected_value = (ev), \ + .ptr = (void *)(p), \ + .end = false, \ + }) + +#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_ diff --git a/ulib/log.h b/ulib/log.h new file mode 100644 index 0000000..757ae8f --- /dev/null +++ b/ulib/log.h @@ -0,0 +1,17 @@ +#ifndef ULIB_LOG_H_ +#define ULIB_LOG_H_ + +#include + +enum { + LOG_ERR, + LOG_DBG, + LOG_INF, + LOG_WRN, +}; + +static const char *_LOG_STR[] = { "ERROR", "DEBUG", "INFO", "WARNING" }; + +#define LOG(mode, fmt, ...) uprintf("%s: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__); + +#endif // ULIB_LOG_H_ diff --git a/ulib/machine/limits.h b/ulib/machine/limits.h new file mode 100644 index 0000000..5b642f3 --- /dev/null +++ b/ulib/machine/limits.h @@ -0,0 +1,25 @@ +#ifndef ULIB_MACHINE_LIMITS_H_ +#define ULIB_MACHINE_LIMITS_H_ + +#define CHAR_BIT (8) +#define SHORT_BIT (16) +#define WCHAR_BIT (16) +#define INT_BIT (32) +#define LONG_LONG_BIT (64) +#define SCHAR_MIN (-128) +#define SCHAR_MAX (127) +#define UCHAR_MAX (255) +#define SHRT_MIN (-32768) +#define SHRT_MAX (32767) +#define USHRT_MAX (65535) +#define INT_MIN (-2147483648) +#define INT_MAX (2147483647) +#define UINT_MAX (4294967295U) +#define LONG_MAX (2147483647L) +#define LONG_MIN (-2147483648L) +#define ULONG_MAX (18446744073709551615UL) +#define LLONG_MAX (9223372036854775807LL) +#define LLONG_MIN (-9223372036854775808LL) +#define ULLONG_MAX (18446744073709551615ULL) + +#endif // ULIB_MACHINE_LIMITS_H_ diff --git a/ulib/std/limits.h b/ulib/std/limits.h new file mode 100644 index 0000000..eb42c40 --- /dev/null +++ b/ulib/std/limits.h @@ -0,0 +1,6 @@ +#ifndef ULIB_STD_LIMITS_H_ +#define ULIB_STD_LIMITS_H_ + +#include + +#endif // ULIB_STD_LIMITS_H_ diff --git a/ulib/std/stdlib.h b/ulib/std/stdlib.h new file mode 100644 index 0000000..e149c20 --- /dev/null +++ b/ulib/std/stdlib.h @@ -0,0 +1,17 @@ +#ifndef ULIB_STD_STDLIB_H_ +#define ULIB_STD_STDLIB_H_ + +#include +#include + +#define printf uprintf +#define sprintf usprintf +#define vsprintf uvsprintf +#define snprintf usnprintf +#define vsnprintf uvsnprintf +#define vprintf uvprintf + +#define strtoul string_conv_strtoul +#define strtol string_conv_strtol + +#endif // ULIB_STD_STDLIB_H_ diff --git a/ulib/std/string.h b/ulib/std/string.h new file mode 100644 index 0000000..dcb3181 --- /dev/null +++ b/ulib/std/string.h @@ -0,0 +1,17 @@ +#ifndef ULIB_STD_STRING_H_ +#define ULIB_STD_STRING_H_ + +#include + +#define memset string_memset +#define memcpy string_memcpy +#define strlen string_len +#define memcmp string_memcmp +#define strcmp string_strcmp +#define strcspn string_strcspn +#define strspn string_strspn +#define strcpy string_strcpy +#define strchr string_strchr +#define strncmp string_strncmp + +#endif // ULIB_STD_STRING_H_ diff --git a/ulib/string/char.h b/ulib/string/char.h new file mode 100644 index 0000000..145f35f --- /dev/null +++ b/ulib/string/char.h @@ -0,0 +1,17 @@ +#ifndef ULIB_STRING_CHAR_H_ +#define ULIB_STRING_CHAR_H_ + +#define string_chr_islower(c) ((c) >= 'a' && (c) <= 'z') +#define string_chr_isupper(c) ((c) >= 'A' && (c) <= 'Z') +#define string_chr_isalpha(c) (string_chr_islower((c)) || string_chr_isupper((c))) +#define string_chr_isctl(c) (((c) >= 0 && (c) <= 0x1f) || (c) == 0x7f) +#define string_chr_isdigit(c) ((c) >= '0' && (c) <= '9') +#define string_chr_isalnum(c) (string_chr_isalpha((c)) || string_chr_isdigit((c))) +#define string_chr_isprint(c) ((c) > 0x1f && (c) < 0x7f) +#define string_chr_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == '\v') +#define string_chr_tolower(c) (string_chr_isupper((c)) ? ((c) - 'A' + 'a') : (c)) +#define string_chr_toupper(c) (string_chr_islower((c)) ? ((c) - 'a' + 'A') : (c)) +#define string_chr_isascii(c) (!((c) < 0 || (c) > 0x7f)) +#define string_chr_isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) + +#endif // ULIB_STRING_CHAR_H_ diff --git a/ulib/string/conv.c b/ulib/string/conv.c new file mode 100644 index 0000000..d63aa6e --- /dev/null +++ b/ulib/string/conv.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include + +// https://android.googlesource.com/platform/bionic/+/ics-mr0/libc/stdlib/strtoul.c +unsigned long string_conv_strtoul(const char *nptr, char **endptr, int base) +{ + const char *s; + unsigned long acc, cutoff; + int c; + int neg, any, cutlim; + /* + * See strtol for comments as to the logic used. + */ + s = nptr; + do { + c = (unsigned char) *s++; + } while (string_chr_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = ULONG_MAX / (unsigned long)base; + cutlim = ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = (unsigned char) *s++) { + if (string_chr_isdigit(c)) + c -= '0'; + else if (string_chr_isalpha(c)) + c -= string_chr_isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0) + continue; + if (acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = ULONG_MAX; + } else { + any = 1; + acc *= (unsigned long)base; + acc += c; + } + } + if (neg && any > 0) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +// https://android.googlesource.com/platform/bionic/+/ics-mr0/libc/stdlib/strtol.c +long string_conv_strtol(const char *nptr, char **endptr, int base) +{ + const char *s; + long acc, cutoff; + int c; + int neg, any, cutlim; + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = (unsigned char) *s++; + } while (string_chr_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? LONG_MIN : LONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + if (neg) { + if (cutlim > 0) { + cutlim -= base; + cutoff += 1; + } + cutlim = -cutlim; + } + for (acc = 0, any = 0;; c = (unsigned char) *s++) { + if (string_chr_isdigit(c)) + c -= '0'; + else if (string_chr_isalpha(c)) + c -= string_chr_isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0) + continue; + if (neg) { + if (acc < cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LONG_MIN; + } else { + any = 1; + acc *= base; + acc -= c; + } + } else { + if (acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = LONG_MAX; + } else { + any = 1; + acc *= base; + acc += c; + } + } + } + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/ulib/string/conv.h b/ulib/string/conv.h new file mode 100644 index 0000000..8ad3a90 --- /dev/null +++ b/ulib/string/conv.h @@ -0,0 +1,7 @@ +#ifndef ULIB_STRING_CONV_H_ +#define ULIB_STRING_CONV_H_ + +unsigned long string_conv_strtoul(const char *nptr, char **endptr, int base); +long string_conv_strtol(const char *nptr, char **endptr, int base); + +#endif // ULIB_STRING_CONV_H_ diff --git a/ulib/string/string.c b/ulib/string/string.c index d8410eb..9664a50 100644 --- a/ulib/string/string.c +++ b/ulib/string/string.c @@ -111,3 +111,22 @@ char *string_strchr(const char *s, int c) { } return NULL; } + +// https://stackoverflow.com/questions/32560167/strncmp-implementation +int string_strncmp( const char * s1, const char * s2, size_t n ) +{ + while ( n && *s1 && ( *s1 == *s2 ) ) + { + ++s1; + ++s2; + --n; + } + if ( n == 0 ) + { + return 0; + } + else + { + return ( *(unsigned char *)s1 - *(unsigned char *)s2 ); + } +} diff --git a/ulib/string/string.h b/ulib/string/string.h index 97895c7..52e861d 100644 --- a/ulib/string/string.h +++ b/ulib/string/string.h @@ -6,9 +6,6 @@ #include #include -#define memset string_memset -#define memcpy string_memcpy - size_t string_len(const char *s); void *string_memset(void *p, int c, size_t n); void *string_memcpy(void *dst, const void *src, size_t n); @@ -18,6 +15,7 @@ size_t string_strcspn(const char *s, const char *reject); 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); #endif diff --git a/user/Makefile.inc b/user/Makefile.inc index 274a750..c9f7b4a 100644 --- a/user/Makefile.inc +++ b/user/Makefile.inc @@ -1,5 +1,6 @@ CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc \ - -isystem $(ROOT)/std/include -isystem $(ROOT)/ulib -isystem $(ROOT)/share + -isystem $(ROOT)/std/include -isystem $(ROOT)/ulib -isystem $(ROOT)/share \ + -isystem $(ROOT)/ulib/std CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) diff --git a/user/init/main.c b/user/init/main.c index ba7d946..1c74621 100644 --- a/user/init/main.c +++ b/user/init/main.c @@ -1,60 +1,42 @@ #include #include #include -#include #include #include #include #include +#include + +void *string_memset2(void *p, int c, size_t n) { + char *cp = p; + for (size_t i = 0; i < n; i++) cp[i] = c; + return p; +} void main(void) { - uprintf(ANSIQ_CUR_SET(0, 0)); - uprintf(ANSIQ_SCR_CLR_ALL); - - int32_t ioh = ioctl(IOCTL_NOHANDLE, - IOCTL_OPENF, - (uint64_t)"temp:/hello.txt", - IOCTL_F_WRITE | IOCTL_F_READ | IOCTL_F_MAKE, - 0 - ); - - char *text = "Hello from FS"; - ioctl(ioh, IOCTL_WRITE, (uint64_t)text, string_len(text), 0); - - char buf[0x100] = {0}; - ioctl(ioh, IOCTL_READ, (uint64_t)buf, string_len(text), 0); - - uprintf("file contents: %s\n", buf); - - ioctl(ioh, IOCTL_CLOSEF, 0, 0, 0); - - uprintf("Hello world using uprintf\n"); - - const char *tbargs[] = { "-i" }; - int32_t tb = processctl(-1, PCTL_SPAWN, (uint64_t)"base:/bin/tb", (uint64_t)tbargs, 1); + char *tbargs[] = { "-m", "interactive" }; + int32_t tb = processctl(-1, PCTL_SPAWN, (uint64_t)"base:/bin/tb", (uint64_t)&tbargs, 2); uint64_t selfpid = (uint64_t)processctl(-1, PCTL_GETPID, 0, 0, 0); ipcpipe(tb, IPCPIPE_OUT, IPCPIPE_REPLACE, (uint8_t *)selfpid, IPCPIPE_OUT); processctl(tb, PCTL_RUN, 0, 0, 0); - while(processctl(tb, PCTL_POLLSTATE, 0, 0, 0) != 2); - if (ipcpipe(IPCPIPE_SELFPID, 10, IPCPIPE_MAKE, NULL, 0) < 0) { - uprintf("failed to create 10th pipe\n"); - } + ipcpipe(IPCPIPE_SELFPID, 10, IPCPIPE_MAKE, NULL, 0); + ipcpipe(IPCPIPE_SELFPID, 10, IPCPIPE_ADD_BCAST, NULL, 1); - int32_t r = ipcpipe(IPCPIPE_SELFPID, 10, IPCPIPE_ADD_BCAST, NULL, 1); - uprintf("%d\n", r); - - while(1) { + while(processctl(tb, PCTL_POLLSTATE, 0, 0, 0) != 2) { int32_t kbchr; int32_t read = ipcpipe(IPCPIPE_SELFPID, 10, IPCPIPE_READ, (uint8_t *)&kbchr, sizeof(kbchr)); if (read > 0) { - kbchr &= 0xFF; - if ((kbchr >= 0x20 && kbchr <= 0x7F) || kbchr == 0xA) { - uprintf("%c", kbchr & 0xFF); + uint8_t c = kbchr & 0xff; + if (string_chr_isascii(c)) { + if (c != 0) { + ipcpipe(tb, IPCPIPE_IN, IPCPIPE_WRITE, &c, 1); + } + if (string_chr_isprint(c)) { + uprintf("%c", c); + } } } } - - for(;;); } diff --git a/user/tb/main.c b/user/tb/main.c index fefecc9..b600ba3 100644 --- a/user/tb/main.c +++ b/user/tb/main.c @@ -1,12 +1,76 @@ +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include -void main(void) { - uprintf("Hello from tb!\n"); +static struct { + char *modestr; + enum { MODE_INTERACTIVE = 1, MODE_RUNFILE = 2 } mode; +} CONFIG; - for (size_t i = 0; i < argslen(); i++) { - uprintf("i = %d\n", i); - uprintf("arg: %s\n", args()[i]); +#define LINEBUF_MAX 1024 + +static Arg ARGS[] = { + ARG("-m", ARG_STRING, &CONFIG.modestr), + ARG_END(), +}; + +void set_config(void) { + int32_t ret; + if ((ret = parse_args(args(), argslen(), ARGS)) < 0) { + uprintf("Could not parse args: %d\n", ret); + } + + if (CONFIG.modestr != NULL) { + if (string_strcmp(CONFIG.modestr, "interactive") == 0) { + CONFIG.mode = MODE_INTERACTIVE; + } else if (string_strcmp(CONFIG.modestr, "runfile") == 0) { + CONFIG.mode = MODE_RUNFILE; + } else { + LOG(LOG_ERR, "Unknown mode %s\n", CONFIG.modestr); + } + } else { + CONFIG.mode = MODE_RUNFILE; + } + uprintf("CONFIG.mode = %d\n", CONFIG.mode); +} + +void process_cmd(char *cmdtext) { + +} + +void do_mode_interactive(void) { + char linebuf[LINEBUF_MAX]; + size_t cursor; + for(;;) { + uprintf("tb# "); + + cursor = 0; + string_memset(linebuf, 0, LINEBUF_MAX); + char c = 0; + while (c != '\n') { + int32_t rd = ipcpipe(IPCPIPE_SELFPID, IPCPIPE_IN, IPCPIPE_READ, (uint8_t *)&c, 1); + if (rd > 0 && cursor < LINEBUF_MAX) { + linebuf[cursor++] = c; + } + } + linebuf[cursor - 1] = '\0'; + uprintf("\n"); + + process_cmd(linebuf); + } +} + +void main(void) { + set_config(); + + if (CONFIG.mode == MODE_INTERACTIVE) { + do_mode_interactive(); } }