Overview
Comment: | begin work on kcli module; continue to build out infra for error explanation function |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
c0e04b901565b65b6b949db7cab9ebed |
User & Date: | lexi on 2019-10-30 03:34:34 |
Other Links: | manifest | tags |
Context
2019-10-30
| ||
07:44 | factor out write buffer code so any module and libk users can call it; update documentation to match; add kssz string length function check-in: 8d6b36fcac user: lexi tags: trunk | |
03:34 | begin work on kcli module; continue to build out infra for error explanation function check-in: c0e04b9015 user: lexi tags: trunk | |
2019-10-23
| ||
10:05 | continue work on plans for kconf module check-in: 623e0fdd96 user: lexi tags: trunk | |
Changes
Modified build.sh from [1a5246e64d] to [4e982ff144].
21 21 if test "$1" = "-C"; then 22 22 say "precleaning repo" 23 23 ./clean.sh 24 24 fi 25 25 26 26 # TODO: make it possible for user to change 27 27 # default set with environment vars 28 -modules=(kcore kmem kstr kio kgraft kfile) 28 +modules=(kcore kmem kstr kio kgraft kfile kcli) 29 29 30 30 # compose an arch tuple. this is used in 31 31 # places, mostly to select the correct 32 32 # version of assembly files for a given 33 33 # platform (each has an arch tuple in its 34 34 # name, following the linkage specifier) 35 35 target=$arch.$os
Modified global/build-manpage.sh from [132a7e50b4] to [af11c2c865].
42 42 descline=$(echo "$dhead" | cut -d: -f1) 43 43 offset=1 44 44 else 45 45 descline=$(grep -m2 -n "^#" "$file" | tail -n1 | cut -d: -f1) 46 46 offset=0 47 47 fi 48 48 49 -tail -n+2 $file | head -n$(expr $descline - 2) | cmark -t man >>"$fmt" 49 +tail -n+2 $file | head -n$(expr $descline - 2) | cmark --smart -t man >>"$fmt" 50 50 51 51 echo >>"$fmt" ".SH DESCRIPTION" 52 52 53 -tail -n+$(expr $descline + $offset) "$file" | cmark -t man >> "$fmt" 53 +tail -n+$(expr $descline + $offset) "$file" | cmark --smart --normalize -t man >> "$fmt" 54 54 55 55 test "$doc_html" = "yes" && { 56 56 mkdir -p "$htmldest" 57 57 groff -Thtml -Kutf8 -m man "$fmt" > "$html" 58 58 test "$verbose" != "loud" || 59 59 say "wrote html page for $stem to $html" 60 60 }
Added mod/kcli/cli.h version [a50dc5f1ed].
1 +#ifndef KIcli 2 +#define KIcli 3 + 4 +#include <k/core.h> 5 +#include <k/io.h> 6 +#include <k/type.h> 7 +#include <k/internal.egroup.h> 8 + 9 +/* input types */ 10 + 11 +typedef struct kcli_opt { 12 + codepoint id; 13 + const char* name; 14 + enum kcli_opt_kind { 15 + kcli_opt_none /* flag is disabled and hidden */, 16 + kcli_opt_string /* flag takes a string argument */, 17 + kcli_opt_flag /* on if present, off if absent */, 18 + kcli_opt_toggle /* off by default, value toggles 19 + * for each occurrence */, 20 + kcli_opt_accumulate /* u8, value increases for each 21 + * occurrence, saturates at 255 */, 22 + kcli_opt_enum /* matched against a table of string 23 + * values to retrieve the corresponding 24 + * integer ID */, 25 + 26 + kcli_opt_int = 0x40, 27 + /* kcli_opt_int takes a default base parameter. 28 + * for instance, to take a decimal number, you 29 + * might write `kcli_opt_int | 10.` if the 30 + * argument takes a base prefix, the default 31 + * base will be disregarded. */ 32 + kcli_opt_oct = kcli_opt_int | 8, 33 + kcli_opt_dec = kcli_opt_int | 10, 34 + kcli_opt_hex = kcli_opt_int | 16, 35 + } kind; 36 + void* val; 37 + const char* desc; 38 +} kcli_opt; 39 + 40 +typedef struct kcli_param { 41 + const char* name; 42 + enum kcli_param_kind { 43 + kcli_param_none, 44 + kcli_param_string, 45 + kcli_param_enum, 46 + kcli_param_int = 0x40, 47 + kcli_param_oct = kcli_param_int | 8, 48 + kcli_param_dec = kcli_param_int | 10, 49 + kcli_param_hex = kcli_param_int | 16, 50 + } kind; 51 + enum kcli_rule { 52 + kcli_rule_forbidden, 53 + kcli_rule_optional, 54 + kcli_rule_required, 55 + } rule; 56 +} kcli_param; 57 + 58 +typedef struct kcli_set { 59 + const char* name; 60 + const char* version; 61 + const char** args; sz argc; 62 + const char* desc; 63 + const kcli_param* params; sz paramc; 64 + const kcli_opt* opts; sz optc; 65 +} kcli_set; 66 + 67 +/* output types */ 68 + 69 +typedef enum kcli_cond { 70 + kcli_cond_ok = kcli_cond_id, 71 + kcli_cond_extra /* parse succeded, but arguments or 72 + flags were left over */, 73 + kcli_cond_fail /* unspecified error */, 74 + kcli_cond_parse /* bad syntax, parse failed */, 75 +} kcli_cond; 76 + 77 +typedef enum kcli_flag { 78 + kcli_flag_off = 0, 79 + kcli_flag_on = 1, 80 +} kcli_flag; 81 + 82 +/* functions */ 83 + 84 +kcond kcli_usage(kcli_set, kiochan); 85 +kcli_cond kcli_parse(kcli_set); 86 + 87 +/* macros */ 88 + 89 +#define Kcli_param(field,kind,rule,description) \ 90 + {#field, kcli_param_##kind, kcli_rule_##rule, &field, description} 91 +#define Kcli_opt(long,short,kind,description) \ 92 + {short, #long, kcli_opt_##kind, &long, description} 93 + 94 +#endif
Modified mod/kcli/kcli.md from [fb0395874f] to [6a6012e12f].
28 28 29 29 ## kcli_usage(kcli_set, kiochan) 30 30 kcli_usage() takes a `kcli_set` and prints a succinct usage summary to a [kiochan](../kio/kio.md). 31 31 32 32 # types 33 33 34 34 ## struct kcli_set 35 -`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. 35 +`kcli_set` is a struct containing information about your program, such as its name, a synopsis of its function, a pointer to an array of arguments, and a list of `kcli_opt`s. 36 36 37 37 * `const char* name` - program name (if null, will be determined from argv instead) 38 + * `const char* version` - a string describing the program version (if null, version will not be printed) 39 + * `const char** args` - the `argv` pointer passed to the `entry` function, representing the command-line arguments passed to the program. 38 40 * `size_t argc` - the number of arguments in the `argv` array. 39 - * `const char** argv` - the `argv` pointer passed to the `entry` function, representing the command-line arguments passed to the program. 40 41 * `const char* desc` - program description 41 42 * `const kcli_param* params` - a list of options expected by the program. 42 43 * `size_t paramc` - the number of params in the list to process. 43 44 * `const kcli_opt* opts` - a list of options expected by the program. 44 45 * `size_t optc` - the number of options in the list to process. 45 46 46 47 a kcli_set might be used like so: ................................................................................ 51 52 stat entry(kenv e) { 52 53 kcli_flag aardvark; 53 54 kcli_flag zebra; 54 55 char* user; 55 56 char* password; 56 57 long age; 57 58 kcli_param params[] = { 58 - { "user", kcli_param_string, kcli_class_required, 59 + { "user", kcli_param_string, kcli_rule_required, 59 60 &user, "the user to log in as" } 60 61 // or Kcli_param(user,string,required,"the user to log in as"), 61 62 62 - { "age", kcli_param_dec, kcli_class_optional, 63 + { "age", kcli_param_dec, kcli_rule_optional, 63 64 &age, "the age of the user" } 64 65 // or Kcli_param(age,dec,optional,"the age of the user"), 65 66 }; 66 67 kcli_opt options[] = { 67 68 { 'a', "aardvark", kcli_opt_flag, &aardvark, 68 69 "a nocturnal burrowing mammal" }, 69 70 // or Kcli_opt(aardvark, 'a', flag, "a nocturnal burrowing mammal") 70 71 { 'z', "zebra", kcli_opt_flag, &zebra, 71 72 "a striped equine" }, 72 73 { 'p', "password", kcli_opt_string, &password, 73 74 "the password to log in with" } 74 75 }; 75 76 kcli_set argset = { 76 - "demo", e.argc, e.argv, 77 + "demo", e.args, e.argc, 77 78 "a demonstration of the kcli_set type", 78 79 params, Kmsz(params), 79 80 options, Kmsz(options) 80 81 }, 81 - size_t args_parsed = kcli_parse(&argset); 82 - if (args_parsed == 0) { kcli_usage(&me, e.err); return 1; } 82 + size_t args_parsed = kcli_parse(argset); 83 + if (args_parsed == 0) { kcli_usage(me, e.err); return 1; } 83 84 84 85 return 0; 85 86 } 86 87 87 -### struct kcli_opt 88 +## struct kcli_opt 88 89 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`. 89 90 90 91 * `char id` - the short single-character form of the flag (or NUL for no short form) 91 92 * `const char* name` - the long string form of the flag (or NULL for no long form) 92 93 * `kcli_opt_kind kind` - enum that describes how the flag will function 93 94 * `void* val` - a pointer to an appropriate type to store the return value in. 94 95 * `const char* desc` - a description of the flag's purpose and function (or NULL for no description) 95 96 96 -#### enum kcli_opt_kind 97 +## enum kcli_opt_kind 97 98 98 99 * `kcli_opt_none` - flag is disabled and will not be shown in usage 99 100 * `kcli_opt_string` - flag tells kcli to add a string to the list of expected parameters; appropriate string will be returned 101 + * `kcli_opt_int` - flag tells kcli to add an integer to the last of expected parameters; must be bitwise-OR'd with default base 100 102 * `kcli_opt_oct` - flag tells kcli to add an octal number to the list of expected parameters 101 103 * `kcli_opt_dec` - flag tells kcli to add a decimal number to the list of expected parameters 102 104 * `kcli_opt_hex` - flag tells kcli to add a hexdecimal number to the list of expected parameters 103 105 * `kcli_opt_flag` - flag is an option: will return `kcli_flag_on` if entered at least once, `kcli_flag_off` otherwise. 104 106 * `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. 105 107 * `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`). 106 108 * `kcli_opt_enum` - flag is one of a series of enumerated values, which will be matched against a table to yield the associated integer. 107 109 108 -### struct kcli_param 110 +## struct kcli_param 109 111 `kcli_param` describes a parameter that may be passed to the program whether or not any flags are passed. 110 112 111 113 * `const char* name` - a short name for the parameter 112 114 * `kcli_param_kind kind` - the kind of parameter passed 113 - * `kcli_class class` - whether or not the parameter is optional 115 + * `kcli_rule rule` - whether or not the parameter is optional 114 116 * `void* val` - a pointer to an appropriate type of variable to fill 115 117 * `const char* desc` - a description of the parameter's function 116 118 117 -#### enum kcli_param_kind 119 +### enum kcli_param_kind 118 120 * `kcli_param_none` - parameter is disabled and will not be expected or accepted 119 121 * `kcli_param_string` - parameter will not be parsed; a raw string will be returned 122 + * `kcli_param_enum` - parameter will be matched against an enumeration table 123 + * `kcli_param_int` - parameter will be parsed as an integer; must be bitwise-OR'd with default base 120 124 * `kcli_param_oct` - parameter will be parsed as an octal number 121 125 * `kcli_param_dec` - parameter will be parsed as a decimal number 122 126 * `kcli_param_hex` - parameter will be parsed as a hexadecimal number 123 127 124 -### enum kcli_class 125 - * `kcli_class_forbidden` - parameter may not be passed 126 - * `kcli_class_optional` - parameter may or may not be passed 127 - * `kcli_class_required` - parameter must be passed 128 +## enum kcli_rule 129 + * `kcli_rule_forbidden` - parameter may not be passed 130 + * `kcli_rule_optional` - parameter may or may not be passed 131 + * `kcli_rule_required` - parameter must be passed 128 132 129 -### enum kcli_flag 133 +## enum kcli_flag 130 134 results that an option of kind `kcli_opt_flag` can return. 131 135 132 136 * `kcli_flag_off = 0` - flag is off 133 137 * `kcli_flag_on = 1` - flag is on 134 138 135 -## macros 139 +# macros 136 140 137 -### Kcli_param(field, kind, class, description) 141 +## Kcli_param(field, kind, class, description) 138 142 a convenience macro for filling out parameter lists. 139 143 140 144 `Kcli_param(field,a,b,"description")` is transformed into: 141 145 142 - { "field", kcli_param_a, kcli_class_b, &field, "description" } 146 + { "field", kcli_param_a, kcli_rule_b, &field, "description" } 143 147 144 -### Kcli_opt(field, kind, class, description) 148 +## Kcli_opt(field, kind, class, description) 145 149 a convenience macro for filling out option lists. 146 150 147 151 `Kcli_opt(name,'n',string,"description")` is transformed into: 148 152 149 153 { 'n', "name", kcli_opt_string, &name, "description" }
Added mod/kcli/parse.fn.c version [1d4ed1c3cd].
1 +#include <k/cli.h> 2 + 3 +kcli_cond 4 +kcli_parse(kcli_set prg) { 5 + 6 +}
Added mod/kcli/testbin.exe.c version [7d0c94d714].
1 +#include <k/core.h> 2 +#include <k/cli.h> 3 + 4 +stat 5 +entry (kenv e) { 6 + kcli_set testbin = { 7 + "testbin", "1.0.0", e.args, e.argc, 8 + "this is a test of the kcli module", 9 + }; 10 + 11 + kcli_usage(testbin, e.err); 12 + 13 + return 0; 14 +}
Added mod/kcli/usage.fn.c version [2416d97ee0].
1 +#include <k/cli.h> 2 +#include <k/io.h> 3 +#include <k/str.h> 4 + 5 +typedef struct buffer { 6 + char* cur; 7 + kiochan channel; 8 + sz run; 9 + char buf []; 10 +} buffer; 11 + 12 +static buffer* 13 +buffer_new(void* mem, kiochan channel, sz run) { 14 + buffer* r = mem; 15 + r -> cur = r -> buf; 16 + r -> channel = channel; 17 + r -> run = run; 18 + return r; 19 +} 20 + 21 +static kiocond 22 +buffer_flush(buffer* b) { 23 + ksraw str = {b -> cur - b -> buf, b -> buf}; 24 + b -> cur = b -> buf; 25 + return kiosend(b -> channel, str, null); 26 +} 27 + 28 +static kcond 29 +buffer_send(buffer* b, const char* str) { 30 + ksmut buf = { b->run - (b->cur - b->buf), b->cur }; 31 + ksraw src = { 0, str }; 32 + kscond sc = kscp(src, buf, &src.size); 33 + if (sc != kscond_ok) return sc; 34 + 35 + b->cur += src.size; 36 + if (b->cur >= (b->buf + b->run)) { 37 + return buffer_flush(b); 38 + } else return kiocond_ok; 39 +} 40 + 41 +kcond 42 +kcli_usage(kcli_set prg, kiochan ch) { 43 + ubyte buf_space [sizeof(buffer) + 256]; 44 + buffer* out = buffer_new(buf_space, ch, 256); 45 + 46 + const char* msg [] = { 47 + prg.name, " v", prg.version, "\n\n", 48 + prg.desc, "\n\n", 49 + }; 50 + for (sz i = 0; i != sizeof msg / sizeof msg[0]; ++ i) { 51 + kcond c = buffer_send(out, msg[i]); 52 + if (!kokay(c)) return c; 53 + } 54 + 55 + return buffer_flush(out); 56 +}
Modified mod/kcore/boot.rt.c from [7899b05286] to [e3e3209cc1].
1 1 #include <k/core.h> 2 2 #include <k/type.h> 3 3 extern stat entry(kenv); 4 4 5 5 unsigned long long 6 6 _boot(unsigned int argc, /* argument count */ 7 - char** argv, /* arguments */ 7 + const char** argv, /* arguments */ 8 8 char** envp /* environment */ ) { 9 9 10 10 envp ++; /* envp seems to point at a leading null; 11 11 this is probably a sign of breakage but 12 12 i don't know what else to do about it for 13 13 the moment. */ 14 14 ................................................................................ 35 35 36 36 kenv e = { 37 37 /* TODO: determine terminal class and set term vs ansi correctly! */ 38 38 { {kiostream_term, 0}, {kiostream_term, 1} }, // chan std 39 39 { {kiostream_closed}, {kiostream_term, 2} }, // chan err 40 40 argc, argv, ep - envp, variables 41 41 }; 42 + 42 43 return entry(e); 43 44 }
Modified mod/kcore/core.h from [2582f2493d] to [4d5847ec2c].
14 14 ksraw val; 15 15 char* platform; 16 16 } kvar; 17 17 18 18 typedef struct kenv { 19 19 kiochan std; 20 20 kiochan err; 21 - sz argc; char** args; 21 + sz argc; const char** args; 22 22 sz varc; kvar* vars; 23 23 } kenv; 24 24 25 25 /* i'm really sorry okay */ 26 26 typedef 27 27 #if (__STDC_VERSION__ >= 199901L) 28 28 _Bool bool;
Modified mod/kcore/type.h.m from [efe9d86768] to [3822f60b11].
179 179 ”)dnl 180 180 181 181 // exit status integer types - pls use kbad in <k/magic.h> instead 182 182 ifelse(target_posix,“yes”,“ 183 183 /* by convention, posix return values are 8-bit, 184 184 * but note that many modern UNIXes do technically 185 185 * support higher-bit values. for this reason, 186 - * longstat is defined differently under posix. */ 186 + * stat_long is defined differently under posix. */ 187 187 typedef u8 stat; 188 188 typedef u32 stat_long; 189 189 ”,“dnl 190 190 ifelse(atom_target_os,“win”,“ 191 191 typedef u32 stat; 192 192 ”,“dnl 193 193 ifelse(atom_target_os,“vms”,“ ................................................................................ 197 197 /* we don't know a specific exit status type 198 198 * for your arch so we're going with a sane 199 199 * default. if this is wrong, help us fix it! */ 200 200 ”)”)dnl 201 201 typedef stat stat_long; 202 202 ”)dnl 203 203 204 +/* unicode types */ 205 + 206 +typedef u32 codepoint; 207 + /* a codepoint is a UTF-32 character */ 208 +typedef u8 rune [5]; 209 + /* a rune is a valid UTF-8 character terminated with a nul. */ 210 + 204 211 #endif
Modified mod/kio/io.h.m from [f45741da3f] to [34396da060].
74 74 kiocond_fail_over_quota, 75 75 kiocond_fail_pfault, 76 76 kiocond_fail_too_big, 77 77 kiocond_fail_stream_mismatch, 78 78 } kiocond; 79 79 80 80 kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel 81 +kiocond kiosendall(kiochan, ksraw); // keep sending data to a channel until it's all sent 81 82 kiocond kiorecv(kiochan, ksraw*); // receive data from a channel 82 83 kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel 83 84 // kmkind is only used if kmcell* is null 84 85 kiocond kiocon(kiochan, kiochan); // connect one channel to another 85 86 86 87 #ifdef __cplusplus 87 88 } 88 89 #endif 89 90 90 91 #endif
Added mod/kstr/scp.fn.c version [214672f460].
1 +#include <k/core.h> 2 +#include <k/str.h> 3 + 4 +kscond kscp(ksraw str, ksmut dest, sz* len) { 5 + if (str.size == 0) { /* calculate length on the fly */ 6 + for(; str.ptr[str.size] != 0; ++ str.size) { 7 + if (str.size >= dest.size) return kscond_no_room; 8 + 9 + dest.ptr[str.size] = str.ptr[str.size]; 10 + } 11 + } else { 12 + if (dest.size < str.size) return kscond_no_room; 13 + 14 + if (dest.ptr == null || str.ptr == null) return kscond_null; 15 + 16 + for(sz idx = 0; idx < str.size; ++ idx) { 17 + dest.ptr[idx] = str.ptr[idx]; 18 + } 19 + } 20 + 21 + /* did we copy a nul? */ 22 + if (str.ptr[str.size - 1] != 0) 23 + /* we didn't, can we? */ 24 + if (dest.size > str.size) 25 + /* set a final nul */ 26 + dest.ptr[str.size] = 0; 27 + 28 + if (len != null) *len = str.size; 29 + return kscond_ok; 30 +}
Modified mod/kstr/str.h from [0c79e2a160] to [43535adcf4].
24 24 25 25 #include <k/internal.egroup.h> 26 26 typedef enum kscond { 27 27 kscond_ok = kscond_id, 28 28 kscond_fail, 29 29 kscond_unimplemented, 30 30 kscond_nonnumeric, 31 + kscond_no_room, 32 + kscond_null, 31 33 } kscond; 32 34 33 35 enum ksconv { 34 36 ksconv_default = 0, 35 37 36 38 ksconv_raw = 1, 37 39 ksconv_bin = 2, ................................................................................ 49 51 kscond ks_to_int(ksraw str, 50 52 enum ksconv mode, 51 53 u8* dest, sz size); 52 54 53 55 kscond ks_of_int(u8* number, sz size, 54 56 enum ksconv mode, 55 57 char* bufstart, sz bufsize); 58 + 59 +kscond kscp(ksraw str, ksmut dest, sz* len); 56 60 57 61 #ifdef __cplusplus 58 62 } 59 63 #endif 60 64 61 65 #endif