libk  Check-in [6479e060a3]

Overview
Comment:major update. fix ridiculous old type size determination mechanism. mmap is still broken and i'm not sure why; the syscall does not appear to be going through correctly - see posix_mmap, kmheapa, and kcore/testbin.exe.fn
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6479e060a3558bd8c304bd0018448ebcad1ef74984ee467f972978f7aebb9a7a
User & Date: lexi on 2019-07-26 09:51:02
Other Links: manifest | tags
Context
2019-07-26
10:52
update kcore docs, fix bad type names and dumb logic check-in: 175dc46a91 user: lexi tags: trunk
09:51
major update. fix ridiculous old type size determination mechanism. mmap is still broken and i'm not sure why; the syscall does not appear to be going through correctly - see posix_mmap, kmheapa, and kcore/testbin.exe.fn check-in: 6479e060a3 user: lexi tags: trunk
2019-06-29
09:31
add a bunch of code, port the header mechanism to gpp; add a fuckton of definitions and compatibility header code; notably, add core function kstop and x86.lin.{32,64} impl. update docs accordingly check-in: e794c5edef user: lexi tags: trunk
Changes

Modified arch/makefile from [622e8ca4bc] to [3adea95421].

3
4
5
6
7
8
9





${TMP}/calls.x86.lin.32.s: ${lin-headers}/unistd_32.h ${TMP}
	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
${TMP}/calls.x86.lin.64.s: ${lin-headers}/unistd_64.h ${TMP}
	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
${TMP}/calls.x86.fbsd.%.s: ${fbsd-headers}/syscall.h ${TMP}
	grep "#define	SYS_" $< | sed 's;^#define	SYS_;%define sys.;' > $@











>
>
>
>
3
4
5
6
7
8
9
10
11
12
13

${TMP}/calls.x86.lin.32.s: ${lin-headers}/unistd_32.h ${TMP}
	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
${TMP}/calls.x86.lin.64.s: ${lin-headers}/unistd_64.h ${TMP}
	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
${TMP}/calls.x86.fbsd.%.s: ${fbsd-headers}/syscall.h ${TMP}
	grep "#define	SYS_" $< | sed 's;^#define	SYS_;%define sys.;' > $@
${TMP}/typesize: typesize.c
	$(CC) -std=c11 $< -o $@
${TMP}/typesize.def: ${TMP}/typesize
	$< > $@

Added arch/typesize.c version [9ee84449d7].

















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#include <stdio.h>
#include <limits.h>
#include <stddef.h>

