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: |
6f17de476745e01bc24c082213de5656 |
| 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 +return function(tbl) 2 + local options = terralib.types.newstruct('options') do 3 + local flags = '' for _,d in pairs(tbl) do flags = flags .. d[1] end 4 + local helpstr = 'usage: parsav [-' .. flags .. '] [<arg>...]\n' 5 + options.entries = { 6 + {field = 'arglist', type = lib.mem.ptr(rawstring)} 7 + } 8 + local shortcases, longcases, init = {}, {}, {} 9 + local self = symbol(&options) 10 + local arg = symbol(rawstring) 11 + local skip = label() 12 + for o,desc in pairs(tbl) do 13 + options.entries[#options.entries + 1] = { 14 + field = o, type = bool 15 + } 16 + helpstr = helpstr .. string.format(' -%s --%s: %s\n', 17 + desc[1], o, desc[2]) 18 + end 19 + for o,desc in pairs(tbl) do 20 + local flag = desc[1] 21 + init[#init + 1] = quote [self].[o] = false end 22 + shortcases[#shortcases + 1] = quote 23 + case [int8]([string.byte(flag)]) then [self].[o] = true end 24 + end 25 + longcases[#longcases + 1] = quote 26 + if lib.str.cmp([arg]+2, o) == 0 then 27 + [self].[o] = true 28 + goto [skip] 29 + end 30 + end 31 + end 32 + options.methods.parse = terra([self], argc: int, argv: &rawstring) 33 + [init] 34 + var parseopts = true 35 + self.arglist = lib.mem.heapa(rawstring, argc) 36 + var finalargc = 0 37 + for i=0,argc do 38 + var [arg] = argv[i] 39 + if arg[0] == ('-')[0] and parseopts then 40 + if arg[1] == ('-')[0] then -- long option 41 + if arg[2] == 0 then -- last option 42 + parseopts = false 43 + else [longcases] end 44 + else -- short options 45 + var j = 1 46 + while arg[j] ~= 0 do 47 + switch arg[j] do [shortcases] end 48 + j = j + 1 49 + end 50 + end 51 + else 52 + self.arglist.ptr[finalargc] = arg 53 + finalargc = finalargc + 1 54 + end 55 + ::[skip]:: 56 + end 57 + if finalargc == 0 then self.arglist:free() 58 + else self.arglist:resize(finalargc) end 59 + end 60 + options.helptxt = helpstr 61 + end 62 + return options 63 +end
Modified common.lua from [9dc63595c4] to [3d397d42e6].
20 20 if val then return os.execute(cmd) else 21 21 local fd = io.popen(cmd,'r') 22 22 local t = fd:read('*a') 23 23 return chomp(t), fd:close() 24 24 end 25 25 end 26 26 27 -local function dump(v,pfx) 27 +local function dump(v,pfx,cyc) 28 28 pfx = pfx or '' 29 + cyc = cyc or {} 29 30 local np = pfx .. ' ' 31 + 32 + if type(v) == 'table' then 33 + if cyc[v] then return '<...>' else cyc[v] = true end 34 + end 35 + 30 36 if type(v) == 'string' then 31 37 return string.format('%q', v) 32 38 elseif type(v) == 'table' then 33 39 local str = '' 34 40 for k,v in pairs(v) do 35 - str = str .. string.format('%s[%s] = %s\n', np, dump(k,np), dump(v,np)) 41 + local tkey, tval = dump(k,np,cyc), dump(v,np,cyc) 42 + str = str .. string.format('%s[%s] = %s\n', np, tkey,tval) 36 43 end 37 44 return '{\n' .. str .. pfx .. '}\n' 38 45 else 39 46 return string.format('%s', v) 40 47 end 41 48 end 42 49 local ping = function(path) ................................................................................ 50 57 s = ({ 51 58 yes = true, ['true'] = true, on = true, ['1'] = true; 52 59 no = false, ['false'] = false, off = false, ['0'] = false; 53 60 })[string.lower(s)] 54 61 if not s then return false end 55 62 return true 56 63 end 64 + 65 +if ping '/dev/urandom' then 66 + local r = io.open('/dev/urandom') 67 + local ent = r:read(8) r:close() 68 + local seed = 1 for i = 1, 8 do 69 + seed = seed * string.byte(string.sub(ent,i,i)) 70 + end 71 + math.randomseed(seed) 72 +else math.randomseed(os.time()) end 73 + 57 74 return { 58 75 exec = exec; 59 76 dump = dump; 60 77 ping = ping; 61 78 chomp = chomp; 62 79 map = map; 63 80 tobool = tobool; 81 + rndstr = function(len) 82 + local s = '' 83 + for i=1,len do 84 + local ofs = math.random(0,10 + 26) 85 + if ofs >= 10 then ofs = 0x60 + (ofs - 10) 86 + else ofs = 0x30 + ofs end 87 + s = s .. string.char(ofs) 88 + end 89 + return s 90 + end; 64 91 append = function(a,b) 65 92 for _, v in pairs(b) do a[#a+1] = v end 66 93 end; 67 94 has = function(haystack,needle,eq) 68 95 eq = eq or function(a,b) return a == b end 69 96 for k,v in pairs(haystack) do 70 97 if eq(needle,v) then return k end 71 98 end 99 + end; 100 + ingest = function(f) 101 + local h = io.open(f, 'r') 102 + if h == nil then return nil end 103 + local txt = f:read('*a') f:close() 104 + return chomp(txt) 72 105 end; 73 106 parseargs = function(a) 74 107 local raw = false 75 108 local opts, args = {}, {} 76 109 for i,v in ipairs(a) do 77 110 if v == '--' then 78 111 raw = true
Modified config.lua from [f14c1e8df4] to [85408f7c8a].
1 1 local u = dofile('common.lua') 2 2 local default = function(var,def) 3 3 local v = os.getenv(var) 4 4 if v then return v else return def end 5 +end 6 +local function coalesce(x,...) 7 + if x ~= nil then return x else 8 + if select('#',...) == 0 then return nil end 9 + return coalesce(...) 10 + end 5 11 end 6 12 local posixes = { 7 13 linux = true; osx = true; 8 14 android = true; haiku = true; 9 15 } 16 +local default_os = 'linux' 10 17 local conf = { 11 18 pkg = {}; 12 - os = default('parsav_target_os', 'linux'); 13 - dist = default('parsav_dist', os.getenv('NIX_PATH') and 'nixos'); 19 + dist = default('parsav_dist', coalesce( 20 + os.getenv('NIX_PATH') and 'nixos', 21 + os.getenv('NIX_STORE') and 'nixos', 22 + '')); 14 23 tgttrip = default('parsav_arch_triple'); -- target triple, used in xcomp 15 24 tgtcpu = default('parsav_arch_cpu'); -- target cpu, used in xcomp 16 25 tgthf = u.tobool(default('parsav_arch_armhf',true)); 26 + build = { 27 + id = u.rndstr(6); 28 + release = u.ingest('release'); 29 + when = os.date(); 30 + }; 31 + feat = {}; 17 32 } 33 +if u.ping '.fslckout' or u.ping '_FOSSIL_' then 34 + if u.ping '_FOSSIL_' then default_os = 'windows' end 35 + conf.build.branch = u.exec { 'fossil', 'branch', 'current' } 36 + conf.build.checkout = (u.exec { 'fossil', 'sql', 37 + [[select value from localdb.vvar where name = 'checkout-hash']] 38 + }):gsub("^'(.*)'$", '%1') 39 +end 40 +conf.os = default('parsav_host_os', default_os); 41 +conf.tgtos = default('parsav_target_os', default_os); 18 42 conf.posix = posixes[conf.os] 19 43 conf.exe = u.tobool(default('parsav_link',not conf.tgttrip)); -- turn off for partial builds 44 +conf.build.origin = coalesce( 45 + os.getenv('parsav_builder'), 46 + string.format('%s@%s', coalesce ( 47 + os.getenv('USER'), 48 + u.exec{'whoami'} 49 + ), u.exec{'hostname'}) -- whoami and hostname are present on both windows & unix 50 +) 51 +if conf.build.release then 52 + local v = conf.build.release 53 + conf.build.str = string.format('release %s', conf.build.release) 54 +else 55 + conf.build.str = string.format('build %s-%s', conf.build.id, conf.build.origin) 56 + if conf.build.branch then 57 + conf.build.str = conf.build.str .. string.format(':%s(%s)', 58 + conf.build.branch, string.sub(conf.build.checkout,1,10)) 59 + end 60 +end 61 + 62 +if conf.tgtos == 'linux' then 63 + conf.feat.randomizer = default('parsav_feat_randomizer', 'kern') 64 +else 65 + conf.feat.randomizer = default('parsav_feat_randomizer', 'libc') 66 +end 20 67 68 +local choplib = function(l) 69 + if string.sub(l,1,3) == 'lib' then return string.sub(l,4) end 70 + return l 71 +end 21 72 local fallback = dofile('pkgdata.lua') 22 73 local libfind do local mkf = function(p) 23 74 return function(l) return string.format(p,l) end 24 75 end 25 76 local unx = function(p) 26 77 return function(l) 27 78 if string.sub(l,1,3) == 'lib' ................................................................................ 28 79 then return string.format('%s.%s',l,p) 29 80 else return string.format('lib%s.%s',l,p) 30 81 end 31 82 end 32 83 end 33 84 34 85 libfind = { 35 - linux = { 36 - static = unx 'a'; 37 - dynamic = unx 'so'; 38 - }; 39 - osx = { dynamic = mkf '%s.dylib'; }; 40 - win = { dynamic = mkf '%s.dll'; }; 86 + linux = { static = unx 'a', dynamic = unx 'so'; }; 87 + osx = { dynamic = mkf '%s.dylib'; }; 88 + win = { dynamic = mkf '%s.dll'; }; 41 89 } 42 90 end 43 91 local pkg = function(name) 44 - local fbo = fallback[name] and fallback[name].osvars 45 - and fallback[name].osvars[conf.os .. '_' .. conf.dist] 92 + local fbo = fallback[name] and fallback[name].osvars and coalesce( 93 + fallback[name].osvars[conf.os .. '_' .. conf.dist], 94 + fallback[name].osvars[conf.os] 95 + ) 46 96 local fbv = fallback[name] and fallback[name].vars 97 + local fb = fallback[name] 47 98 local pkgenv = function(e) 48 99 return os.getenv(string.format('parsav_pkg_%s_%s',name,e)) 49 100 end 50 - name = pkgenv('override') or name 51 101 local nul = function() end 52 102 local pkc, pkv = nul, nul 103 + local locdep = false 53 104 local cnfvar = function(v,e) 54 105 local eval = function(e) 55 106 if type(e) == 'function' 56 107 then return e(conf) 57 108 else return e 58 109 end 59 110 end 60 - return pkgenv(v) or pkv(e or v) or (fbo and eval(fbo[v])) or (fbv and eval(fbv[v])) 111 + return coalesce( 112 + pkgenv(v), 113 + pkv(e or v), 114 + (fbo and eval(fbo[v])), 115 + (fbv and eval(fbv[v]))) 61 116 end 117 + local name = cnfvar('override') or name 118 + local pcname = coalesce(cnfvar('pcname'), name) 62 119 if conf.posix then 63 - pkc = function(...) return u.exec { 'pkg-config'; name; ... } end 64 - local pkcv = function(...) return u.exec({ 'pkg-config'; name; ... }, true) end 120 + pkc = function(...) if locdep then return nil end 121 + return u.exec { 'pkg-config'; pcname; ... } end 122 + local pkcv = function(...) return u.exec({ 'pkg-config'; pcname; ... }, true) end 65 123 if pkcv('--exists') == 0 then 66 - pkv = function(v) 124 + pkv = function(v) 125 + if locdep then return nil end 67 126 return pkc('--variable', v) 68 127 end 69 128 else pkc = nul end 70 129 else 71 130 print '(warn) configuring on non-POSIX OS, all relevant paths must be specified manually in environment variables or build will fail!' 72 131 end 73 - local locdep = u.ping('./lib/' .. name) 74 - local prefix 132 + locdep = u.ping('./lib/' .. name) 133 + local incdir, libdir, prefix 75 134 if locdep then 76 135 prefix = './lib/' .. name 77 - end 78 - prefix = prefix or cnfvar('prefix') 79 - local libdir = cnfvar('libdir') 80 - if not libdir then 81 - if locdep 82 - then libdir = prefix .. (cnfvar('builddir') or cnfvar('libbuilddir')) or '' 83 - else libdir = prefix .. '/lib' 84 - end 136 + libdir = prefix .. coalesce(cnfvar('libbuilddir'),cnfvar('builddir'),'') 137 + incdir = prefix .. coalesce(cnfvar('srcincdir'),cnfvar('builddir'),'/include') 138 + else 139 + prefix = coalesce(cnfvar('prefix'), '/usr') 140 + libdir = cnfvar('libdir') 141 + incdir = cnfvar('incdir','includedir') 85 142 end 86 - local incdir = cnfvar('incdir','includedir') or (prefix .. '/include') 143 + libdir = libdir or prefix .. '/lib' 144 + incdir = incdir or prefix .. '/include' 145 + 87 146 local libstr = pkc '--libs-only-l' -- (--static is not reliable) 88 - local libs = fallback[name] and fallback[name].libs or {} 147 + local libs = fb and fb.libs or {} 89 148 local linkstatic = locdep 90 149 if (not locdep) and libstr then 91 150 libs = {} 92 151 for m in string.gmatch(libstr, '-l(%g+)') do 93 152 libs[#libs + 1] = m 94 153 end 95 154 else ................................................................................ 112 171 local ldf = {} 113 172 for _,v in pairs(me.statlibs) do 114 173 local fl = libdir .. '/' .. v 115 174 if u.ping(fl) then ldf[#ldf+1] = fl end 116 175 end 117 176 me.linkargs = ldf 118 177 else 119 - local arg = name 120 - if string.sub(arg,1,3) == 'lib' then arg = string.sub(arg,4) end 121 - local linkline = libstr or string.format('-l%s', arg) 178 + local arg = choplib(name) 179 + local linkline = libstr 180 + if not linkline and #libs == 0 then 181 + linkline = string.format('-l%s', arg) 182 + elseif not linkline then linkline = '' end 122 183 me.linkargs = { 123 184 string.format('-L%s', me.libdir); 124 185 } 125 186 for m in string.gmatch(linkline, '(%g+)') do 126 187 me.linkargs[#me.linkargs+1] = m 127 188 end 128 189 129 190 -- siiiiigh 130 191 for _,l in pairs(libs) do 131 - local sw = string.format('-l%s', l) 192 + local sw = string.format('-l%s', choplib(l)) 132 193 local found = false 133 194 for _,a in pairs(me.linkargs) do 134 195 if a == sw then found = true break end 135 196 end 136 197 if not found then 137 198 me.linkargs[#me.linkargs+1] = sw 138 199 end 139 200 end 140 201 end 141 202 end 142 203 143 204 pkg('mbedtls') 144 -pkg('libhttp') 205 +pkg('mongoose') 145 206 pkg('json-c') 207 +pkg('libc') 208 +pkg('libpq') 146 209 147 210 return conf
Added crypt.t version [340864c560].
1 +-- vim: ft=terra 2 +local const = { 3 + keybits = 2048; 4 + sighash = lib.md.MBEDTLS_MD_SHA256; 5 +} 6 +local err = { 7 + rawcode = terra(code: int) 8 + if code < 0 then code = -code end 9 + return code and 0xFF80 10 + end; 11 + toobig = -lib.pk.MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; 12 +} 13 +const.maxpemsz = math.floor((const.keybits / 8)*6.4) + 128 -- idk why this formula works but it basically seems to 14 + 15 +local ctx = lib.pk.mbedtls_pk_context 16 + 17 +local m = { 18 + pemfile = uint8[const.maxpemsz]; 19 +} 20 +local callbacks = {} 21 +if config.feat.randomizer == 'kern' then 22 + local rnd = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff); 23 + terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int 24 + return rnd(dest, sz, 0) 25 + end 26 +elseif config.feat.randomizer == 'devfs' then 27 + terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int 28 + var gen = lib.io.open("/dev/urandom",0) 29 + lib.io.read(gen, dest, sz) 30 + lib.io.close(gen) 31 + return sz 32 + end 33 +elseif config.feat.randomizer == 'libc' then 34 + local rnd = terralib.externfunction('rand', {} -> int); 35 + local srnd = terralib.externfunction('srand', uint -> int); 36 + local time = terralib.includec 'time.h' 37 + lib.init[#lib.init + 1] = quote srnd(time.time(nil)) end 38 + print '(warn) using libc soft-rand function for cryptographic purposes, this is very bad!' 39 + terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int 40 + for i=0,sz do dest[i] = [uint8](rnd()) end 41 + return sz 42 + end 43 +end 44 + 45 +terra m.pem(pub: bool, key: &ctx, buf: &uint8): bool 46 + if pub then 47 + return lib.pk.mbedtls_pk_write_pubkey_pem(key, buf, const.maxpemsz) == 0 48 + else 49 + return lib.pk.mbedtls_pk_write_key_pem(key, buf, const.maxpemsz) == 0 50 + end 51 +end 52 + 53 +m.destroy = lib.dispatch { 54 + [ctx] = function(v) return `lib.pk.mbedtls_pk_free(&v) end; 55 + 56 + [false] = function(ptr) return `ptr:free() end; 57 +} 58 + 59 +terra m.genkp(): lib.pk.mbedtls_pk_context 60 + lib.dbg('generating new keypair') 61 + 62 + var pk: ctx 63 + lib.pk.mbedtls_pk_init(&pk) 64 + lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA)) 65 + var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx) 66 + lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, const.keybits, 65537) 67 + 68 + return pk 69 +end 70 + 71 +terra m.loadpriv(buf: &uint8, len: intptr): ctx 72 + lib.dbg('parsing saved keypair') 73 + 74 + var pk: ctx 75 + lib.pk.mbedtls_pk_init(&pk) 76 + lib.pk.mbedtls_pk_parse_key(&pk, buf, len + 1, nil, 0) 77 + return pk 78 +end 79 + 80 +terra m.sign(pk: &ctx, txt: rawstring, len: intptr) 81 + lib.dbg('signing message') 82 + var osz: intptr = 0 83 + var sig = lib.mem.heapa(int8, 2048) 84 + var hash: uint8[32] 85 + 86 + lib.dbg('(1/2) hashing message') 87 + if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(const.sighash), [&uint8](txt), len, hash) ~= 0 then 88 + lib.bail('could not hash message') 89 + end 90 + 91 + lib.dbg('(2/2) signing hash') 92 + var ret = lib.pk.mbedtls_pk_sign(pk, const.sighash, hash, 0, [&uint8](sig.ptr), &osz, callbacks.randomize, nil) 93 + if ret ~= 0 then lib.bail('could not sign message hash') 94 + else sig:resize(osz) end 95 + 96 + return sig 97 +end 98 + 99 +terra m.verify(pk: &ctx, txt: rawstring, len: intptr, 100 + sig: rawstring, siglen: intptr): {bool, uint8} 101 + lib.dbg('verifying signature') 102 + var osz: intptr = 0 103 + var hash: uint8[64] 104 + 105 + -- there does not appear to be any way to extract the hash algorithm 106 + -- from the message, so we just have to try likely algorithms until 107 + -- we find one that fits or give up. a security level is attached 108 + -- to indicate our relative confidence in the hash; 0 == 'likely forgeable' 109 + var algs = array( 110 + -- common hashes 111 + {lib.md.MBEDTLS_MD_SHA256, 'sha256', 2}, 112 + {lib.md.MBEDTLS_MD_SHA512, 'sha512', 3}, 113 + {lib.md.MBEDTLS_MD_SHA1, 'sha1', 1}, 114 + -- uncommon hashes 115 + {lib.md.MBEDTLS_MD_SHA384, 'sha384', 2}, 116 + {lib.md.MBEDTLS_MD_SHA224, 'sha224', 2}, 117 + -- bad hashes 118 + {lib.md.MBEDTLS_MD_MD5, 'md5', 0}, 119 + {lib.md.MBEDTLS_MD_MD4, 'md4', 0}, 120 + {lib.md.MBEDTLS_MD_MD2, 'md2', 0} 121 + ) 122 + 123 + for i = 0, [algs.type.N] do 124 + var hk, aname, secl = algs[i] 125 + 126 + lib.dbg('(1/2) trying hash algorithm ',aname) 127 + if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(hk), [&uint8](txt), len, hash) ~= 0 then 128 + lib.bail('could not hash message') 129 + end 130 + 131 + lib.dbg('(2/2) verifying hash') 132 + if lib.pk.mbedtls_pk_verify(pk, hk, hash, 0, [&uint8](sig), siglen) == 0 then 133 + return true, secl 134 + end 135 + end 136 + lib.dbg('all hash algorithms failed') 137 + return false, 0 138 +end 139 + 140 +return m
Added http.t version [6d6c40fc94].
1 +-- vim: ft=terra 2 +local m = {} 3 +local util = dofile('common.lua') 4 + 5 +struct m.header { 6 + key: rawstring 7 + value: rawstring 8 +} 9 +struct m.page { 10 + respcode: uint16 11 + body: lib.mem.ptr(int8) 12 + headers: lib.mem.ptr(m.header) 13 +} 14 + 15 +local resps = { 16 + [200] = 'OK'; 17 + [201] = 'Created'; 18 + [301] = 'Moved Permanently'; 19 + [302] = 'Found'; 20 + [303] = 'See Other'; 21 + [307] = 'Temporary Redirect'; 22 + [404] = 'Not Found'; 23 + [401] = 'Unauthorized'; 24 + [403] = 'Forbidden'; 25 + [418] = 'I\'m a teapot'; 26 + [405] = 'Method Not Allowed'; 27 + [500] = 'Internal Server Error'; 28 +} 29 +local resptext = symbol(rawstring) 30 +local resplen = symbol(intptr) 31 +local respbranches = {} 32 +for k,v in pairs(resps) do 33 + local txt = string.format('%u %s\r\n',k,v) 34 + respbranches[#respbranches + 1] = quote 35 + case [uint16](k) then resptext = [txt] resplen = [#txt] end 36 + end 37 +end 38 +m.codestr = terra(code: uint16) 39 + var [resptext] var [resplen] 40 + switch code do [respbranches] end 41 + return resptext, resplen 42 +end 43 +m.page.methods = { 44 + free = terra(self: &m.page) 45 + self.body:free() 46 + self.headers:free() 47 + end; 48 + send = terra(self: &m.page, con: &lib.net.mg_connection) 49 + var code: rawstring 50 + var [resptext] var [resplen] 51 + switch self.respcode do [respbranches] end 52 + lib.net.mg_send(con, "HTTP/1.1 ", 9) 53 + lib.net.mg_send(con, resptext, resplen) 54 + for i = 0, self.headers.ct do 55 + var h = self.headers.ptr[i] 56 + lib.net.mg_send(con, h.key, lib.str.sz(h.key)) 57 + lib.net.mg_send(con, ": ", 2) 58 + lib.net.mg_send(con, h.value, lib.str.sz(h.value)) 59 + lib.net.mg_send(con, "\r\n", 2) 60 + end 61 + lib.net.mg_printf(con, 'Content-Length: %llu\r\n\r\n', self.body.ct) 62 + lib.net.mg_send(con,self.body.ptr,self.body.ct) 63 + end; 64 +} 65 +return m
Modified makefile from [b49975ddb0] to [0f98e9b572].
5 5 terra $(dbg-flags) $< 6 6 parsav.o: parsav.t config.lua pkgdata.lua 7 7 env parsav_link=no terra $(dbg-flags) $< 8 8 9 9 clean: 10 10 rm parsav parsav.o 11 11 12 -dep: dep.mbedtls dep.libhttp dep.json-c 12 +install: parsav 13 + mkdir $(prefix)/bin 14 + cp $< $(prefix)/bin/ 15 + 16 +dep: dep.mbedtls dep.mongoose dep.json-c 13 17 dep.mbedtls: lib/mbedtls/library/libmbedtls.a \ 14 18 lib/mbedtls/library/libmbedcrypto.a \ 15 19 lib/mbedtls/library/libmbedx509.a 16 -dep.libhttp: lib/libhttp/lib/libhttp.a 17 -dep.json-c: lib/libhttp/json-c.a 20 +dep.mongoose: lib/mongoose/libmongoose.a 21 +dep.json-c: lib/json-c/libjson-c.a 18 22 19 23 lib: 20 24 mkdir $@ 21 25 # parsav is designed to be fronted by a real web 22 26 # server like nginx if SSL is to be used 23 -# caveat: libhttp is a mess. the docs are completely 24 -# full of shit. there is no lua support as far as i 25 -# can tell. 26 -lib/libhttp/lib/libhttp.a: lib/libhttp 27 - $(MAKE) -C $< lib/libhttp.a \ 28 - RM='rm -f' \ 29 - CC="$(CC) -Wno-unused-result" \ 30 - DFLAGS="-DNO_SSL -DNO_FILES -DNO_CGI -DUSE_STACK_SIZE=102400 -DUSE_IPV6" 27 +# generate a shim static library so mongoose cooperates 28 +# with the build apparatus 29 +lib/mongoose/libmongoose.a: lib/mongoose lib/mongoose/mongoose.c lib/mongoose/mongoose.h 30 + $(CC) -c $</mongoose.c -o lib/mongoose/mongoose.o \ 31 + -DMG_ENABLE_THREADS \ 32 + -DMG_ENABLE_IPV6 \ 33 + -DMG_ENABLE_HTTP_WEBDAV \ 34 + -DMG_ENABLE_HTTP_WEBSOCKET=0 35 + ar rcs $@ lib/mongoose/*.o 36 + ranlib $@ 31 37 32 38 lib/json-c/Makefile: lib/json-c lib/json-c/CMakeLists.txt 33 39 cd lib/json-c && cmake . 34 40 lib/json-c/libjson-c.a: lib/json-c/Makefile 35 41 $(MAKE) -C lib/json-c 36 42 lib/mbedtls/library/%.a: lib/mbedtls 37 43 $(MAKE) -C lib/mbedtls/library $*.a 38 44 39 45 ifeq ($(dl), git) 40 -lib/libhttp: lib 41 - cd lib && git clone https://github.com/lammertb/libhttp.git 46 +lib/mongoose: lib 47 + cd lib && git clone https://github.com/cesanta/mongoose 42 48 lib/mbedtls: lib 43 49 cd lib && git clone https://github.com/ARMmbed/mbedtls.git 44 50 lib/json-c: lib 45 51 cd lib && git clone https://github.com/json-c/json-c.git 46 52 else 47 53 lib/%: lib/%.tar.gz 48 54 cd lib && tar zxf $*.tar.gz ................................................................................ 52 58 dlfile = wget "$(1)" -O "$(2)" 53 59 endif 54 60 55 61 ifeq ($(dl), curl) 56 62 dlfile = curl "$(1)" -o "$(2)" 57 63 endif 58 64 59 -lib/libhttp.tar.gz: lib 60 - $(call dlfile,https://api.github.com/repos/lammertb/libhttp/tarball/master,$@) 65 +lib/mongoose.tar.gz: lib 66 + $(call dlfile,https://api.github.com/repos/cesanta/mongoose/tarball/master,$@) 61 67 lib/mbedtls.tar.gz: lib 62 68 $(call dlfile,https://api.github.com/repos/ARMmbed/mbedtls/tarball/master,$@) 63 69 lib/json-c.tar.gz: lib 64 70 $(call dlfile,https://api.github.com/repos/json-c/json-c/tarball/master,$@) 65 71 endif
Modified parsav.t from [d2f35b212c] to [889180c92d].
1 1 -- vim: ft=terra 2 2 3 3 local util = dofile('common.lua') 4 4 local buildopts, buildargs = util.parseargs{...} 5 +config = dofile('config.lua') 5 6 6 -local config = dofile('config.lua') 7 - 8 -local lib = { 7 +lib = { 8 + init = {}; 9 9 loadlib = function(name,hdr) 10 10 local p = config.pkg[name] 11 11 -- for _,v in pairs(p.dylibs) do 12 12 -- terralib.linklibrary(p.libdir .. '/' .. v) 13 13 -- end 14 14 return terralib.includec(p.incdir .. '/' .. hdr) 15 15 end; 16 - randomize = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff); 16 + dispatch = function(tbl) 17 + return macro(function(v,...) 18 + for ty,fn in pairs(tbl) do 19 + if v.tree.type == ty then return fn(v,...) end 20 + end 21 + return (tbl[false])(v,...) 22 + end) 23 + end; 24 + emit = function(...) 25 + local code = {} 26 + for i,v in ipairs{...} do 27 + if type(v) == 'string' or type(v) == 'number' then 28 + local str = tostring(v) 29 + code[#code+1] = `lib.io.send(2, str, [#str]) 30 + elseif v.tree:is 'constant' then 31 + local str = tostring(v:asvalue()) 32 + code[#code+1] = `lib.io.send(2, str, [#str]) 33 + else 34 + code[#code+1] = quote var n = v in 35 + lib.io.send(2, n, lib.str.sz(n)) end 36 + end 37 + end 38 + code[#code+1] = `lib.io.send(2, '\n', 1) 39 + return code 40 + end; 41 + proc = { 42 + exit = terralib.externfunction('exit', int -> {}); 43 + getenv = terralib.externfunction('getenv', rawstring -> rawstring); 44 + }; 45 + io = { 46 + open = terralib.externfunction('open', {rawstring, int} -> int); 47 + close = terralib.externfunction('close', {int} -> int); 48 + send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff); 49 + recv = terralib.externfunction('read', {int, rawstring, intptr} -> ptrdiff); 50 + say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end); 51 + fmt = terralib.externfunction('printf', 52 + terralib.types.funcpointer({rawstring},{int},true)); 53 + }; 54 + str = { 55 + sz = terralib.externfunction('strlen', rawstring -> intptr); 56 + cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int); 57 + cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring); 58 + ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring); 59 + fmt = terralib.externfunction('asprintf', 60 + terralib.types.funcpointer({&rawstring},{int},true)); 61 + }; 62 + mem = { 63 + zero = macro(function(r) 64 + return quote 65 + for i = 0, [r.tree.type.N] do r[i] = 0 end 66 + end 67 + end); 68 + heapa_raw = terralib.externfunction('malloc', intptr -> &opaque); 69 + heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque); 70 + heapf = terralib.externfunction('free', &opaque -> {}); 71 + cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque); 72 + heapa = macro(function(ty, sz) 73 + local p = lib.mem.ptr(ty:astype()) 74 + return `p { 75 + ptr = [&ty:astype()](lib.mem.heapa_raw(sizeof(ty) * sz)); 76 + ct = sz; 77 + } 78 + end) 79 + }; 17 80 } 81 + 82 +local noise = global(uint8,1) 83 +local defrep = function(level,n,code) 84 + return macro(function(...) 85 + local q = lib.emit("\27["..code..";1m(parsav "..n..")\27[m ", ...) 86 + return quote 87 + if noise >= level then [q] end 88 + end 89 + end); 90 +end 91 +lib.dbg = defrep(3,'debug', '32') 92 +lib.report = defrep(2,'info', '35') 93 +lib.warn = defrep(1,'warn', '33') 94 +lib.bail = macro(function(...) 95 + local q = lib.emit("\27[31;1m(parsav fatal)\27[m ", ...) 96 + return quote 97 + [q] 98 + lib.proc.exit(1) 99 + end 100 +end); 101 +lib.mem.ptr = terralib.memoize(function(ty) 102 + local t = terralib.types.newstruct(string.format('ptr<%s>', ty)) 103 + t.entries = { 104 + {'ptr', &ty}; 105 + {'ct', intptr}; 106 + } 107 + local recurse = false 108 + if ty:isstruct() then 109 + if ty.methods.free then recurse = true end 110 + end 111 + t.methods = { 112 + free = terra(self: &t): bool 113 + [recurse and quote 114 + self.ptr:free() 115 + end or {}] 116 + if self.ct > 0 then 117 + lib.mem.heapf(self.ptr) 118 + self.ct = 0 119 + return true 120 + end 121 + return false 122 + end; 123 + init = terra(self: &t, newct: intptr): bool 124 + var nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct)) 125 + if nv ~= nil then 126 + self.ptr = nv 127 + self.ct = newct 128 + return true 129 + else return false end 130 + end; 131 + resize = terra(self: &t, newct: intptr): bool 132 + var nv: &ty 133 + if self.ct > 0 134 + then nv = [&ty](lib.mem.heapr_raw(self.ptr, sizeof(ty) * newct)) 135 + else nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct)) 136 + end 137 + if nv ~= nil then 138 + self.ptr = nv 139 + self.ct = newct 140 + return true 141 + else return false end 142 + end; 143 + } 144 + return t 145 +end) 146 + 147 +lib.err = lib.loadlib('mbedtls','mbedtls/error.h') 18 148 lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h') 19 149 lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h') 150 +lib.md = lib.loadlib('mbedtls','mbedtls/md.h') 151 +lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h') 152 +lib.net = lib.loadlib('mongoose','mongoose.h') 153 +lib.pq = lib.loadlib('libpq','libpq-fe.h') 154 +lib.crypt = terralib.loadfile('crypt.t')() 155 +lib.http = terralib.loadfile('http.t')() 156 +lib.tpl = terralib.loadfile('tpl.t')() 157 +lib.string = terralib.loadfile('string.t')() 158 +lib.store = terralib.loadfile('store.t')() 159 +lib.cmdparse = terralib.loadfile('cmdparse.t')() 20 160 21 -local callbacks = { 22 - randomize = terra(ctx: &opaque, dest: &uint8, sz: intptr): int 23 - return lib.randomize(dest, sz, 0) 161 +do local collate = function(path,f, ...) 162 + return loadfile(path..'/'..f..'.lua')(path, ...) 163 +end 164 +data = { 165 + view = collate('view','load'); 166 +} end 167 + 168 +-- slightly silly -- because we're using plain lua to gather up 169 +-- the template sources, they have to be actually turned into 170 +-- templates in the terra code, so we "mutate" them here 171 +for k,v in pairs(data.view) do 172 + local t = lib.tpl.mk { body = v, id = 'view/'..k } 173 + data.view[k] = t 174 +end 175 + 176 +local pemdump = macro(function(pub, kp) 177 + local msg = (pub:asvalue() and ' * emitting public key\n') or ' * emitting private key\n' 178 + return quote 179 + var buf: lib.crypt.pemfile 180 + lib.mem.zero(buf) 181 + lib.crypt.pem(pub, &kp, buf) 182 + lib.io.send(1, msg, [#msg]) 183 + lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf))) 184 + lib.io.send(1, '\n', 1) 185 + end 186 +end) 187 + 188 +local handle = { 189 + http = terra(con: &lib.net.mg_connection, event: int, p: &opaque, ext: &opaque) 190 + switch event do 191 + case lib.net.MG_EV_HTTP_MSG then 192 + lib.dbg('routing HTTP request') 193 + var msg = [&lib.net.mg_http_message](p) 194 + 195 + end 196 + end 24 197 end; 25 198 } 199 +do 200 + local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when) 201 + terra version() lib.io.send(1, p, [#p]) end 202 +end 203 +terra noise_init() 204 + var n = lib.proc.getenv('parsav_noise') 205 + if n ~= nil then 206 + if n[0] >= 0x30 and n[0] <= 0x39 and n[1] == 0 then 207 + noise = n[0] - 0x30 208 + return 209 + end 210 + end 211 + noise = 1 212 +end 213 + 214 +local options = lib.cmdparse { 215 + version = {'V', 'display information about the binary build and exit'}; 216 + quiet = {'q', 'do not print to standard out'}; 217 + help = {'h', 'display this list'} 218 +} 219 + 220 +terra entry(argc: int, argv: &rawstring): int 221 + noise_init() 222 + [lib.init] 223 + 224 + var mode: options 225 + mode:parse(argc,argv) 226 + if mode.version then 227 + version() 228 + return 0 229 + end 230 + if mode.help then 231 + lib.io.send(1, [options.helptxt], [#options.helptxt]) 232 + return 0 233 + end 234 + 235 + var bind = lib.proc.getenv('parsav_bind') 236 + if bind == nil then bind = '[::]:10917' end 237 + 238 + var nm: lib.net.mg_mgr 239 + lib.net.mg_mgr_init(&nm) 240 + 241 + var nmc = lib.net.mg_http_listen(&nm, bind, handle.http, nil) 242 + 243 + while true do 244 + lib.net.mg_mgr_poll(&nm,1000) 245 + end 26 246 27 -terra entry(): int 28 - var pk: lib.pk.mbedtls_pk_context 29 - lib.pk.mbedtls_pk_init(&pk) 30 - lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA)) 31 - var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx) 32 - lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, 2048, 65537) 247 + lib.net.mg_mgr_free(&nm) 33 248 return 0 34 249 end 35 250 36 251 local bflag = function(long,short) 37 252 if short and util.has(buildopts, short) then return true end 38 253 if long and util.has(buildopts, long) then return true end 39 254 return false ................................................................................ 45 260 end 46 261 47 262 local emit = print 48 263 if bflag('quiet','q') then emit = function() end end 49 264 50 265 local out = config.exe and 'parsav' or 'parsav.o' 51 266 local linkargs = {} 267 +if config.posix then 268 + linkargs[#linkargs+1] = '-pthread' 269 +end 52 270 for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end 53 271 emit('linking with args',util.dump(linkargs)) 54 272 terralib.saveobj(out, { 55 273 main = entry 56 274 }, 57 275 linkargs, 58 276 config.tgttrip and terralib.newtarget { 59 277 Triple = config.tgttrip; 60 278 CPU = config.tgtcpu; 61 279 FloatABIHard = config.tgthf; 62 280 } or nil)
Modified pkgdata.lua from [b4c0388029] to [8c50f1b4b0].
1 1 local util = dofile('common.lua') 2 2 local sthunk = function(...) local a = {...} return function() return util.exec(a) end end 3 + 3 4 return { 4 5 mbedtls = { 5 6 libs = {'mbedtls', 'mbedcrypto', 'mbedx509'}; 6 7 osvars = { 7 8 linux_nixos = { -- lacks a *.pc on nixos systems 8 9 prefix = sthunk('nix', 'path-info', 'nixos.mbedtls'); 9 10 } 10 11 }; 11 12 vars = { builddir = '/library' }; 12 13 }; 13 - libhttp = { vars = { builddir = '/lib' }; }; 14 + mongoose = { vars = { builddir = '' } }; 15 + libpq = { 16 + osvars = { 17 + linux_nixos = { 18 + prefix = sthunk('nix', 'path-info', 'nixos.postgresql.lib'); 19 + incdir = function() 20 + local a = {'nix', 'path-info', 'nixos.postgresql'} 21 + return (util.exec(a)) .. '/include'; 22 + end; 23 + }; 24 + }; 25 + vars = {pcname = 'postgresql';} 26 + }; 27 + libc = { 28 + libs = {'dl'}; -- libc.so does not need explicit mention 29 + osvars = { 30 + linux_nixos = { 31 + prefix = sthunk('nix', 'path-info', 'nixos.glibc'); 32 + override = 'glibc'; 33 + }; 34 + linux = { override = 'glibc'; }; 35 + } 36 + }; 14 37 }
Added store.t version [a0814e5c61].
1 +-- vim: ft=terra 2 +local m = {} 3 + 4 +local backend = { 5 + pgsql = { 6 + }; 7 +} 8 + 9 +struct m.user { 10 + uid: rawstring 11 + nym: rawstring 12 + handle: rawstring 13 + 14 + localuser: bool 15 +}
Added string.t version [a0d1de486b].
1 +-- vim: ft=terra 2 +-- string.t: string classes 3 + 4 +local m = {} 5 + 6 +struct m.acc { 7 + buf: rawstring 8 + sz: intptr 9 + run: intptr 10 + space: intptr 11 +} 12 + 13 +local terra biggest(a: intptr, b: intptr) 14 + if a > b then return a else return b end 15 +end 16 + 17 +m.acc.methods = { 18 + init = terra(self: &m.acc, run: intptr) 19 + lib.dbg('initializing string accumulator') 20 + self.buf = [rawstring](lib.mem.heapa_raw(run)) 21 + self.run = run 22 + self.space = run 23 + self.sz = 0 24 + end; 25 + free = terra(self: &m.acc) 26 + lib.dbg('freeing string accumulator') 27 + if self.buf ~= nil and self.space > 0 then 28 + lib.mem.heapf(self.buf) 29 + end 30 + end; 31 + crush = terra(self: &m.acc) 32 + lib.dbg('crushing string accumulator') 33 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz)) 34 + self.space = self.sz 35 + return self 36 + end; 37 +} 38 + 39 +m.acc.methods.finalize = terra(self: &m.acc) 40 + lib.dbg('finalizing string accumulator') 41 + self:crush() 42 + var pt: lib.mem.ptr(int8) 43 + pt.ptr = self.buf 44 + pt.ct = self.sz 45 + self.buf = nil 46 + self.sz = 0 47 + return pt 48 +end; 49 +m.acc.methods.push = terra(self: &m.acc, str: rawstring, len: intptr) 50 + lib.dbg('pushing "',str,'" onto accumulator') 51 + if self.buf == nil then self:init(self.run) end 52 + if len == 0 then len = lib.str.sz(str) end 53 + if len >= self.space - self.sz then 54 + self.space = self.space + biggest(self.run,len + 1) 55 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 56 + end 57 + lib.mem.cpy(self.buf + self.sz, str, len) 58 + self.sz = self.sz + len 59 + self.buf[self.sz] = 0 60 + return self 61 +end; 62 +m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8)) 63 + self:push(str.ptr, str.ct) return self end; 64 +m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8)) 65 + self:push(str.ptr, str.ct) str:free() return self end; 66 + 67 +return m
Added tpl.t version [ad44dd6129].
1 +-- vim: ft=terra 2 +-- string template generator: 3 +-- returns a function that fills out a template 4 +-- with the strings given 5 + 6 +local util = dofile 'common.lua' 7 +local m = {} 8 +function m.mk(tplspec) 9 + local str 10 + if type(tplspec) == 'string' 11 + then str = tplspec tplspec = {} 12 + else str = tplspec.body 13 + end 14 + local tplchar_o = tplspec.sigil or '@' 15 + local tplchar = tplchar_o 16 + local magic = { 17 + ['%'] = true, ['$'] = true, ['^'] = true; 18 + ['.'] = true, ['*'] = true, ['+'] = true; 19 + ['-'] = true, ['?'] = true; 20 + } 21 + tplchar_o = string.gsub(tplchar_o,'%%','%%%%') 22 + tplchar = string.gsub(tplchar, '.', function(c) 23 + if magic[c] then return '%' .. c end 24 + end) 25 + local last = 1 26 + local fields = {} 27 + local segs = {} 28 + local constlen = 0 29 + -- strip out all irrelevant whitespace to tidy things up 30 + -- TODO: find way to exclude <pre> tags? 31 + str = str:gsub('[\n^]%s+','') 32 + str = str:gsub('%s+[\n$]','') 33 + str = str:gsub('\n','') 34 + for start, key, stop in string.gmatch(str,'()'..tplchar..'(%w+)()') do 35 + if string.sub(str,start-1,start-1) ~= '\\' then 36 + segs[#segs+1] = string.sub(str,last,start-1) 37 + fields[#segs] = key 38 + last = stop 39 + end 40 + end 41 + segs[#segs+1] = string.sub(str,last) 42 + for i, s in ipairs(segs) do 43 + segs[i] = string.gsub(s, '\\'..tplchar, tplchar_o) 44 + constlen = constlen + string.len(segs[i]) 45 + end 46 + 47 + local runningtally = symbol(intptr) 48 + local tallyup = {quote 49 + var [runningtally] = 1 + constlen 50 + end} 51 + local rec = terralib.types.newstruct(string.format('template<%s>',tplspec.id or '')) 52 + local symself = symbol(&rec) 53 + do local kfac = {} 54 + for afterseg,key in pairs(fields) do 55 + if not kfac[key] then 56 + rec.entries[#rec.entries + 1] = { 57 + field = key; 58 + type = rawstring; 59 + } 60 + end 61 + kfac[key] = (kfac[key] or 0) + 1 62 + end 63 + for key, fac in pairs(kfac) do 64 + tallyup[#tallyup + 1] = quote 65 + [runningtally] = [runningtally] + lib.str.sz([symself].[key])*fac 66 + end 67 + end 68 + end 69 + 70 + local copiers = {} 71 + local senders = {} 72 + local symtxt = symbol(lib.mem.ptr(int8)) 73 + local cpypos = symbol(&opaque) 74 + local destcon = symbol(&lib.net.mg_connection) 75 + for idx, seg in ipairs(segs) do 76 + copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end 77 + senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end 78 + if fields[idx] then 79 + copiers[#copiers+1] = quote 80 + [cpypos] = lib.mem.cpy([cpypos], 81 + [&opaque](symself.[fields[idx]]), 82 + lib.str.sz(symself.[fields[idx]])) 83 + end 84 + senders[#senders+1] = quote 85 + lib.net.mg_send([destcon], 86 + symself.[fields[idx]], 87 + lib.str.sz(symself.[fields[idx]])) 88 + end 89 + end 90 + end 91 + 92 + local tid = tplspec.id or '<anonymous>' 93 + rec.methods.tostr = terra([symself]) 94 + lib.dbg(['compiling template ' .. tid]) 95 + [tallyup] 96 + var [symtxt] = lib.mem.heapa(int8, [runningtally]) 97 + var [cpypos] = [&opaque](symtxt.ptr) 98 + [copiers] 99 + @[&int8](cpypos) = 0 100 + return symtxt 101 + end 102 + rec.methods.send = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header)) 103 + lib.dbg(['transmitting template ' .. tid]) 104 + [tallyup] 105 + lib.net.mg_printf([destcon], 'HTTP/1.1 %s', lib.http.codestr(code)) 106 + for i = 0, hd.ct do 107 + lib.net.mg_printf([destcon], '%s: %s\r\n', hd.ptr[i].key, hd.ptr[i].value) 108 + end 109 + lib.net.mg_printf([destcon],'Content-Length: %llu\r\n\r\n', [runningtally] + 1) 110 + [senders] 111 + lib.net.mg_send([destcon],'\r\n',2) 112 + end 113 + 114 + return rec 115 +end 116 + 117 +return m
Added view/docskel.tpl version [1d38dac966].
1 +<!doctype html> 2 +<html> 3 + <head> 4 + <title>@instance :: @title</title> 5 + <link rel="stylesheet" href="/style.css"> 6 + </head> 7 + <body> 8 + <h1>@title</h1> 9 + @body 10 + </body> 11 +</html>
Added view/load.lua version [f2a65d7b61].
1 +-- because lua can't scan directories, we need a 2 +-- file that indexes the templates manually, and 3 +-- copies them into a data structure we can then 4 +-- create templates from when we return to terra 5 +local path = ... 6 +local sources = { 7 + 'docskel'; 8 + 'tweet'; 9 +} 10 + 11 +local ingest = function(filename) 12 + local hnd = io.open(path..'/'..filename) 13 + local txt = hnd:read('*a') 14 + io.close(hnd) 15 + txt = txt:gsub('([^\\])!%b[]', '%1') 16 + txt = txt:gsub('([^\\])!!.-\n', '%1') 17 + txt = txt:gsub('\\(!%b[])', '%1') 18 + txt = txt:gsub('\\(!!)', '%1') 19 + return txt 20 +end 21 + 22 + 23 +local views = {} 24 +for _,n in pairs(sources) do views[n] = ingest(n .. '.tpl') end 25 +return views
Added view/tweet.tpl version [59ae4e4ad9].
1 +<div class="post"> 2 + <div class="detail"> 3 + <a class="username" href="@link"> 4 + <span class="nym">@nym</span> <span class="handle">[@handle]</span> 5 + </div> 6 + <div class="when">@when</div> 7 + </div> 8 + <div class="content"> 9 + <img class="avatar" src="@avatar"> 10 + <div class="text">@text</div> 11 + </div> 12 +</div>