223 lines
7.7 KiB
Rust
223 lines
7.7 KiB
Rust
#![warn(clippy::pedantic)]
|
|
#![allow(
|
|
clippy::cast_lossless,
|
|
clippy::cast_possible_truncation,
|
|
clippy::cast_possible_wrap,
|
|
clippy::cast_sign_loss,
|
|
clippy::items_after_statements,
|
|
clippy::let_underscore_untyped,
|
|
clippy::missing_errors_doc,
|
|
clippy::missing_safety_doc,
|
|
clippy::too_many_lines
|
|
)]
|
|
|
|
mod cstr;
|
|
|
|
use self::cstr::CStr;
|
|
use std::env;
|
|
use std::error::Error;
|
|
use std::ffi::c_void;
|
|
use std::fmt::Write as _;
|
|
use std::fs::File;
|
|
use std::io::{self, Read, Write};
|
|
use std::mem::MaybeUninit;
|
|
use std::process::{self, ExitCode};
|
|
use std::ptr::addr_of_mut;
|
|
use std::slice;
|
|
use unsafe_libyaml::{
|
|
yaml_event_delete, yaml_event_t, yaml_event_type_t, yaml_parser_delete, yaml_parser_initialize,
|
|
yaml_parser_parse, yaml_parser_set_input, yaml_parser_t, YAML_ALIAS_EVENT,
|
|
YAML_DOCUMENT_END_EVENT, YAML_DOCUMENT_START_EVENT, YAML_DOUBLE_QUOTED_SCALAR_STYLE,
|
|
YAML_FOLDED_SCALAR_STYLE, YAML_LITERAL_SCALAR_STYLE, YAML_MAPPING_END_EVENT,
|
|
YAML_MAPPING_START_EVENT, YAML_NO_EVENT, YAML_PLAIN_SCALAR_STYLE, YAML_SCALAR_EVENT,
|
|
YAML_SEQUENCE_END_EVENT, YAML_SEQUENCE_START_EVENT, YAML_SINGLE_QUOTED_SCALAR_STYLE,
|
|
YAML_STREAM_END_EVENT, YAML_STREAM_START_EVENT,
|
|
};
|
|
|
|
pub(crate) unsafe fn unsafe_main(
|
|
mut stdin: &mut dyn Read,
|
|
stdout: &mut dyn Write,
|
|
) -> Result<(), Box<dyn Error>> {
|
|
let mut parser = MaybeUninit::<yaml_parser_t>::uninit();
|
|
let parser = parser.as_mut_ptr();
|
|
if yaml_parser_initialize(parser).fail {
|
|
return Err("Could not initialize the parser object".into());
|
|
}
|
|
|
|
unsafe fn read_from_stdio(
|
|
data: *mut c_void,
|
|
buffer: *mut u8,
|
|
size: u64,
|
|
size_read: *mut u64,
|
|
) -> i32 {
|
|
let stdin: *mut &mut dyn Read = data.cast();
|
|
let slice = slice::from_raw_parts_mut(buffer.cast(), size as usize);
|
|
match (*stdin).read(slice) {
|
|
Ok(n) => {
|
|
*size_read = n as u64;
|
|
1
|
|
}
|
|
Err(_) => 0,
|
|
}
|
|
}
|
|
|
|
yaml_parser_set_input(parser, read_from_stdio, addr_of_mut!(stdin).cast());
|
|
|
|
let mut event = MaybeUninit::<yaml_event_t>::uninit();
|
|
let event = event.as_mut_ptr();
|
|
loop {
|
|
if yaml_parser_parse(parser, event).fail {
|
|
let mut error = format!("Parse error: {}", CStr::from_ptr((*parser).problem));
|
|
if (*parser).problem_mark.line != 0 || (*parser).problem_mark.column != 0 {
|
|
let _ = write!(
|
|
error,
|
|
"\nLine: {} Column: {}",
|
|
((*parser).problem_mark.line).wrapping_add(1_u64),
|
|
((*parser).problem_mark.column).wrapping_add(1_u64),
|
|
);
|
|
}
|
|
yaml_parser_delete(parser);
|
|
return Err(error.into());
|
|
}
|
|
|
|
let type_: yaml_event_type_t = (*event).type_;
|
|
if type_ == YAML_NO_EVENT {
|
|
let _ = writeln!(stdout, "???");
|
|
} else if type_ == YAML_STREAM_START_EVENT {
|
|
let _ = writeln!(stdout, "+STR");
|
|
} else if type_ == YAML_STREAM_END_EVENT {
|
|
let _ = writeln!(stdout, "-STR");
|
|
} else if type_ == YAML_DOCUMENT_START_EVENT {
|
|
let _ = write!(stdout, "+DOC");
|
|
if !(*event).data.document_start.implicit {
|
|
let _ = write!(stdout, " ---");
|
|
}
|
|
let _ = writeln!(stdout);
|
|
} else if type_ == YAML_DOCUMENT_END_EVENT {
|
|
let _ = write!(stdout, "-DOC");
|
|
if !(*event).data.document_end.implicit {
|
|
let _ = write!(stdout, " ...");
|
|
}
|
|
let _ = writeln!(stdout);
|
|
} else if type_ == YAML_MAPPING_START_EVENT {
|
|
let _ = write!(stdout, "+MAP");
|
|
if !(*event).data.mapping_start.anchor.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" &{}",
|
|
CStr::from_ptr((*event).data.mapping_start.anchor as *const i8),
|
|
);
|
|
}
|
|
if !(*event).data.mapping_start.tag.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" <{}>",
|
|
CStr::from_ptr((*event).data.mapping_start.tag as *const i8),
|
|
);
|
|
}
|
|
let _ = writeln!(stdout);
|
|
} else if type_ == YAML_MAPPING_END_EVENT {
|
|
let _ = writeln!(stdout, "-MAP");
|
|
} else if type_ == YAML_SEQUENCE_START_EVENT {
|
|
let _ = write!(stdout, "+SEQ");
|
|
if !(*event).data.sequence_start.anchor.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" &{}",
|
|
CStr::from_ptr((*event).data.sequence_start.anchor as *const i8),
|
|
);
|
|
}
|
|
if !(*event).data.sequence_start.tag.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" <{}>",
|
|
CStr::from_ptr((*event).data.sequence_start.tag as *const i8),
|
|
);
|
|
}
|
|
let _ = writeln!(stdout);
|
|
} else if type_ == YAML_SEQUENCE_END_EVENT {
|
|
let _ = writeln!(stdout, "-SEQ");
|
|
} else if type_ == YAML_SCALAR_EVENT {
|
|
let _ = write!(stdout, "=VAL");
|
|
if !(*event).data.scalar.anchor.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" &{}",
|
|
CStr::from_ptr((*event).data.scalar.anchor as *const i8),
|
|
);
|
|
}
|
|
if !(*event).data.scalar.tag.is_null() {
|
|
let _ = write!(
|
|
stdout,
|
|
" <{}>",
|
|
CStr::from_ptr((*event).data.scalar.tag as *const i8),
|
|
);
|
|
}
|
|
let _ = stdout.write_all(match (*event).data.scalar.style {
|
|
YAML_PLAIN_SCALAR_STYLE => b" :",
|
|
YAML_SINGLE_QUOTED_SCALAR_STYLE => b" '",
|
|
YAML_DOUBLE_QUOTED_SCALAR_STYLE => b" \"",
|
|
YAML_LITERAL_SCALAR_STYLE => b" |",
|
|
YAML_FOLDED_SCALAR_STYLE => b" >",
|
|
_ => process::abort(),
|
|
});
|
|
print_escaped(
|
|
stdout,
|
|
(*event).data.scalar.value,
|
|
(*event).data.scalar.length,
|
|
);
|
|
let _ = writeln!(stdout);
|
|
} else if type_ == YAML_ALIAS_EVENT {
|
|
let _ = writeln!(
|
|
stdout,
|
|
"=ALI *{}",
|
|
CStr::from_ptr((*event).data.alias.anchor as *const i8),
|
|
);
|
|
} else {
|
|
process::abort();
|
|
}
|
|
|
|
yaml_event_delete(event);
|
|
if type_ == YAML_STREAM_END_EVENT {
|
|
break;
|
|
}
|
|
}
|
|
yaml_parser_delete(parser);
|
|
Ok(())
|
|
}
|
|
|
|
unsafe fn print_escaped(stdout: &mut dyn Write, mut str: *mut u8, length: u64) {
|
|
let end = str.offset(length as isize);
|
|
while str < end {
|
|
let repr = match &*str {
|
|
b'\\' => b"\\\\",
|
|
b'\0' => b"\\0",
|
|
b'\x08' => b"\\b",
|
|
b'\n' => b"\\n",
|
|
b'\r' => b"\\r",
|
|
b'\t' => b"\\t",
|
|
c => slice::from_ref(c),
|
|
};
|
|
let _ = stdout.write_all(repr);
|
|
str = str.offset(1);
|
|
}
|
|
}
|
|
|
|
fn main() -> ExitCode {
|
|
let args = env::args_os().skip(1);
|
|
if args.len() == 0 {
|
|
let _ = writeln!(io::stderr(), "Usage: run-parser-test-suite <in.yaml>...");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
for arg in args {
|
|
let mut stdin = File::open(arg).unwrap();
|
|
let mut stdout = io::stdout();
|
|
let result = unsafe { unsafe_main(&mut stdin, &mut stdout) };
|
|
if let Err(err) = result {
|
|
let _ = writeln!(io::stderr(), "{}", err);
|
|
return ExitCode::FAILURE;
|
|
}
|
|
}
|
|
ExitCode::SUCCESS
|
|
}
|