#define sflag(flag,val) printf("-D"#flag"=\"%s\" ", val)
#define mflag(flag,val) printf("-D"#flag"=-%llu ", val + 1)
#define iflag(flag,val) printf("-D"#flag"=%llu ", val)
#define fflag(flag,val) printf("-D"#flag"=%Lf ", val)
#define type_found(val) (found_type & (val / 8))
#define checkbits(type,x) \
	if(!type_found(x) && sizeof(type) == (x/CHAR_BIT)) \
		sflag(type_bit##x, #type), found_type |= (x / 8)

#define describe_integral(type,label) { \
	unsigned type maxval = -1; \
	unsigned type smaxval = (maxval/2) - 1; \
	iflag(type_max_u_##label, maxval); \
	iflag(type_max_s_##label, smaxval); \
	mflag(type_min_s_##label, smaxval); \
	iflag(type_##label##_bits, (CHAR_BIT * sizeof(type))); \
	checkbits(type, 8); else checkbits(type,16); else \
	checkbits(type,32); else checkbits(type,64); else \
	checkbits(type,128); else \
	if (!found_sz && sizeof(type) == sizeof(size_t)) \
		found_sz = 1, sflag(type_sz, "unsigned " #type); \
	if (!found_ofs && sizeof(type) == sizeof(ptrdiff_t)) \
		found_ofs = 1, sflag(type_offset, "signed " #type); \
}

int main() {
	int found_sz = 0, found_ofs = 0, found_type = 0;
	iflag(byte_bits,CHAR_BIT);
	describe_integral(char,char);
	describe_integral(short,short);
	describe_integral(int,int);
	describe_integral(long,long);
	describe_integral(long long,llong);
	printf("\n");
	return 0;
}

Added kconf/kconf.md version [b260f2842a].

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# kconf

while there are a number of existing configuration parser libraries out there, they all have their problems, and all depend on libc. since configuration string parsing is a fairly core functionality that would force many programs to either write their own code or drag libc back into their dependencies, supplying a basic parser with libk makes sense.

## basic principles

kconf is intended to be fast, lightweight, transparent, and low-overhead.

to initialize a kconf structure, we begin by supplying a list of *atoms.* like in Xlib, an atom is a performant way to reference a known string of text from a compiled program. we can do this in two different ways, either by generating the values ourselves at compile time with an enum, or by generating them at runtime using the appropriate kconf interface. note that if you supply your own with an enum, because zero is used for in-band error signalling, the first atom should always be an error token. alternately, it may be explicitly set to a non-zero number and a return value of zero can be checked for implicitly or against a literal 0.

note that, in a recurring libk pattern, if an element count of zero (or `null`) is passed to a function that takes an array of nullables, that function will treat its array argument as a null-terminated array to be counted at runtime.

kconf is initialized by filling out the struct `kconf` with the parameters of operations and then passing it to the appropriate function.

    enum atoms { parse_error, user, pw, email, atomct };
    kconf kc = {
    	.decl = { atomct, {
    		{ user,  {4, "user"    } },
    		{ pw,    {8, "password"} },
    		{ email, {5, "email"   } }
    	}}
    };

	/* with runtime counts:
     * enum atoms { parse_error, user, pw, email };
     * kconf kc = {
     * 	.decl = { null, {
     * 		{ user,  {0, "user"    } },
     * 		{ pw,    {0, "password"} },
     * 		{ email, {0, "email"   } },
	 *		{ null }
     * 	}}
     * }; */

	/* with macros:
     * enum atoms { parse_error, user, password, email };
     * kconf kc = {
     * 	.decl = {Kmpsa(kconf_decl, {
	 * 		Kconf_atom(user),
	 * 		Kconf_atom(password),
	 * 		Kconf_atom(email)
	 * 	})};
	 * }; */

## types

### struct kconf
	* `union { kconf_decl decl; kconf_gen gen; };`

### struct kconf_atom

 * `sz key`
 * `ksraw string`

### struct kconf_pair

 * `kconf_atom atom`
 * `ksraw* dest`


## macros

 * `Kconf_atom(atom)` - a convenience macro for definining an pre-defined atom structure (`kconf_atom`), under the assumption that the C enumerator name is the same as the string used to name the field in the configuration file. inserts the text `{atom, {sizeof(#atom), #atom}}`
 * `Kconf_atom_pfx(pfx,atom)` - a convenience macro for definining an pre-defined atom structure (`kconf_atom`), under the assumption that the C enumerator name is the string used to name the field in the configuration file with a prefix attached. inserts the text `{pfx##atom, {sizeof(#atom), #atom}}`

Added kconf/makefile version [f0df06fe05].



>
1
include ../modmake

Modified kcore/core.h from [ded1289884] to [46cfa15699].

85
86
87
88
89
90
91






92
93
94
95
96
97
98
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#		define KVstd c++
#		if (__cplusplus >= 201103L)
#			define KFstd_cpp11
#			define KVstd c++11
#		endif /* TODO: add more */
#	endif
#endif







/* hooo boy. null. that one's got a storied
 * history across the versions and dialects.
 * below, we try to find the ideal way to
 * offer a "null" "keyword" depending on
 * dialect, version, and whether the user
 * has asked for macros to be suspended.
................................................................................
#	define noreturn [[ noreturn ]]
#elif __STDC_VERSION__ >= 201103L
#	define noreturn _Noreturn
#else
#	define noreturn
#endif

noreturn void kstop(longstat code);

#ifdef KFclean
#	undef noreturn
#endif

#endif







>
>
>
>
>
>







 







|






85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#		define KVstd c++
#		if (__cplusplus >= 201103L)
#			define KFstd_cpp11
#			define KVstd c++11
#		endif /* TODO: add more */
#	endif
#endif

#ifdef KFstd_c11
#	define Kassert _Static_assert
#else
#	define Kassert(x) { struct { int assertion_failed[(x) ? 1 : -1] }; }
#endif

/* hooo boy. null. that one's got a storied
 * history across the versions and dialects.
 * below, we try to find the ideal way to
 * offer a "null" "keyword" depending on
 * dialect, version, and whether the user
 * has asked for macros to be suspended.
................................................................................
#	define noreturn [[ noreturn ]]
#elif __STDC_VERSION__ >= 201103L
#	define noreturn _Noreturn
#else
#	define noreturn
#endif

noreturn void kstop(stat_long code);

#ifdef KFclean
#	undef noreturn
#endif

#endif

Modified kcore/def.h.m from [9abe158651] to [9c53671363].

1
2
3
4
5
6


7
8
9
10
11
12
13
..
26
27
28
29
30
31
32


--- kcore/def.h.m → <k/def.h>
--- ~ lexi hale <lexi@hale.su>
--- this file gathers information on the environment it's
--- being compiled in, setting macros that other headers
--- need. it will be emitted as <k/def.h>.
--- vim: ft=c



[ifdef atom_target_bits]
	[define target: [atom_target_arch].[atom_target_os].[atom_target_bits]]
	#define KVbits [atom_target_bits]
[else]
	[define target: [atom_target_arch].[atom_target_os]]
[endif]
................................................................................
#define Kpragma(p) _Pragma(#p)
#if defined(__GNUC__) || defined(__clang__)
#   define Kerror(msg) Kpragma(GCC error #msg) 
#else
#   define Kerror(msg) Kpragma(message #msg)
#endif
#define Knoimpl(fn) Kerror(no implementation of fn for platform [target])








>
>







 







>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
28
29
30
31
32
33
34
35
36
--- kcore/def.h.m → <k/def.h>
--- ~ lexi hale <lexi@hale.su>
--- this file gathers information on the environment it's
--- being compiled in, setting macros that other headers
--- need. it will be emitted as <k/def.h>.
--- vim: ft=c
#ifndef KIdef
#define KIdef

[ifdef atom_target_bits]
	[define target: [atom_target_arch].[atom_target_os].[atom_target_bits]]
	#define KVbits [atom_target_bits]
[else]
	[define target: [atom_target_arch].[atom_target_os]]
[endif]
................................................................................
#define Kpragma(p) _Pragma(#p)
#if defined(__GNUC__) || defined(__clang__)
#   define Kerror(msg) Kpragma(GCC error #msg) 
#else
#   define Kerror(msg) Kpragma(message #msg)
#endif
#define Knoimpl(fn) Kerror(no implementation of fn for platform [target])

#endif

Modified kcore/magic.h from [1f7f63c3e2] to [a7232aabca].

2
3
4
5
6
7
8



9
10
11
12
13
14
15
16




17
18
19
20
21
22
23
..
61
62
63
64
65
66
67


 * ~ lexi hale <lexi@hale.su>
 * one of libk's biggest goals is standardization across
 * software. for this reason, we define here a variety
 * of "magical numbers" used to signal or describe
 * various states, messages, and errors. suggestions are
 * welcome.
 */



#include <k/type.h>

typedef enum kbad {
	// values to be returned by an entry function
	kbad_ok = 0,
		/* the requested operation completed
		 * successfully */





	/* these are synchronized with freebsd's existing
	 * sysexit.h conventions. */
	kbad_usage = 64,
		/* # fbsd EX_USAGE
		 * a usage screen was displayed to the user
		 * on request or due to improperly formed call */
	kbad_data = 65,
................................................................................
		/* # fbsd EX_NOPERM
		 * you or the program do not have permissions
		 * to do the thing requested */
	kbad_conf = 78,
		/* # fbsd EX_CONFIG
		 * your configuration is fucked */
} kbad;









>
>
>








>
>
>
>







 







>
>
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
..
68
69
70
71
72
73
74
75
76
 * ~ lexi hale <lexi@hale.su>
 * one of libk's biggest goals is standardization across
 * software. for this reason, we define here a variety
 * of "magical numbers" used to signal or describe
 * various states, messages, and errors. suggestions are
 * welcome.
 */
#ifndef KImagic
#define KImagic

#include <k/type.h>

typedef enum kbad {
	// values to be returned by an entry function
	kbad_ok = 0,
		/* the requested operation completed
		 * successfully */

	kbad_mem = 1,
		/* the system does not have enough free
		 * memory to complete the requested operation */

	/* these are synchronized with freebsd's existing
	 * sysexit.h conventions. */
	kbad_usage = 64,
		/* # fbsd EX_USAGE
		 * a usage screen was displayed to the user
		 * on request or due to improperly formed call */
	kbad_data = 65,
................................................................................
		/* # fbsd EX_NOPERM
		 * you or the program do not have permissions
		 * to do the thing requested */
	kbad_conf = 78,
		/* # fbsd EX_CONFIG
		 * your configuration is fucked */
} kbad;

#endif

Modified kcore/makefile from [c01fcd380e] to [f9fefae3d1].

3
4
5
6
7
8
9



10
11
12
13
14
15
16
# for stddef.h, and that can't be written in portable C.
# so we're generating it at build time.

# gen-headers = type.h

include ../modmake




## the below code predates the introduction of gpp
## to generate these headers from templates instead
## of trying to write one for everypossible arch 
## tuple. it is left as a monument to a terrible
## and now blissfully forgotten past.
#
# look, imma just be straight with you. the mechanism we're







>
>
>







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# for stddef.h, and that can't be written in portable C.
# so we're generating it at build time.

# gen-headers = type.h

include ../modmake

${OUT}/k/type.h: type.h.m ${TMP}/typesize.def
	$(m-comp) $< $(file < ${TMP}/typesize.def) > $@

## the below code predates the introduction of gpp
## to generate these headers from templates instead
## of trying to write one for everypossible arch 
## tuple. it is left as a monument to a terrible
## and now blissfully forgotten past.
#
# look, imma just be straight with you. the mechanism we're

Modified kcore/stop.fn.c from [c4373dead4] to [5c15d4cc49].

5
6
7
8
9
10
11
12
13
14
15
16
17

#include <k/core.h>
#include <k/def.h> // so we know what system this is
#include <k/type.h>

#ifdef KFenv_posix
#	define STOPFN kio_posix_exit
	extern void STOPFN(int);
#else
	Knoimpl(kstop)
#endif

noreturn void kstop (longstat code) { STOPFN(code); }







|




|
5
6
7
8
9
10
11
12
13
14
15
16
17

#include <k/core.h>
#include <k/def.h> // so we know what system this is
#include <k/type.h>

#ifdef KFenv_posix
#	define STOPFN kio_posix_exit
	extern noreturn void STOPFN(int);
#else
	Knoimpl(kstop)
#endif

noreturn void kstop (stat_long code) { STOPFN(code); }

Modified kcore/testbin.exe.c from [f1bdb07ea2] to [5796abefa5].

1
2
3
4






5
6
7
8
9
10
11
12
13
14
15
16
17
18







#include <k/core.h>
#include <k/mem.h>
#include <k/io.h>
#include <k/magic.h>







kbad entry(kenv e) {
	const char msg[] = "hello from libk\n";
	ksraw ptr = { Kmsz(msg), msg };

	bool maybe = true;
	maybe = no;

	if (kiosend(e.std, ptr, null) == kiocond_ok) {
		return kbad_ok;
	} else {
		return kbad_io;
	}
}











>
>
>
>
>
>









|



|
>
>
>
>
>
>
>
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
#include <k/core.h>
#include <k/mem.h>
#include <k/io.h>
#include <k/magic.h>

struct object {
	u8 a;
	s16 b;
	bool c;
};

kbad entry(kenv e) {
	const char msg[] = "hello from libk\n";
	ksraw ptr = { Kmsz(msg), msg };

	bool maybe = true;
	maybe = no;

	if (kiosend(e.std, ptr, null) == kiocond_ok) {
		/* great, continue */
	} else {
		return kbad_io;
	}

	struct object* block = kmheapa(sizeof (struct object) * 4);
	if (block == null) return kbad_mem; else return kbad_ok;
	
	block[1].a = 5;

	return kbad_ok;
}

Modified kcore/type.h.m from [8b1f2e0cb2] to [a9978dfd3a].

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


--- kcore/type.h.m → <k/def.h>
--- ~ lexi hale <lexi@hale.su>
--- this file gathers information on the environment it's
--- being compiled in, defining types that our code
--- needs. it will be emitted as <k/type.h>.
--- vim: ft=c



// arch bit length [atom_target_bits]
--- make some gigantic fucking assumptions
[if [atom_target_bits] >= 8]
    typedef unsigned char  u8;
    typedef signed char    s8;
    [if [atom_target_bits] >= 16]
        typedef unsigned short u16;


        typedef signed short   s16;
        [if [atom_target_bits] >= 32]
            typedef unsigned long  u32;

            typedef signed long    s32;
            [if [atom_target_bits] >= 64]
                typedef unsigned long long u64;
                typedef signed long long s64;
                [if [atom_target_arch] == x86]

                    #if defined(__GNUC__) || defined(__clang__)
                        typedef __uint128_t u128;
                        typedef __int128_t  s128;



                    #endif







                [endif]











            [endif]
        [endif]






    [endif]




[endif]

typedef u[atom_target_bits]  sz;
typedef s[atom_target_bits] ssz;










--- make sure something unlikely doesn't happen

[define [maxtype name, n]:
	[if [n] > [atom_target_bits]]
		typedef u[atom_target_bits] [name]





















	[else]











		typedef u[n] [name]


	[endif]]




















// exit status integer types - pls use kbad in <k/magic.h> instead
[if [target_posix] == yes]
	/* by convention, posix return values are 8-bit,
	 * but note that many modern UNIXes do technically
	 * support higher-bit values. for this reason,
	 * longstat is defined differently under posix. */
	typedef u8 stat;
	[maxtype longstat, 32];
[else]
	[if ([atom_target_os] == win) ||
		([atom_target_os] == vms)]
		[maxtype stat, 32]
	[else]
		typedef u8 stat;
		/* we don't know a specific exit status type
		 * for your arch so we're going with a sane
		 * default. if this is wrong, help us fix it! */
	[endif]
	typedef stat longstat;
[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
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
73

74
75


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
--- kcore/type.h.m → <k/type.h>
--- ~ lexi hale <lexi@hale.su>
--- this file gathers information on the environment it's
--- being compiled in, defining types that our code
--- needs. it will be emitted as <k/type.h>.
--- vim: ft=c
#ifndef KItype
#define KItype




typedef unsigned char      kc_uint_min;
typedef   signed char      kc_sint_min;

typedef unsigned long long kc_uint_max;
typedef   signed long long kc_sint_max;

[ifdef type_bit8]

	typedef unsigned [type_bit8] u8;
	typedef   signed [type_bit8] s8;
[else]
	typedef kc_uint_min u8;
	typedef	kc_sint_min s8;
[endif]


[ifdef type_bit16]
	typedef unsigned [type_bit16] u16;
	typedef   signed [type_bit16] s16;
[else]
	typedef kc_uint_max u16;
	typedef	kc_sint_max s16;
[endif]

[ifdef type_bit32]
	typedef unsigned [type_bit32] u32;
	typedef   signed [type_bit32] s32;
[else]
	typedef kc_uint_max u32;
	typedef	kc_sint_max s32;
[endif]

[ifdef type_bit64]
	typedef unsigned [type_bit64] u64;
	typedef   signed [type_bit64] s64;
	[ifndef type_bit128]
#		if defined(__GNUC__) || defined(__clang__)
			typedef unsigned __int128_t u128;
			typedef   signed __int128_t s128;
#		else
			typedef kc_uint_max u128;
			typedef kc_sint_max s128;
#		endif
	[endif]
[else]
	typedef kc_uint_max u64;
	typedef	kc_sint_max s64;

	typedef kc_uint_max u128;
	typedef	kc_sint_max s128;
[endif]

[ifdef type_bit128]
	typedef unsigned [type_bit128] u128;
	typedef   signed [type_bit128] s128;
[endif]



enum /* max-min values of each type */ {
	/* assuming two's complement. TODO: check math */
	/* TODO: figure out how to calc min */
	kc_byte_bits = [byte_bits],
	  u8_min = 0,   u8_max = ((u8)-1),
	 u16_min = 0,  u16_max = ((u16)-1),
	 u32_min = 0,  u32_max = ((u32)-1),
	 u64_min = 0,  u32_max = ((u64)-1),
	u128_min = 0, u128_max = ((u128)-1),


	[define merge: $1$2]
	[define [sspec type]:


		[merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2),
		[merge [type],_max] =      (1 << sizeof([type]) * kc_byte_bits) / 2 - 1]

	[sspec s8], [sspec s16], [sspec s32],
	[sspec s64], [sspec s128],

	kc_min_uchar  = 0, kc_max_uchar  = [type_max_u_char],
	kc_min_ushort = 0, kc_max_ushort = [type_max_u_short],
	kc_min_uint   = 0, kc_max_uint   = [type_max_u_int],
	kc_min_ulong  = 0, kc_max_ulong  = [type_max_u_long],
	kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong],

	kc_min_schar  = [type_min_s_char],  kc_max_schar  = [type_max_s_char],
	kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short],
	kc_min_sint   = [type_min_s_int],   kc_max_sint   = [type_max_s_int],
	kc_min_slong  = [type_min_s_long],  kc_max_slong  = [type_max_s_long],
	kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong],
};

[ifdef type_sz]
	typedef [type_sz] sz;
[else]
#	ifdef __cplusplus
 	   /* C++ gives us a clean, standardized way to do this */
 	   typedef decltype (sizeof(char)) sz;
#	else
#		if defined(__GNUC__) || defined(__clang__)
			typedef __typeof__ (sizeof(char)) sz;
#		else
			/* we're stumped - set sz to the safest possible value under
			 * the circumstances, and warn the user. */
#			warning no authoritative sz (size_t) type definition \
			        available; defaulting to largest unsigned integer type
			typedef kc_uint_max sz;
#		endif
#	endif
[endif]

[ifdef type_offset]
	typedef [type_offset] offset;
[else]
#	ifdef __cplusplus
 	   /* C++ gives us a clean, standardized way to do this */
		typedef decltype (((void*)-1) - 1) offset;
#	else
#		if defined(__GNUC__) || defined(__clang__)
			typedef __typeof__ (((void*)10) - ((void*)5)) offset;
#		else
			/* no dice - set offset to the safest possible value under
			 * the circumstances, and warn the user. */
#			warning no authoritative offset (ptrdiff_t) type definition \
			        available; defaulting to largest unsigned integer type
			typedef kc_sint_max offset;
#		endif
#	endif
[endif]

// exit status integer types - pls use kbad in <k/magic.h> instead
[if [target_posix] == yes]
	/* by convention, posix return values are 8-bit,
	 * but note that many modern UNIXes do technically
	 * support higher-bit values. for this reason,
	 * longstat is defined differently under posix. */
	typedef u8 stat;
	typedef u32 stat_long;
[else]
	[if ([atom_target_os] == win) ||
		([atom_target_os] == vms)]
		typedef u32 stat;
	[else]
		typedef u8 stat;
		/* we don't know a specific exit status type
		 * for your arch so we're going with a sane
		 * default. if this is wrong, help us fix it! */
	[endif]
	typedef stat stat_long;
[endif]

#endif

Added kdb/kdb.md version [1c2867c8a9].





































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# kdb

kdb is a module for storing and loading data from files.

## model

the first argument to all kdb functions is of type `struct kdb`, which describes the database to be accessed. the first field of that struct is a pointer to a struct of type `struct kdb_fmt` which describes the format of the database.

kdb encodes records as a tuple of three fields: (kind, key, value). `kind` is a 16-bit integer, `key` is an integer of platform width, and `value` is a blob decoded according to the type of the record, which is not saved in the database itself. records are indexed by the tuple (kind, key); `key` may be null. `kind` denotes the structure of the record, and is user-defined.

to use strings as the keys for database entries, either atoms should be stored in the database or a hash function may be used. kdb contains procedures to automate the use of atoms as keys.

## types

### struct kdb

 * `struct kdb_fmt* fmt`
 * `enum kdb_conn conn`
 * `union { kfile* file; const kdb_store* mem; kmptr ptr; } store;`

### struct kdb_rec

 * `u16 kind`
 * `word key`
 * `ksraw value`

### enum kdb_conn

 * `kdb_conn_none`: no database is connected; calls will fail
 * `kdb_conn_file`: the database is stored in a file; calls to modify it will modify the file on-disk
 * `kdb_conn_file_static`: the database is stored in a file; calls to modify it will fail. if the file is writable to the process, can be seamlessly changed to `kdb_conn_file` and vice-versa
 * `kdb_conn_mem`: the database is stored in-memory, allocated by kmem and referenced by `ptr`. calls to modify it will re-allocate memory via the appropriate interfaces.
 * `kdb_conn_mem_static`: the database is stored in-memory, referenced by `mem`; calls to modify it will fail

Added kdb/makefile version [f0df06fe05].



>
1
include ../modmake

Modified kio/io.h from [aa4095c969] to [e3d3c3c357].

39
40
41
42
43
44
45
46




47


48
49
50
51
52
53
54
55
56
57
58
	kiostream in;
	  // text can be read from this stream
	kiostream out;
	  // text can be written to this stream
} kiochan;

typedef enum kiocond {
	kiocond_ok,




	  // success


    kiocond_fail,
	  // action failed
} kiocond;

kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel
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

#endif







|
>
>
>
>
|
>
>
|
|









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
	kiostream in;
	  // text can be read from this stream
	kiostream out;
	  // text can be written to this stream
} kiochan;

typedef enum kiocond {
	/* to check if a call failed, perform (x >= kiocond_fail) where x
	 * is that call's return value. more typically however you should
	 * select explicitly against kiocond_ok or kiocond_partial, since
	 * those situations will usually need to be handled differently. */

	kiocond_ok, // success
	kiocond_partial, // partial read or write

    kiocond_fail, // action failed - unspecified reason
	kiocond_fail_closed_stream, // action failed because stream is closed
} kiocond;

kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel
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

#endif

Deleted kio/kio_posix_fd_write.fn.x86.lin.32.s version [7b77d86bab].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bits 32
global kio_posix_fd_write

%include "../arch/x86.lin.32.s"
; vim: ft=nasm

kio_posix_fd_write:
	mov sys.reg.0, sys.call.write
	mov sys.reg.1, [esp + 4] ; holy god but this took the most
	mov sys.reg.2, [esp + 8] ; stupidly long time to fucking
	mov sys.reg.3, [esp + 12]; figure out
	sys.call
	ret

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




























Deleted kio/kio_posix_fd_write.fn.x86.lin.64.s version [b72b3eff18].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bits 64
global kio_posix_fd_write

%include "../arch/x86.lin.64.s"
; vim: ft=nasm

kio_posix_fd_write:
	mov sys.reg.0, sys.write
	; mov sys.reg.1, ccall.reg.0 - nop
	; mov sys.reg.2, ccall.reg.1 - nop
	; mov sys.reg.3, ccall.reg.2 - nop
	sys.call
	ret

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




























Added kio/posix_fd_write.fn.x86.lin.32.s version [7b77d86bab].





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bits 32
global kio_posix_fd_write

%include "../arch/x86.lin.32.s"
; vim: ft=nasm

kio_posix_fd_write:
	mov sys.reg.0, sys.call.write
	mov sys.reg.1, [esp + 4] ; holy god but this took the most
	mov sys.reg.2, [esp + 8] ; stupidly long time to fucking
	mov sys.reg.3, [esp + 12]; figure out
	sys.call
	ret

Added kio/posix_fd_write.fn.x86.lin.64.s version [b72b3eff18].





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bits 64
global kio_posix_fd_write

%include "../arch/x86.lin.64.s"
; vim: ft=nasm

kio_posix_fd_write:
	mov sys.reg.0, sys.write
	; mov sys.reg.1, ccall.reg.0 - nop
	; mov sys.reg.2, ccall.reg.1 - nop
	; mov sys.reg.3, ccall.reg.2 - nop
	sys.call
	ret

Deleted kio/send.c version [d88d1642fe].

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
#include <k/io.h>
#include <k/core.h>
#include <k/def.h>
/* send.c - kiosend()
 * ~ lexi hale <lexi@hale.su>
 * kiosend() writes to a channel with an open out stream
 */

// we define all platform functions here,
// whether or not they're for the correct
// platform - only the ones actually called
// by the generated code will be linked
extern sz kio_posix_fd_write(int fd, const char* buf, sz len);

kiocond kiosend(kiochan target, ksraw string, sz* len) {
#	ifdef KFenv_posix
		sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size);
		if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors
#	else
#		if KVos == win
#			error windows IO send function not yet defined
#		else
			Knoimpl(kiosend,KVos);
#			error missing implementation // boring error for plebs
#		endif
#	endif

	if (len != null) *len = size;
	return kiocond_ok;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Modified kio/send.fn.c from [430158e543] to [5cc5cc2649].

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
#include <k/io.h>
#include <k/core.h>
#include <k/def.h>
/* send.c - kiosend()
 * ~ lexi hale <lexi@hale.su>
 * kiosend() writes to a channel with an open out stream
 */

// we define all platform functions here,
// whether or not they're for the correct
// platform - only the ones actually called
// by the generated code will be linked
extern sz kio_posix_fd_write(int fd, const char* buf, sz len);

kiocond kiosend(kiochan target, ksraw string, sz* len) {


#	ifdef KFenv_posix
		sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size);
		if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors
#	else
#		if KVos == win
#			error windows IO send function not yet defined
#		else
			_Pragma("GCC diagnostic error \"" // fancy error for gcc
				"IO send fn for platform " #KVos " not defined"
			"\""))
#			error IO send fn not defined for platform
			   // boring error for plebs
#		endif
#	endif

	if (len != null) *len = size;
	return kiocond_ok;
}



