Index: arch/makefile ================================================================== --- arch/makefile +++ arch/makefile @@ -1,4 +1,5 @@ -calls.x86.lin.32.s: /usr/include/asm/unistd_32.h +linux-headers = /usr/include/asm/ +calls.x86.lin.32.s: $(linux-headers)/unistd_32.h grep "#define __NR_" $< | sed "s;^#define __NR_;%define sys.;" > $@ -calls.x86.lin.64.s: /usr/include/asm/unistd_64.h +calls.x86.lin.64.s: $(linux-headers)/unistd_64.h grep "#define __NR_" $< | sed "s;^#define __NR_;%define sys.;" > $@ Index: arch/x86.lin.64.s ================================================================== --- arch/x86.lin.64.s +++ arch/x86.lin.64.s @@ -7,10 +7,11 @@ ; syscall ops %define sys.call syscall ; register order for syscall convention %define sys.reg.n 7 +%define sys.reg.ret rax %define sys.reg.0 rax %define sys.reg.1 rdi %define sys.reg.2 rsi %define sys.reg.3 rdx %define sys.reg.4 r10 @@ -17,10 +18,11 @@ %define sys.reg.5 r8 %define sys.reg.6 r9 ; register order for ccall convention %define ccall.reg.ct 6 +%define ccall.reg.ret rdi %define ccall.reg.0 rdi %define ccall.reg.1 rsi %define ccall.reg.2 rdx %define ccall.reg.3 rcx %define ccall.reg.4 r8 ADDED kcli/kcli.md Index: kcli/kcli.md ================================================================== --- kcli/kcli.md +++ kcli/kcli.md @@ -0,0 +1,125 @@ +# kcli +**kcli** is a module that implements common routines used by command-line utilities, such as option parsing, usage display, and more. + +## functions + +### kcli_usage(kcli_set, kiochan) +kcli_usage() takes a `kcli_set` and prints a succinct usage summary to a [kiochan](../kio/kio.md). + +## types + +### struct kcli_set +`kcli_set` is a struct containing information about your program, such as its name, a synopsis of its function, a pointer to `argv`, and a list of `kcli_opt`s. + + * `const char* name` - program name (if null, will be determined from argv instead) + * `size_t argc` - the number of arguments in the `argv` array. + * `const char** argv` - the `argv` pointer passed to the `entry` function, representing the command-line arguments passed to the program. + * `const char* desc` - program description + * `const kcli_param* params` - a list of options expected by the program. + * `size_t paramc` - the number of params in the list to process. + * `const kcli_opt* opts` - a list of options expected by the program. + * `size_t optc` - the number of options in the list to process. + +a kcli_set might be used like so: + + #include + #include + #include + u8 entry(kenv e) { + kcli_flag aardvark; + kcli_flag zebra; + char* user; + char* password; + long age; + kcli_param* params = { + { "user", kcli_param_string, kcli_class_required, + &user, "the user to log in as" } + // or Kcli_param(user,string,required,"the user to log in as"), + + { "age", kcli_param_dec, kcli_class_optional, + &age, "the age of the user" } + // or Kcli_param(age,dec,optional,"the age of the user"), + }; + kcli_opt* options = { + { 'a', "aardvark", kcli_opt_flag, &aardvark, + "a nocturnal burrowing mammal" }, + // or Kcli_opt(aardvark, 'a', flag, "a nocturnal burrowing mammal") + { 'z', "zebra", kcli_opt_flag, &zebra, + "a striped equine" }, + { 'p', "password", kcli_opt_string, &password, + "the password to log in with" } + }; + kcli_set me = { + "demo", e.argc, e.argv, + "a demonstration of the kcli_set type", + params, Kmsz(params), + options, Kmsz(options) + }, + size_t args_parsed = kcli_parse(&me); + if (args_parsed == 0) { kcli_usage(&me, e.err); return 1; } + + return 0; + } + +### struct kcli_opt +a `kcli_opt` is a representation of a command-line flag and its function. each option must have a unique `id` and/or a unique `name`. + + * `char id` - the short single-character form of the flag (or NUL for no short form) + * `const char* name` - the long string form of the flag (or NULL for no long form) + * `kcli_opt_kind kind` - enum that describes how the flag will function + * `void* val` - a pointer to an appropriate type to store the return value in. + * `const char* desc` - a description of the flag's purpose and function (or NULL for no description) + +#### enum kcli_opt_kind + + * `kcli_opt_none` - flag is disabled and will not be shown in usage + * `kcli_opt_string` - flag tells kcli to add a string to the list of expected parameters; appropriate string will be returned + * `kcli_opt_oct` - flag tells kcli to add an octal number to the list of expected parameters + * `kcli_opt_dec` - flag tells kcli to add a decimal number to the list of expected parameters + * `kcli_opt_hex` - flag tells kcli to add a hexdecimal number to the list of expected parameters + * `kcli_opt_flag` - flag is an option: will return `kcli_flag_on` if entered at least once, `kcli_flag_off` otherwise. + * `kcli_opt_toggle` - flag toggles value on and off: will return `kcli_flag_on` if entered an odd number of times, `kcli_flag_off` otherwise. + * `kcli_opt_accumulate` - flag increments a value every time it is entered; often used to implement `-v (--verbose)`-style options (e.g. `-vvvv` would return a value of `4`). + +### struct kcli_param +`kcli_param` describes a parameter that may be passed to the program whether or not any flags are passed. + + * `const char* name` - a short name for the parameter + * `kcli_param_kind kind` - the kind of parameter passed + * `kcli_class class` - whether or not the parameter is optional + * `void* val` - a pointer to an appropriate type of variable to fill + * `const char* desc` - a description of the parameter's function + +#### enum kcli_param_kind + * `kcli_param_none` - parameter is disabled and will not be expected or accepted + * `kcli_param_string` - parameter will not be parsed; a raw string will be returned + * `kcli_param_oct` - parameter will be parsed as an octal number + * `kcli_param_dec` - parameter will be parsed as a decimal number + * `kcli_param_hex` - parameter will be parsed as a hexadecimal number + +### enum kcli_class + * `kcli_class_forbidden` - parameter may not be passed + * `kcli_class_optional` - parameter may or may not be passed + * `kcli_class_required` - parameter must be passed + +### enum kcli_flag +results that an option of kind `kcli_opt_flag` can return. + + * `kcli_flag_off = 0` - flag is off + * `kcli_flag_on = 1` - flag is on + +## macros + +### Kcli_param(field, kind, class, description) +a convenience macro for filling out parameter lists. + +`Kcli_param(field,a,b,"description")` is transformed into: + + { "field", kcli_param_a, kcli_class_b, &field, "description" } + +### Kcli_opt(field, kind, class, description) +a convenience macro for filling out option lists. + +`Kcli_opt(name,'n',string,"description")` is transformed into: + + { 'n', "name", kcli_opt_string, &name, "description" } ADDED kcore/boot.c Index: kcore/boot.c ================================================================== --- kcore/boot.c +++ kcore/boot.c @@ -0,0 +1,8 @@ +#include "core.h" +extern stat entry(kenv); + +stat _boot(unsigned int argc, char** argv) { + kenv e = { argc, argv }; + return entry(e); +} + ADDED kcore/core.h Index: kcore/core.h ================================================================== --- kcore/core.h +++ kcore/core.h @@ -0,0 +1,12 @@ +#ifndef KIcore +#define KIcore + +typedef unsigned long long sz; +typedef unsigned char stat; + +typedef struct kenv { + sz argc; + char** argv; +} kenv; + +#endif ADDED kcore/kcore.md Index: kcore/kcore.md ================================================================== --- kcore/kcore.md +++ kcore/kcore.md @@ -0,0 +1,34 @@ +# kcore +**kcore** is the foundation for the rest of libk. it defines types and structs that are needed by every program, and provides the stub that launches a program's "entry" function. + +## entry +when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform. + +## types +kcore contains fixed-width integer types. note that the available of each depends on your platform; compilation will fail if e.g. you try to use a u64 or a u128 on a 32-bit platform, so where exact lengths are not required, you may wish to use the built-in C types instead. + + * `u8` - an unsigned 8-bit integer + * `s8` - a signed 8-bit integer + * `u16` - an unsigned 16-bit integer + * `s16` - a signed 16-bit integer + * `u32` - an unsigned 32-bit integer + * `s32` - a signed 32-bit integer + * `u64` - an unsigned 64-bit integer + * `s64` - a signed 64-bit integer + * `u128` - an unsigned 128-bit integer + * `s128` - a signed 128-bit integer + * `word` - an unsigned integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) + * `sword` - a signed integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) + * `stat` - the type of process return values expected by the platform (usually u8 on linux) + +### struct kenv +`kenv` is a struct that encompasses the environment the program was launched in. + * `kiochan std` - a stereo IO channel for reading and writing to and from stdout. + * `kiochan err` - a mono IO channel for writing to stderr. + * `kvar* env` - a pointer into the program's environment + +### struct kvar +`kvar` is a struct that abstracts over platform environment variables. + * `kstr name` - the name of an environment variable + * `kstr val` - the value of an environment variable + * `char* platform` - a pointer into the platform's underlying representation ADDED kcore/makefile Index: kcore/makefile ================================================================== --- kcore/makefile +++ kcore/makefile @@ -0,0 +1,1 @@ +include ../modmake ADDED kcore/start.x86.lin.64.s Index: kcore/start.x86.lin.64.s ================================================================== --- kcore/start.x86.lin.64.s +++ kcore/start.x86.lin.64.s @@ -0,0 +1,17 @@ +; vim: ft=nasm +bits 64 +%include "../arch/x86.lin.64.s" +global _start +extern _boot +extern entry; + +_start: + mov rbp, rsp + mov rdi, [rbp + 0] ; argc + lea rsi, [rbp + 8] ; argv + + call _boot; + + mov sys.reg.1, sys.reg.ret + mov sys.reg.0, sys.exit + sys.call Index: libk.md ================================================================== --- libk.md +++ libk.md @@ -180,8 +180,8 @@ if you disagree with this philosophy, you are welcome to continue using libc. ## what does the k stand for? -nothing. it was chosen in reference to libc - the letter C was part of the original roman alphabet, while K was added later by analogy to the Greek kappa ‹κ›. in my native language, the older letter ‹c› can make a number of different sounds based on context, including [k] and [s], while ‹k› is fairly consistently used for the sound [k]. hopefully the analogy is obvious. +nothing. it was chosen in reference to libc - the letter C was part of the original roman alphabet, while K was added later by analogy to the Greek kappa ‹κ›. in my native language, the older letter ‹c› can make a number of different sounds based on context, including [k] and [s], while ‹k› is fairly consistently used for the sound [k]. and for orthographical reasons, [k] is often represented by the digraph ‹ck› - that is, a C followed by a K. hopefully the analogies are obvious. this project has nothing to do with KDE. Index: modmake ================================================================== --- modmake +++ modmake @@ -53,15 +53,15 @@ # from yasm is trivial. linux only supports one ABI per format, # at least with ELF, so that's all we need to do. #${OUT}/$(mod).%.x86.lin.32.o: %.x86.lin.32.s $(call arch,x86.lin.32) - yasm -felf32 $< -o $@ + yasm -gdwarf2 -felf32 $< -o $@ #${OUT}/$(mod).%.x86.lin.64.o: %.x86.lin.64.s $(call arch,x86.lin.64) - yasm -felf64 $< -o $@ + yasm -gdwarf2 -felf64 $< -o $@ #-- freebsd # the freebsd ABI is different, so it will require different code # (though there might be ways to minimize that). freebsd uses the # same binary format as Linux (though it also supports a.out and