freq.ha (2795B)
- // Collection of utilities inspired by Plan9
- // SPDX-FileCopyrightText: 2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- use getopt;
- use fmt;
- use os;
- use io;
- use ascii;
- use types;
- use strings;
- use encoding::utf8;
- fn is_unicode_cc(r: rune) bool = {
- let r = r: u32;
- if(r <= 0x0000 && r >= 0x001F) { return true; }; // C0 Controls
- if(r == 0x007F) { return true; }; // Delete
- if(r <= 0x0080 && r >= 0x009F) { return true; }; // C1 Controls
- return false;
- };
- export fn main() void = {
- let runic = false;
- const cmd = getopt::parse(os::args,
- "Print histogram frequency of bytes/characters",
- ('r', "Rune (unicode character) frequency instead of byte frequency"),
- "file ...",
- );
- defer getopt::finish(&cmd);
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- const opt = cmd.opts[i];
- switch(opt.0) {
- case 'r' => runic = true;
- case => abort("unhandled option");
- };
- };
- if(runic) {
- let runes_count: [](rune, size) = [];
- let buf: [32]u8 = [0...];
- for(true) {
- let s = match(io::read(os::stdin, &buf)) {
- case let s: size =>
- yield s;
- case io::EOF =>
- break;
- case let e: io::error =>
- fmt::fatal("freq: I/O error: {}", io::strerror(e));
- };
- let buf_s = match(strings::fromutf8(buf[0..s])) {
- case let s: str =>
- yield s;
- case utf8::invalid =>
- fmt::fatal("freq: Invalid UTF-8");
- };
- let buf_iter = strings::iter(buf_s);
- for(true) {
- const r = match(strings::next(&buf_iter)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
- for(let i = 0z; true; i += 1) {
- if(i < len(runes_count)) {
- if(runes_count[i].0 == r) {
- runes_count[i].1 += 1;
- break;
- };
- } else {
- append(runes_count, (r, 1));
- break;
- };
- };
- };
- };
- for(let i = 0z; i < len(runes_count); i += 1) {
- const rune_c = runes_count[i];
- let c = if(!is_unicode_cc(rune_c.0)) {
- yield rune_c.0;
- } else {
- yield "-";
- };
- // 1114109 4177775 10fffd
- fmt::printfln("{0:7} {0:7o} {0:6x} {1} {2}", rune_c.0: u32, c, rune_c.1)!;
- };
- } else {
- // Stupid table of all bytes
- let bytes_count: [256]size = [0...];
- let buf: [32]u8 = [0...];
- for(true) {
- let s = match(io::read(os::stdin, &buf)) {
- case let s: size =>
- yield s;
- case io::EOF =>
- break;
- case let e: io::error =>
- fmt::fatal("freq: I/O error: {}", io::strerror(e));
- };
- for(let i = 0z; i < s; i += 1) {
- bytes_count[buf[i]] += 1;
- };
- };
- for(let i = 0u32; i < len(bytes_count); i += 1) {
- if(bytes_count[i] != 0) {
- let c = i: rune;
- let c = if(ascii::isprint(c)) {
- yield c;
- } else {
- yield "-";
- };
- fmt::printfln("{0:3} {0:03o} {0:02x} {1} {2}", i, c, bytes_count[i])!;
- };
- };
- };
- };