|




|
|
|
|



>
>







|
<
<
<
|






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
#include <k/io.h>
#include <k/core.h>
#include <k/def.h>
/* send.c - kiosend() "send to channel"
 * ~ lexi hale <lexi@hale.su>
 * kiosend() writes to a channel with an open out stream
 */

/* we define all platform functions here,
 * whether or not they're for the correct
 * platform - only the ones actually called
 * by the generated code will be linked */
extern sz kio_posix_fd_write(int fd, const char* buf, sz len);

kiocond kiosend(kiochan target, ksraw string, sz* len) {
	if (target.out.kind == kiostream_closed) return kiocond_fail_closed_stream;

#	ifdef KFenv_posix
		sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size);
		if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors
#	else
#		if KVos == win
#			error windows IO send function not yet defined
#		else
			Knoimpl(kiosend,KVos);



#			error missing implementation // boring error for plebs
#		endif
#	endif

	if (len != null) *len = size;
	return kiocond_ok;
}

Added kmem/heapa.fn.c version [f32eb209ee].

























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#include <k/core.h>
#include <k/def.h>
/* heapa.c - kmheapa() "heap alloc"
 * ~ lexi hale <lexi@hale.su>
 * kmheapa() allocates a pointer on the heap à la libc malloc()
 * see also: kmheapf() "heap free"
 */

