Skip to main content

run_parser_test_suite/
run-parser-test-suite.rs

1#![warn(clippy::pedantic)]
2#![allow(
3    clippy::cast_lossless,
4    clippy::cast_possible_truncation,
5    clippy::cast_possible_wrap,
6    clippy::cast_sign_loss,
7    clippy::items_after_statements,
8    clippy::let_underscore_untyped,
9    clippy::missing_errors_doc,
10    clippy::missing_safety_doc,
11    clippy::too_many_lines,
12    clippy::uninlined_format_args
13)]
14// c2rust transliteration: unsafe operations are called directly inside `unsafe fn` bodies.
15// Same rationale as `unsafe_libyaml/src/lib.rs`.
16#![allow(unsafe_op_in_unsafe_fn)]
17
18mod cstr;
19
20use std::{
21    env,
22    error::Error,
23    ffi::c_void,
24    fmt::Write as _,
25    fs::File,
26    io::{self, Read, Write},
27    mem::MaybeUninit,
28    process::{self, ExitCode},
29    ptr::addr_of_mut,
30    slice,
31};
32
33use unsafe_libyaml::{
34    YAML_ALIAS_EVENT, YAML_DOCUMENT_END_EVENT, YAML_DOCUMENT_START_EVENT, YAML_DOUBLE_QUOTED_SCALAR_STYLE,
35    YAML_FOLDED_SCALAR_STYLE, YAML_LITERAL_SCALAR_STYLE, YAML_MAPPING_END_EVENT, YAML_MAPPING_START_EVENT,
36    YAML_NO_EVENT, YAML_PLAIN_SCALAR_STYLE, YAML_SCALAR_EVENT, YAML_SEQUENCE_END_EVENT, YAML_SEQUENCE_START_EVENT,
37    YAML_SINGLE_QUOTED_SCALAR_STYLE, YAML_STREAM_END_EVENT, YAML_STREAM_START_EVENT, yaml_event_delete, yaml_event_t,
38    yaml_event_type_t, yaml_parser_delete, yaml_parser_initialize, yaml_parser_parse, yaml_parser_set_input,
39    yaml_parser_t,
40};
41
42use self::cstr::CStr;
43
44pub(crate) unsafe fn unsafe_main(mut stdin: &mut dyn Read, stdout: &mut dyn Write) -> Result<(), Box<dyn Error>> {
45    let mut parser = MaybeUninit::<yaml_parser_t>::uninit();
46    let parser = parser.as_mut_ptr();
47    if yaml_parser_initialize(parser).fail {
48        return Err("Could not initialize the parser object".into());
49    }
50
51    unsafe fn read_from_stdio(data: *mut c_void, buffer: *mut u8, size: u64, size_read: *mut u64) -> i32 {
52        let stdin: *mut &mut dyn Read = data.cast();
53        let slice = slice::from_raw_parts_mut(buffer.cast(), size as usize);
54        match (*stdin).read(slice) {
55            Ok(n) => {
56                *size_read = n as u64;
57                1
58            }
59            Err(_) => 0,
60        }
61    }
62
63    yaml_parser_set_input(parser, read_from_stdio, addr_of_mut!(stdin).cast());
64
65    let mut event = MaybeUninit::<yaml_event_t>::uninit();
66    let event = event.as_mut_ptr();
67    loop {
68        if yaml_parser_parse(parser, event).fail {
69            let mut error = format!("Parse error: {}", CStr::from_ptr((&(*parser)).problem));
70            if (&(*parser)).problem_mark.line != 0 || (&(*parser)).problem_mark.column != 0 {
71                let _ = write!(
72                    error,
73                    "\nLine: {} Column: {}",
74                    ((&(*parser)).problem_mark.line).wrapping_add(1_u64),
75                    ((&(*parser)).problem_mark.column).wrapping_add(1_u64),
76                );
77            }
78            yaml_parser_delete(parser);
79            return Err(error.into());
80        }
81
82        let type_: yaml_event_type_t = (*event).type_;
83        if type_ == YAML_NO_EVENT {
84            let _ = writeln!(stdout, "???");
85        } else if type_ == YAML_STREAM_START_EVENT {
86            let _ = writeln!(stdout, "+STR");
87        } else if type_ == YAML_STREAM_END_EVENT {
88            let _ = writeln!(stdout, "-STR");
89        } else if type_ == YAML_DOCUMENT_START_EVENT {
90            let _ = write!(stdout, "+DOC");
91            if !(*event).data.document_start.implicit {
92                let _ = write!(stdout, " ---");
93            }
94            let _ = writeln!(stdout);
95        } else if type_ == YAML_DOCUMENT_END_EVENT {
96            let _ = write!(stdout, "-DOC");
97            if !(*event).data.document_end.implicit {
98                let _ = write!(stdout, " ...");
99            }
100            let _ = writeln!(stdout);
101        } else if type_ == YAML_MAPPING_START_EVENT {
102            let _ = write!(stdout, "+MAP");
103            if !(*event).data.mapping_start.anchor.is_null() {
104                let _ = write!(stdout, " &{}", CStr::from_ptr((*event).data.mapping_start.anchor as *const i8),);
105            }
106            if !(*event).data.mapping_start.tag.is_null() {
107                let _ = write!(stdout, " <{}>", CStr::from_ptr((*event).data.mapping_start.tag as *const i8),);
108            }
109            let _ = writeln!(stdout);
110        } else if type_ == YAML_MAPPING_END_EVENT {
111            let _ = writeln!(stdout, "-MAP");
112        } else if type_ == YAML_SEQUENCE_START_EVENT {
113            let _ = write!(stdout, "+SEQ");
114            if !(*event).data.sequence_start.anchor.is_null() {
115                let _ = write!(stdout, " &{}", CStr::from_ptr((*event).data.sequence_start.anchor as *const i8),);
116            }
117            if !(*event).data.sequence_start.tag.is_null() {
118                let _ = write!(stdout, " <{}>", CStr::from_ptr((*event).data.sequence_start.tag as *const i8),);
119            }
120            let _ = writeln!(stdout);
121        } else if type_ == YAML_SEQUENCE_END_EVENT {
122            let _ = writeln!(stdout, "-SEQ");
123        } else if type_ == YAML_SCALAR_EVENT {
124            let _ = write!(stdout, "=VAL");
125            if !(*event).data.scalar.anchor.is_null() {
126                let _ = write!(stdout, " &{}", CStr::from_ptr((*event).data.scalar.anchor as *const i8),);
127            }
128            if !(*event).data.scalar.tag.is_null() {
129                let _ = write!(stdout, " <{}>", CStr::from_ptr((*event).data.scalar.tag as *const i8),);
130            }
131            let _ = stdout.write_all(match (*event).data.scalar.style {
132                YAML_PLAIN_SCALAR_STYLE => b" :",
133                YAML_SINGLE_QUOTED_SCALAR_STYLE => b" '",
134                YAML_DOUBLE_QUOTED_SCALAR_STYLE => b" \"",
135                YAML_LITERAL_SCALAR_STYLE => b" |",
136                YAML_FOLDED_SCALAR_STYLE => b" >",
137                _ => process::abort(),
138            });
139            print_escaped(stdout, (*event).data.scalar.value, (*event).data.scalar.length);
140            let _ = writeln!(stdout);
141        } else if type_ == YAML_ALIAS_EVENT {
142            let _ = writeln!(stdout, "=ALI *{}", CStr::from_ptr((*event).data.alias.anchor as *const i8),);
143        } else {
144            process::abort();
145        }
146
147        yaml_event_delete(event);
148        if type_ == YAML_STREAM_END_EVENT {
149            break;
150        }
151    }
152    yaml_parser_delete(parser);
153    Ok(())
154}
155
156unsafe fn print_escaped(stdout: &mut dyn Write, mut str: *mut u8, length: u64) {
157    let end = str.offset(length as isize);
158    while str < end {
159        let repr = match &*str {
160            b'\\' => b"\\\\",
161            b'\0' => b"\\0",
162            b'\x08' => b"\\b",
163            b'\n' => b"\\n",
164            b'\r' => b"\\r",
165            b'\t' => b"\\t",
166            c => slice::from_ref(c),
167        };
168        let _ = stdout.write_all(repr);
169        str = str.offset(1);
170    }
171}
172
173fn main() -> ExitCode {
174    let args = env::args_os().skip(1);
175    if args.len() == 0 {
176        let _ = writeln!(io::stderr(), "Usage: run-parser-test-suite <in.yaml>...");
177        return ExitCode::FAILURE;
178    }
179    for arg in args {
180        let mut stdin = File::open(arg).unwrap();
181        let mut stdout = io::stdout();
182        let result = unsafe { unsafe_main(&mut stdin, &mut stdout) };
183        if let Err(err) = result {
184            let _ = writeln!(io::stderr(), "{}", err);
185            return ExitCode::FAILURE;
186        }
187    }
188    ExitCode::SUCCESS
189}