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 };