/* we define all platform functions here,
 * whether or not they're for the correct
 * platform - only the ones actually called
 * by the generated code will be linked,
 * linker errors are our friend here! */
extern void* kmem_posix_mmap(void* addr,
		unsigned long sz, unsigned long prot, unsigned long flags,
		unsigned long fd, unsigned long off);

enum posix_prot {
	posix_prot_none  = 0,
	posix_prot_read  = 1 << 0,
	posix_prot_write = 1 << 1,
	posix_prot_exec  = 1 << 2
};

enum posix_map {
	posix_map_shared  = 1,
	posix_map_private = 2
};

enum posix_flag {
	posix_flag_fixed     = 0x10,
	posix_flag_anonymous = 0x20,

	/* platform flags */
	posix_flag_linux_hugetlb = 0x40000
};

void* kmheapa(sz len) {
	/* allocate an object on the heap and return
	 * a pointer, or NULL if the allocation failed. */
	void* val;

#	ifdef KFenv_posix
 	   /* posix APIs - we've got it easy */
		val = kmem_posix_mmap(null, len, posix_prot_read | posix_prot_write,
				posix_flag_anonymous, -1, 0);
		/* impl note: while per manpage fd is "ignored"
		 * for MAP_ANONYMOUS, "some implementations" require
		 * a value of -1 */

		if (val == (void*) -1) return null;
		/* worth retrieving errno? discuss */

#	else
 	   Knoimpl(kmheapa,KVos);
#		error missing implementation
#	endif

	return val;
}

