libk  Check-in [8d6b36fcac]

Overview
Comment:factor out write buffer code so any module and libk users can call it; update documentation to match; add kssz string length function
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8d6b36fcac4d6db018f6597f71ce140e71a9ecd22d6203462f17cc62d2a7f197
User & Date: lexi on 2019-10-30 07:44:12
Other Links: manifest | tags
Context
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
03:34
begin work on kcli module; continue to build out infra for error explanation function check-in: c0e04b9015 user: lexi tags: trunk
Changes

Modified mod/kcli/testbin.exe.c from [7d0c94d714] to [9c55c30fa9].

4
5
6
7
8
9
10
11
12
13
14
stat
entry (kenv e) {
	kcli_set testbin = {
		"testbin", "1.0.0", e.args, e.argc,
		"this is a test of the kcli module",
	};

	kcli_usage(testbin, e.err);

	return 0;
}







|

|

4
5
6
7
8
9
10
11
12
13
14
stat
entry (kenv e) {
	kcli_set testbin = {
		"testbin", "1.0.0", e.args, e.argc,
		"this is a test of the kcli module",
	};

	kcond c = kcli_usage(testbin, e.err);

	return c;
}

Modified mod/kcli/usage.fn.c from [2416d97ee0] to [09e6f94502].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <k/cli.h>
#include <k/io.h>
#include <k/str.h>

typedef struct buffer {
	char* cur;
	kiochan channel;
	sz run;
	char buf [];
} buffer;

static buffer*
buffer_new(void* mem, kiochan channel, sz run) {
	buffer* r = mem;
	r -> cur = r -> buf;
	r -> channel = channel;
	r -> run = run;
	return r;
}

static kiocond
buffer_flush(buffer* b) {
	ksraw str = {b -> cur - b -> buf, b -> buf};
	b -> cur = b -> buf;
	return kiosend(b -> channel, str, null);
}

static kcond
buffer_send(buffer* b, const char* str) {
	ksmut buf = { b->run - (b->cur - b->buf), b->cur };
	ksraw src = { 0, str };
	kscond sc = kscp(src, buf, &src.size);
	if (sc != kscond_ok) return sc;

	b->cur += src.size;
	if (b->cur >= (b->buf + b->run)) {
		return buffer_flush(b);
	} else return kiocond_ok;
}

kcond
kcli_usage(kcli_set prg, kiochan ch) {
	ubyte buf_space [sizeof(buffer) + 256];
	buffer* out = buffer_new(buf_space, ch, 256);

	const char* msg [] = {
		prg.name, " v", prg.version, "\n\n",
		prg.desc, "\n\n",
	};
	for (sz i = 0; i != sizeof msg / sizeof msg[0]; ++ i) {
		kcond c = buffer_send(out, msg[i]);
		if (!kokay(c)) return c;
	}
	
	return buffer_flush(out);
}




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|
|





|
|
|


|

1
2
3
4




































5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <k/cli.h>
#include <k/io.h>
#include <k/str.h>





































kcond
kcli_usage(kcli_set prg, kiochan ch) {
	ubyte buf_space [sizeof(ksbuf) + 256];
	ksbuf* out = ksbufmk(buf_space, ch, 256);

	const char* msg [] = {
		prg.name, " v", prg.version, "\n\n",
		prg.desc, "\n\n",
	};
	for (sz i = 0; i != Kmsz(msg); ++ i) {
		ksraw str = { 0, msg[i] };
		kcond c = ksbufput(out, str);
	}
	
	return ksbufflush(out);
}

Modified mod/kcore/core.h from [4d5847ec2c] to [4054dd1b64].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
36
37
38
39
40
41
42


43
44
45
46
47
48
49
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169





















170
171
172
173
174
175
176
177
#ifndef KIcore
#define KIcore
#include <k/type.h>
#include <k/io.h>
#include <k/str.h>
#include <k/internal.egroup.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct kvar {
	ksraw name;
	ksraw val;
	char* platform;
} kvar;

