From d1310a03ad54accb03e1c1ed4f7887ffa2741988 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 2 Jun 2026 19:24:40 +0900 Subject: [PATCH] lib: char-literals for ascii/fnmatch/shlex magic decimals (Wave-1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace magic ASCII decimals with char literals in ascii/fnmatch/shlex predicates (e.g. `c < 48` → `c < '0'`). Byte-id-neutral: ascii params are rune, so rune 57) { return false; }; + if (c < '0') { return false; }; + if (c > '9') { return false; }; return true; }; export fn isupper(c: rune) bool = { - if (c < 65) { return false; }; - if (c > 90) { return false; }; + if (c < 'A') { return false; }; + if (c > 'Z') { return false; }; return true; }; export fn islower(c: rune) bool = { - if (c < 97) { return false; }; - if (c > 122) { return false; }; + if (c < 'a') { return false; }; + if (c > 'z') { return false; }; return true; }; @@ -37,22 +37,22 @@ export fn isalnum(c: rune) bool = { // isspace — the C/Hare set: space, tab, NL, VT, FF, CR. export fn isspace(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' - if (c == 10) { return true; }; // '\n' - if (c == 11) { return true; }; // '\v' - if (c == 12) { return true; }; // '\f' - if (c == 13) { return true; }; // '\r' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; + if (c == '\n') { return true; }; + if (c == '\v') { return true; }; + if (c == '\f') { return true; }; + if (c == '\r') { return true; }; return false; }; export fn isxdigit(c: rune) bool = { if (isdigit(c)) { return true; }; - if (c >= 65) { - if (c <= 70) { return true; }; // 'A'..'F' + if (c >= 'A') { + if (c <= 'F') { return true; }; }; - if (c >= 97) { - if (c <= 102) { return true; }; // 'a'..'f' + if (c >= 'a') { + if (c <= 'f') { return true; }; }; return false; }; @@ -86,22 +86,22 @@ export fn iscntrl(c: rune) bool = { // isblank — space and tab. export fn isblank(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; return false; }; // isprint — printable: space through '~'. export fn isprint(c: rune) bool = { - if (c < 32) { return false; }; - if (c > 126) { return false; }; + if (c < ' ') { return false; }; + if (c > '~') { return false; }; return true; }; // isgraph — printable, non-space. export fn isgraph(c: rune) bool = { - if (c < 33) { return false; }; - if (c > 126) { return false; }; + if (c < '!') { return false; }; + if (c > '~') { return false; }; return true; }; diff --git a/lib/fnmatch/fnmatch.ww b/lib/fnmatch/fnmatch.ww index c5182533..f5fd9a33 100644 --- a/lib/fnmatch/fnmatch.ww +++ b/lib/fnmatch/fnmatch.ww @@ -113,17 +113,17 @@ fn pat_next(pat: str, pos: *i32, fl: flag) (u8 | star | question | bracket | end if (*pos >= pat.len) { let e: endt; return e; }; let c: u8 = pat[*pos]; *pos += 1; - if (c == 42u8) { let r: star; return r; }; // '*' - if (c == 63u8) { let r: question; return r; }; // '?' - if (c == 91u8) { let r: bracket; return r; }; // '[' - if (c == 92u8) { // '\\' + if (c == '*') { let r: star; return r; }; + if (c == '?') { let r: question; return r; }; + if (c == '[') { let r: bracket; return r; }; + if (c == '\\') { if (((fl as i32) & (flag.NOESCAPE as i32)) == 0) { if (*pos >= pat.len) { let e: invalid; return e; }; let c2: u8 = pat[*pos]; *pos += 1; return c2; }; - return 92u8; + return '\\'; }; return c; }; @@ -161,7 +161,7 @@ fn match_ctype(pat: str, pos: *i32, c: u8) (bool | invalid) = { let nameoff: i32 = *pos; let i: i32 = 0; let r: u8 = 0u8; - for (r != 58u8) { // ':' + for (r != ':') { let rr = advance_or_err(pat, pos); match (rr) { case let e: invalid => return e; @@ -176,7 +176,7 @@ fn match_ctype(pat: str, pos: *i32, c: u8) (bool | invalid) = { match (rr) { case let e: invalid => return e; case let f: u8 => { - if (f != 93u8) { let e: invalid; return e; }; // ']' + if (f != ']') { let e: invalid; return e; }; }; }; let name: str; @@ -212,9 +212,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { case let e: invalid => return e; case let f: u8 => { first = f; }; }; - if (first == 94u8) { let e: invalid; return e; }; // '^' is Hare-invalid + if (first == '^') { let e: invalid; return e; }; // '^' is Hare-invalid let inv: bool = false; - if (first == 33u8) { // '!' + if (first == '!') { inv = true; let r1 = advance_or_err(pat, pos); match (r1) { @@ -222,10 +222,10 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { case let f: u8 => { first = f; }; }; }; - let found: bool = (first != 91u8) && (first == c); + let found: bool = (first != '[') && (first == c); let havelast: bool = true; let last: u8 = first; - if (first == 93u8) { // ']' as first member + if (first == ']') { // ']' as first member let r2 = advance_or_err(pat, pos); match (r2) { case let e: invalid => return e; @@ -235,22 +235,22 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { let r: u8 = first; let loop: bool = true; for (loop) { - if (r == 93u8) { // ']' closes + if (r == ']') { // ']' closes loop = false; - } else { if (r == 45u8) { // '-' range + } else { if (r == '-') { // '-' range let er = advance_or_err(pat, pos); let endv: u8 = 0u8; match (er) { case let e: invalid => return e; case let f: u8 => { endv = f; }; }; - if (endv == 93u8) { + if (endv == ']') { // Trailing '-' matches itself. Un-eat ']' // so the next iteration sees it. *pos -= 1; - last = 45u8; + last = '-'; havelast = true; - if (c == 45u8) { found = true; }; + if (c == '-') { found = true; }; } else { if (!havelast) { let e: invalid; return e; }; if ((last: u32) <= (c: u32) && (c: u32) <= (endv: u32)) { @@ -258,16 +258,16 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { }; havelast = false; // forbid `a-f-n` }; - } else { if (r == 91u8) { // '[' + } else { if (r == '[') { let nx = advance_or_err(pat, pos); let nxv: u8 = 0u8; match (nx) { case let e: invalid => return e; case let f: u8 => { nxv = f; }; }; - if (nxv == 61u8) { let e: invalid; return e; }; // '=' - if (nxv == 46u8) { let e: invalid; return e; }; // '.' - if (nxv == 58u8) { // ':' class + if (nxv == '=') { let e: invalid; return e; }; + if (nxv == '.') { let e: invalid; return e; }; + if (nxv == ':') { // ':' class let t = match_ctype(pat, pos, c); match (t) { case let e: invalid => return e; @@ -278,9 +278,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { } else { // Not a class — un-eat the byte after '['. *pos -= 1; - if (c == 91u8) { found = true; }; + if (c == '[') { found = true; }; }; - last = 91u8; + last = '['; havelast = true; } else { // literal byte if (c == r) { found = true; }; @@ -300,9 +300,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = { // have been an empty collating/equivalence/class). let cnt: i32 = *pos - oldpos; if (havelast && first == last && cnt >= 4) { - if (first == 61u8) { let e: invalid; return e; }; - if (first == 46u8) { let e: invalid; return e; }; - if (first == 58u8) { let e: invalid; return e; }; + if (first == '=') { let e: invalid; return e; }; + if (first == '.') { let e: invalid; return e; }; + if (first == ':') { let e: invalid; return e; }; }; if (inv) { return !found; }; return found; @@ -534,7 +534,7 @@ fn fnmatch_pathname(pattern: str, string: str, fl: flag) (bool | invalid) = { case let e: invalid => return e; case endt => { kind = 1; inner = false; }; case let r: u8 => { - if (r == 47u8) { kind = 0; inner = false; }; + if (r == '/') { kind = 0; inner = false; }; }; case bracket => { let mr = match_bracket(pattern, &pp, 0u8); @@ -552,7 +552,7 @@ fn fnmatch_pathname(pattern: str, string: str, fl: flag) (bool | invalid) = { if (donetokens) { return false; }; let segstart_s: i32 = sp; for (sp < string.len) { - if (string[sp] == 47u8) { break; }; + if (string[sp] == '/') { break; }; sp += 1; }; let seg: str; diff --git a/lib/fnmatch/fnmatchtest.ww b/lib/fnmatch/fnmatchtest.ww index ecbed4c3..5b98f299 100644 --- a/lib/fnmatch/fnmatchtest.ww +++ b/lib/fnmatch/fnmatchtest.ww @@ -134,6 +134,16 @@ fn check(pat: str, s: str, expected: bool, flags: i32) void = { check("[[alpha:]]", ":]", true, 0); check("[[:alpha:]]", "a", true, 0); check("[[:blank:]]", " ", true, 0); + // pin the ascii.is{blank,space,print,graph} predicates: their + // char-literal bounds are reachable only through these classes. + check("[[:blank:]]", "\t", true, 0); + check("[[:space:]]", " ", true, 0); + check("[[:space:]]", "\t", true, 0); + check("[[:space:]]", "x", false, 0); + check("[[:print:]]", "~", true, 0); + check("[[:print:]]", "\t", false, 0); + check("[[:graph:]]", "a", true, 0); + check("[[:graph:]]", " ", false, 0); check("[[:alnum:]]a", "a]a", false, 0); check("[[:alnum:][[:digit:]]", "a", true, 0); diff --git a/lib/shlex/shlex.ww b/lib/shlex/shlex.ww index 96529469..f46ea213 100644 --- a/lib/shlex/shlex.ww +++ b/lib/shlex/shlex.ww @@ -181,7 +181,7 @@ fn scan_backslash(out: io.stream, in: str, pos: *i32) (void | syntaxerr) = { if (*pos >= in.len) { let e: syntaxerr; return e; }; let r: u8 = in[*pos]; *pos += 1; - if (r == 10u8) { return; }; // '\n' deleted + if (r == '\n') { return; }; // deleted per POSIX let _w = writebyte(out, r); return; }; @@ -195,8 +195,8 @@ fn scan_double(out: io.stream, in: str, pos: *i32) (void | syntaxerr) = { if (*pos >= in.len) { let e: syntaxerr; return e; }; let r: u8 = in[*pos]; *pos += 1; - if (r == 34u8) { loop = false; } // '"' - else { if (r == 92u8) { // '\\' + if (r == '"') { loop = false; } + else { if (r == '\\') { let er = scan_backslash(out, in, pos); match (er) { case let e: syntaxerr => return e; @@ -218,7 +218,7 @@ fn scan_single(out: io.stream, in: str, pos: *i32) (void | syntaxerr) = { if (*pos >= in.len) { let e: syntaxerr; return e; }; let r: u8 = in[*pos]; *pos += 1; - if (r == 39u8) { loop = false; } // "'" + if (r == '\'') { loop = false; } else { let _w = writebyte(out, r); }; }; return; @@ -254,14 +254,14 @@ export fn split(in: str) ([]str | syntaxerr) = { pos += 1; dirty = true; - if (r == 32u8 || r == 9u8 || r == 10u8) { + if (r == ' ' || r == '\t' || r == '\n') { // Collapse a run of whitespace. let inner: bool = true; for (inner) { if (pos >= in.len) { inner = false; } else { let r2: u8 = in[pos]; - if (r2 != 32u8 && r2 != 9u8 && r2 != 10u8) { + if (r2 != ' ' && r2 != '\t' && r2 != '\n') { inner = false; } else { pos += 1; @@ -275,7 +275,7 @@ export fn split(in: str) ([]str | syntaxerr) = { memio.reset(&st); }; dirty = false; - } else { if (r == 92u8) { // '\\' + } else { if (r == '\\') { let er = scan_backslash(snk, in, &pos); match (er) { case let e: syntaxerr => { @@ -285,7 +285,7 @@ export fn split(in: str) ([]str | syntaxerr) = { }; case void => {}; }; - } else { if (r == 34u8) { // '"' + } else { if (r == '"') { let er = scan_double(snk, in, &pos); match (er) { case let e: syntaxerr => { @@ -295,7 +295,7 @@ export fn split(in: str) ([]str | syntaxerr) = { }; case void => {}; }; - } else { if (r == 39u8) { // "'" + } else { if (r == '\'') { let er = scan_single(snk, in, &pos); match (er) { case let e: syntaxerr => { @@ -332,15 +332,15 @@ fn issafe(s: str) bool = { for (i < s.len) { let c: u8 = s[i]; // Hare's switch list: '@', '%', '+', '=', ':', ',', '.', '/', '-'. - if (c == 64u8 || c == 37u8 || c == 43u8 || c == 61u8 - || c == 58u8 || c == 44u8 || c == 46u8 || c == 47u8 - || c == 45u8) { + if (c == '@' || c == '%' || c == '+' || c == '=' + || c == ':' || c == ',' || c == '.' || c == '/' + || c == '-') { i += 1; } else { let alnum: bool = false; - if (c >= 48u8 && c <= 57u8) { alnum = true; }; // 0-9 - if (c >= 65u8 && c <= 90u8) { alnum = true; }; // A-Z - if (c >= 97u8 && c <= 122u8) { alnum = true; }; // a-z + if (c >= '0' && c <= '9') { alnum = true; }; + if (c >= 'A' && c <= 'Z') { alnum = true; }; + if (c >= 'a' && c <= 'z') { alnum = true; }; if (!alnum) { return false; }; i += 1; }; @@ -361,7 +361,7 @@ fn issafe(s: str) bool = { export fn quote(sink: io.stream, s: str) (size | io.error) = { if (s.len == 0) { let buf: [2]u8; - buf[0] = 39u8; buf[1] = 39u8; + buf[0] = '\''; buf[1] = '\''; let r = io.write(sink, buf[0:2]); match (r) { case let n: size => return n; @@ -380,7 +380,7 @@ export fn quote(sink: io.stream, s: str) (size | io.error) = { }; let total: size = 0; - let r1 = writebyte(sink, 39u8); // "'" + let r1 = writebyte(sink, '\''); match (r1) { case let n: size => { total += n; }; case let e: io.error => return e; @@ -388,10 +388,10 @@ export fn quote(sink: io.stream, s: str) (size | io.error) = { let i: i32 = 0; for (i < s.len) { let c: u8 = s[i]; - if (c == 39u8) { // "'" → '"'"' + if (c == '\'') { // "'" → '"'"' let pat: [5]u8; - pat[0] = 39u8; pat[1] = 34u8; pat[2] = 39u8; - pat[3] = 34u8; pat[4] = 39u8; + pat[0] = '\''; pat[1] = '"'; pat[2] = '\''; + pat[3] = '"'; pat[4] = '\''; let rr = io.write(sink, pat[0:5]); match (rr) { case let n: size => { total += n; }; @@ -406,7 +406,7 @@ export fn quote(sink: io.stream, s: str) (size | io.error) = { }; i += 1; }; - let r2 = writebyte(sink, 39u8); // "'" + let r2 = writebyte(sink, '\''); match (r2) { case let n: size => { total += n; }; case let e: io.error => return e; diff --git a/lib/shlex/shlextest.ww b/lib/shlex/shlextest.ww index 4c4f0d55..36fc2501 100644 --- a/lib/shlex/shlextest.ww +++ b/lib/shlex/shlextest.ww @@ -149,6 +149,8 @@ fn checkquote(in: str, expected: str) void = { check3("with\\ backslashes 'single quoted' \"double quoted\"", "with backslashes", "single quoted", "double quoted"); check2("'multiple spaces' 42", "multiple spaces", "42"); + // pin the '\t'/'\n' arms of split's whitespace test. + check3("a\tb\nc", "a", "b", "c"); // Invalid checkerr("\"dangling double quote"); @@ -172,6 +174,8 @@ fn checkquote(in: str, expected: str) void = { checkquote("'hello' \"world\"", "''\"'\"'hello'\"'\"' \"world\"'"); checkquote("hello\\world", "'hello\\world'"); checkquote("", "''"); + // pin issafe's special-char set: all safe → emitted raw, unquoted. + checkquote("@%+=:,./-", "@%+=:,./-"); }; // ---- quotestr ------------------------------------------------------ diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index ed531e09..6163794c 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -4363,20 +4363,20 @@ package ascii; import strings; export fn isdigit(c: rune) bool = { - if (c < 48) { return false; }; - if (c > 57) { return false; }; + if (c < '0') { return false; }; + if (c > '9') { return false; }; return true; }; export fn isupper(c: rune) bool = { - if (c < 65) { return false; }; - if (c > 90) { return false; }; + if (c < 'A') { return false; }; + if (c > 'Z') { return false; }; return true; }; export fn islower(c: rune) bool = { - if (c < 97) { return false; }; - if (c > 122) { return false; }; + if (c < 'a') { return false; }; + if (c > 'z') { return false; }; return true; }; @@ -4392,22 +4392,22 @@ export fn isalnum(c: rune) bool = { // isspace — the C/Hare set: space, tab, NL, VT, FF, CR. export fn isspace(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' - if (c == 10) { return true; }; // '\n' - if (c == 11) { return true; }; // '\v' - if (c == 12) { return true; }; // '\f' - if (c == 13) { return true; }; // '\r' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; + if (c == '\n') { return true; }; + if (c == '\v') { return true; }; + if (c == '\f') { return true; }; + if (c == '\r') { return true; }; return false; }; export fn isxdigit(c: rune) bool = { if (isdigit(c)) { return true; }; - if (c >= 65) { - if (c <= 70) { return true; }; // 'A'..'F' + if (c >= 'A') { + if (c <= 'F') { return true; }; }; - if (c >= 97) { - if (c <= 102) { return true; }; // 'a'..'f' + if (c >= 'a') { + if (c <= 'f') { return true; }; }; return false; }; @@ -4441,22 +4441,22 @@ export fn iscntrl(c: rune) bool = { // isblank — space and tab. export fn isblank(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; return false; }; // isprint — printable: space through '~'. export fn isprint(c: rune) bool = { - if (c < 32) { return false; }; - if (c > 126) { return false; }; + if (c < ' ') { return false; }; + if (c > '~') { return false; }; return true; }; // isgraph — printable, non-space. export fn isgraph(c: rune) bool = { - if (c < 33) { return false; }; - if (c > 126) { return false; }; + if (c < '!') { return false; }; + if (c > '~') { return false; }; return true; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 59718946..6ea44d46 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -4363,20 +4363,20 @@ package ascii; import strings; export fn isdigit(c: rune) bool = { - if (c < 48) { return false; }; - if (c > 57) { return false; }; + if (c < '0') { return false; }; + if (c > '9') { return false; }; return true; }; export fn isupper(c: rune) bool = { - if (c < 65) { return false; }; - if (c > 90) { return false; }; + if (c < 'A') { return false; }; + if (c > 'Z') { return false; }; return true; }; export fn islower(c: rune) bool = { - if (c < 97) { return false; }; - if (c > 122) { return false; }; + if (c < 'a') { return false; }; + if (c > 'z') { return false; }; return true; }; @@ -4392,22 +4392,22 @@ export fn isalnum(c: rune) bool = { // isspace — the C/Hare set: space, tab, NL, VT, FF, CR. export fn isspace(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' - if (c == 10) { return true; }; // '\n' - if (c == 11) { return true; }; // '\v' - if (c == 12) { return true; }; // '\f' - if (c == 13) { return true; }; // '\r' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; + if (c == '\n') { return true; }; + if (c == '\v') { return true; }; + if (c == '\f') { return true; }; + if (c == '\r') { return true; }; return false; }; export fn isxdigit(c: rune) bool = { if (isdigit(c)) { return true; }; - if (c >= 65) { - if (c <= 70) { return true; }; // 'A'..'F' + if (c >= 'A') { + if (c <= 'F') { return true; }; }; - if (c >= 97) { - if (c <= 102) { return true; }; // 'a'..'f' + if (c >= 'a') { + if (c <= 'f') { return true; }; }; return false; }; @@ -4441,22 +4441,22 @@ export fn iscntrl(c: rune) bool = { // isblank — space and tab. export fn isblank(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; return false; }; // isprint — printable: space through '~'. export fn isprint(c: rune) bool = { - if (c < 32) { return false; }; - if (c > 126) { return false; }; + if (c < ' ') { return false; }; + if (c > '~') { return false; }; return true; }; // isgraph — printable, non-space. export fn isgraph(c: rune) bool = { - if (c < 33) { return false; }; - if (c > 126) { return false; }; + if (c < '!') { return false; }; + if (c > '~') { return false; }; return true; }; diff --git a/selfhost/test/smoke.combined.ww b/selfhost/test/smoke.combined.ww index afe38ebe..2988c1ea 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -4363,20 +4363,20 @@ package ascii; import strings; export fn isdigit(c: rune) bool = { - if (c < 48) { return false; }; - if (c > 57) { return false; }; + if (c < '0') { return false; }; + if (c > '9') { return false; }; return true; }; export fn isupper(c: rune) bool = { - if (c < 65) { return false; }; - if (c > 90) { return false; }; + if (c < 'A') { return false; }; + if (c > 'Z') { return false; }; return true; }; export fn islower(c: rune) bool = { - if (c < 97) { return false; }; - if (c > 122) { return false; }; + if (c < 'a') { return false; }; + if (c > 'z') { return false; }; return true; }; @@ -4392,22 +4392,22 @@ export fn isalnum(c: rune) bool = { // isspace — the C/Hare set: space, tab, NL, VT, FF, CR. export fn isspace(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' - if (c == 10) { return true; }; // '\n' - if (c == 11) { return true; }; // '\v' - if (c == 12) { return true; }; // '\f' - if (c == 13) { return true; }; // '\r' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; + if (c == '\n') { return true; }; + if (c == '\v') { return true; }; + if (c == '\f') { return true; }; + if (c == '\r') { return true; }; return false; }; export fn isxdigit(c: rune) bool = { if (isdigit(c)) { return true; }; - if (c >= 65) { - if (c <= 70) { return true; }; // 'A'..'F' + if (c >= 'A') { + if (c <= 'F') { return true; }; }; - if (c >= 97) { - if (c <= 102) { return true; }; // 'a'..'f' + if (c >= 'a') { + if (c <= 'f') { return true; }; }; return false; }; @@ -4441,22 +4441,22 @@ export fn iscntrl(c: rune) bool = { // isblank — space and tab. export fn isblank(c: rune) bool = { - if (c == 32) { return true; }; // ' ' - if (c == 9) { return true; }; // '\t' + if (c == ' ') { return true; }; + if (c == '\t') { return true; }; return false; }; // isprint — printable: space through '~'. export fn isprint(c: rune) bool = { - if (c < 32) { return false; }; - if (c > 126) { return false; }; + if (c < ' ') { return false; }; + if (c > '~') { return false; }; return true; }; // isgraph — printable, non-space. export fn isgraph(c: rune) bool = { - if (c < 33) { return false; }; - if (c > 126) { return false; }; + if (c < '!') { return false; }; + if (c > '~') { return false; }; return true; };