summaryrefslogtreecommitdiffstats
path: root/bins/count
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-27 16:58:31 +0200
committersalmonik <salmonik@tuta.io>2026-08-27 16:58:31 +0200
commit300c0acbd7ab3fae8596ff839c39d9a17c70c68d (patch)
tree5a600b24c037dc798766e3ce3fc004956e517abb /bins/count
parentexec: PE32+ loader, versioned ABI, first external binaries (v0.6.0) (diff)
downloadrs-dos-300c0acbd7ab3fae8596ff839c39d9a17c70c68d.tar.gz
rs-dos-300c0acbd7ab3fae8596ff839c39d9a17c70c68d.zip
streams: per-invocation channel, pumping mode, filter pipeline wiring
exec: LineChannel bounded ring (cap=16) with abort/eof/marker fields. Shell 'pumping mode' assembles canonical lines from its queue into the channel while the command runs; ^C marks the channel aborted. Shell-side grammar: USE/TIL pre-drain into the channel before spawn; <cmd> <path> TIL <marker> sugar drains paths until the marker line. Interactive TIL: pump_key checks each submitted line against the marker and closes the channel when it matches. Exports callbacks run in the command task but touch shell-owned state: this is safe by construction — the shell blocks in exec_external until the command completes. put_line feeds Pipeline::line directly; get_line pops from the channel (yield-poll when empty). load: drop NX from image mapping (single-privilege kernel, NX bit 63 reserved when EFER.NXE is set by OVMF); compute image span from section RVAs not file size. bins/count: gate binary — reads lines via get_line, reports count via put_line. Verified: count USE file → 6; count <path> TIL END → 2; interactive count TIL DONE → 3; -h filter across task boundary; ^C abort. v1 stream exports: put_line → Pipeline, get_line ← channel, log_line → klog append, exit → abort_current. Accounting: print_one_line → pipe.line() returns false (head kill / pager ^C) → the binary should wrap up promptly; accepted: binary does not check the return value in v1 (phase 3 simplification).
Diffstat (limited to '')
-rw-r--r--bins/count/Cargo.toml10
-rw-r--r--bins/count/src/main.rs64
2 files changed, 74 insertions, 0 deletions
diff --git a/bins/count/Cargo.toml b/bins/count/Cargo.toml
new file mode 100644
index 0000000..5ab50cf
--- /dev/null
+++ b/bins/count/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "count"
3version.workspace = true
4edition.workspace = true
5
6[lints]
7workspace = true
8
9[dependencies]
10rsapi = { path = "../../rsapi" }
diff --git a/bins/count/src/main.rs b/bins/count/src/main.rs
new file mode 100644
index 0000000..6fd6f17
--- /dev/null
+++ b/bins/count/src/main.rs
@@ -0,0 +1,64 @@
1//! count — stream-input consumer (ADR 0006 Phase 3 gate).
2//!
3//! Reads lines through `get_line` until EOF or Abort, then reports how
4//! many it saw via `put_line`. Proves: USE pre-drain, TIL truncation,
5//! interactive pumping, and ^C abort across the task boundary.
6
7#![no_std]
8#![no_main]
9
10use rsapi::{Exports, StreamResult};
11
12#[panic_handler]
13fn panic(_info: &core::panic::PanicInfo) -> ! {
14 loop {
15 core::hint::spin_loop();
16 }
17}
18
19fn put_u32(exports: &Exports, mut v: u32) {
20 // Small fixed buffer; u32 max is 10 digits.
21 let mut buf = [0u8; 10];
22 let mut i = buf.len();
23 if v == 0 {
24 i -= 1;
25 buf[i] = b'0';
26 }
27 while v > 0 {
28 i -= 1;
29 buf[i] = b'0' + (v % 10) as u8;
30 v /= 10;
31 }
32 let suffix = b" line(s)";
33 let mut msg = [0u8; 18];
34 let n = buf.len() - i;
35 msg[..n].copy_from_slice(&buf[i..]);
36 msg[n..n + suffix.len()].copy_from_slice(suffix);
37 (exports.put_line)(rsapi::Line {
38 ptr: msg.as_ptr(),
39 len: n + suffix.len(),
40 });
41}
42
43/// The image entry point — the loader jumps here with the ABI arguments.
44#[unsafe(no_mangle)]
45pub extern "C" fn efi_main(
46 exports: &'static Exports,
47 _argc: usize,
48 _argv: *const rsapi::Arg,
49) -> i32 {
50 let mut count: u32 = 0;
51 loop {
52 let mut line = rsapi::Line {
53 ptr: core::ptr::null(),
54 len: 0,
55 };
56 match (exports.get_line)(&mut line) {
57 StreamResult::Line => count += 1,
58 StreamResult::Eof => break,
59 StreamResult::Abort => return 130, // 128+SIGINT convention
60 }
61 }
62 put_u32(exports, count);
63 0
64}