commit b47f65e8fc00c584505e9490181138891e1a9059
parent 19bc7463d0bd485b162826f043b722cad87b1450
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 2 Jun 2026 17:39:17 -0700
driver: add standard-named aliases for hash and compress
Expose the hash and compress tools under the conventional command names so
they drop into existing toolchains:
hash -> sha256sum, b2sum, crc32 (algorithm pinned, -a rejected)
compress -> gzip, gunzip, lz4, lz4c (container + direction pinned,
-z rejected, -d flips direction)
Each alias is a thin wrapper over a shared persona-driven core. sha256sum is
byte-for-byte compatible with coreutils; kit's b2sum is BLAKE2b-256 (GNU
defaults to 512, so digests differ in width). The compress aliases accept the
common gzip/lz4 flags (-c/-k/-f, levels, ...) as no-ops but always stream to
stdout/-o rather than rewriting the input in place. cksum is intentionally
not provided (different CRC variant + decimal output).
The aliases are tagged BYTEUTIL, so `kit install` lays them down by default
alongside xxd/cmp. Docs and tools/install smoke tests updated.
Diffstat:
9 files changed, 245 insertions(+), 35 deletions(-)
diff --git a/README.md b/README.md
@@ -27,6 +27,9 @@ It features:
addr2line, strings
- Standalone gzip and LZ4-frame compression (`compress`), interoperable with
stock `gzip`/`lz4`
+- Content hashing (`hash`: SHA-256, BLAKE2b-256, CRC-32)
+- Drop-in standard names for the above: `sha256sum`, `b2sum`, `crc32`, `gzip`,
+ `gunzip`, `lz4`, `lz4c`
- A single multi-call binary, with an `install` command that drops per-tool
symlinks (hard links on Windows) into a directory for drop-in toolchain use
- Debug info generation and consumption (DWARF)
diff --git a/doc/DRIVER.md b/doc/DRIVER.md
@@ -96,7 +96,9 @@ tool reaches into compiler internals.
| `xxd` | Hex dump *any* file (format-agnostic, unlike `objdump -s`); reverse a dump to binary (`-r`), plain (`-p`), C array (`-i`). |
| `cmp` | Compare two files byte by byte; GNU/BSD-compatible messages and 0/1/2 exit codes. |
| `hash` | SHA-256, BLAKE2b-256, or CRC-32 (`-a`) of files or stdin; coreutils-style output. Backed by the public `<kit/hash.h>`. |
+| `sha256sum` / `b2sum` / `crc32` | `hash` under standard names, each pinning its algorithm (`-a` rejected). `sha256sum` is byte-compatible with coreutils; kit's `b2sum` is BLAKE2b-**256** (GNU defaults to 512). |
| `compress` | Compress/decompress a stream with gzip (`.gz`, default) or the LZ4 frame format (`.lz4`); `-d` decompresses (format auto-detected from magic). Output interoperates with stock `gzip`/`lz4`. Backed by the public `<kit/compress.h>`. |
+| `gzip` / `gunzip` / `lz4` / `lz4c` | `compress` under standard names: a pinned container + default direction. `-d` flips direction, `-z` is rejected, and the common gzip/lz4 flags (`-c`/`-k`/`-f`, `-1..-9`, …) are accepted as no-ops; output always streams to stdout/`-o` (no in-place rewrite). |
| `disas` | Disassemble a raw, headerless byte buffer (file/stdin/inline `-x` hex) for a `-target` arch. |
| `mc` | Assemble one instruction and show its encoding (llvm-mc style); lists any relocations. |
| `run` | JIT-compile inputs and call the entry symbol in-process. |
diff --git a/driver/cmd/compress.c b/driver/cmd/compress.c
@@ -11,13 +11,41 @@
* interoperable containers: gzip (`.gz`, default) or the LZ4 frame format
* (`.lz4`). Reads a FILE operand or stdin, writes to `-o OUT` or stdout. On
* decompress the format is auto-detected from the input's magic bytes unless
- * `-z` forces it. Drives the public kit/compress.h API. */
+ * `-z` forces it. Drives the public kit/compress.h API.
+ *
+ * The same core backs the standard-named aliases, each pinning a container and
+ * a default direction so it drops in for the matching command:
+ * gzip -> compress, gzip gunzip -> decompress, gzip
+ * lz4 -> compress, LZ4 frame lz4c -> compress, LZ4 frame (legacy name)
+ * Under an alias -z is rejected (the container is fixed), the common
+ * gzip/lz4 flags (-c/-k/-f, levels, ...) are accepted, and -d still flips the
+ * direction. kit always streams to stdout/`-o` and never rewrites the input in
+ * place, so the in-place file flags are deliberately not emulated. */
#define COMPRESS_TOOL "compress"
+/* Invocation personality. The generic `compress` leaves format and direction
+ * to flags; the aliases pin a container and a starting direction. */
+typedef struct CompressPersona {
+ const char* name; /* tool name for diagnostics: compress/gzip/... */
+ KitCompressFormat format; /* default (and, when locked, the only) container */
+ int locked_format; /* alias pins the container: -z is rejected, no
+ * decompress auto-detection */
+ int default_decompress; /* alias starts in decompress mode (gunzip) */
+ int compat; /* accept gzip/lz4-style compatibility flags */
+} CompressPersona;
+
+static const CompressPersona CZ_GENERIC = {"compress", KIT_COMPRESS_GZIP, 0, 0,
+ 0};
+static const CompressPersona CZ_GZIP = {"gzip", KIT_COMPRESS_GZIP, 1, 0, 1};
+static const CompressPersona CZ_GUNZIP = {"gunzip", KIT_COMPRESS_GZIP, 1, 1, 1};
+static const CompressPersona CZ_LZ4 = {"lz4", KIT_COMPRESS_LZ4_FRAME, 1, 0, 1};
+static const CompressPersona CZ_LZ4C = {"lz4c", KIT_COMPRESS_LZ4_FRAME, 1, 0,
+ 1};
+
typedef struct CompressOpts {
int decompress; /* -d */
- int have_format; /* whether -z/--format was given */
+ int have_format; /* whether -z/--format (or a pinned container) was given */
KitCompressFormat format;
int seen_input; /* a FILE or `-` operand was seen */
const char* in; /* input path, or NULL = stdin */
@@ -36,6 +64,31 @@ static int compress_parse_format(const char* s, KitCompressFormat* out) {
return 1;
}
+/* gzip/lz4-style flags accepted (as no-ops) under an alias so the tool works
+ * as a drop-in. kit always streams stdin/-o to stdout and never mutates the
+ * input in place, so -c/--stdout, -k/--keep and -f/--force have nothing to do;
+ * the codecs expose no level, so -1..-9 / --fast[=N] / --best are ignored too.
+ * Direction (-d) and the long decompress spellings are handled by the caller.
+ * Returns 1 if `a` is one of these accepted no-ops. */
+static int compress_compat_noop(const char* a) {
+ if (driver_streq(a, "-c") || driver_streq(a, "--stdout") ||
+ driver_streq(a, "--to-stdout"))
+ return 1;
+ if (driver_streq(a, "-k") || driver_streq(a, "--keep")) return 1;
+ if (driver_streq(a, "-f") || driver_streq(a, "--force")) return 1;
+ if (driver_streq(a, "-n") || driver_streq(a, "--no-name")) return 1;
+ if (driver_streq(a, "-q") || driver_streq(a, "--quiet")) return 1;
+ if (driver_streq(a, "--best") || driver_streq(a, "--fast")) return 1;
+ if (driver_strneq(a, "--fast=", 7)) return 1;
+ /* -N / -NN compression level (gzip 1-9, lz4 up to 12): a dash then digits. */
+ if (a[0] == '-' && a[1] >= '1' && a[1] <= '9') {
+ size_t k = 2;
+ while (a[k] >= '0' && a[k] <= '9') ++k;
+ if (a[k] == '\0') return 1;
+ }
+ return 0;
+}
+
void driver_help_compress(void) {
driver_printf(
"%.*s",
@@ -60,11 +113,21 @@ void driver_help_compress(void) {
" -o OUT write output to OUT (default: stdout)\n"
" -h, --help show this help\n"
"\n"
+ "ALIASES\n"
+ " Invoked as gzip / lz4 (or lz4c) compresses to that container; as\n"
+ " gunzip decompresses gzip. -d flips direction; -z is rejected "
+ "(the\n"
+ " container is fixed). Common gzip/lz4 flags (-c/--stdout, -k, -f,\n"
+ " -1..-9, --fast, --best) are accepted; output still goes to "
+ "stdout\n"
+ " or -o, never rewriting the input in place.\n"
+ "\n"
"EXIT CODES\n"
" 0 success 1 I/O or codec error 2 bad usage\n")));
}
-int driver_compress(int argc, char** argv) {
+static int compress_main(int argc, char** argv,
+ const CompressPersona* persona) {
DriverEnv env;
KitContext ctx;
CompressOpts o;
@@ -83,19 +146,31 @@ int driver_compress(int argc, char** argv) {
}
memset(&o, 0, sizeof o);
- o.format = KIT_COMPRESS_GZIP;
+ o.format = persona->format;
+ /* A pinned container both fixes the format and disables decompress
+ * auto-detection (gunzip only reads gzip, lz4 only reads LZ4). */
+ o.have_format = persona->locked_format;
+ o.decompress = persona->default_decompress;
driver_env_init(&env);
ctx = driver_env_to_context(&env);
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
- if (driver_streq(a, "-d")) {
+ if (driver_streq(a, "-d") ||
+ (persona->compat && (driver_streq(a, "--decompress") ||
+ driver_streq(a, "--uncompress")))) {
o.decompress = 1;
continue;
}
if (driver_streq(a, "-z") || driver_streq(a, "--format")) {
+ if (persona->locked_format) {
+ driver_errf(persona->name, "-z is not accepted; %s always uses %s",
+ persona->name,
+ persona->format == KIT_COMPRESS_GZIP ? "gzip" : "lz4");
+ goto done;
+ }
if (i + 1 >= argc || compress_parse_format(argv[++i], &o.format) != 0) {
- driver_errf(COMPRESS_TOOL, "-z requires gzip or lz4");
+ driver_errf(persona->name, "-z requires gzip or lz4");
goto done;
}
o.have_format = 1;
@@ -103,7 +178,7 @@ int driver_compress(int argc, char** argv) {
}
if (driver_streq(a, "-o")) {
if (i + 1 >= argc) {
- driver_errf(COMPRESS_TOOL, "-o requires a file path");
+ driver_errf(persona->name, "-o requires a file path");
goto done;
}
o.out = argv[++i];
@@ -111,18 +186,19 @@ int driver_compress(int argc, char** argv) {
}
if (driver_streq(a, "-")) { /* explicit stdin */
if (o.seen_input) {
- driver_errf(COMPRESS_TOOL, "only one input may be given");
+ driver_errf(persona->name, "only one input may be given");
goto done;
}
o.seen_input = 1;
continue;
}
+ if (persona->compat && compress_compat_noop(a)) continue;
if (a[0] == '-' && a[1] != '\0') {
- driver_errf(COMPRESS_TOOL, "unknown option: %s", a);
+ driver_errf(persona->name, "unknown option: %s", a);
goto done;
}
if (o.seen_input) {
- driver_errf(COMPRESS_TOOL, "only one input may be given");
+ driver_errf(persona->name, "only one input may be given");
goto done;
}
o.seen_input = 1;
@@ -132,7 +208,7 @@ int driver_compress(int argc, char** argv) {
/* Load the whole input. */
if (o.in) {
KitSlice input;
- if (driver_load_bytes(&env.file_io, COMPRESS_TOOL, o.in, &ld, &input) !=
+ if (driver_load_bytes(&env.file_io, persona->name, o.in, &ld, &input) !=
0) {
rc = 1;
goto done;
@@ -142,7 +218,7 @@ int driver_compress(int argc, char** argv) {
len = input.len;
} else {
if (!driver_read_stdin(&env, &sbuf, &sbuf_len)) {
- driver_errf(COMPRESS_TOOL, "failed to read stdin");
+ driver_errf(persona->name, "failed to read stdin");
rc = 1;
goto done;
}
@@ -155,7 +231,7 @@ int driver_compress(int argc, char** argv) {
fmt = o.format;
if (o.decompress && !o.have_format) {
if (kit_compress_detect(data, len, &fmt) != KIT_OK) {
- driver_errf(COMPRESS_TOOL, "cannot detect input format; use -z gzip|lz4");
+ driver_errf(persona->name, "cannot detect input format; use -z gzip|lz4");
rc = 1;
goto done;
}
@@ -164,7 +240,7 @@ int driver_compress(int argc, char** argv) {
/* Open the output. */
if (o.out) {
if (ctx.file_io->open_writer(ctx.file_io->user, o.out, &w) != KIT_OK) {
- driver_errf(COMPRESS_TOOL, "failed to open output: %s", o.out);
+ driver_errf(persona->name, "failed to open output: %s", o.out);
rc = 1;
goto done;
}
@@ -189,3 +265,23 @@ done:
driver_env_fini(&env);
return rc;
}
+
+int driver_compress(int argc, char** argv) {
+ return compress_main(argc, argv, &CZ_GENERIC);
+}
+
+int driver_gzip(int argc, char** argv) {
+ return compress_main(argc, argv, &CZ_GZIP);
+}
+
+int driver_gunzip(int argc, char** argv) {
+ return compress_main(argc, argv, &CZ_GUNZIP);
+}
+
+int driver_lz4(int argc, char** argv) {
+ return compress_main(argc, argv, &CZ_LZ4);
+}
+
+int driver_lz4c(int argc, char** argv) {
+ return compress_main(argc, argv, &CZ_LZ4C);
+}
diff --git a/driver/cmd/hash.c b/driver/cmd/hash.c
@@ -11,16 +11,45 @@
* input. Output is coreutils-style ("<hex> <name>"), so it diffs cleanly
* against sha256sum / b2sum / cksum -a output. With no FILE, or with `-`,
* reads stdin. Drives the streaming kit_hasher_* API (the one-shot
- * kit_hash stays for library callers). */
-
-#define HASH_TOOL "hash"
+ * kit_hash stays for library callers).
+ *
+ * The same core also backs the standard-named aliases, each of which pins the
+ * algorithm so the tool is a drop-in for the matching command:
+ * sha256sum -> SHA-256 b2sum -> BLAKE2b-256 crc32 -> CRC-32
+ * (Note: GNU b2sum defaults to BLAKE2b-512; kit's BLAKE2b is 256-bit, so the
+ * digests differ in width.) The aliases reject -a, since their algorithm is
+ * fixed; the generic `hash` tool keeps -a for selecting any of the three. */
static const char HASH_HEX[] = "0123456789abcdef";
+/* Invocation personality: which algorithm, and whether the name pins it. */
+typedef struct HashPersona {
+ const char* name; /* tool name for diagnostics: hash/sha256sum/... */
+ KitHashAlgo algo; /* default (and, when locked, the only) algorithm */
+ int locked; /* alias pins the algorithm: -a is rejected */
+} HashPersona;
+
+static const HashPersona HASH_GENERIC = {"hash", KIT_HASH_SHA256, 0};
+static const HashPersona HASH_SHA256SUM = {"sha256sum", KIT_HASH_SHA256, 1};
+static const HashPersona HASH_B2SUM = {"b2sum", KIT_HASH_BLAKE2B, 1};
+static const HashPersona HASH_CRC32 = {"crc32", KIT_HASH_CRC32, 1};
+
typedef struct HashOpts {
KitHashAlgo algo;
} HashOpts;
+static const char* hash_algo_name(KitHashAlgo algo) {
+ switch (algo) {
+ case KIT_HASH_SHA256:
+ return "sha256";
+ case KIT_HASH_BLAKE2B:
+ return "blake2b";
+ case KIT_HASH_CRC32:
+ return "crc32";
+ }
+ return "?";
+}
+
static int hash_parse_algo(const char* s, KitHashAlgo* out) {
if (driver_streq(s, "sha256")) {
*out = KIT_HASH_SHA256;
@@ -54,21 +83,27 @@ void driver_help_hash(void) {
" -a ALGO sha256 (default) | blake2b | crc32\n"
" -h, --help show this help\n"
"\n"
+ "ALIASES\n"
+ " Invoked as sha256sum, b2sum, or crc32 the algorithm is fixed to\n"
+ " SHA-256, BLAKE2b-256, or CRC-32 respectively and -a is rejected.\n"
+ " (GNU b2sum defaults to BLAKE2b-512; this BLAKE2b is 256-bit.)\n"
+ "\n"
"EXIT CODES\n"
" 0 success 1 I/O error 2 bad usage\n")));
}
/* Hash data[0..len) with opts->algo and print "<hex> <name>". Returns 0 on
- * success, 1 on failure (error already reported). */
+ * success, 1 on failure (error already reported under `tool`). */
static int hash_one(const KitContext* ctx, const HashOpts* opts,
- const uint8_t* data, size_t len, const char* name) {
+ const char* tool, const uint8_t* data, size_t len,
+ const char* name) {
KitHasher* h = NULL;
uint8_t digest[KIT_HASH_MAX_LEN];
char hex[KIT_HASH_MAX_LEN * 2 + 1];
size_t dlen = 0, i;
if (kit_hasher_new(ctx, opts->algo, &h) != KIT_OK) {
- driver_errf(HASH_TOOL, "failed to start hasher");
+ driver_errf(tool, "failed to start hasher");
return 1;
}
kit_hasher_update(h, data, len);
@@ -84,7 +119,7 @@ static int hash_one(const KitContext* ctx, const HashOpts* opts,
return 0;
}
-int driver_hash(int argc, char** argv) {
+static int hash_main(int argc, char** argv, const HashPersona* persona) {
DriverEnv env;
KitContext ctx;
HashOpts opts;
@@ -96,7 +131,7 @@ int driver_hash(int argc, char** argv) {
}
memset(&opts, 0, sizeof opts);
- opts.algo = KIT_HASH_SHA256;
+ opts.algo = persona->algo;
driver_env_init(&env);
ctx = driver_env_to_context(&env);
@@ -104,8 +139,14 @@ int driver_hash(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
if (driver_streq(a, "-a")) {
+ if (persona->locked) {
+ driver_errf(persona->name, "-a is not accepted; %s always uses %s",
+ persona->name, hash_algo_name(persona->algo));
+ rc = 2;
+ goto done;
+ }
if (i + 1 >= argc || hash_parse_algo(argv[++i], &opts.algo) != 0) {
- driver_errf(HASH_TOOL, "-a requires sha256, blake2b, or crc32");
+ driver_errf(persona->name, "-a requires sha256, blake2b, or crc32");
rc = 2;
goto done;
}
@@ -116,7 +157,7 @@ int driver_hash(int argc, char** argv) {
continue;
}
if (a[0] == '-' && a[1] != '\0') {
- driver_errf(HASH_TOOL, "unknown option: %s", a);
+ driver_errf(persona->name, "unknown option: %s", a);
rc = 2;
goto done;
}
@@ -128,11 +169,11 @@ int driver_hash(int argc, char** argv) {
uint8_t* buf = NULL;
size_t n = 0;
if (!driver_read_stdin(&env, &buf, &n)) {
- driver_errf(HASH_TOOL, "failed to read stdin");
+ driver_errf(persona->name, "failed to read stdin");
rc = 1;
goto done;
}
- rc = hash_one(&ctx, &opts, buf, n, "-");
+ rc = hash_one(&ctx, &opts, persona->name, buf, n, "-");
driver_free(&env, buf, n);
goto done;
}
@@ -142,29 +183,30 @@ int driver_hash(int argc, char** argv) {
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
if (driver_streq(a, "-a")) {
- ++i; /* skip its value */
+ ++i; /* skip its value (only reachable for the generic, unlocked tool) */
continue;
}
if (driver_streq(a, "-")) {
uint8_t* buf = NULL;
size_t n = 0;
if (!driver_read_stdin(&env, &buf, &n)) {
- driver_errf(HASH_TOOL, "failed to read stdin");
+ driver_errf(persona->name, "failed to read stdin");
rc = 1;
continue;
}
- if (hash_one(&ctx, &opts, buf, n, "-") != 0) rc = 1;
+ if (hash_one(&ctx, &opts, persona->name, buf, n, "-") != 0) rc = 1;
driver_free(&env, buf, n);
continue;
}
{
DriverLoad ld = {0};
KitSlice input;
- if (driver_load_bytes(&env.file_io, HASH_TOOL, a, &ld, &input) != 0) {
+ if (driver_load_bytes(&env.file_io, persona->name, a, &ld, &input) != 0) {
rc = 1;
continue;
}
- if (hash_one(&ctx, &opts, input.data, input.len, a) != 0) rc = 1;
+ if (hash_one(&ctx, &opts, persona->name, input.data, input.len, a) != 0)
+ rc = 1;
driver_release_bytes(&env.file_io, &ld);
}
}
@@ -173,3 +215,19 @@ done:
driver_env_fini(&env);
return rc;
}
+
+int driver_hash(int argc, char** argv) {
+ return hash_main(argc, argv, &HASH_GENERIC);
+}
+
+int driver_sha256sum(int argc, char** argv) {
+ return hash_main(argc, argv, &HASH_SHA256SUM);
+}
+
+int driver_b2sum(int argc, char** argv) {
+ return hash_main(argc, argv, &HASH_B2SUM);
+}
+
+int driver_crc32(int argc, char** argv) {
+ return hash_main(argc, argv, &HASH_CRC32);
+}
diff --git a/driver/cmd/install.c b/driver/cmd/install.c
@@ -37,9 +37,9 @@ void driver_help_install(void) {
"\n"
" With no TOOL given, installs the default set: the binutils/compiler\n"
" toolchain (cc cpp as ld ar ranlib strip objcopy objdump nm size\n"
- " addr2line strings) plus the standard-named byte utilities (xxd cmp).\n"
- " Use --all for every tool, or name specific TOOLs to install just\n"
- " those.\n"
+ " addr2line strings) plus the standard-named byte utilities (xxd cmp\n"
+ " sha256sum b2sum crc32 gzip gunzip lz4 lz4c). Use --all for every\n"
+ " tool, or name specific TOOLs to install just those.\n"
"\n"
"OPTIONS\n"
" -s, --symlink create symlinks (default except on Windows)\n"
diff --git a/driver/driver.h b/driver/driver.h
@@ -59,7 +59,14 @@ int driver_pkg(int argc, char** argv);
int driver_xxd(int argc, char** argv);
int driver_cmp(int argc, char** argv);
int driver_hash(int argc, char** argv);
+int driver_sha256sum(int argc, char** argv);
+int driver_b2sum(int argc, char** argv);
+int driver_crc32(int argc, char** argv);
int driver_compress(int argc, char** argv);
+int driver_gzip(int argc, char** argv);
+int driver_gunzip(int argc, char** argv);
+int driver_lz4(int argc, char** argv);
+int driver_lz4c(int argc, char** argv);
int driver_disas(int argc, char** argv);
int driver_mc(int argc, char** argv);
diff --git a/driver/main.c b/driver/main.c
@@ -131,10 +131,24 @@ static const DriverToolDesc driver_tools[] = {
#if KIT_TOOL_HASH_ENABLED
{"hash", driver_hash, driver_help_hash,
"Hash files with SHA-256, BLAKE2b, or CRC-32", DRIVER_GROUP_OTHER},
+ {"sha256sum", driver_sha256sum, driver_help_hash,
+ "SHA-256 of files or stdin (sha256sum-compatible)", DRIVER_GROUP_BYTEUTIL},
+ {"b2sum", driver_b2sum, driver_help_hash,
+ "BLAKE2b-256 of files or stdin (b2sum-style)", DRIVER_GROUP_BYTEUTIL},
+ {"crc32", driver_crc32, driver_help_hash, "CRC-32 of files or stdin",
+ DRIVER_GROUP_BYTEUTIL},
#endif
#if KIT_TOOL_COMPRESS_ENABLED
{"compress", driver_compress, driver_help_compress,
"Compress or decompress data (gzip, lz4 frame)", DRIVER_GROUP_OTHER},
+ {"gzip", driver_gzip, driver_help_compress,
+ "Compress to gzip (.gz); -d to decompress", DRIVER_GROUP_BYTEUTIL},
+ {"gunzip", driver_gunzip, driver_help_compress,
+ "Decompress gzip (.gz) streams", DRIVER_GROUP_BYTEUTIL},
+ {"lz4", driver_lz4, driver_help_compress,
+ "Compress to LZ4 frame (.lz4); -d to decompress", DRIVER_GROUP_BYTEUTIL},
+ {"lz4c", driver_lz4c, driver_help_compress,
+ "Compress to LZ4 frame (.lz4) (lz4 alias)", DRIVER_GROUP_BYTEUTIL},
#endif
#if KIT_TOOL_DISAS_ENABLED
{"disas", driver_disas, driver_help_disas,
diff --git a/test/driver/run.sh b/test/driver/run.sh
@@ -964,7 +964,7 @@ fi
inst_dir="$work/inst"
run_ok "install-default" "$KIT" install "$inst_dir"
for t in cc cpp as ld ar ranlib strip objcopy objdump nm size addr2line \
- strings xxd cmp; do
+ strings xxd cmp sha256sum b2sum crc32 gzip gunzip lz4 lz4c; do
assert_file_exists "install-has-$t" "$inst_dir/$t"
done
is_executable "install-cc-executable" "$inst_dir/cc"
diff --git a/test/tools/run.sh b/test/tools/run.sh
@@ -59,6 +59,18 @@ printf 'abc' | "$KIT" hash -a sha256 > "$work/sha.out" 2>&1
contains hash-sha256 "$work/sha.out" \
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
+# Standard-named aliases pin the algorithm and match `hash -a` exactly.
+printf 'abc' | "$KIT" sha256sum > "$work/sha256sum.out" 2>&1
+contains alias-sha256sum "$work/sha256sum.out" \
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad -"
+printf 'abc' | "$KIT" b2sum > "$work/b2sum.out" 2>&1
+printf 'abc' | "$KIT" hash -a blake2b > "$work/b2ref.out" 2>&1
+same_file alias-b2sum-matches-hash "$work/b2sum.out" "$work/b2ref.out"
+"$KIT" crc32 "$work/crc.in" > "$work/crc32.out" 2>&1
+contains alias-crc32 "$work/crc32.out" "cbf43926"
+# A pinned alias rejects -a (its algorithm is fixed).
+run_fail alias-sha256sum-no-a "$KIT" sha256sum -a blake2b "$work/crc.in"
+
# ---- disas -----------------------------------------------------------------
"$KIT" disas -target aarch64 -x "1f 20 03 d5" > "$work/d-aa64.out" 2>&1
contains disas-aa64-nop "$work/d-aa64.out" "nop"
@@ -111,6 +123,24 @@ done
"$KIT" compress "$work/cz.txt" | "$KIT" compress -d > "$work/cz.def"
same_file compress-default-gzip "$work/cz.txt" "$work/cz.def"
+# Standard-named aliases: gzip/gunzip and lz4 round-trip through each other and
+# through the generic tool; gunzip is just `compress -d` pinned to gzip.
+"$KIT" gzip "$work/cz.txt" | "$KIT" gunzip > "$work/cz.gzalias"
+same_file alias-gzip-gunzip "$work/cz.txt" "$work/cz.gzalias"
+"$KIT" gzip "$work/cz.txt" | "$KIT" compress -d > "$work/cz.gz2generic"
+same_file alias-gzip-to-generic "$work/cz.txt" "$work/cz.gz2generic"
+"$KIT" lz4 "$work/cz.txt" | "$KIT" lz4 -d > "$work/cz.lz4alias"
+same_file alias-lz4-roundtrip "$work/cz.txt" "$work/cz.lz4alias"
+"$KIT" lz4c "$work/cz.txt" | "$KIT" lz4 -d > "$work/cz.lz4calias"
+same_file alias-lz4c-roundtrip "$work/cz.txt" "$work/cz.lz4calias"
+# gzip -d flips direction; the common gzip flags (-c, level -9) are no-ops.
+"$KIT" gzip -9 -c "$work/cz.txt" | "$KIT" gzip -d > "$work/cz.compat"
+same_file alias-gzip-compat-flags "$work/cz.txt" "$work/cz.compat"
+# A pinned alias rejects -z, and gunzip will not auto-detect a foreign container.
+run_fail alias-gzip-no-z "$KIT" gzip -z lz4 "$work/cz.txt"
+"$KIT" lz4 "$work/cz.txt" > "$work/cz.lz4only"
+run_fail alias-gunzip-wrong-format "$KIT" gunzip "$work/cz.lz4only"
+
# Error exits: bad format / two inputs / missing file all exit non-zero.
run_fail compress-err-bad-format "$KIT" compress -z bogus "$work/cz.txt"
run_fail compress-err-two-inputs "$KIT" compress "$work/cz.txt" "$work/cz.empty"