typedef struct kenv {
	kiochan std;
	kiochan err;
	sz argc; const char** args;
	sz varc; kvar* vars;
} kenv;

/* i'm really sorry okay */
typedef
#if (__STDC_VERSION__ >= 199901L)
	_Bool bool;
#endif
enum
................................................................................
	false = 0, no  = 0,
	true  = 1, yes = 1
}
#if !(__STDC_VERSION__ >= 199901L)
	bool /* } bool ; */
#endif
;



#ifndef KFclean
#	include <k/internal.egroup.h>
#	define Kokay(cond) (((cond) % kglobal_module_offset) == 0)
#	if (__STDC_VERSION__ >= 199901L) ||\
	   (__cplusplus      >= 201103L)
#		define KVvm_args __VA_ARGS__
................................................................................
	[[noreturn]] void kstop(stat_long code);
#elif __STDC_VERSION__ >= 201103L
	_Noreturn void kstop(stat_long code);
#else
	void kstop(stat_long code);
#endif

typedef u16 kcond;
/* this will probably not need to be altered,
 * as libk sports a modest number of modules,
 * and there are few enough error conditions
 * in each  that 16-bit address space should
 * be more  than enough for the  foreseeable
 * future. however if that changes, altering
 * the  definition here will effect all  the
 * necessary changes throughout the library */
bool kokay(kcond);

typedef struct kerror {
	const char* module_name,
	          * module_desc,
			  * error_string;
	kcond cond;
} kerror;






















kerror kexplain(kcond);

#ifdef __cplusplus
}
#endif

#endif


|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<







 







>
>







 







<
<
<
<
<
<
<
<
<
<
<






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








1
2
3
4
5
6
7
8
9
10
11
12
13
14









15
16
17
18
19
20
21
..
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
139
140
141
142
143
144
145











146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#ifndef KIcore
#define KIcore

#include <k/type.h>

typedef u16 kcond;
/* this will probably not need to be altered,
 * as libk sports a modest number of modules,
 * and there are few enough error conditions
 * in each  that 16-bit address space should
 * be more  than enough for the  foreseeable
 * future. however if that changes, altering
 * the  definition here will effect all  the
 * necessary changes throughout the library */










/* i'm really sorry okay */
typedef
#if (__STDC_VERSION__ >= 199901L)
	_Bool bool;
#endif
enum
................................................................................
	false = 0, no  = 0,
	true  = 1, yes = 1
}
#if !(__STDC_VERSION__ >= 199901L)
	bool /* } bool ; */
#endif
;

bool kokay(kcond);

#ifndef KFclean
#	include <k/internal.egroup.h>
#	define Kokay(cond) (((cond) % kglobal_module_offset) == 0)
#	if (__STDC_VERSION__ >= 199901L) ||\
	   (__cplusplus      >= 201103L)
#		define KVvm_args __VA_ARGS__
................................................................................
	[[noreturn]] void kstop(stat_long code);
#elif __STDC_VERSION__ >= 201103L
	_Noreturn void kstop(stat_long code);
#else
	void kstop(stat_long code);
#endif












typedef struct kerror {
	const char* module_name,
	          * module_desc,
			  * error_string;
	kcond cond;
} kerror;

#include <k/io.h>
#include <k/str.h>
#include <k/internal.egroup.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct kvar {
	ksraw name;
	ksraw val;
	char* platform;
} kvar;

typedef struct kenv {
	kiochan std;
	kiochan err;
	sz argc; const char** args;
	sz varc; kvar* vars;
} kenv;

kerror kexplain(kcond);

#ifdef __cplusplus
}
#endif

#endif

Modified mod/kio/io.h.m from [34396da060] to [03256457ff].

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
72
73
74
75
76
77
78


