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