Modified kmem/kmem.md from [9ed4178122] to [18509d6a57].

155
156
157
158
159
160
161



   * `kmtreef(void*) → kmptr` - frees a node and all its children

## macros

kmem defines the following macros.

 * `Kmsz(array)` - a convenience macro to return the number of elements in a static array. inserts the text `( sizeof (array) / sizeof (array) [0] )`










>
>
>
155
156
157
158
159
160
161
162
163
164
   * `kmtreef(void*) → kmptr` - frees a node and all its children

## macros

kmem defines the following macros.

 * `Kmsz(array)` - a convenience macro to return the number of elements in a static array. inserts the text `( sizeof (array) / sizeof (array) [0] )`
 * `Kmszs(type, struct)` - a convenience macro to return the size of a struct. requires compound literals.
 * `Kmszsa(type, array)` - calculates the number of elements in an array of a given struct type. inserts the text `( sizeof ( (type) array ) / sizeof (type) )`
 * `Kmpsa(type, struct)` - a convenience macro to insert a "pascal struct array" - that is, a struct array prefixed with a size value. this is equivalent to `Kmszsa(type, array), array`

Modified kmem/mem.h from [551899b415] to [ace4d63e01].

31
32
33
34
35
36
37





38
typedef struct kmptr {
	kmkind kind;
	kmshred shred;
	void* ref;
	kmcell* cell;
} kmptr;






