parsav  Check-in [6f17de4767]

Overview
Comment:more boilerplate, add template framework
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6f17de476745e01bc24c082213de56561e17aaf4b06cec660319e6b1b1acb1f4
User & Date: lexi on 2020-12-14 14:40:34
Other Links: manifest | tags
Context
2020-12-16
08:46
iterating check-in: 59e1d7d56a user: lexi tags: trunk
2020-12-14
14:40
more boilerplate, add template framework check-in: 6f17de4767 user: lexi tags: trunk
2020-12-10
05:28
initial commit check-in: e18c9de34d user: lexi tags: trunk
Changes

Added cmdparse.t version [8abc7a6fc7].































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
return function(tbl)
	local options = terralib.types.newstruct('options') do
		local flags = '' for _,d in pairs(tbl) do flags = flags .. d[1] end
		local helpstr = 'usage: parsav [-' .. flags .. '] [<arg>...]\n'
		options.entries = {
			{field = 'arglist', type = lib.mem.ptr(rawstring)}
		}
		local shortcases, longcases, init = {}, {}, {}
		local self = symbol(&options)
		local arg = symbol(rawstring)
		local skip = label()
		for o,desc in pairs(tbl) do
			options.entries[#options.entries + 1] = {
				field = o, type = bool
			}
			helpstr = helpstr .. string.format('    -%s --%s: %s\n',
				desc[1], o, desc[2])
		end
		for o,desc in pairs(tbl) do
			local flag = desc[1]
			init[#init + 1] = quote [self].[o] = false end
			shortcases[#shortcases + 1] = quote
				case [int8]([string.byte(flag)]) then [self].[o] = true end
			end
			longcases[#longcases + 1] = quote
				if lib.str.cmp([arg]+2, o) == 0 then
					[self].[o] = true
					goto [skip]
				end
			end
		end
		options.methods.parse = terra([self], argc: int, argv: &rawstring)
			[init]
			var parseopts = true
			self.arglist = lib.mem.heapa(rawstring, argc)
			var finalargc = 0
			for i=0,argc do
				var [arg] = argv[i]
				if arg[0] == ('-')[0] and parseopts then
					if arg[1] == ('-')[0] then -- long option
						if arg[2] == 0 then -- last option
							parseopts = false
						else [longcases] end
					else -- short options
						var j = 1
						while arg[j] ~= 0 do
							switch arg[j] do [shortcases] end
							j = j + 1
						end
					end
				else
					self.arglist.ptr[finalargc] = arg
					finalargc = finalargc + 1
				end
				::[skip]::
			end
			if finalargc == 0 then self.arglist:free()
							  else self.arglist:resize(finalargc) end
		end
		options.helptxt = helpstr
	end
	return options
end

Modified common.lua from [9dc63595c4] to [3d397d42e6].

20
21
22
23
24
25
26
27
28

29





30
31
32
33
34

35
36
37
38
39
40
41
42
..
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
	if val then return os.execute(cmd) else
		local fd = io.popen(cmd,'r')
		local t = fd:read('*a')
		return chomp(t), fd:close()
	end
end

local function dump(v,pfx)
	pfx = pfx or ''

	local np = pfx .. '  '





	if type(v) == 'string' then
		return string.format('%q', v)
	elseif type(v) == 'table' then
		local str = ''
		for k,v in pairs(v) do

			str = str .. string.format('%s[%s] = %s\n', np, dump(k,np), dump(v,np))
		end
		return '{\n' .. str .. pfx .. '}\n'
	else
		return string.format('%s', v)
	end
end
local ping = function(path)
................................................................................
	s = ({
		yes = true, ['true'] = true,   on = true,   ['1'] = true;
		no = false, ['false'] = false, off = false, ['0'] = false;
	})[string.lower(s)]
	if not s then return false end
	return true
end










return {
	exec = exec;
	dump = dump;
	ping = ping;
	chomp = chomp;
	map = map;
	tobool = tobool;










	append = function(a,b)
		for _, v in pairs(b) do a[#a+1] = v end
	end;
	has = function(haystack,needle,eq)
		eq = eq or function(a,b) return a == b end
		for k,v in pairs(haystack) do
			if eq(needle,v) then return k end
		end






	end;
	parseargs = function(a)
		local raw = false
		local opts, args = {}, {}
		for i,v in ipairs(a) do
			if v == '--' then
				raw = true 







|

>

>
>
>
>
>





>
|







 







>
>
>
>
>
>
>
>
>
>







>
>
>
>
>
>
>
>
>
>








>
>
>
>
>
>







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
..
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
	if val then return os.execute(cmd) else
		local fd = io.popen(cmd,'r')
		local t = fd:read('*a')
		return chomp(t), fd:close()
	end
end

local function dump(v,pfx,cyc)
	pfx = pfx or ''
	cyc = cyc or {}
	local np = pfx .. '  '

	if type(v) == 'table' then
		if cyc[v] then return '<...>' else cyc[v] = true end
	end

	if type(v) == 'string' then
		return string.format('%q', v)
	elseif type(v) == 'table' then
		local str = ''
		for k,v in pairs(v) do
			local tkey, tval = dump(k,np,cyc), dump(v,np,cyc)
			str = str .. string.format('%s[%s] = %s\n', np, tkey,tval)
		end
		return '{\n' .. str .. pfx .. '}\n'
	else
		return string.format('%s', v)
	end
end
local ping = function(path)
................................................................................
	s = ({
		yes = true, ['true'] = true,   on = true,   ['1'] = true;
		no = false, ['false'] = false, off = false, ['0'] = false;
	})[string.lower(s)]
	if not s then return false end
	return true
end

if ping '/dev/urandom' then
	local r = io.open('/dev/urandom')
	local ent = r:read(8) r:close()
	local seed = 1 for i = 1, 8 do
		seed = seed * string.byte(string.sub(ent,i,i))
	end
	math.randomseed(seed)
else math.randomseed(os.time()) end

return {
	exec = exec;
	dump = dump;
	ping = ping;
	chomp = chomp;
	map = map;
	tobool = tobool;
	rndstr = function(len)
		local s = ''
		for i=1,len do
			local ofs = math.random(0,10 + 26)
			if ofs >= 10 then ofs = 0x60 + (ofs - 10)
						 else ofs = 0x30 + ofs end
			s = s .. string.char(ofs) 
		end
		return s
	end;
	append = function(a,b)
		for _, v in pairs(b) do a[#a+1] = v end
	end;
	has = function(haystack,needle,eq)
		eq = eq or function(a,b) return a == b end
		for k,v in pairs(haystack) do
			if eq(needle,v) then return k end
		end
	end;
	ingest = function(f)
		local h = io.open(f, 'r')
		if h == nil then return nil end
		local txt = f:read('*a') f:close()
		return chomp(txt)
	end;
	parseargs = function(a)
		local raw = false
		local opts, args = {}, {}
		for i,v in ipairs(a) do
			if v == '--' then
				raw = true 

Modified config.lua from [f14c1e8df4] to [85408f7c8a].

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
...
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
local u = dofile('common.lua')
local default = function(var,def)
	local v = os.getenv(var)
	if v then return v else return def end






end
local posixes = {
	linux = true; osx = true;
	android = true; haiku = true;
}

local conf = {
	pkg = {};
	os        = default('parsav_target_os', 'linux');
	dist      = default('parsav_dist', os.getenv('NIX_PATH') and 'nixos');


	tgttrip   = default('parsav_arch_triple'); -- target triple, used in xcomp
	tgtcpu    = default('parsav_arch_cpu'); -- target cpu, used in xcomp
	tgthf     = u.tobool(default('parsav_arch_armhf',true)); 




}











conf.posix = posixes[conf.os]
conf.exe   = u.tobool(default('parsav_link',not conf.tgttrip)); -- turn off for partial builds




























local fallback = dofile('pkgdata.lua')
local libfind do local mkf = function(p)
		return function(l) return string.format(p,l) end
	end
	local unx = function(p)
		return function(l)
			if string.sub(l,1,3) == 'lib'
................................................................................
				then return string.format('%s.%s',l,p)
				else return string.format('lib%s.%s',l,p)
			end
		end
	end

	libfind = {
		linux = {
			static = unx 'a';
			dynamic = unx 'so';
		};
		osx = { dynamic = mkf '%s.dylib'; };
		win = { dynamic = mkf '%s.dll'; };
	}
end
local pkg = function(name)
	local fbo = fallback[name] and fallback[name].osvars
		and fallback[name].osvars[conf.os .. '_' .. conf.dist]


	local fbv = fallback[name] and fallback[name].vars

	local pkgenv = function(e)
		return os.getenv(string.format('parsav_pkg_%s_%s',name,e))
	end
	name = pkgenv('override') or name
	local nul = function() end
	local pkc, pkv = nul, nul

	local cnfvar = function(v,e)
		local eval = function(e)
			if type(e) == 'function'
				then return e(conf)
				else return e
			end
		end



		return pkgenv(v) or pkv(e or v) or (fbo and eval(fbo[v])) or (fbv and eval(fbv[v]))

	end


	if conf.posix then

		pkc  = function(...) return u.exec { 'pkg-config'; name; ...  } end
		local pkcv = function(...) return u.exec({ 'pkg-config'; name; ...  }, true) end
		if pkcv('--exists') == 0 then
			 pkv = function(v)

				return pkc('--variable', v)
			end
		else pkc = nul end
	else
		print '(warn) configuring on non-POSIX OS, all relevant paths must be specified manually in environment variables or build will fail!'
	end
	local locdep = u.ping('./lib/' .. name)
	local prefix
	if locdep then
		prefix = './lib/' .. name
	end


	prefix = prefix or cnfvar('prefix')
	local libdir = cnfvar('libdir')
	if not libdir then
		if locdep
			then libdir = prefix .. (cnfvar('builddir') or cnfvar('libbuilddir')) or ''
			else libdir = prefix .. '/lib'
		end
	end

	local incdir = cnfvar('incdir','includedir') or (prefix .. '/include')

	local libstr = pkc '--libs-only-l' -- (--static is not reliable)
	local libs = fallback[name] and fallback[name].libs or {}
	local linkstatic = locdep
	if (not locdep) and libstr then
		libs = {}
		for m in string.gmatch(libstr, '-l(%g+)') do
			libs[#libs + 1] = m
		end
	else
................................................................................
		local ldf = {}
		for _,v in pairs(me.statlibs) do
			local fl = libdir .. '/' .. v
			if u.ping(fl) then ldf[#ldf+1] = fl end
		end
		me.linkargs = ldf
	else
		local arg = name
		if string.sub(arg,1,3) == 'lib' then arg = string.sub(arg,4) end

		local linkline = libstr or string.format('-l%s', arg)

		me.linkargs = {
			string.format('-L%s', me.libdir);
		}
		for m in string.gmatch(linkline, '(%g+)') do
			me.linkargs[#me.linkargs+1] = m
		end

		-- siiiiigh
		for _,l in pairs(libs) do
			local sw = string.format('-l%s', l) 
			local found = false
			for _,a in pairs(me.linkargs) do
				if a == sw then found = true break end
			end
			if not found then
				me.linkargs[#me.linkargs+1] = sw
			end
		end
	end
end

pkg('mbedtls')
pkg('libhttp')
pkg('json-c')



return conf




>
>
>
>
>
>





>


|
|
>
>



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


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







 







<
<
|
<
|
|



|
|
>
>

>



<


>







>
>
>
|
>

>
>

>
|
|

|
>






|
|


|
>
>
|
|
<
<
|
<
|
<
>
|
>

|







 







|
|
>
|
>









|












|

>
>


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
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
local u = dofile('common.lua')
local default = function(var,def)
	local v = os.getenv(var)
	if v then return v else return def end
end
local function coalesce(x,...)
	if x ~= nil then return x else
		if select('#',...) == 0 then return nil end
		return coalesce(...)
	end
end
local posixes = {
	linux = true; osx = true;
	android = true; haiku = true;
}
local default_os = 'linux'
local conf = {
	pkg = {};
	dist      = default('parsav_dist', coalesce(
		os.getenv('NIX_PATH')  and 'nixos',
		os.getenv('NIX_STORE') and 'nixos',
	''));
	tgttrip   = default('parsav_arch_triple'); -- target triple, used in xcomp
	tgtcpu    = default('parsav_arch_cpu'); -- target cpu, used in xcomp
	tgthf     = u.tobool(default('parsav_arch_armhf',true)); 
	build     = {
		id = u.rndstr(6);
		release = u.ingest('release');
		when = os.date();
	};
	feat = {};
}
if u.ping '.fslckout' or u.ping '_FOSSIL_' then
	if u.ping '_FOSSIL_' then default_os = 'windows' end
	conf.build.branch = u.exec { 'fossil', 'branch', 'current' }
	conf.build.checkout = (u.exec { 'fossil', 'sql',
		[[select value from localdb.vvar where name = 'checkout-hash']]
	}):gsub("^'(.*)'$", '%1')
end
conf.os    = default('parsav_host_os', default_os);
conf.tgtos = default('parsav_target_os', default_os);
conf.posix = posixes[conf.os]
conf.exe   = u.tobool(default('parsav_link',not conf.tgttrip)); -- turn off for partial builds
conf.build.origin = coalesce(
	os.getenv('parsav_builder'),
	string.format('%s@%s', coalesce (
		os.getenv('USER'),
		u.exec{'whoami'}
	), u.exec{'hostname'}) -- whoami and hostname are present on both windows & unix
)
if conf.build.release then
	local v = conf.build.release
	conf.build.str = string.format('release %s', conf.build.release)
else
	conf.build.str = string.format('build %s-%s', conf.build.id, conf.build.origin)
	if conf.build.branch then
		conf.build.str = conf.build.str .. string.format(':%s(%s)',
			conf.build.branch, string.sub(conf.build.checkout,1,10))
	end
end

if conf.tgtos == 'linux' then
	conf.feat.randomizer = default('parsav_feat_randomizer', 'kern')
else
	conf.feat.randomizer = default('parsav_feat_randomizer', 'libc')
end

local choplib = function(l)
	if string.sub(l,1,3) == 'lib' then return string.sub(l,4) end
	return l
end
local fallback = dofile('pkgdata.lua')
local libfind do local mkf = function(p)
		return function(l) return string.format(p,l) end
	end
	local unx = function(p)
		return function(l)
			if string.sub(l,1,3) == 'lib'
................................................................................
				then return string.format('%s.%s',l,p)
				else return string.format('lib%s.%s',l,p)
			end
		end
	end

	libfind = {


		linux = { static = unx 'a', dynamic = unx 'so'; };

		osx   = { dynamic = mkf '%s.dylib'; };
		win   = { dynamic = mkf '%s.dll'; };
	}
end
local pkg = function(name)
	local fbo = fallback[name] and fallback[name].osvars and coalesce(
		fallback[name].osvars[conf.os .. '_' .. conf.dist],
		fallback[name].osvars[conf.os]
	)
	local fbv = fallback[name] and fallback[name].vars
	local fb = fallback[name]
	local pkgenv = function(e)
		return os.getenv(string.format('parsav_pkg_%s_%s',name,e))
	end

	local nul = function() end
	local pkc, pkv = nul, nul
	local locdep = false
	local cnfvar = function(v,e)
		local eval = function(e)
			if type(e) == 'function'
				then return e(conf)
				else return e
			end
		end
		return coalesce(
			pkgenv(v),
			pkv(e or v),
			(fbo and eval(fbo[v])),
			(fbv and eval(fbv[v])))
	end
	local name = cnfvar('override') or name
	local pcname = coalesce(cnfvar('pcname'), name)
	if conf.posix then
		pkc  = function(...) if locdep then return nil end
			return u.exec { 'pkg-config'; pcname; ...  } end
		local pkcv = function(...) return u.exec({ 'pkg-config'; pcname; ...  }, true) end
		if pkcv('--exists') == 0 then
			pkv = function(v)
				if locdep then return nil end
				return pkc('--variable', v)
			end
		else pkc = nul end
	else
		print '(warn) configuring on non-POSIX OS, all relevant paths must be specified manually in environment variables or build will fail!'
	end
	locdep = u.ping('./lib/' .. name)
	local incdir, libdir, prefix
	if locdep then
		prefix = './lib/' .. name
		libdir = prefix .. coalesce(cnfvar('libbuilddir'),cnfvar('builddir'),'')
		incdir = prefix .. coalesce(cnfvar('srcincdir'),cnfvar('builddir'),'/include')
	else
		prefix = coalesce(cnfvar('prefix'), '/usr')
		libdir = cnfvar('libdir')


		incdir = cnfvar('incdir','includedir')

	end

	libdir = libdir or prefix .. '/lib'
	incdir = incdir or prefix .. '/include'

	local libstr = pkc '--libs-only-l' -- (--static is not reliable)
	local libs = fb and fb.libs or {}
	local linkstatic = locdep
	if (not locdep) and libstr then
		libs = {}
		for m in string.gmatch(libstr, '-l(%g+)') do
			libs[#libs + 1] = m
		end
	else
................................................................................
		local ldf = {}
		for _,v in pairs(me.statlibs) do
			local fl = libdir .. '/' .. v
			if u.ping(fl) then ldf[#ldf+1] = fl end
		end
		me.linkargs = ldf
	else
		local arg = choplib(name)
		local linkline = libstr
		if not linkline and #libs == 0 then
			linkline = string.format('-l%s', arg)
		elseif not linkline then linkline = '' end
		me.linkargs = {
			string.format('-L%s', me.libdir);
		}
		for m in string.gmatch(linkline, '(%g+)') do
			me.linkargs[#me.linkargs+1] = m
		end

		-- siiiiigh
		for _,l in pairs(libs) do
			local sw = string.format('-l%s', choplib(l)) 
			local found = false
			for _,a in pairs(me.linkargs) do
				if a == sw then found = true break end
			end
			if not found then
				me.linkargs[#me.linkargs+1] = sw
			end
		end
	end
end

pkg('mbedtls')
pkg('mongoose')
pkg('json-c')
pkg('libc')
pkg('libpq')

return conf

Added crypt.t version [340864c560].

























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- vim: ft=terra
local const = {
	keybits = 2048;
	sighash = lib.md.MBEDTLS_MD_SHA256;
}
local err = {
	rawcode = terra(code: int)
		if code < 0 then code = -code end
		return code and 0xFF80
	end;
	toobig = -lib.pk.MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
}
const.maxpemsz = math.floor((const.keybits / 8)*6.4) + 128 -- idk why this formula works but it basically seems to

local ctx = lib.pk.mbedtls_pk_context

local m = {
	pemfile = uint8[const.maxpemsz];
}
local callbacks = {}
if config.feat.randomizer == 'kern' then
	local rnd = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff);
	terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
		return rnd(dest, sz, 0)
	end
elseif config.feat.randomizer == 'devfs' then
	terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
		var gen = lib.io.open("/dev/urandom",0)
		lib.io.read(gen, dest, sz)
		lib.io.close(gen)
		return sz
	end
elseif config.feat.randomizer == 'libc' then
	local rnd = terralib.externfunction('rand', {} -> int);
	local srnd = terralib.externfunction('srand', uint -> int);
	local time = terralib.includec 'time.h'
	lib.init[#lib.init + 1] = quote srnd(time.time(nil)) end
	print '(warn) using libc soft-rand function for cryptographic purposes, this is very bad!'
	terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
		for i=0,sz do dest[i] = [uint8](rnd()) end
		return sz
	end
end

terra m.pem(pub: bool, key: &ctx, buf: &uint8): bool
	if pub then
		return lib.pk.mbedtls_pk_write_pubkey_pem(key, buf, const.maxpemsz) == 0
	else
		return lib.pk.mbedtls_pk_write_key_pem(key, buf, const.maxpemsz) == 0
	end
end

m.destroy = lib.dispatch {
	[ctx] = function(v) return `lib.pk.mbedtls_pk_free(&v) end;

	[false] = function(ptr) return `ptr:free() end;
}

terra m.genkp(): lib.pk.mbedtls_pk_context
	lib.dbg('generating new keypair')

	var pk: ctx
	lib.pk.mbedtls_pk_init(&pk)
	lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA))
	var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx)
	lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, const.keybits, 65537)

	return pk
end

terra m.loadpriv(buf: &uint8, len: intptr): ctx
	lib.dbg('parsing saved keypair')

	var pk: ctx
	lib.pk.mbedtls_pk_init(&pk)
	lib.pk.mbedtls_pk_parse_key(&pk, buf, len + 1, nil, 0)
	return pk
end

terra m.sign(pk: &ctx, txt: rawstring, len: intptr)
	lib.dbg('signing message')
	var osz: intptr = 0
	var sig = lib.mem.heapa(int8, 2048)
	var hash: uint8[32]
	
	lib.dbg('(1/2) hashing message')
	if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(const.sighash), [&uint8](txt), len, hash) ~= 0 then
		lib.bail('could not hash message')
	end

	lib.dbg('(2/2) signing hash')
	var ret = lib.pk.mbedtls_pk_sign(pk, const.sighash, hash, 0, [&uint8](sig.ptr), &osz, callbacks.randomize, nil)
	if ret ~= 0 then lib.bail('could not sign message hash')
	else sig:resize(osz) end

	return sig
end

terra m.verify(pk: &ctx, txt: rawstring, len: intptr,
                        sig: rawstring, siglen: intptr): {bool, uint8}
	lib.dbg('verifying signature')
	var osz: intptr = 0
	var hash: uint8[64]

	-- there does not appear to be any way to extract the hash algorithm
	-- from the message, so we just have to try likely algorithms until
	-- we find one that fits or give up. a security level is attached
	-- to indicate our relative confidence in the hash; 0 == 'likely forgeable'
	var algs = array(
		-- common hashes
		{lib.md.MBEDTLS_MD_SHA256, 'sha256', 2},
		{lib.md.MBEDTLS_MD_SHA512, 'sha512', 3},
		{lib.md.MBEDTLS_MD_SHA1,   'sha1',   1},
		-- uncommon hashes
		{lib.md.MBEDTLS_MD_SHA384, 'sha384', 2},
		{lib.md.MBEDTLS_MD_SHA224, 'sha224', 2},
		-- bad hashes
		{lib.md.MBEDTLS_MD_MD5,   'md5', 0},
		{lib.md.MBEDTLS_MD_MD4,   'md4', 0},
		{lib.md.MBEDTLS_MD_MD2,   'md2', 0}
	)
	
	for i = 0, [algs.type.N] do
		var hk, aname, secl = algs[i]

		lib.dbg('(1/2) trying hash algorithm ',aname)
		if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(hk), [&uint8](txt), len, hash) ~= 0 then
			lib.bail('could not hash message')
		end

		lib.dbg('(2/2) verifying hash')
		if lib.pk.mbedtls_pk_verify(pk, hk, hash, 0, [&uint8](sig), siglen) == 0 then
			return true, secl
		end
	end
	lib.dbg('all hash algorithms failed')
	return false, 0
end

return m

Added http.t version [6d6c40fc94].



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- vim: ft=terra
local m = {}
local util = dofile('common.lua')

struct m.header {
	key: rawstring
	value: rawstring
}
struct m.page {
	respcode: uint16
	body: lib.mem.ptr(int8)
	headers: lib.mem.ptr(m.header)
}

local resps = {
	[200] = 'OK';
	[201] = 'Created';
	[301] = 'Moved Permanently';
	[302] = 'Found';
	[303] = 'See Other';
	[307] = 'Temporary Redirect';
	[404] = 'Not Found';
	[401] = 'Unauthorized';
	[403] = 'Forbidden';
	[418] = 'I\'m a teapot';
	[405] = 'Method Not Allowed';
	[500] = 'Internal Server Error';
}
local resptext = symbol(rawstring)
local resplen = symbol(intptr)
local respbranches = {}
for k,v in pairs(resps) do
	local txt = string.format('%u %s\r\n',k,v)
	respbranches[#respbranches + 1] = quote
		case [uint16](k) then resptext = [txt] resplen = [#txt] end
	end
end
m.codestr = terra(code: uint16)
	var [resptext] var [resplen]
	switch code do [respbranches] end
	return resptext, resplen
end
m.page.methods = {
	free = terra(self: &m.page)
		self.body:free()
		self.headers:free()
	end;
	send = terra(self: &m.page, con: &lib.net.mg_connection)
		var code: rawstring
		var [resptext] var [resplen]
		switch self.respcode do [respbranches] end
		lib.net.mg_send(con, "HTTP/1.1 ", 9)
		lib.net.mg_send(con, resptext, resplen)
		for i = 0, self.headers.ct do
			var h = self.headers.ptr[i]
			lib.net.mg_send(con, h.key, lib.str.sz(h.key))
			lib.net.mg_send(con, ": ", 2)
			lib.net.mg_send(con, h.value, lib.str.sz(h.value))
			lib.net.mg_send(con, "\r\n", 2)
		end
		lib.net.mg_printf(con, 'Content-Length: %llu\r\n\r\n', self.body.ct)
		lib.net.mg_send(con,self.body.ptr,self.body.ct)
	end;
}
return m

Modified makefile from [b49975ddb0] to [0f98e9b572].

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
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
	terra $(dbg-flags) $<
parsav.o: parsav.t config.lua pkgdata.lua
	env parsav_link=no terra $(dbg-flags) $<

clean:
	rm parsav parsav.o





dep: dep.mbedtls dep.libhttp dep.json-c
dep.mbedtls: lib/mbedtls/library/libmbedtls.a \
	lib/mbedtls/library/libmbedcrypto.a \
	lib/mbedtls/library/libmbedx509.a
dep.libhttp: lib/libhttp/lib/libhttp.a
dep.json-c: lib/libhttp/json-c.a

lib:
	mkdir $@
# parsav is designed to be fronted by a real web
# server like nginx if SSL is to be used
# caveat: libhttp is a mess. the docs are completely
# full of shit. there is no lua support as far as i
# can tell.
lib/libhttp/lib/libhttp.a: lib/libhttp
	$(MAKE) -C $< lib/libhttp.a \
		RM='rm -f' \
		CC="$(CC) -Wno-unused-result" \
		DFLAGS="-DNO_SSL -DNO_FILES -DNO_CGI -DUSE_STACK_SIZE=102400 -DUSE_IPV6"



lib/json-c/Makefile: lib/json-c lib/json-c/CMakeLists.txt
	cd lib/json-c && cmake .
lib/json-c/libjson-c.a: lib/json-c/Makefile
	$(MAKE) -C lib/json-c
lib/mbedtls/library/%.a: lib/mbedtls 
	$(MAKE) -C lib/mbedtls/library $*.a

ifeq ($(dl), git)
lib/libhttp: lib
	cd lib && git clone https://github.com/lammertb/libhttp.git
lib/mbedtls: lib
	cd lib && git clone https://github.com/ARMmbed/mbedtls.git
lib/json-c: lib
	cd lib && git clone https://github.com/json-c/json-c.git
else
lib/%: lib/%.tar.gz
	cd lib && tar zxf $*.tar.gz
................................................................................
    dlfile = wget "$(1)" -O "$(2)"
endif

ifeq ($(dl), curl)
    dlfile = curl "$(1)" -o "$(2)"
endif

lib/libhttp.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/lammertb/libhttp/tarball/master,$@)
lib/mbedtls.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/ARMmbed/mbedtls/tarball/master,$@)
lib/json-c.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/json-c/json-c/tarball/master,$@)
endif







>
>
>
>
|



|
|





|
|
|
|
|
|
|
|
>
>









|
|







 







|
|





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
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
	terra $(dbg-flags) $<
parsav.o: parsav.t config.lua pkgdata.lua
	env parsav_link=no terra $(dbg-flags) $<

clean:
	rm parsav parsav.o

install: parsav
	mkdir $(prefix)/bin
	cp $< $(prefix)/bin/

dep: dep.mbedtls dep.mongoose dep.json-c
dep.mbedtls: lib/mbedtls/library/libmbedtls.a \
	lib/mbedtls/library/libmbedcrypto.a \
	lib/mbedtls/library/libmbedx509.a
dep.mongoose: lib/mongoose/libmongoose.a
dep.json-c: lib/json-c/libjson-c.a

lib:
	mkdir $@
# parsav is designed to be fronted by a real web
# server like nginx if SSL is to be used
# generate a shim static library so mongoose cooperates
# with the build apparatus
lib/mongoose/libmongoose.a: lib/mongoose lib/mongoose/mongoose.c lib/mongoose/mongoose.h
	$(CC) -c $</mongoose.c -o lib/mongoose/mongoose.o \
		-DMG_ENABLE_THREADS \
		-DMG_ENABLE_IPV6 \
		-DMG_ENABLE_HTTP_WEBDAV \
		-DMG_ENABLE_HTTP_WEBSOCKET=0
	ar rcs $@ lib/mongoose/*.o
	ranlib $@

lib/json-c/Makefile: lib/json-c lib/json-c/CMakeLists.txt
	cd lib/json-c && cmake .
lib/json-c/libjson-c.a: lib/json-c/Makefile
	$(MAKE) -C lib/json-c
lib/mbedtls/library/%.a: lib/mbedtls 
	$(MAKE) -C lib/mbedtls/library $*.a

ifeq ($(dl), git)
lib/mongoose: lib
	cd lib && git clone https://github.com/cesanta/mongoose
lib/mbedtls: lib
	cd lib && git clone https://github.com/ARMmbed/mbedtls.git
lib/json-c: lib
	cd lib && git clone https://github.com/json-c/json-c.git
else
lib/%: lib/%.tar.gz
	cd lib && tar zxf $*.tar.gz
................................................................................
    dlfile = wget "$(1)" -O "$(2)"
endif

ifeq ($(dl), curl)
    dlfile = curl "$(1)" -o "$(2)"
endif

lib/mongoose.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/cesanta/mongoose/tarball/master,$@)
lib/mbedtls.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/ARMmbed/mbedtls/tarball/master,$@)
lib/json-c.tar.gz: lib
	$(call dlfile,https://api.github.com/repos/json-c/json-c/tarball/master,$@)
endif

Modified parsav.t from [d2f35b212c] to [889180c92d].

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
..
45
46
47
48
49
50
51



52
53
54
55
56
57
58
59
60
61
62
-- vim: ft=terra

local util = dofile('common.lua')
local buildopts, buildargs = util.parseargs{...}

local config = dofile('config.lua')

local lib = {

	loadlib = function(name,hdr)
		local p = config.pkg[name]
		-- for _,v in pairs(p.dylibs) do
		-- 	terralib.linklibrary(p.libdir .. '/' .. v)
		-- end
		return terralib.includec(p.incdir .. '/' .. hdr)
	end;



































	randomize = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff);

}






























































































lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h')
lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h')











local callbacks = {
	randomize = terra(ctx: &opaque, dest: &uint8, sz: intptr): int
		return lib.randomize(dest, sz, 0)


	end;



}




















































terra entry(): int
	var pk: lib.pk.mbedtls_pk_context
	lib.pk.mbedtls_pk_init(&pk)
	lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA))
	var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx)
	lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, 2048, 65537)



























	return 0
end

local bflag = function(long,short)
	if short and util.has(buildopts, short) then return true end
	if long and util.has(buildopts, long) then return true end
	return false
................................................................................
end

local emit = print
if bflag('quiet','q') then emit = function() end end

local out = config.exe and 'parsav' or 'parsav.o'
local linkargs = {}



for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end
emit('linking with args',util.dump(linkargs))
terralib.saveobj(out, {
		main = entry
	},
	linkargs,
	config.tgttrip and terralib.newtarget {
		Triple = config.tgttrip;
		CPU = config.tgtcpu;
		FloatABIHard = config.tgthf;
	} or nil)




<
|

|
>







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


>
>
>
>
>
>
>
>
>
>

<
<
<
>
>
|
>
>
>
|
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>











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
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220





221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
-- vim: ft=terra

local util = dofile('common.lua')
local buildopts, buildargs = util.parseargs{...}

config = dofile('config.lua')

lib = {
	init = {};
	loadlib = function(name,hdr)
		local p = config.pkg[name]
		-- for _,v in pairs(p.dylibs) do
		-- 	terralib.linklibrary(p.libdir .. '/' .. v)
		-- end
		return terralib.includec(p.incdir .. '/' .. hdr)
	end;
	dispatch = function(tbl)
		return macro(function(v,...)
			for ty,fn in pairs(tbl) do
				if v.tree.type == ty then return fn(v,...) end
			end
			return (tbl[false])(v,...)
		end)
	end;
	emit = function(...)
		local code = {}
		for i,v in ipairs{...} do
			if type(v) == 'string' or type(v) == 'number' then
				local str = tostring(v)
				code[#code+1] = `lib.io.send(2, str, [#str])
			elseif v.tree:is 'constant' then
				local str = tostring(v:asvalue())
				code[#code+1] = `lib.io.send(2, str, [#str])
			else
				code[#code+1] = quote var n = v in
					lib.io.send(2, n, lib.str.sz(n)) end
			end
		end
		code[#code+1] = `lib.io.send(2, '\n', 1)
		return code
	end;
	proc = {
		exit = terralib.externfunction('exit', int -> {});
		getenv = terralib.externfunction('getenv', rawstring -> rawstring);
	};
	io = {
		open = terralib.externfunction('open', {rawstring, int} -> int);
		close = terralib.externfunction('close',  {int} -> int);
		send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff);
		recv = terralib.externfunction('read',  {int, rawstring, intptr} -> ptrdiff);
		say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end);
		fmt = terralib.externfunction('printf',
			terralib.types.funcpointer({rawstring},{int},true));
	};
	str = {
		sz = terralib.externfunction('strlen', rawstring -> intptr);
		cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int);
		cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring);
		ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring);
		fmt = terralib.externfunction('asprintf',
			terralib.types.funcpointer({&rawstring},{int},true));
	};
	mem = {
		zero = macro(function(r)
			return quote
				for i = 0, [r.tree.type.N] do r[i] = 0 end
			end
		end);
		heapa_raw = terralib.externfunction('malloc', intptr -> &opaque);
		heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque);
		heapf = terralib.externfunction('free', &opaque -> {});
		cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque);
		heapa = macro(function(ty, sz)
			local p = lib.mem.ptr(ty:astype())
			return `p {
				ptr = [&ty:astype()](lib.mem.heapa_raw(sizeof(ty) * sz));
				ct = sz;
			}
		end)
	};
}

local noise = global(uint8,1)
local defrep = function(level,n,code)
	return macro(function(...)
		local q = lib.emit("\27["..code..";1m(parsav "..n..")\27[m ", ...)
		return quote
			if noise >= level then [q] end
		end
	end);
end
lib.dbg = defrep(3,'debug', '32')
lib.report = defrep(2,'info', '35')
lib.warn = defrep(1,'warn', '33')
lib.bail = macro(function(...)
	local q = lib.emit("\27[31;1m(parsav fatal)\27[m ", ...)
	return quote
		[q]
		lib.proc.exit(1)
	end
end);
lib.mem.ptr = terralib.memoize(function(ty)
	local t = terralib.types.newstruct(string.format('ptr<%s>', ty))
	t.entries = {
		{'ptr', &ty};
		{'ct', intptr};
	}
	local recurse = false
	if ty:isstruct() then
		if ty.methods.free then recurse = true end
	end
	t.methods = {
		free = terra(self: &t): bool
			[recurse and quote
				self.ptr:free()
			end or {}]
			if self.ct > 0 then
				lib.mem.heapf(self.ptr)
				self.ct = 0
				return true
			end
			return false
		end;
		init = terra(self: &t, newct: intptr): bool
			var nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct))
			if nv ~= nil then
				self.ptr = nv
				self.ct = newct
				return true
			else return false end
		end;
		resize = terra(self: &t, newct: intptr): bool
			var nv: &ty
			if self.ct > 0
				then nv = [&ty](lib.mem.heapr_raw(self.ptr, sizeof(ty) * newct))
				else nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct))
			end
			if nv ~= nil then
				self.ptr = nv
				self.ct = newct
				return true
			else return false end
		end;
	}
	return t
end)

lib.err = lib.loadlib('mbedtls','mbedtls/error.h')
lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h')
lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h')
lib.md = lib.loadlib('mbedtls','mbedtls/md.h')
lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h')
lib.net = lib.loadlib('mongoose','mongoose.h')
lib.pq = lib.loadlib('libpq','libpq-fe.h')
lib.crypt = terralib.loadfile('crypt.t')()
lib.http = terralib.loadfile('http.t')()
lib.tpl = terralib.loadfile('tpl.t')()
lib.string = terralib.loadfile('string.t')()
lib.store = terralib.loadfile('store.t')()
lib.cmdparse = terralib.loadfile('cmdparse.t')()




do local collate = function(path,f, ...)
	return loadfile(path..'/'..f..'.lua')(path, ...)
end
data = {
	view = collate('view','load');
} end

-- slightly silly -- because we're using plain lua to gather up
-- the template sources, they have to be actually turned into
-- templates in the terra code, so we "mutate" them here
for k,v in pairs(data.view) do
	local t = lib.tpl.mk { body = v, id = 'view/'..k }
	data.view[k] = t
end

local pemdump = macro(function(pub, kp)
	local msg = (pub:asvalue() and ' * emitting public key\n') or ' * emitting private key\n'
	return quote
		var buf: lib.crypt.pemfile
		lib.mem.zero(buf)
		lib.crypt.pem(pub, &kp, buf)
		lib.io.send(1, msg, [#msg])
		lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf)))
		lib.io.send(1, '\n', 1)
	end
end)

local handle = {
	http = terra(con: &lib.net.mg_connection, event: int, p: &opaque, ext: &opaque)
		switch event do
			case lib.net.MG_EV_HTTP_MSG then
				lib.dbg('routing HTTP request')
				var msg = [&lib.net.mg_http_message](p)

			end
		end
	end;
}
do
	local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
	terra version() lib.io.send(1, p, [#p]) end
end
terra noise_init()
	var n = lib.proc.getenv('parsav_noise')
	if n ~= nil then
		if n[0] >= 0x30 and n[0] <= 0x39 and n[1] == 0 then
			noise = n[0] - 0x30
			return
		end
	end
	noise = 1
end

local options = lib.cmdparse {
	version = {'V', 'display information about the binary build and exit'};
	quiet = {'q', 'do not print to standard out'};
	help = {'h', 'display this list'}
}

terra entry(argc: int, argv: &rawstring): int





	noise_init()
	[lib.init]

	var mode: options
	mode:parse(argc,argv)
	if mode.version then
		version()
		return 0
	end
	if mode.help then
		lib.io.send(1,  [options.helptxt], [#options.helptxt])
		return 0
	end

	var bind = lib.proc.getenv('parsav_bind')
	if bind == nil then bind = '[::]:10917' end

	var nm: lib.net.mg_mgr
	lib.net.mg_mgr_init(&nm)

	var nmc = lib.net.mg_http_listen(&nm, bind, handle.http, nil)

	while true do
		lib.net.mg_mgr_poll(&nm,1000)
	end

	lib.net.mg_mgr_free(&nm)
	return 0
end

local bflag = function(long,short)
	if short and util.has(buildopts, short) then return true end
	if long and util.has(buildopts, long) then return true end
	return false
................................................................................
end

local emit = print
if bflag('quiet','q') then emit = function() end end

local out = config.exe and 'parsav' or 'parsav.o'
local linkargs = {}
if config.posix then
	linkargs[#linkargs+1] = '-pthread'
end
for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end
emit('linking with args',util.dump(linkargs))
terralib.saveobj(out, {
		main = entry
	},
	linkargs,
	config.tgttrip and terralib.newtarget {
		Triple = config.tgttrip;
		CPU = config.tgtcpu;
		FloatABIHard = config.tgthf;
	} or nil)

Modified pkgdata.lua from [b4c0388029] to [8c50f1b4b0].

1
2

3
4
5
6
7
8
9
10
11
12
13








14














local util = dofile('common.lua')
local sthunk = function(...) local a = {...} return function() return util.exec(a) end end

return {
	mbedtls = { 
		libs = {'mbedtls', 'mbedcrypto', 'mbedx509'};
		osvars = {
			linux_nixos = { -- lacks a *.pc on nixos systems
				prefix = sthunk('nix', 'path-info', 'nixos.mbedtls');
			}
		};
		vars = { builddir = '/library' };
	};
	libhttp = { vars = { builddir = '/lib' }; };








}
















>










|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
local util = dofile('common.lua')
local sthunk = function(...) local a = {...} return function() return util.exec(a) end end

return {
	mbedtls = { 
		libs = {'mbedtls', 'mbedcrypto', 'mbedx509'};
		osvars = {
			linux_nixos = { -- lacks a *.pc on nixos systems
				prefix = sthunk('nix', 'path-info', 'nixos.mbedtls');
			}
		};
		vars = { builddir = '/library' };
	};
	mongoose = { vars = { builddir = '' } };
	libpq = {
		osvars = {
			linux_nixos = {
				prefix = sthunk('nix', 'path-info', 'nixos.postgresql.lib');
				incdir = function()
					local a = {'nix', 'path-info', 'nixos.postgresql'}
					return (util.exec(a)) .. '/include';
				end;
			};
		};
		vars = {pcname = 'postgresql';}
	};
	libc = {
		libs = {'dl'}; -- libc.so does not need explicit mention
		osvars = {
			linux_nixos = {
				prefix = sthunk('nix', 'path-info', 'nixos.glibc');
				override = 'glibc';
			};
			linux = { override = 'glibc'; };
		}
	};
}

Added store.t version [a0814e5c61].































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- vim: ft=terra
local m = {}

local backend = {
	pgsql = {
	};
}

struct m.user {
	uid: rawstring
	nym: rawstring
	handle: rawstring

	localuser: bool
}

Added string.t version [a0d1de486b].







































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- vim: ft=terra
-- string.t: string classes

local m = {}

struct m.acc {
	buf: rawstring
	sz: intptr
	run: intptr
	space: intptr
}

local terra biggest(a: intptr, b: intptr)
	if a > b then return a else return b end
end

m.acc.methods = {
	init = terra(self: &m.acc, run: intptr)
		lib.dbg('initializing string accumulator')
		self.buf = [rawstring](lib.mem.heapa_raw(run))
		self.run = run
		self.space = run
		self.sz = 0
	end;
	free = terra(self: &m.acc)
		lib.dbg('freeing string accumulator')
		if self.buf ~= nil and self.space > 0 then
			lib.mem.heapf(self.buf)
		end
	end;
	crush = terra(self: &m.acc)
		lib.dbg('crushing string accumulator')
		self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz))
		self.space = self.sz
		return self
	end;
}

m.acc.methods.finalize = terra(self: &m.acc)
	lib.dbg('finalizing string accumulator')
	self:crush()
	var pt: lib.mem.ptr(int8)
	pt.ptr = self.buf
	pt.ct = self.sz
	self.buf = nil
	self.sz = 0
	return pt
end;
m.acc.methods.push = terra(self: &m.acc, str: rawstring, len: intptr)
	lib.dbg('pushing "',str,'" onto accumulator')
	if self.buf == nil then self:init(self.run) end
	if len == 0 then len = lib.str.sz(str) end
	if len >= self.space - self.sz then
		self.space = self.space + biggest(self.run,len + 1)
		self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
	end
	lib.mem.cpy(self.buf + self.sz, str, len)
	self.sz = self.sz + len
	self.buf[self.sz] = 0
	return self
end;
m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8))
	self:push(str.ptr, str.ct)            return self end;
m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
	self:push(str.ptr, str.ct) str:free() return self end;

return m

Added tpl.t version [ad44dd6129].











































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- vim: ft=terra
-- string template generator:
-- returns a function that fills out a template
-- with the strings given

local util = dofile 'common.lua'
local m = {}
function m.mk(tplspec)
	local str
	if type(tplspec) == 'string'
		then str = tplspec tplspec = {}
		else str = tplspec.body
	end
	local tplchar_o = tplspec.sigil or '@'
	local tplchar = tplchar_o
	local magic = {
		['%'] = true, ['$'] = true, ['^'] = true;
		['.'] = true, ['*'] = true, ['+'] = true;
		['-'] = true, ['?'] = true;
	}
	tplchar_o = string.gsub(tplchar_o,'%%','%%%%')
	tplchar = string.gsub(tplchar, '.', function(c)
		if magic[c] then return '%' .. c end
	end)
	local last = 1
	local fields = {}
	local segs = {}
	local constlen = 0
	-- strip out all irrelevant whitespace to tidy things up
	-- TODO: find way to exclude <pre> tags?
	str = str:gsub('[\n^]%s+','')
	str = str:gsub('%s+[\n$]','')
	str = str:gsub('\n','')
	for start, key, stop in string.gmatch(str,'()'..tplchar..'(%w+)()') do
		if string.sub(str,start-1,start-1) ~= '\\' then
			segs[#segs+1] = string.sub(str,last,start-1)
			fields[#segs] = key
			last = stop
		end
	end
	segs[#segs+1] = string.sub(str,last)
	for i, s in ipairs(segs) do
		segs[i] = string.gsub(s, '\\'..tplchar, tplchar_o)
		constlen = constlen + string.len(segs[i])
	end

	local runningtally = symbol(intptr)
	local tallyup = {quote
		var [runningtally] = 1 + constlen
	end}
	local rec = terralib.types.newstruct(string.format('template<%s>',tplspec.id or ''))
	local symself = symbol(&rec)
	do local kfac = {}
		for afterseg,key in pairs(fields) do
			if not kfac[key] then
				rec.entries[#rec.entries + 1] = {
					field = key;
					type = rawstring;
				}
			end
			kfac[key] = (kfac[key] or 0) + 1
		end
		for key, fac in pairs(kfac) do
			tallyup[#tallyup + 1] = quote
				[runningtally] = [runningtally] + lib.str.sz([symself].[key])*fac
			end
		end
	end

	local copiers = {}
	local senders = {}
	local symtxt = symbol(lib.mem.ptr(int8))
	local cpypos = symbol(&opaque)
	local destcon = symbol(&lib.net.mg_connection)
	for idx, seg in ipairs(segs) do
		copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end
		senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end
		if fields[idx] then
			copiers[#copiers+1] = quote
				[cpypos] = lib.mem.cpy([cpypos],
					[&opaque](symself.[fields[idx]]),
					lib.str.sz(symself.[fields[idx]]))
			end
			senders[#senders+1] = quote
				lib.net.mg_send([destcon],
					symself.[fields[idx]],
					lib.str.sz(symself.[fields[idx]]))
			end
		end
	end

	local tid = tplspec.id or '<anonymous>'
	rec.methods.tostr = terra([symself])
		lib.dbg(['compiling template ' .. tid])
		[tallyup]
		var [symtxt] = lib.mem.heapa(int8, [runningtally])
		var [cpypos] = [&opaque](symtxt.ptr)
		[copiers]
		@[&int8](cpypos) = 0
		return symtxt
	end
	rec.methods.send = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header))
		lib.dbg(['transmitting template ' .. tid])
		[tallyup]
		lib.net.mg_printf([destcon], 'HTTP/1.1 %s', lib.http.codestr(code))
		for i = 0, hd.ct do
			lib.net.mg_printf([destcon], '%s: %s\r\n', hd.ptr[i].key, hd.ptr[i].value)
		end
		lib.net.mg_printf([destcon],'Content-Length: %llu\r\n\r\n', [runningtally] + 1)
		[senders]
		lib.net.mg_send([destcon],'\r\n',2)
	end

	return rec
end

return m

Added view/docskel.tpl version [1d38dac966].























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
<!doctype html>
<html>
	<head>
		<title>@instance :: @title</title>
		<link rel="stylesheet" href="/style.css">
	</head>
	<body>
		<h1>@title</h1>
		@body
	</body>
</html>

Added view/load.lua version [f2a65d7b61].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
-- because lua can't scan directories, we need a
-- file that indexes the templates manually, and
-- copies them into a data structure we can then
-- create templates from when we return to terra
local path = ...
local sources = {
	'docskel';
	'tweet';
}

local ingest = function(filename)
	local hnd = io.open(path..'/'..filename)
	local txt = hnd:read('*a')
	io.close(hnd)
	txt = txt:gsub('([^\\])!%b[]', '%1')
	txt = txt:gsub('([^\\])!!.-\n', '%1')
	txt = txt:gsub('\\(!%b[])', '%1')
	txt = txt:gsub('\\(!!)', '%1')
	return txt
end


local views = {}
for _,n in pairs(sources) do views[n] = ingest(n .. '.tpl') end
return views

Added view/tweet.tpl version [59ae4e4ad9].

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
<div class="post">
	<div class="detail">
		<a class="username" href="@link">
			<span class="nym">@nym</span> <span class="handle">[@handle]</span>
		</div>
		<div class="when">@when</div>
	</div>
	<div class="content">
		<img class="avatar" src="@avatar">
		<div class="text">@text</div>
	</div>
</div>