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