#endif







>
>
>
>
>

31
32
33
34
35
36
37
38
39
40
41
42
43
typedef struct kmptr {
	kmkind kind;
	kmshred shred;
	void* ref;
	kmcell* cell;
} kmptr;

/* heap functions */

void* kmheapa(sz);
void  kmheapf(void*);

#endif

Added kmem/posix_mmap.fn.x86.lin.64.s version [0ee1179d8c].

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bits 64
%include "../arch/x86.lin.64.s"
%include "../arch/x86.cdecl.64.s"
; vim: ft=nasm

global kmem_posix_mmap
kmem_posix_mmap:
	; to call mmap, we need to translate the cdecl64
	; register arguments to their appropriate syscall64
	; registers. these are mostly the same, with one
	; obnoxious exception. the NOPs have been written
	; in as comments to aid in understanding.

	  mov sys.reg.1, ccall.reg.0 ;nop - rdi → rdi
	  mov sys.reg.2, ccall.reg.1 ;nop - rsi → rsi
	  mov sys.reg.3, ccall.reg.2 ;nop - rdx → rdx
	  mov sys.reg.4, ccall.reg.3 ; OP - rcx → r10
	  mov sys.reg.5, ccall.reg.4 ;nop - r8 → r8
	  mov sys.reg.6, ccall.reg.5 ;nop - r9 → r9

	mov sys.reg.0, sys.mmap
	sys.call

	mov ccall.reg.ret, sys.reg.ret ; rax → rdi

