libk  Check-in [927371b674]

Overview
Comment:add usage display for parameters and command line switches for kcli_set, the structure used to define command line syntax for the parser; add more string & buffer functions
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 927371b67487d7546aab169d03e001d0568918f1d94d0f0cf34caf19e7b4f2b0
User & Date: lexi on 2019-10-31 03:44:25
Other Links: manifest | tags
Context
2019-11-01
06:28
Mostly fix NixOS build. Docs are still broken. The rest of the problems, mostly from small changes since NixOS was last tested, are fixed. check-in: 009b0289f2 user: glowpelt tags: trunk
06:27
remove nonexistant --normalize option check-in: 0ed5f80174 user: lexi tags: trunk
2019-10-31
03:44
add usage display for parameters and command line switches for kcli_set, the structure used to define command line syntax for the parser; add more string & buffer functions check-in: 927371b674 user: lexi tags: trunk
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
Changes

Modified mod/kcli/cli.h from [a50dc5f1ed] to [5126e2cc55].

     5      5   #include <k/io.h>
     6      6   #include <k/type.h>
     7      7   #include <k/internal.egroup.h>
     8      8   
     9      9   /* input types */
    10     10   
    11     11   typedef struct kcli_opt {
    12         -	codepoint id;
           12  +	rune id;
    13     13   	const char* name;
    14     14   	enum kcli_opt_kind {
    15     15   		kcli_opt_none /* flag is disabled and hidden */,
    16     16   		kcli_opt_string /* flag takes a string argument */,
    17     17   		kcli_opt_flag /* on if present, off if absent */,
    18     18   		kcli_opt_toggle /* off by default, value toggles
    19     19   		                 * for each occurrence */,
................................................................................
    46     46   		kcli_param_int = 0x40,
    47     47   			kcli_param_oct = kcli_param_int | 8,
    48     48   			kcli_param_dec = kcli_param_int | 10,
    49     49   			kcli_param_hex = kcli_param_int | 16,
    50     50   	} kind;
    51     51   	enum kcli_rule {
    52     52   		kcli_rule_forbidden,
    53         -		kcli_rule_optional,
    54     53   		kcli_rule_required,
           54  +		kcli_rule_optional,
           55  +		kcli_rule_overflow,
    55     56   	} rule;
           57  +	void* val;
           58  +	const char* desc;
    56     59   } kcli_param;
    57     60   
    58     61   typedef struct kcli_set {
    59     62   	const char*       name;
    60     63   	const char*       version;
    61     64   	const char**      args;   sz argc;
    62     65   	const char*       desc;
................................................................................
    68     71   
    69     72   typedef enum kcli_cond {
    70     73   	kcli_cond_ok = kcli_cond_id,
    71     74   	kcli_cond_extra /* parse succeded, but arguments or
    72     75   	                   flags were left over */,
    73     76   	kcli_cond_fail /* unspecified error */,
    74     77   	kcli_cond_parse /* bad syntax, parse failed */,
           78  +	kcli_cond_overlong /* a string in the configuration structures is longer than allowed */,
    75     79   } kcli_cond;
    76     80   
    77     81   typedef enum kcli_flag {
    78     82   	kcli_flag_off = 0,
    79     83   	kcli_flag_on = 1,
    80     84   } kcli_flag;
    81     85   

Modified mod/kcli/kcli.md from [6a6012e12f] to [0390b41ce1].

    84     84   
    85     85   		return 0;
    86     86   	}
    87     87   
    88     88   ## struct kcli_opt
    89     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`.
    90     90   
    91         - * `char id` - the short single-character form of the flag (or NUL for no short form)
           91  + * `rune id` - the short single-character form of the flag as a UTF-8 codepoint (or initial NUL for no short form)
    92     92    * `const char* name` - the long string form of the flag (or NULL for no long form)
    93     93    * `kcli_opt_kind kind` - enum that describes how the flag will function
    94     94    * `void* val` - a pointer to an appropriate type to store the return value in.
    95     95    * `const char* desc` - a description of the flag's purpose and function (or NULL for no description)
    96     96   
    97     97   ## enum kcli_opt_kind
    98     98   

Modified mod/kcli/testbin.exe.c from [9c55c30fa9] to [92e78f7400].

     1      1   #include <k/core.h>
     2      2   #include <k/cli.h>
     3      3   
     4      4   stat
     5      5   entry (kenv e) {
            6  +	kcli_flag verbose = false,
            7  +	          debug = false;
            8  +	
            9  +	kcli_opt options[] = {
           10  +		{ "v", "verbose", kcli_opt_flag, &verbose,
           11  +		  "induce information overload" },
           12  +		{ "d", "debug-mode", kcli_opt_flag, &debug,
           13  +		  "run the program in debug mode"},
           14  +	};
           15  +
           16  +	const char* perp, * place, * weapon;
           17  +
           18  +	kcli_param params[] = {
           19  +		{"perp", kcli_param_string, kcli_rule_required, &perp,
           20  +		 "the one who did the dastardly deed"},
           21  +		{"place", kcli_param_string, kcli_rule_required, &place,
           22  +		 "where the crime was committed"},
           23  +		{"murder weapon", kcli_param_string, kcli_rule_optional, &weapon,
           24  +		 "the implement used to murder the victim"},
           25  +	};
           26  +
     6     27   	kcli_set testbin = {
     7     28   		"testbin", "1.0.0", e.args, e.argc,
     8     29   		"this is a test of the kcli module",
           30  +		params, Kmsz(params),
           31  +		options, Kmsz(options),
     9     32   	};
    10     33   
    11     34   	kcond c = kcli_usage(testbin, e.err);
    12     35   
    13     36   	return c;
    14     37   }

Modified mod/kcli/usage.fn.c from [09e6f94502] to [51bd833f89].

            1  +#include <k/core.h>
     1      2   #include <k/cli.h>
     2      3   #include <k/io.h>
     3      4   #include <k/str.h>
            5  +
            6  +extern char* _k_internal_binary_name;
            7  +
            8  +static const struct { const char* front, * back; } param_styles [] = {
            9  +	[kcli_rule_required] = { "<",">" },
           10  +	[kcli_rule_optional] = { "[","]" },
           11  +	[kcli_rule_overflow] = { "","..." },
           12  +};
     4     13   
     5     14   kcond
     6     15   kcli_usage(kcli_set prg, kiochan ch) {
           16  +	enum { max_name_len = 32 };
           17  +
           18  +	kcond c;
     7     19   	ubyte buf_space [sizeof(ksbuf) + 256];
     8     20   	ksbuf* out = ksbufmk(buf_space, ch, 256);
     9     21   
           22  +	const char* name = prg.name != null ?
           23  +		prg.name : _k_internal_binary_name;
           24  +
    10     25   	const char* msg [] = {
    11         -		prg.name, " v", prg.version, "\n\n",
           26  +		name, " v", prg.version, "\n\n",
    12     27   		prg.desc, "\n\n",
           28  +		"usage: ", _k_internal_binary_name,
           29  +		prg.optc == 0 ? null : " [-",
    13     30   	};
    14         -	for (sz i = 0; i != Kmsz(msg); ++ i) {
    15         -		ksraw str = { 0, msg[i] };
    16         -		kcond c = ksbufput(out, str);
           31  +
           32  +	if (!kokay(c = ksbufwrite(out, msg))) return c;
           33  +
           34  +	u8 longest_opt = 0;
           35  +	u8 opt_lens [prg.optc];
           36  +	for (sz i = 0; i != prg.optc; ++ i) {
           37  +		if (prg.opts[i].id[0] == 0) continue;
           38  +
           39  +		opt_lens[i] = kssz(prg.opts[i].name, max_name_len);
           40  +		if (opt_lens[i] > longest_opt)
           41  +			longest_opt = opt_lens[i];
           42  +
           43  +		ksraw str = { kssz(prg.opts[i].id, 4), prg.opts[i].id };
           44  +		if (!kokay(c = ksbufput(out, str))) return c;
    17     45   	}
           46  +
           47  +	if (!kokay(c = ksbufput(out, Ksraw("]")))) return c;
    18     48   	
           49  +	u8 longest_param = 0;
           50  +	u8 param_lens [prg.paramc];
           51  +	for (sz i = 0; i != prg.paramc; ++ i) {
           52  +		enum kcli_rule r = prg.params[i].rule;
           53  +
           54  +		param_lens[i] = kssz(prg.params[i].name, max_name_len);
           55  +		if (param_lens[i] > longest_param)
           56  +			longest_param = param_lens[i];
           57  +
           58  +		const char* param[] = {
           59  +			" ", param_styles[r].front, prg.params[i].name,
           60  +			param_styles[r].back, null
           61  +		};
           62  +
           63  +		if (!kokay(c = ksbufwrite(out,param))) return c;
           64  +	}
           65  +
           66  +	if (!kokay(c = ksbufput(out, Ksraw("\n")))) return c;
           67  +
           68  +	const char spacing [] = "                                ";
           69  +	Kassert(sizeof spacing - 1 == max_name_len,
           70  +			"spacing string not equal in length to max_name_len");
           71  +	/* yes, yes, i know */
           72  +
           73  +	for (sz i = 0; i != prg.paramc; ++ i) {
           74  +		u8 pad = (longest_param - param_lens[i]) + 1;
           75  +		const char* tpl [] = {
           76  +			"\n    ", spacing + (sizeof spacing - pad),
           77  +			prg.params[i].name, ": ", prg.params[i].desc, null
           78  +		};
           79  +
           80  +		if (!kokay(c = ksbufwrite(out, tpl))) return c;
           81  +	}
           82  +
           83  +	if (!kokay(c = ksbufput(out, (ksraw){1, "\n"}))) return c;
           84  +
           85  +	for (sz i = 0; i != prg.optc; ++ i) {
           86  +		u8 pad = (longest_opt - opt_lens[i]) + 1;
           87  +		const char* tpl [] = {
           88  +			"\n    -", prg.opts[i].id, ", --", prg.opts[i].name,
           89  +			spacing + (sizeof spacing - pad), ": ", prg.opts[i].desc, null
           90  +		};
           91  +
           92  +		if (!kokay(c = ksbufwrite(out, tpl))) return c;
           93  +	}
           94  +
    19     95   	return ksbufflush(out);
    20     96   }

Modified mod/kcore/boot.rt.c from [e3e3209cc1] to [a8282db34a].

     1      1   #include <k/core.h>
     2      2   #include <k/type.h>
     3      3   extern stat entry(kenv);
     4      4   
            5  +const char* _k_internal_binary_name;
            6  +
     5      7   unsigned long long
     6      8   _boot(unsigned int argc, /* argument count */
     7      9   		const char** argv, /* arguments */
     8     10   		char** envp /* environment */ ) {
           11  +
           12  +	_k_internal_binary_name = argv[0];
     9     13   
    10     14   	envp ++; /* envp seems to point at a leading null;
    11     15   				this is probably a sign of breakage but
    12     16   				i don't know what else to do about it for
    13     17   				the moment. */
    14     18   
    15     19   	char** ep;

Added mod/kstr/bufwrite.fn.c version [564ff21d85].

            1  +#include <k/type.h>
            2  +#include <k/str.h>
            3  +#include <k/io.h>
            4  +
            5  +kcond
            6  +ksbufwrite(ksbuf* out, const char** array) {
            7  +	for (sz i=0; array[i] != null; ++ i) {
            8  +		ksraw str = { 0, array[i] };
            9  +		kcond c = ksbufput(out, str);
           10  +		if (!kokay(c)) return c;
           11  +	}
           12  +
           13  +	return kscond_ok;
           14  +}

Added mod/kstr/emitc.fn.c version [0654040df9].

            1  +#include <k/type.h>
            2  +#include <k/str.h>
            3  +#include <k/io.h>
            4  +
            5  +kcond
            6  +ksemitc(const char** array, sz bufsz, kiochan channel) {
            7  +	ubyte cache [sizeof(ksbuf) + bufsz];
            8  +	ksbuf* out = ksbufmk(cache, channel, bufsz);
            9  +
           10  +	kcond c = ksbufwrite(out, array);
           11  +	if (!kokay(c)) return c;
           12  +
           13  +	return ksbufflush(out);
           14  +}

Modified mod/kstr/kstr.md from [7f4b99ca6c] to [0b0860371c].

    55     55   
    56     56   ## ksbufmk
    57     57   `ksbuf* ksbufmk(void* where, kiochan channel, sz run)` initializes a new buffer at the specified address. `run` should be equivalent to the full length of the memory region minus `sizeof(struct ksbuf)` - in other words, the size of the string the `ksbuf` can hold. memory should be allocated by the user, either by creating an array on the stack or with `kmem` allocation functions. `ksbufmk()` returns a pointer to the new structure. the return value will always point to the same point in memory as `where`, but will be of the appropriate type to pass to buffer functions.
    58     58   
    59     59   ## ksbufput
    60     60   `kcond ksbufput(ksbuf* b, ksraw str)` copies a string into a buffer with `kscp`. flushing it as necessary.
    61     61   
    62         -# ksbufflush
           62  +## ksbufflush
    63     63   `kcond ksbufflush(ksbuf* b)` flushes a buffer to its assigned channel, emptying it and readying it for another write cycle. a buffer should almost always be flushed before it goes out of scope or is deallocated.
    64     64   
    65     65   ## kscomp
    66     66   `char* kscomp(size_t ct, ksraw struct[], kmbuf* buf)` is a **string composition** function. it serves as an efficient, generalized replacement for functions like `strcat` and `strdup`.
    67     67   
    68     68   to use kscomp, create an array of `kstr` and fill it with the strings you wish to concatenate. for example, to programmatically generate an HTML link tag, you might use the following code.
    69     69   
................................................................................
    76     76   			ksref(text),
    77     77   		Kstr("</a>")
    78     78   	};
    79     79   	char* html = kscomp(Kmsz(chain), chain, &buf);
    80     80   
    81     81   kscomp will only calculate the length of individual strings if they are not already known. when it needs to calculate the length of a string, it will store that length in the original array so repeated calls can be made without needing to repeatedly calculate the lengths. this is not always desirable, so the variant `kscompc` exists, which is exactly the same as `kscomp` in every respect except that `chain` is not altered in any way.
    82     82   
    83         -## macros
           83  +## ksemit
           84  +`ksemit(sz len, ksraw* array, kiochan channel)` takes a `len`-length `array` of `ksraw`s and prints them to a channel. a buffer will be allocated based on the total length of the strings to avoid unnecessary write calls.
           85  +
           86  +## ksemitc
           87  +`ksemitc(const char** array, sz bufsz, kiochan channel)` takes a null-terminated `array` of NUL-terminated strings and buffer-prints them to a channel. `bufsz` controls the size of the buffer used, and should be as close as possible to the size of the strings emitted. the buffer will be kept on the stack, so no memory management or cleanup is necessary.
           88  +
           89  +# macros
    84     90   if `KFclean` is not set when <k/str.h> is included, the following macros are defined.
    85     91   
    86         - * `Kstr(string)` - the compile-time equivalent to `kstr()`. `Kstr` takes a literal string and inserts the text `{ sizeof (string), string }` into the document, suitable for initializing a kstr.
           92  + * `Kstr(string)` - the compile-time equivalent to `kstr()`. `Kstr` takes a literal string and inserts the text `{ sizeof (string) - 1, string }` into the document, suitable for initializing a kstr.

Modified mod/kstr/str.h from [18dd12a221] to [48272504c4].

     8      8   #endif
     9      9   
    10     10   typedef struct ksraw {
    11     11   	sz size;
    12     12   	const char* ptr;
    13     13   } ksraw;
    14     14   
           15  +#define Ksraw(str) ((ksraw){sizeof(str),str})
           16  +
    15     17   typedef struct ksmut {
    16     18   	sz size;
    17     19   	char* ptr;
    18     20   } ksmut;
    19     21   
    20     22   sz kssz(const char* str, sz max);
    21     23   
    22     24   #include <k/mem.h>
    23     25   
    24     26   typedef struct kstr {
    25     27   	sz size;
    26     28   	kmptr ptr;
    27     29   } kstr;
           30  +
    28     31   
    29     32   #include <k/io.h>
    30     33   
    31     34   #include <k/internal.egroup.h>
    32     35   typedef enum kscond {
    33     36   	kscond_ok = kscond_id,
    34     37   	kscond_partial,
................................................................................
    75     78   
    76     79   kscond kscp(ksraw str, ksmut dest, sz* len);
    77     80   
    78     81   ksbuf* ksbufmk(void* where, kiochan channel, sz run);
    79     82   
    80     83   #include <k/core.h>
    81     84   
    82         -kcond ksbufput(ksbuf*, ksraw);
    83         -
           85  +kcond   ksbufput(ksbuf*, ksraw);
    84     86   kiocond ksbufflush(ksbuf*);
           87  +kcond   ksbufwrite(ksbuf*, const char** array);
           88  +kcond   ksemitc(const char** array, sz bufsz, kiochan channel);
    85     89   
    86     90   #ifdef __cplusplus
    87     91   }
    88     92   #endif
    89     93   
    90     94   #endif