hare

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

main.ha (3630B)


      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("export const db = &_db;\n")!;
     42 
     43 	for (let i = 0z; i < len(oids); i += 1) {
     44 		fmt::print("export def ")!;
     45 		write_varname(os::stdout, oids[i].name)!;
     46 		fmt::printfln(": asn1::oid = {};", i)!;
     47 	};
     48 };
     49 
     50 fn parse_oids() []entry = {
     51 	let s = bufio::newscanner(os::stdin);
     52 	defer bufio::finish(&s);
     53 	let oids: []entry = [];
     54 
     55 	for (let line => bufio::scan_line(&s)!) {
     56 		if (line == "" || strings::hasprefix(line, '#')) {
     57 			continue;
     58 		};
     59 
     60 		const p = strings::split(line, " ");
     61 		defer free(p);
     62 		const name = p[0];
     63 		const val = p[len(p)-1];
     64 
     65 		append(oids, entry {
     66 			name = strings::dup(name),
     67 			val = strings::dup(val),
     68 			...
     69 		});
     70 	};
     71 
     72 	return oids;
     73 };
     74 
     75 fn free_oids(oids: []entry) void = {
     76 	for (let oid .. oids) {
     77 		free(oid.name);
     78 		free(oid.val);
     79 	};
     80 
     81 	free(oids);
     82 };
     83 
     84 fn write_db(h: io::handle, oids: []entry) (void | io::error) = {
     85 	fmt::print("\tlut = [")?;
     86 
     87 	const maxcols = 12z;
     88 	let idx = 0z;
     89 
     90 	for (let e .. oids) {
     91 		e.idx = idx;
     92 
     93 		let der = oidtoder(e.val);
     94 		assert(len(der) <= 0xff);
     95 		insert(der[0], len(der): u8);
     96 		defer free(der);
     97 
     98 		for (let byte .. der) {
     99 			fmt::print(if (idx % maxcols == 0) "\n\t\t" else " ")?;
    100 			fmt::printf("0x{:.2x},", byte)?;
    101 			idx += 1;
    102 		};
    103 	};
    104 	fmt::println("\n\t],")?;
    105 
    106 	const maxcols = 9z;
    107 	fmt::print("\tindex = [")?;
    108 	for (let i = 0z; i < len(oids); i += 1) {
    109 		fmt::print(if (i % maxcols == 0) "\n\t\t" else " ")?;
    110 		fmt::printf("0x{:.4x},", oids[i].idx)?;
    111 	};
    112 	fmt::println("\n\t],")?;
    113 };
    114 
    115 fn oidtoder(oid: str) []u8 = {
    116 	let nums = oidtou64s(oid);
    117 	defer free(nums);
    118 
    119 	let der: []u8 = alloc([0...], 1);
    120 	assert(nums[0] <= 6);
    121 	assert(nums[1] < 40);
    122 	der[0] = nums[0]: u8 * 40 + nums[1]: u8;
    123 	let end = 1z;
    124 
    125 	for (let n .. nums) {
    126 		if (n == 0) {
    127 			insert(der[end], 0u8);
    128 			end = len(der);
    129 			continue;
    130 		};
    131 
    132 		let first = true;
    133 		for (n > 0) {
    134 			let p: u8 = n: u8 & 0x7f;
    135 			n >>= 7;
    136 			if (first) {
    137 				first = false;
    138 			} else {
    139 				p |= 0x80;
    140 			};
    141 			insert(der[end], p);
    142 		};
    143 
    144 		end = len(der);
    145 	};
    146 
    147 	return der;
    148 };
    149 
    150 fn oidtou64s(oid: str) []u64 = {
    151 	let nums = strings::tokenize(oid, ".");
    152 	let intnums: []u64 = [];
    153 
    154 	for (let s => strings::next_token(&nums)) {
    155 		append(intnums, strconv::stou64(s)!);
    156 	};
    157 
    158 	return intnums;
    159 };
    160 
    161 fn write_varname(h: io::handle, name: str) (void | io::error) = {
    162 	// assume that names are in ascii
    163 	let i = strings::iter(name);
    164 	let prevlow = false;
    165 	for (let r => strings::next(&i)) {
    166 		let r = if (r == '-') {
    167 			prevlow = false;
    168 			yield '_';
    169 		} else if (ascii::isdigit(r)) {
    170 			prevlow = true;
    171 			yield r;
    172 		} else if (ascii::isupper(r)) {
    173 			if (prevlow) {
    174 				fmt::fprint(h, "_")?;
    175 				prevlow = false;
    176 			};
    177 			yield r;
    178 		} else if (ascii::islower(r)) {
    179 			prevlow = true;
    180 			yield ascii::toupper(r);
    181 		} else {
    182 			fmt::fatalf("Unexpected character in oid name: {}", r);
    183 		};
    184 
    185 		fmt::fprint(h, r)?;
    186 	};
    187 };