Modified kstr/str.h from [f7e947c0d1] to [69d05c5e37].

6
7
8
9
10
11
12
13
14





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

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





#endif







|

>
>
>
>
>

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
#endif

Modified makefile from [d63468c69f] to [ce9c7792cb].

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114



115
116
117
118
119
120
121

%.tool: %/makefile $(TMP)/precomp.g $(OUT)
	cd $* && $(MAKE) tool

%.dbg: %/makefile $(OUT)
	cd $* && $(MAKE) dbg

%.def: %/makefile $(TMP)/precomp.g $(OUT) $(OUT)/k
	cd $* && $(MAKE) def

%.calls: arch/makefile
	cd arch && $(MAKE) $(TMP)/calls.$*.s

$(TMP)/precomp.g: grammar/precomp.g.gpp $(TMP)
	cd grammar && $(MAKE) $@




$(OUT)/libk.so: $(fnobjects) 
	ld -shared $(COMPLIB) -o $@ $^
	@# $(CC) -shared -fPIC -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o

$(OUT)/boot.o: $(rtobjects)
	ld -r $^ -o $(OUT)/boot.o







|







>
>
>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

%.tool: %/makefile $(TMP)/precomp.g $(OUT)
	cd $* && $(MAKE) tool

%.dbg: %/makefile $(OUT)
	cd $* && $(MAKE) dbg

%.def: %/makefile $(TMP)/precomp.g $(TMP)/typesize.def $(OUT) $(OUT)/k
	cd $* && $(MAKE) def

%.calls: arch/makefile
	cd arch && $(MAKE) $(TMP)/calls.$*.s

$(TMP)/precomp.g: grammar/precomp.g.gpp $(TMP)
	cd grammar && $(MAKE) $@

$(TMP)/typesize.def: arch/makefile $(TMP)
	cd arch && $(MAKE) $@

$(OUT)/libk.so: $(fnobjects) 
	ld -shared $(COMPLIB) -o $@ $^
	@# $(CC) -shared -fPIC -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o

$(OUT)/boot.o: $(rtobjects)
	ld -r $^ -o $(OUT)/boot.o