hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

main.ha (3819B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use ascii;
      5 use bufio;
      6 use fmt;
      7 use io;
      8 use os;
      9 use strconv;
     10 use strings;
     11 
     12 type entry = struct {
     13 	name: str,
     14 	val: str,
     15 	idx: size,
     16 };
     17 
     18 // Parses an oid database from stdin and writes the database as hare code to
     19 // stdout.
     20 export fn main() void = {
     21 	let oids = parse_oids();
     22 	defer free_oids(oids);
     23 
     24 	fmt::println("// SPDX-License-Identifier: MPL-2.0\n"
     25 		"// (c) Hare authors <https://harelang.org>\n"
     26 		"// This is an auto generated file. Do not edit.\n"
     27 		"\n"
     28 		"use encoding::asn1;\n")!;
     29 
     30 	fmt::println("const _db = asn1::oiddb {")!;
     31 
     32 	write_db(os::stdout, oids)!;
     33 
     34 	fmt::println("\tnames = [")!;
     35 	for (let oid .. oids) {
     36 		fmt::printfln("\t\t\"{}\",", oid.name)!;
     37 	};
     38 	fmt::println("\t],")!;
     39 	fmt::println("};\n")!;
     40 
     41 	fmt::println("// Database")!;
     42 	fmt::println("export const db = &_db;")!;
     43 
     44 	for (let i = 0z; i < len(oids); i += 1) {
     45 		let oid = &oids[i];
     46 		fmt::println()!;
     47 		fmt::println("// id:  ", oid.val)!;
     48 		fmt::println("// name:", oid.name)!;
     49 		fmt::print("export def ")!;
     50 		write_varname(os::stdout, oid.name)!;
     51 		fmt::printfln(": asn1::oid = {};", i)!;
     52 	};
     53 };
     54 
     55 fn parse_oids() []entry = {
     56 	let s = bufio::newscanner(os::stdin);
     57 	defer bufio::finish(&s);
     58 	let oids: []entry = [];
     59 
     60 	for (let line => bufio::scan_line(&s)!) {
     61 		if (line == "" || strings::hasprefix(line, '#')) {
     62 			continue;
     63 		};
     64 
     65 		const p = strings::split(line, " ");
     66 		defer free(p);
     67 		const name = p[0];
     68 		const val = p[len(p)-1];
     69 
     70 		append(oids, entry {
     71 			name = strings::dup(name),
     72 			val = strings::dup(val),
     73 			...
     74 		})!;
     75 	};
     76 
     77 	return oids;
     78 };
     79 
     80 fn free_oids(oids: []entry) void = {
     81 	for (let oid .. oids) {
     82 		free(oid.name);
     83 		free(oid.val);
     84 	};
     85 
     86 	free(oids);
     87 };
     88 
     89 fn write_db(h: io::handle, oids: []entry) (void | io::error) = {
     90 	fmt::print("\tlut = [")?;
     91 
     92 	const maxcols = 12z;
     93 	let idx = 0z;
     94 
     95 	for (let e &.. oids) {
     96 		e.idx = idx;
     97 
     98 		let der = oidtoder(e.val);
     99 		assert(len(der) <= 0xff);
    100 		insert(der[0], len(der): u8)!;
    101 		defer free(der);
    102 
    103 		for (let byte .. der) {
    104 			fmt::print(if (idx % maxcols == 0) "\n\t\t" else " ")?;
    105 			fmt::printf("0x{:.2x},", byte)?;
    106 			idx += 1;
    107 		};
    108 	};
    109 	fmt::println("\n\t],")?;
    110 
    111 	const maxcols = 9z;
    112 	fmt::print("\tindex = [")?;
    113 	for (let i = 0z; i < len(oids); i += 1) {
    114 		fmt::print(if (i % maxcols == 0) "\n\t\t" else " ")?;
    115 		fmt::printf("0x{:.4x},", oids[i].idx)?;
    116 	};
    117 	fmt::println("\n\t],")?;
    118 };
    119 
    120 fn oidtoder(oid: str) []u8 = {
    121 	let nums = oidtou64s(oid);
    122 	defer free(nums);
    123 
    124 	let der: []u8 = alloc([0...], 1)!;
    125 	assert(nums[0] <= 6);
    126 	assert(nums[1] < 40);
    127 	der[0] = nums[0]: u8 * 40 + nums[1]: u8;
    128 	let end = 1z;
    129 
    130 	for (let i = 2z; i < len(nums); i += 1) {
    131 		let n = nums[i];
    132 		if (n == 0) {
    133 			insert(der[end], 0u8)!;
    134 			end = len(der);
    135 			continue;
    136 		};
    137 
    138 		let first = true;
    139 		for (n > 0) {
    140 			let p: u8 = n: u8 & 0x7f;
    141 			n >>= 7;
    142 			if (first) {
    143 				first = false;
    144 			} else {
    145 				p |= 0x80;
    146 			};
    147 			insert(der[end], p)!;
    148 		};
    149 
    150 		end = len(der);
    151 	};
    152 
    153 	return der;
    154 };
    155 
    156 fn oidtou64s(oid: str) []u64 = {
    157 	let nums = strings::tokenize(oid, ".");
    158 	let intnums: []u64 = [];
    159 
    160 	for (let s => strings::next_token(&nums)) {
    161 		append(intnums, strconv::stou64(s)!)!;
    162 	};
    163 
    164 	return intnums;
    165 };
    166 
    167 fn write_varname(h: io::handle, name: str) (void | io::error) = {
    168 	// assume that names are in ascii
    169 	let i = strings::iter(name);
    170 	let prevlow = false;
    171 	for (let r => strings::next(&i)) {
    172 		let r = if (r == '-') {
    173 			prevlow = false;
    174 			yield '_';
    175 		} else if (ascii::isdigit(r)) {
    176 			prevlow = true;
    177 			yield r;
    178 		} else if (ascii::isupper(r)) {
    179 			if (prevlow) {
    180 				fmt::fprint(h, "_")?;
    181 				prevlow = false;
    182 			};
    183 			yield r;
    184 		} else if (ascii::islower(r)) {
    185 			prevlow = true;
    186 			yield ascii::toupper(r);
    187 		} else {
    188 			fmt::fatalf("Unexpected character in oid name: {}", r);
    189 		};
    190 
    191 		fmt::fprint(h, r)?;
    192 	};
    193 };