79
80
81
82
83
84
85
86
87
88
89
90
91
 * ~ lexi hale <lexi@hale.su>
 * this header declares IO primitive functions and
 * structures. it is the same for all platforms.
 * platform-specific code is found in the *.platform.h
 * files.
 */

#include <k/str.h>
#include <k/type.h>
#include <k/mem.h>

#ifdef __cplusplus
extern "C" {
#endif

................................................................................
	kiocond_fail_no_space,
	kiocond_fail_forbidden,
	kiocond_fail_over_quota,
	kiocond_fail_pfault,
	kiocond_fail_too_big,
	kiocond_fail_stream_mismatch,
} kiocond;



kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel
kiocond kiosendall(kiochan, ksraw); // keep sending data to a channel until it's all sent
kiocond kiorecv(kiochan, ksraw*); // receive data from a channel
kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel
  // kmkind is only used if kmcell* is null
kiocond kiocon(kiochan, kiochan); // connect one channel to another

#ifdef __cplusplus
}
#endif

#endif







<







 







>
>













4
5
6
7
8
9
10

11
12
13
14
15
16
17
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 * ~ lexi hale <lexi@hale.su>
 * this header declares IO primitive functions and
 * structures. it is the same for all platforms.
 * platform-specific code is found in the *.platform.h
 * files.
 */


#include <k/type.h>
#include <k/mem.h>

#ifdef __cplusplus
extern "C" {
#endif

................................................................................
	kiocond_fail_no_space,
	kiocond_fail_forbidden,
	kiocond_fail_over_quota,
	kiocond_fail_pfault,
	kiocond_fail_too_big,
	kiocond_fail_stream_mismatch,
} kiocond;

#include <k/str.h>

kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel
kiocond kiosendall(kiochan, ksraw); // keep sending data to a channel until it's all sent
kiocond kiorecv(kiochan, ksraw*); // receive data from a channel
kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel
  // kmkind is only used if kmcell* is null
kiocond kiocon(kiochan, kiochan); // connect one channel to another

#ifdef __cplusplus
}
#endif

#endif

Added mod/kstr/bufflush.fn.c version [45cb80b779].





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
#include <k/type.h>
#include <k/str.h>
#include <k/io.h>

kiocond
ksbufflush(ksbuf* b) {
	ksraw str = {b -> cur - b -> buf, b -> buf};
	b -> cur = b -> buf;
	return kiosend(b -> channel, str, null);
}

Added mod/kstr/bufmk.fn.c version [25e9d731b6].























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
#include <k/type.h>
#include <k/str.h>

ksbuf*
ksbufmk (void* where, kiochan channel, sz run) {
	ksbuf* r = where;
	r -> cur = r -> buf;
	r -> channel = channel;
	r -> run = run;
	return r;
}

Added mod/kstr/bufput.fn.c version [32dbad6423].





























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <k/type.h>
#include <k/io.h>
#include <k/str.h>

kcond
ksbufput(ksbuf* b, ksraw src) {
	ksmut dest = { b->run - (b->cur - b->buf), b->cur };
	/* there are a number of scenarios we need to account for:
	 *
	 * - the ksraw has an unknown size. in this case, we
	 *   determine the size with kssz and proceed according to
	 *   the following rules. we could also count the string
	 *   as we copy, taking advantage of kscp's behavior on
	 *   strings of unknown length, but this would drastically
	 *   complicate the code for an almost certainly negligible
	 *   gain in performance.
	 *
	 * - the ksraw has a known size that is shorter than the
	 *   remaining space in the buffer. in this case, we copy
	 *   it into the buffer and return the result of the copy.
	 *
	 * - the ksraw has a known size that is the same as the
	 *   remaining space in the buffer. in this case, we copy
	 *   it into the buffer and flush the buffer immediately.
	 *
	 * - the ksraw has a known size that is longer than the
	 *   remaining space in the buffer. in this case, we flush
	 *   the buffer immediately and then copy in the new string.
	 *
	 * - the ksraw has a known size that is greater than or
	 *   equal to the buffer's run. in this case, we flush the
	 *   buffer and print the ksraw directly, bypassing the
	 *   buffer as it would only be a performance impediment.
	 */

	if (src.size == 0) src.size = kssz(src.ptr, -1);

	if (src.size < dest.size) {
		kcond c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return kscond_ok;
	} else if (src.size == dest.size) {
		kcond c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return ksbufflush(b);
	} else if (src.size > b -> run) {
		kcond c = ksbufflush(b);
		if (!kokay(c)) return c;
		return kiosend(b -> channel, src, null);
	} else if (src.size > dest.size) {
		kcond c = ksbufflush(b);
		if (!kokay(c)) return c;
		dest.size = b -> run;
		dest.ptr = b -> cur;
		c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return kscond_ok;
	} else return kscond_fail; /* what in the sam heck */
}

