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