1use std::collections::VecDeque;
12use std::io::{self, BufRead, BufReader, Read};
13
14const SHIN_BUF_SIZE: usize = 8192;
16
17const INSTACK_INITIAL: usize = 4;
19
20pub mod flags {
22 pub const INP_FREE: u32 = 0x01; pub const INP_CONT: u32 = 0x02; pub const INP_ALIAS: u32 = 0x04; pub const INP_HIST: u32 = 0x08; pub const INP_LINENO: u32 = 0x10; pub const INP_APPEND: u32 = 0x20; pub const INP_ALCONT: u32 = 0x40; pub const INP_HISTCONT: u32 = 0x80; pub const INP_RAW_KEEP: u32 = 0x100; }
32
33#[derive(Debug, Clone)]
35struct InputStackEntry {
36 buf: String,
38 pos: usize,
40 flags: u32,
42 alias: Option<String>,
44}
45
46impl Default for InputStackEntry {
47 fn default() -> Self {
48 InputStackEntry {
49 buf: String::new(),
50 pos: 0,
51 flags: 0,
52 alias: None,
53 }
54 }
55}
56
57pub struct InputBuffer {
59 stack: Vec<InputStackEntry>,
61 buf: String,
63 pos: usize,
65 flags: u32,
67 pub buf_ct: usize,
69 pub strin: bool,
71 pub lineno: usize,
73 pub lexstop: bool,
75 shin_buffer: String,
77 shin_pos: usize,
79 shin_save_stack: Vec<(String, usize)>,
81 pushback: VecDeque<char>,
83 raw_input: String,
85}
86
87impl Default for InputBuffer {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl InputBuffer {
94 pub fn new() -> Self {
95 InputBuffer {
96 stack: Vec::with_capacity(INSTACK_INITIAL),
97 buf: String::new(),
98 pos: 0,
99 flags: 0,
100 buf_ct: 0,
101 strin: false,
102 lineno: 1,
103 lexstop: false,
104 shin_buffer: String::new(),
105 shin_pos: 0,
106 shin_save_stack: Vec::new(),
107 pushback: VecDeque::new(),
108 raw_input: String::new(),
109 }
110 }
111
112 pub fn shin_buf_reset(&mut self) {
114 self.shin_buffer.clear();
115 self.shin_pos = 0;
116 }
117
118 pub fn shin_buf_alloc(&mut self) {
120 self.shin_buffer = String::with_capacity(SHIN_BUF_SIZE);
121 self.shin_buf_reset();
122 }
123
124 pub fn shin_buf_save(&mut self) {
126 self.shin_save_stack
127 .push((std::mem::take(&mut self.shin_buffer), self.shin_pos));
128 self.shin_buf_alloc();
129 }
130
131 pub fn shin_buf_restore(&mut self) {
133 if let Some((buffer, pos)) = self.shin_save_stack.pop() {
134 self.shin_buffer = buffer;
135 self.shin_pos = pos;
136 }
137 }
138
139 pub fn shin_getchar<R: Read>(&mut self, reader: &mut BufReader<R>) -> Option<char> {
141 if self.shin_pos < self.shin_buffer.len() {
143 let ch = self.shin_buffer.chars().nth(self.shin_pos)?;
144 self.shin_pos += 1;
145 return Some(ch);
146 }
147
148 self.shin_buf_reset();
150 let mut line = String::new();
151 match reader.read_line(&mut line) {
152 Ok(0) => None, Ok(_) => {
154 self.shin_buffer = line;
155 self.shin_pos = 1;
156 self.shin_buffer.chars().next()
157 }
158 Err(_) => None,
159 }
160 }
161
162 pub fn shin_getline<R: Read>(&mut self, reader: &mut BufReader<R>) -> Option<String> {
164 let mut result = String::new();
165
166 loop {
167 match self.shin_getchar(reader) {
168 None => {
169 if result.is_empty() {
170 return None;
171 }
172 return Some(result);
173 }
174 Some('\n') => {
175 result.push('\n');
176 return Some(result);
177 }
178 Some(c) => {
179 if is_meta(c) {
180 result.push(META);
181 result.push(meta_encode(c));
182 } else {
183 result.push(c);
184 }
185 }
186 }
187 }
188 }
189
190 pub fn ingetc(&mut self) -> Option<char> {
192 if self.lexstop {
193 return Some(' ');
194 }
195
196 if let Some(c) = self.pushback.pop_front() {
198 self.raw_add(c);
199 return Some(c);
200 }
201
202 loop {
203 if self.pos < self.buf.len() {
205 let c = self.buf.chars().nth(self.pos)?;
206 self.pos += 1;
207 self.buf_ct = self.buf_ct.saturating_sub(1);
208
209 if is_tok(c) {
211 continue;
212 }
213
214 if ((self.flags & flags::INP_LINENO != 0) || !self.strin) && c == '\n' {
216 self.lineno += 1;
217 }
218
219 self.raw_add(c);
220 return Some(c);
221 }
222
223 if self.buf_ct == 0 && (self.strin || self.lexstop) {
225 self.lexstop = true;
226 return None;
227 }
228
229 if self.flags & flags::INP_CONT != 0 {
231 self.inpop_top();
232 continue;
233 }
234
235 self.lexstop = true;
237 return None;
238 }
239 }
240
241 pub fn inungetc(&mut self, c: char) {
243 if self.lexstop {
244 return;
245 }
246
247 if self.pos > 0 {
248 self.pos -= 1;
249 self.buf_ct += 1;
250 if ((self.flags & flags::INP_LINENO != 0) || !self.strin) && c == '\n' {
251 self.lineno = self.lineno.saturating_sub(1);
252 }
253 self.raw_back();
254 } else if self.flags & flags::INP_CONT == 0 {
255 self.pushback.push_front(c);
257 } else {
258 self.pushback.push_front(c);
260 }
261 }
262
263 pub fn inpush(&mut self, s: &str, flags: u32, alias: Option<String>) {
265 let entry = InputStackEntry {
267 buf: std::mem::take(&mut self.buf),
268 pos: self.pos,
269 flags: self.flags,
270 alias: None,
271 };
272 self.stack.push(entry);
273
274 self.buf = s.to_string();
276 self.pos = 0;
277
278 let mut new_flags = flags;
280 if flags & (flags::INP_ALIAS | flags::INP_HIST) != 0 {
281 new_flags |= flags::INP_CONT | flags::INP_ALIAS;
282 if let Some(ref a) = alias {
283 if let Some(last) = self.stack.last_mut() {
285 last.alias = Some(a.clone());
286 if flags & flags::INP_HIST != 0 {
287 last.flags |= flags::INP_HISTCONT;
288 } else {
289 last.flags |= flags::INP_ALCONT;
290 }
291 }
292 }
293 }
294
295 if new_flags & flags::INP_CONT != 0 {
297 self.buf_ct += self.buf.len();
298 } else {
299 self.buf_ct = self.buf.len();
300 }
301 self.flags = new_flags;
302 }
303
304 fn inpop_top(&mut self) {
306 if let Some(entry) = self.stack.pop() {
307 self.buf = entry.buf;
308 self.pos = entry.pos;
309 self.flags = entry.flags;
310 self.buf_ct = self.buf.len().saturating_sub(self.pos);
311
312 if self.flags & (flags::INP_ALCONT | flags::INP_HISTCONT) != 0 {
314 }
317 }
318 }
319
320 pub fn inpop(&mut self) {
322 loop {
323 let was_cont = self.flags & flags::INP_CONT != 0;
324 self.inpop_top();
325 if !was_cont {
326 break;
327 }
328 }
329 }
330
331 pub fn inpop_alias(&mut self) {
333 while self.flags & flags::INP_ALIAS != 0 {
334 self.inpop_top();
335 }
336 }
337
338 pub fn inputsetline(&mut self, s: &str, flags: u32) {
340 self.buf = s.to_string();
341 self.pos = 0;
342
343 if flags & flags::INP_CONT != 0 {
344 self.buf_ct += self.buf.len();
345 } else {
346 self.buf_ct = self.buf.len();
347 }
348 self.flags = flags;
349 }
350
351 pub fn inerrflush(&mut self) {
353 while !self.lexstop && self.buf_ct > 0 {
354 let _ = self.ingetc();
355 }
356 }
357
358 pub fn ingetptr(&self) -> &str {
360 if self.pos < self.buf.len() {
361 &self.buf[self.pos..]
362 } else {
363 ""
364 }
365 }
366
367 pub fn input_has_alias(&self) -> Option<&str> {
369 let mut flags = self.flags;
370
371 for entry in self.stack.iter().rev() {
372 if flags & flags::INP_CONT == 0 {
373 break;
374 }
375 if let Some(ref alias) = entry.alias {
376 return Some(alias);
377 }
378 flags = entry.flags;
379 }
380 None
381 }
382
383 fn raw_add(&mut self, c: char) {
385 self.raw_input.push(c);
386 }
387
388 fn raw_back(&mut self) {
390 self.raw_input.pop();
391 }
392
393 pub fn take_raw_input(&mut self) -> String {
395 std::mem::take(&mut self.raw_input)
396 }
397
398 pub fn has_input(&self) -> bool {
400 self.buf_ct > 0 || !self.pushback.is_empty()
401 }
402
403 pub fn remaining(&self) -> usize {
405 self.buf_ct + self.pushback.len()
406 }
407}
408
409pub const META: char = '\u{83}';
411
412fn is_meta(c: char) -> bool {
414 let b = c as u32;
415 b < 32 || (b >= 0x83 && b <= 0x9b)
416}
417
418fn is_tok(c: char) -> bool {
420 let b = c as u32;
421 b >= 0x83 && b <= 0x9b
422}
423
424fn meta_encode(c: char) -> char {
426 char::from_u32((c as u32) ^ 32).unwrap_or(c)
427}
428
429pub fn meta_decode(c: char) -> char {
431 char::from_u32((c as u32) ^ 32).unwrap_or(c)
432}
433
434pub fn zstuff(path: &str) -> io::Result<String> {
436 std::fs::read_to_string(path)
437}
438
439pub struct StringInput {
441 input: InputBuffer,
442}
443
444impl StringInput {
445 pub fn new(s: &str) -> Self {
446 let mut input = InputBuffer::new();
447 input.strin = true;
448 input.inputsetline(s, 0);
449 StringInput { input }
450 }
451
452 pub fn getc(&mut self) -> Option<char> {
453 self.input.ingetc()
454 }
455
456 pub fn ungetc(&mut self, c: char) {
457 self.input.inungetc(c);
458 }
459
460 pub fn is_eof(&self) -> bool {
461 self.input.lexstop
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use super::*;
468
469 #[test]
470 fn test_input_buffer_basic() {
471 let mut buf = InputBuffer::new();
472 buf.inputsetline("hello", 0);
473
474 assert_eq!(buf.ingetc(), Some('h'));
475 assert_eq!(buf.ingetc(), Some('e'));
476 assert_eq!(buf.ingetc(), Some('l'));
477 assert_eq!(buf.ingetc(), Some('l'));
478 assert_eq!(buf.ingetc(), Some('o'));
479 assert_eq!(buf.ingetc(), None);
480 }
481
482 #[test]
483 fn test_input_ungetc() {
484 let mut buf = InputBuffer::new();
485 buf.inputsetline("abc", 0);
486
487 assert_eq!(buf.ingetc(), Some('a'));
488 assert_eq!(buf.ingetc(), Some('b'));
489 buf.inungetc('b');
490 assert_eq!(buf.ingetc(), Some('b'));
491 assert_eq!(buf.ingetc(), Some('c'));
492 }
493
494 #[test]
495 fn test_input_stack() {
496 let mut buf = InputBuffer::new();
497 buf.inputsetline("outer", 0);
498
499 assert_eq!(buf.ingetc(), Some('o'));
500
501 buf.inpush("inner", flags::INP_CONT, None);
503 assert_eq!(buf.ingetc(), Some('i'));
504 assert_eq!(buf.ingetc(), Some('n'));
505 assert_eq!(buf.ingetc(), Some('n'));
506 assert_eq!(buf.ingetc(), Some('e'));
507 assert_eq!(buf.ingetc(), Some('r'));
508
509 assert_eq!(buf.ingetc(), Some('u'));
511 assert_eq!(buf.ingetc(), Some('t'));
512 }
513
514 #[test]
515 fn test_line_number_tracking() {
516 let mut buf = InputBuffer::new();
517 buf.inputsetline("a\nb\nc", flags::INP_LINENO);
518
519 assert_eq!(buf.lineno, 1);
520 buf.ingetc(); buf.ingetc(); assert_eq!(buf.lineno, 2);
523 buf.ingetc(); buf.ingetc(); assert_eq!(buf.lineno, 3);
526 }
527
528 #[test]
529 fn test_string_input() {
530 let mut input = StringInput::new("test");
531
532 assert_eq!(input.getc(), Some('t'));
533 assert_eq!(input.getc(), Some('e'));
534 assert_eq!(input.getc(), Some('s'));
535 assert_eq!(input.getc(), Some('t'));
536 assert!(input.is_eof() || input.getc().is_none());
537 }
538
539 #[test]
540 fn test_meta_encoding() {
541 assert!(is_meta('\x00'));
542 assert!(is_meta('\x1f'));
543 assert!(!is_meta('a'));
544 assert!(!is_meta('Z'));
545
546 let encoded = meta_encode('\x00');
547 let decoded = meta_decode(encoded);
548 assert_eq!(decoded, '\x00');
549 }
550
551 #[test]
552 fn test_ingetptr() {
553 let mut buf = InputBuffer::new();
554 buf.inputsetline("hello world", 0);
555
556 buf.ingetc(); buf.ingetc(); buf.ingetc(); buf.ingetc(); buf.ingetc(); assert_eq!(buf.ingetptr(), " world");
563 }
564
565 #[test]
566 fn test_inerrflush() {
567 let mut buf = InputBuffer::new();
568 buf.inputsetline("remaining input", 0);
569
570 buf.ingetc(); buf.inerrflush();
572
573 assert!(buf.lexstop || buf.buf_ct == 0);
574 }
575}