Added mod/kstr/kssz.fn.c version [a254af4df5].

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
#include <k/type.h>
#include <k/str.h>

sz kssz(const char* str, sz max) {
	const char* end;
	for (end = str; *end!=0; ++end);
	return end - str;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53












54
55
56
57
58
59
60
61
..
65
66
67
68
69
70
71
72
73
74
75
# kstr

**kstr** is the libk string library. it uses the **short** naming convention with the glyph `s`. **kstr** implies `#include <k/mem.h>`.

## types

### struct kstr
`struct kstr` is a structure for holding pascal strings (length-prefixed strings). it is the basic libk string type. **note:** if `ptr.ref` ≠ NULL and `sz` = 0, the string's length is unknown and should be calculated by any function that operates on a kstr, storing the result in the object if possible.
 * `sz size` - length of string, excluding any null terminator
 * `kmptr ptr` - pointer to string in memory

### struct ksraw
`struct ksraw` is like `kstr` except it uses raw `char` pointers instead of a `kmptr`.
 * `sz size` - length of string, excluding any null terminator
 * `char* ptr` - pointer to string in memory

### struct ksbuf
`struct ksbuf` is a structure used to hold buffers.
 * `sz size` - maximum size of buffer, including any null terminator


 * `char* buf` - region of memory to store buffer in
 * `ksalloc strat` - allocation strategy
 * `kmkind rule` - kind of allocator to use. only needs to be set if `where` is NULL. see [kmem](../kmem/kmem.md).
 * `kmcell* where` - where to allocate the object, in case of pool or tree allocation.

### struct kschain
`struct kschain` is a structure used for string accumulators that works by aggregating pointers to strings, instead of copying the strings themselves.
 * `kschain_kind kind` - kind of chain
 * `kmkind rule` - kind of allocation to use if `kind` ≠ `kschain_kind_linked`
 * `pstr* ptrs` - pointer to pointer list
 * `sz ptrc` - number of pointers
 * `sz size` - total amount of space in `ptrs`

#### enum kschain_kind
 * `kschain_kind_block` - occupies a single block of memory
 * `kschain_kind_linked` - uses a linked list, allocated and deallocated as necessary

### enum ksalloc
`enum ksalloc` is an enumerator that tells libk what strategy to use when filling a `ksbuf` or `kschain` struct.
 * `ksalloc_static` - do not allocate memory, fill an already-allocated, statically-sized array.
 * `ksalloc_alloc` - allocate a string in memory using the specified kind of allocator.
 * `ksalloc_dynamic` - fill an already-allocated array if possible, allocate a string in memory if the string length exceeds available space.

## functions

### kssz
`size_t kssz(char* str, size_t max)` returns the number of characters in a C string, **including** the final null. will count at most `max` characters if `max` > 0.

### kstr
`kstr kstr(char* str, size_t max)` takes a C string and returns a P-string, calculating the length of `str` and storing it in the return value. `max` works as in `kssz`.

### kstoraw
`ksraw ksref(kstr)` is a simple convenience function that returns the `ksraw` form of a `kstr`.













### kscomp
`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`.

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.

	char mem[512];
	kmptr text = <...>;
	char* src = <...>;
................................................................................
			ksref(text),
		Kstr("</a>")
	};
	char* html = kscomp(Kmsz(chain), chain, &buf);

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.

