cortav  Diff

Differences From Artifact [eb2c53bff4]:

To Artifact [aed49421db]:


1
2
3
4
5
6
7
8
9
10
11
12
13
...
473
474
475
476
477
478
479




















































480
481
482
483
484
485
486
....
1110
1111
1112
1113
1114
1115
1116













































































































































































































1117
1118
1119
1120
1121
1122
1123
-- [ʞ] sirsem.lua
--  ~ lexi hale <lexi@hale.su>
--    glowpelt (hsl conversion)
--  ? utility library with functionality common to
--    cortav.lua and its extensions
--    from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps
	local package = _G.package
	-- prevent namespace from being broken by env shenanigans
	local function namespace(name, tbl)
................................................................................
				bestmatch = k
				bestlen = #kt
			end
		end
	::skip::end
	return tbl[bestmatch] or tbl[true], bestmatch
end





















































ss.math = {}

function ss.math.lerp(t, a, b)
	return (1-t)*a + (t*b)
end

................................................................................
			-- versions at least can launch programs in a sane and secure
			-- way.
		else
			return s
		end
	end, ...))
end














































































































































































































ss.mime = ss.declare {
	ident = 'mime-type';
	mk = function() return {
		class = nil;
		kind = nil;
		opts = {};





|







 







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







 







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







1
2
3
4
5
6
7
8
9
10
11
12
13
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
....
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
-- [ʞ] sirsem.lua
--  ~ lexi hale <lexi@hale.su>
--    glowpelt (hsl conversion)
--  ? utility library with functionality common to
--    cortav.lua and its extensions
--  \ from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps
	local package = _G.package
	-- prevent namespace from being broken by env shenanigans
	local function namespace(name, tbl)
................................................................................
				bestmatch = k
				bestlen = #kt
			end
		end
	::skip::end
	return tbl[bestmatch] or tbl[true], bestmatch
end

function ss.str.b64e(str)
	local bytes = {}
	local n = 1
	for i=1, #str, 3 do
		local triple = {string.byte(str, i, i+2)}
		local T = function(q)
			return triple[q] or 0
		end
		local B = function(q)
		print(q)
			if q <= 25 then
				return string.char(0x41 + q)
			elseif q <= 51 then
				return string.char(0x61 + (q-26))
			elseif q <= 61 then
				return string.char(0x30 + (q-52))
			elseif q == 62 then
				return '+'
			elseif q == 63 then
				return '/'
			else error('base64 algorithm broken') end
		end
		local quads = {
			((T(1) & 0xFC) >> 2);
			((T(1) & 0x03) << 4) | ((T(2) & 0xF0) >> 4);
			((T(2) & 0x0F) << 2) | ((T(3) & 0xC0) >> 6);
			((T(3) & 0x3F));
		}

		bytes[n + 0] = B(quads[1])
		bytes[n + 1] = B(quads[2])
		if triple[2] then
			bytes[n + 2] = B(quads[3])
			if triple[3] then
				bytes[n + 3] = B(quads[4])
			else
				bytes[n + 3] = '='
			end
		else
			bytes[n + 2] = '='
			bytes[n + 3] = '='
		end

		n = n + 4
	end

	return table.concat(bytes)
end

function ss.str.b64d(str)
end

ss.math = {}

function ss.math.lerp(t, a, b)
	return (1-t)*a + (t*b)
end

................................................................................
			-- versions at least can launch programs in a sane and secure
			-- way.
		else
			return s
		end
	end, ...))
end

local fetchexn = ss.exnkind 'fetch'
local fetchableProtocols = {
	http = {
		proto = {
			{'http'};
			{'https'};
			{'http', 'tls'};
		};
		fetch = function(uri)
			fetchexn('cortav must be compiled with the C shim and libcurl support to use http fetch'):throw()
		end;
	};
	file = {
		proto = {
			{'file'};
			{'file', 'txt'};
			{'file', 'bin'};
			{'asset'};
			{'asset', 'txt'};
			{'asset', 'bin'};
		};
		fetch = function(uri, env)
			local assetDir = env.asset_base or '.'
			if uri.namespace then
				fetchexn('authority (hostname) segment is not supported in file: URIs'):throw()
			end
			if uri.svc then
				fetchexn('service segment is not supported in file: URIs'):throw()
			end
			local mode = 'r'
			local path = uri.path
			if uri.class[1] == 'asset' then path = assetDir ..'/'.. path end
			if uri.class[2] == 'bin'   then mode = 'rb' end
			local fd,e = io.open(path, mode)
			if not fd then
				fetchexn('IO error fetching URI “%s” (%s)', tostring(uri), e):throw()
			end
			local data = fd:read '*a'
			fd:close()
			return data
		end;
	};
}

