#include "flags.h" #include #include #include #include #include using namespace std::literals; static std::uint8_t hex_nibble(char b) { switch(b) { case '0': return 0x0; case '1': return 0x1; case '2': return 0x2; case '3': return 0x3; case '4': return 0x4; case '5': return 0x5; case '6': return 0x6; case '7': return 0x7; case '8': return 0x8; case '9': return 0x9; case 'A': case 'a': return 0xA; case 'B': case 'b': return 0xB; case 'C': case 'c': return 0xC; case 'D': case 'd': return 0xD; case 'E': case 'e': return 0xE; case 'F': case 'f': return 0xF; default: __builtin_unreachable(); } } namespace vore { namespace { template struct span { T b, e; constexpr T begin() const noexcept { return this->b; } constexpr T end() const noexcept { return this->e; } }; template span(T, T) -> span; } } int main() { char * line_raw{}; std::size_t linecap{}; std::vector data; auto data_line_strm = fdopen(3, "w"); assert(data_line_strm); for(ssize_t len; (len = getline(&line_raw, &linecap, stdin)) != -1;) { std::string_view line{line_raw, static_cast(len)}; if(line.back() == '\n') line.remove_suffix(1); if(line[0] == '\n' || line[0] == '\0') { dump: std::fwrite(line.data(), 1, line.size(), stdout); std::fputc('\n', stdout); continue; } if(line.starts_with(";;"sv)) goto dump; // 05414D4436340F44454249414E2F424F4F4B574F524D hinfo.group. 85994 IN HINFO // to generate "AMD64" "DEBIAN/BOOKWORM" // 05414D4436340F44454249414E2F424F4F4B574F hinfo.group. 85994 IN HINFO // 05414D4436340F44454249414E2F4121212B574F524D hinfo.group. 85994 IN HINFO auto sh = line; { auto tab = line.find('\t'); line.remove_prefix(tab + 1); sh.remove_suffix(sh.size() - tab); } // https://www.iana.org/assignments/machine-names/machine-names.xml // https://www.iana.org/assignments/operating-system-names/operating-system-names.xhtml // // A machine name or CPU type may be up to 40 characters taken from the // set of uppercase letters, digits, and the two punctuation characters // hyphen and slash. It must start with a letter, and end with a letter // or digit. const constexpr auto alphabet_cpu = "-/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv; const constexpr auto alphabet_system = "-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv; const constexpr auto ok_start = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv; const constexpr auto ok_end = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv; std::string_view cpu, system; data.clear(); for(std::size_t i = 0; i < sh.size(); i += 2) data.emplace_back((hex_nibble(sh[i]) << 4) | hex_nibble(sh[i + 1])); std::uint8_t flags{}; auto itr = std::begin(data); if(itr == std::end(data)) { flags |= f_fcount; goto err; } { auto reallen = *itr++; if(std::distance(itr, std::end(data)) < reallen || !reallen) { flags |= f_cpulen; goto err; } cpu = {reinterpret_cast(&*itr), reallen}; if(cpu.size() > 40) { flags |= f_cpulen; cpu = {cpu.data(), 40}; } std::transform(std::begin(cpu), std::end(cpu), const_cast(std::begin(cpu)), [&](auto c) { if(!std::binary_search(std::begin(alphabet_cpu), std::end(alphabet_cpu), c)) { flags |= f_cpunvl; return '/'; } else return c; }); if(!cpu.empty()) { if(!std::binary_search(std::begin(ok_end), std::end(ok_end), cpu.back())) { const_cast(cpu.back()) = ok_end[0]; flags |= f_cpunvl; } if(!std::binary_search(std::begin(ok_start), std::end(ok_start), cpu[0])) { const_cast(cpu[0]) = ok_start[0]; flags |= f_cpunvl; } } itr += reallen; if(itr == std::end(data)) { flags |= f_fcount; goto err; } reallen = *itr++; if(std::distance(itr, std::end(data)) < reallen || !reallen) { flags |= f_syslen; goto err; } system = {reinterpret_cast(&*itr), reallen}; // char tmp[] = "NIXOS/22.11"; // system = tmp; if(system.size() > 40) { flags |= f_syslen; system = {system.data(), 40}; } std::transform(std::begin(system), std::end(system), const_cast(std::begin(system)), [&](auto c) { if(!std::binary_search(std::begin(alphabet_system), std::end(alphabet_system), c)) { flags |= f_sysnvl; return '/'; } else return c; }); if(!system.empty()) { if(!std::binary_search(std::begin(ok_end), std::end(ok_end), system.back())) { const_cast(system.back()) = ok_end[0]; flags |= f_sysnvl; } if(!std::binary_search(std::begin(ok_start), std::end(ok_start), system[0])) { const_cast(system[0]) = ok_start[0]; flags |= f_sysnvl; } } itr += reallen; if(itr != std::end(data)) flags |= f_fcount; } err: if(system.empty()) { // error std::fwrite(line.data(), 1, line.size(), stderr); std::fputc('\t', stderr); std::fwrite(sh.data(), 1, sh.size(), stderr); std::fputc('\t', stderr); if(flags & f_fcount) std::fputs("Field Count ", stderr); if(flags & f_cpulen) std::fputs("CPU Length ", stderr); if(flags & f_syslen) std::fputs("System Length ", stderr); if(flags & f_cpunvl) std::fputs("CPU Invalid ", stderr); if(flags & f_sysnvl) std::fputs("System Invalid ", stderr); std::fputc('\n', stderr); } else { std::fwrite(line.data(), 1, line.size(), stdout); std::fputc('\n', stdout); std::fputs("\"", data_line_strm); if(system.empty()) std::fwrite(sh.data(), 1, sh.size(), data_line_strm); else { std::fwrite(cpu.data(), 1, cpu.size(), data_line_strm); std::fputs("\" \"", data_line_strm); std::fwrite(system.data(), 1, system.size(), data_line_strm); } std::fputc('"', data_line_strm); if(flags) { std::fputs(" ;", data_line_strm); flags |= f_CANARY; } std::fwrite(&flags, 1, 1, data_line_strm); std::fputc('\n', data_line_strm); } } }