summaryrefslogtreecommitdiffstats
path: root/shell/src/lib.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-01 18:25:55 +0200
committersalmonik <salmonik@tuta.io>2026-08-01 18:25:55 +0200
commit1ea2f68e6a9af135e6cb3274fdf28d4ddc5812d5 (patch)
treef28246586e387293d0c8beaf6b445210aaab8c48 /shell/src/lib.rs
parentklog/tty/pager: no more truncated lines — full lines flow, terminal wraps (diff)
downloadrs-dos-1ea2f68e6a9af135e6cb3274fdf28d4ddc5812d5.tar.gz
rs-dos-1ea2f68e6a9af135e6cb3274fdf28d4ddc5812d5.zip
fix pi-lens warnings: unwraps, shell SC2046, dup code (fmtbuf/scripts/hexdump/cat/ahci/pci)
- memory.rs: self-test Layout::from_size_align no longer panics — the test fails cleanly on an invalid layout - fat.rs: v() no longer unwraps the active-volume slot — invariant violation logs + halts instead of panicking mid-disk-io - strbuf: shared FmtBuf replaces the duplicated PanicBuf/FmtBuf (main.rs + sched.rs) - test-disk.sh: SC2046 — conditional --fresh arg no longer relies on word splitting - scripts: boot.sh/boot-image.sh share lib-boot-args.sh (dup args loop) - shell: cat/hexdump stdin pairs unified with Option<&str> marker; hexdump format_row folded into format_partial - ahci: read/write_sectors unified behind dma_sectors - pci: config_read/write share config_addr
Diffstat (limited to 'shell/src/lib.rs')
-rw-r--r--shell/src/lib.rs94
1 files changed, 21 insertions, 73 deletions
diff --git a/shell/src/lib.rs b/shell/src/lib.rs
index 617e5a4..4640697 100644
--- a/shell/src/lib.rs
+++ b/shell/src/lib.rs
@@ -515,7 +515,12 @@ impl Pipeline {
515 } 515 }
516 } 516 }
517 Filter::Pause => { 517 Filter::Pause => {
518 let StageState::Pause { shown, screen, cols } = st else { 518 let StageState::Pause {
519 shown,
520 screen,
521 cols,
522 } = st
523 else {
519 unreachable!("stage state does not match filter") 524 unreachable!("stage state does not match filter")
520 }; 525 };
521 for l in cur.drain(..) { 526 for l in cur.drain(..) {
@@ -871,7 +876,7 @@ fn cmd_cat(p: &Parsed) {
871 if p.args.is_empty() { 876 if p.args.is_empty() {
872 // Path-less `cat` with no input keyword reads the keyboard 877 // Path-less `cat` with no input keyword reads the keyboard
873 // until ^D. 878 // until ^D.
874 cat_stdin(&mut pipe); 879 cat_stdin(&mut pipe, None);
875 } else { 880 } else {
876 for path in &p.args { 881 for path in &p.args {
877 if !cat_file(&mut pipe, path) { 882 if !cat_file(&mut pipe, path) {
@@ -885,7 +890,7 @@ fn cmd_cat(p: &Parsed) {
885 } 890 }
886 Input::Til(marker) => { 891 Input::Til(marker) => {
887 if p.args.is_empty() { 892 if p.args.is_empty() {
888 cat_stdin_until(&mut pipe, marker); 893 cat_stdin(&mut pipe, Some(marker));
889 } else { 894 } else {
890 // `cat <path> TIL <marker>` — the paths are the input 895 // `cat <path> TIL <marker>` — the paths are the input
891 // source, truncated at the first marker line. 896 // source, truncated at the first marker line.
@@ -904,34 +909,21 @@ fn cmd_cat(p: &Parsed) {
904 pipe.end(); 909 pipe.end();
905} 910}
906 911
907fn cat_stdin(pipe: &mut Pipeline) -> bool { 912/// Read lines from the tty until ^C/^D (or an exact marker line, when
913/// `marker` is Some — the marker itself is not part of the input).
914fn cat_stdin(pipe: &mut Pipeline, marker: Option<&str>) -> bool {
908 loop { 915 loop {
909 match tty::read_line() { 916 match tty::read_line() {
910 LineInput::Line(l) => { 917 LineInput::Line(l) => {
911 if !pipe.line(l.as_str()) { 918 if marker.is_some() && l.as_str() == marker.unwrap() {
912 return false;
913 }
914 }
915 LineInput::Interrupted => return false, // ^C aborts the stream
916 LineInput::Eof => return true, // ^D = EOF
917 }
918 }
919}
920
921fn cat_stdin_until(pipe: &mut Pipeline, marker: &str) -> bool {
922 loop {
923 match tty::read_line() {
924 LineInput::Line(l) => {
925 // Marker line is not part of the input.
926 if l.as_str() == marker {
927 return true; 919 return true;
928 } 920 }
929 if !pipe.line(l.as_str()) { 921 if !pipe.line(l.as_str()) {
930 return false; 922 return false;
931 } 923 }
932 } 924 }
933 LineInput::Interrupted => return false, 925 LineInput::Interrupted => return false, // ^C aborts the stream
934 LineInput::Eof => return true, 926 LineInput::Eof => return true, // ^D = EOF
935 } 927 }
936 } 928 }
937} 929}
@@ -1030,25 +1022,6 @@ struct HexCtx<'a> {
1030 alive: bool, 1022 alive: bool,
1031} 1023}
1032 1024
1033fn format_row(addr: u64, row: &[u8; 16]) -> String {
1034 let mut out = String::new();
1035 use core::fmt::Write as _;
1036 let _ = core::write!(out, "{:08x} ", addr);
1037 for &b in row {
1038 let _ = core::write!(out, "{:02x} ", b);
1039 }
1040 out.push_str(" |");
1041 for &b in row {
1042 out.push(if b.is_ascii_graphic() || b == b' ' {
1043 b as char
1044 } else {
1045 '.'
1046 });
1047 }
1048 out.push('|');
1049 out
1050}
1051
1052fn format_partial(addr: u64, row: &[u8]) -> String { 1025fn format_partial(addr: u64, row: &[u8]) -> String {
1053 let mut out = String::new(); 1026 let mut out = String::new();
1054 use core::fmt::Write as _; 1027 use core::fmt::Write as _;
@@ -1081,7 +1054,7 @@ impl HexCtx<'_> {
1081 self.row[self.row_len] = b; 1054 self.row[self.row_len] = b;
1082 self.row_len += 1; 1055 self.row_len += 1;
1083 if self.row_len == 16 { 1056 if self.row_len == 16 {
1084 let line = format_row(self.pos, &self.row); 1057 let line = format_partial(self.pos, &self.row);
1085 self.alive = self.pipe.line(&line); 1058 self.alive = self.pipe.line(&line);
1086 self.pos += 16; 1059 self.pos += 16;
1087 self.row_len = 0; 1060 self.row_len = 0;
@@ -1106,7 +1079,7 @@ fn cmd_hexdump(p: &Parsed) {
1106 match &p.input { 1079 match &p.input {
1107 Input::None => { 1080 Input::None => {
1108 if p.args.is_empty() { 1081 if p.args.is_empty() {
1109 hexdump_stdin(&mut pipe); 1082 hexdump_stdin(&mut pipe, None);
1110 } else { 1083 } else {
1111 for path in &p.args { 1084 for path in &p.args {
1112 if !hexdump_file(&mut pipe, path) { 1085 if !hexdump_file(&mut pipe, path) {
@@ -1120,7 +1093,7 @@ fn cmd_hexdump(p: &Parsed) {
1120 } 1093 }
1121 Input::Til(marker) => { 1094 Input::Til(marker) => {
1122 if p.args.is_empty() { 1095 if p.args.is_empty() {
1123 hexdump_stdin_until(&mut pipe, marker); 1096 hexdump_stdin(&mut pipe, Some(marker));
1124 } else { 1097 } else {
1125 // `hexdump <path> TIL <marker>` — the paths are the input 1098 // `hexdump <path> TIL <marker>` — the paths are the input
1126 // source, truncated at the first marker line. 1099 // source, truncated at the first marker line.
@@ -1176,34 +1149,9 @@ fn hexdump_file(pipe: &mut Pipeline, path: &str) -> bool {
1176 ctx.alive 1149 ctx.alive
1177} 1150}
1178 1151
1179fn hexdump_stdin(pipe: &mut Pipeline) { 1152/// Hex-dump lines from the tty until ^C/^D (or an exact marker line,
1180 let mut ctx = HexCtx { 1153/// when `marker` is Some — the marker itself is not dumped).
1181 pipe, 1154fn hexdump_stdin(pipe: &mut Pipeline, marker: Option<&str>) {
1182 pos: 0,
1183 row: [0u8; 16],
1184 row_len: 0,
1185 alive: true,
1186 };
1187 loop {
1188 match tty::read_line() {
1189 LineInput::Line(l) => {
1190 ctx.feed(l.as_str().as_bytes());
1191 if !ctx.alive {
1192 break;
1193 }
1194 ctx.feed(b"\n");
1195 if !ctx.alive {
1196 break;
1197 }
1198 }
1199 LineInput::Interrupted => break,
1200 LineInput::Eof => break,
1201 }
1202 }
1203 ctx.flush();
1204}
1205
1206fn hexdump_stdin_until(pipe: &mut Pipeline, marker: &str) {
1207 let mut ctx = HexCtx { 1155 let mut ctx = HexCtx {
1208 pipe, 1156 pipe,
1209 pos: 0, 1157 pos: 0,
@@ -1214,7 +1162,7 @@ fn hexdump_stdin_until(pipe: &mut Pipeline, marker: &str) {
1214 loop { 1162 loop {
1215 match tty::read_line() { 1163 match tty::read_line() {
1216 LineInput::Line(l) => { 1164 LineInput::Line(l) => {
1217 if l.as_str() == marker { 1165 if marker.is_some() && l.as_str() == marker.unwrap() {
1218 break; 1166 break;
1219 } 1167 }
1220 ctx.feed(l.as_str().as_bytes()); 1168 ctx.feed(l.as_str().as_bytes());