### macros
if `KFclean` is not set when <k/str.h> is included, the following macros are defined.

 * `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.




|

|




|




|
|
|
>
>
|
<
<
<

|







|



|
|




|

|


|


|


>
>
>
>
>
>
>
>
>
>
>
>
|







 







|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
76
77
78
79
80
81
82
83
84
85
86
# kstr

**kstr** is the libk string library. it uses the **short** naming convention with the glyph `s`. **kstr** implies `#include <k/mem.h>`.

# types

## struct kstr
`struct kstr` is a structure for holding pascal strings (length-prefixed strings). it is the basic libk string type. **note:** if `ptr.ref` ≠ NULL and `sz` = 0, the string's length is unknown and should be calculated by any function that operates on a kstr, storing the result in the object if possible.
 * `sz size` - length of string, excluding any null terminator
 * `kmptr ptr` - pointer to string in memory

## struct ksraw
`struct ksraw` is like `kstr` except it uses raw `char` pointers instead of a `kmptr`.
 * `sz size` - length of string, excluding any null terminator
 * `char* ptr` - pointer to string in memory

## struct ksbuf
`struct ksbuf` is a structure used for buffered IO.
 * `sz run` - maximum size of buffer, including any null terminator
 * `kiochan channel` - the channel that output will be written to when flushed
 * `char* cur` - a pointer that tracks the length of the buffer
 * `char buf []` - region of memory to store buffer in




## struct kschain
`struct kschain` is a structure used for string accumulators that works by aggregating pointers to strings, instead of copying the strings themselves.
 * `kschain_kind kind` - kind of chain
 * `kmkind rule` - kind of allocation to use if `kind` ≠ `kschain_kind_linked`
 * `pstr* ptrs` - pointer to pointer list
 * `sz ptrc` - number of pointers
 * `sz size` - total amount of space in `ptrs`

### enum kschain_kind
 * `kschain_kind_block` - occupies a single block of memory
 * `kschain_kind_linked` - uses a linked list, allocated and deallocated as necessary

## enum ksalloc
`enum ksalloc` is an enumerator that tells libk what strategy to use when filling a `kschain` struct.
 * `ksalloc_static` - do not allocate memory, fill an already-allocated, statically-sized array.
 * `ksalloc_alloc` - allocate a string in memory using the specified kind of allocator.
 * `ksalloc_dynamic` - fill an already-allocated array if possible, allocate a string in memory if the string length exceeds available space.

# functions

## kssz
`size_t kssz(char* str, size_t max)` returns the number of characters in a C string, **including** the final null. will count at most `max` characters if `max` > 0.

## kstr
`kstr kstr(char* str, size_t max)` takes a C string and returns a P-string, calculating the length of `str` and storing it in the return value. `max` works as in `kssz`.

## kstoraw
`ksraw ksref(kstr)` is a simple convenience function that returns the `ksraw` form of a `kstr`.

## kscp
`kscond kscp(ksraw src, ksmut dest, sz* len)` copies the string pointed to by `src` into `dest`. its behavior varies depending on the value of `src.size` — if the size is already known, attempts to copy a longer string on top of a shorter one will immediately fail with no changes made to either string. if the size is set to zero, `kscp()` will copy as many bytes as it can before it hits either a NUL terminator in the source string or reaches the end of the destination string. if `dest.src` is zero, kscp simply copies until it hits the first NUL, or reaches `src.ptr[src.size - 1]`. for safety reasons, kscp always terminates `dest` with a NUL when it has enough space to, even if neither string ended with a NUL. if a partial copy occurs, `kscp` will return a `kscond` of `kscond_partial`.