function ss.match(a,b, eq)
	if #a ~= #b then return false end
	eq = eq or function(p,q) return p == q end
	for i = 1, #a do
		if not eq(a[i],b[i]) then return false end
	end
	return true
end

ss.uri = ss.declare {
	ident = 'uri';
	mk = function() return {
		class = nil;
		namespace = nil;
		path = nil;
		query = nil;
		frag = nil;
		auth = nil;
	} end;
	construct = function(me, str)
		local enc = ss.str.enc.utf8
		-- URIs must be either ASCII or utf8, so we  read and
		-- store as UTF8. to use a URI in another encoding, it
		-- must be manually converted to and fro using the
		-- appropriate functions, such as encodeUCS
		if not str then return end
		me.raw = str
		local rem = str
		local s_class do
			local s,r = rem:match '^([^:]+):(.*)$'
			s_class, rem = s,r
		end
		if not rem then
			ss.uri.exn('invalid URI “%s”', str):throw()
		end
		local s_ns do
			local s,r = rem:match '^//([^/]*)(.*)$'
			if s then s_ns, rem = s,r end
		end
		local h_query
		local s_frag
		local s_path if rem ~= '' then
			local s,q,r = rem:match '^([^?#]*)([?#]?)(.*)$'
			if s == '' then s = nil end
			s_path, rem = s,r

			if q == '#' then
				s_frag = rem
			elseif q == '?' then
				h_query = true
			end
		else s_path = '' end

		local s_query if h_query then
			local s,q,r = rem:match '^([^#]*)(#?)(.*)$'
			s_query, rem = s,r
			if q~='' then s_frag = rem end
		end

		local function dec(str)
			if not str then return end
			return str:gsub('%%([0-9A-Fa-f][0-9A-Fa-f])', function(hex)
				return string.char(tonumber(hex,16))
			end)
		end

		local s_auth if s_ns then
			local s,r = s_ns:match('^([^@]*)@(.*)$')
			if s then
				s_ns = r
				if s ~= '' then
					 s_auth = s
				end
			end
		end

		local s_svc if s_ns then
			local r,s = s_ns:match('^(.*):(.-)$')
			if r then
				s_ns = r
				if s and s ~= '' then
					s_svc = s
				end
			end
		end

		me.class = ss.str.split(enc, s_class, '+', {keep_empties=true})
		for i,v in ipairs(me.class) do me.class[i] = dec(v) end
		me.auth = dec(s_auth)
		me.svc = dec(s_svc)
		me.namespace = dec(s_ns)
		me.path = dec(s_path)
		me.query = dec(s_query)
		me.frag = dec(s_frag)
	end;
	cast = {
		string = function(me)
			local function san(str, chars)
				-- TODO IRI support
				chars = chars or ''
				local ptn = '-a-zA-Z0-9_.,;'
				ptn = ptn .. chars
				return (str:gsub('[^'..ptn..']', function(c)
					if c == ' ' then return '+' end
					return string.format('%%%02X', string.byte(c))
				end))
			end
			if me.class == nil or next(me.class) == nil then
				return 'none:'
			end
			local parts = {
				table.concat(ss.map(san,me.class), '+') .. ':';
			}
			if me.namespace or me.auth or me.svc then
				table.insert(parts, '//')
				if me.auth then
					table.insert(parts, san(me.auth,':') .. '@')
				end
				if me.namespace then
					table.insert(parts, san(me.namespace))
				end
				if me.svc then
					table.insert(parts, ':' .. san(me.svc))
				end
				if me.path and not ss.str.begins(me.path, '/') then
					table.insert(parts, '/')
				end
			end
			if me.path then
				table.insert(parts, san(me.path,'+/=&'))
			end
			if me.query then
				table.insert(parts, '?' .. san(me.query,'?+/=&'))
			end
			if me.frag then
				table.insert(parts, '#' .. san(me.frag,'+/=&'))
			end
			return table.concat(parts)
		end;
	};
	fns = {
		canfetch = function(me)
			for id, pr in pairs(fetchableProtocols) do
				for _, p in ipairs(pr.proto) do
					if ss.match(me.class, p) then return id end
				end
			end
			return false
		end;
		fetch = function(me, env)
			local pid = me:canfetch()
			if (not pid) or fetchableProtocols[pid].fetch == nil then
				ss.uri.exn("URI “%s” is unfetchable", tostring(me)):throw()
			end
			local proto = fetchableProtocols[pid]
			return proto.fetch(me, env or {})
		end;
	};
}
ss.uri.exn = ss.exnkind 'URI'

ss.mime = ss.declare {
	ident = 'mime-type';
	mk = function() return {
		class = nil;
		kind = nil;
		opts = {};