## ksbufmk
`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.

## ksbufput
`kcond ksbufput(ksbuf* b, ksraw str)` copies a string into a buffer with `kscp`. flushing it as necessary.

# ksbufflush
`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.

## kscomp
`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`.

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.

	char mem[512];
	kmptr text = <...>;
	char* src = <...>;
................................................................................
			ksref(text),
		Kstr("</a>")
	};
	char* html = kscomp(Kmsz(chain), chain, &buf);

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.

## macros
if `KFclean` is not set when <k/str.h> is included, the following macros are defined.

 * `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.

Modified mod/kstr/str.h from [43535adcf4] to [18dd12a221].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23











24
25
26
27

28
29
30
31
32
33
34
..
44
45
46
47
48
49
50










51
52
53
54
55
56
57
58
59








60
61
62
63
64
65
#ifndef KIstr
#define KIstr

#include <k/mem.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct kstr {
	sz size;
	kmptr ptr;
} kstr;

typedef struct ksraw {
	sz size;
	const char* ptr;
} ksraw;

typedef struct ksmut {
	sz size;
	char* ptr;
} ksmut;












#include <k/internal.egroup.h>
typedef enum kscond {
	kscond_ok = kscond_id,

	kscond_fail,
	kscond_unimplemented,
	kscond_nonnumeric,
	kscond_no_room,
	kscond_null,
} kscond;

................................................................................

	ksconv_partial = 1 <<  7,
	ksconv_nopfx   = 1 <<  8,
	ksconv_endh    = 1 <<  9,
	ksconv_endl    = 1 << 10,
};











kscond ks_to_int(ksraw str,
		enum ksconv mode,
		u8* dest, sz size);

kscond ks_of_int(u8* number, sz size,
		enum ksconv mode,
		char* bufstart, sz bufsize);

kscond kscp(ksraw str, ksmut dest, sz* len);









#ifdef __cplusplus
}
#endif

#endif



|





<
<
<
<
<









>
>
>
>
>
>
>
>
>
>
>




>







 







>
>
>
>
>
>
>
>
>
>









>
>
>
>
>
>
>
>






1
2
3
4
5
6
7
8
9





10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#ifndef KIstr
#define KIstr

#include <k/type.h>

#ifdef __cplusplus
extern "C" {
#endif






typedef struct ksraw {
	sz size;
	const char* ptr;
} ksraw;

typedef struct ksmut {
	sz size;
	char* ptr;
} ksmut;

sz kssz(const char* str, sz max);

#include <k/mem.h>

typedef struct kstr {
	sz size;
	kmptr ptr;
} kstr;

#include <k/io.h>

#include <k/internal.egroup.h>
typedef enum kscond {
	kscond_ok = kscond_id,
	kscond_partial,
	kscond_fail,
	kscond_unimplemented,
	kscond_nonnumeric,
	kscond_no_room,
	kscond_null,
} kscond;

................................................................................

	ksconv_partial = 1 <<  7,
	ksconv_nopfx   = 1 <<  8,
	ksconv_endh    = 1 <<  9,
	ksconv_endl    = 1 << 10,
};


typedef struct ksbuf {
	sz run;
	kiochan channel;
	char* cur;
	char buf [];
} ksbuf;

/* functions */

kscond ks_to_int(ksraw str,
		enum ksconv mode,
		u8* dest, sz size);

kscond ks_of_int(u8* number, sz size,
		enum ksconv mode,
		char* bufstart, sz bufsize);

kscond kscp(ksraw str, ksmut dest, sz* len);

ksbuf* ksbufmk(void* where, kiochan channel, sz run);

#include <k/core.h>

kcond ksbufput(ksbuf*, ksraw);

kiocond ksbufflush(ksbuf*);

#ifdef __cplusplus
}
#endif

#endif