use std::ffi::{CStr, CString};
use std::time::SystemTime;
use super::{ExecutionState, IoEventBackend, TectonicBridgeApi};
use crate::errors::{DefinitelySame, ErrorKind, Result};
use crate::io::IoStack;
use crate::status::StatusBackend;
use crate::unstable_opts::UnstableOptions;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TexResult {
Spotless,
Warnings,
Errors,
}
impl DefinitelySame for TexResult {
fn definitely_same(&self, other: &Self) -> bool {
self == other
}
}
#[derive(Debug)]
pub struct TexEngine {
halt_on_error: bool,
initex_mode: bool,
synctex_enabled: bool,
semantic_pagination_enabled: bool,
build_date: SystemTime,
}
impl Default for TexEngine {
fn default() -> Self {
TexEngine {
halt_on_error: true,
initex_mode: false,
synctex_enabled: false,
semantic_pagination_enabled: false,
build_date: SystemTime::UNIX_EPOCH,
}
}
}
impl TexEngine {
pub fn new() -> TexEngine {
TexEngine::default()
}
pub fn halt_on_error_mode(&mut self, halt_on_error: bool) -> &mut Self {
self.halt_on_error = halt_on_error;
self
}
pub fn initex_mode(&mut self, initex: bool) -> &mut Self {
self.initex_mode = initex;
self
}
pub fn synctex(&mut self, synctex_enabled: bool) -> &mut Self {
self.synctex_enabled = synctex_enabled;
self
}
pub fn semantic_pagination(&mut self, enabled: bool) -> &mut Self {
self.semantic_pagination_enabled = enabled;
self
}
pub fn build_date(&mut self, date: SystemTime) -> &mut Self {
self.build_date = date;
self
}
pub fn process(
&mut self,
io: &mut IoStack,
events: &mut dyn IoEventBackend,
status: &mut dyn StatusBackend,
format_file_name: &str,
input_file_name: &str,
unstables: &UnstableOptions,
) -> Result<TexResult> {
let _guard = super::ENGINE_LOCK.lock().unwrap();
let cformat = CString::new(format_file_name)?;
let cinput = CString::new(input_file_name)?;
let mut state = ExecutionState::new(io, events, status);
let bridge = TectonicBridgeApi::new(&mut state);
let v = if unstables.shell_escape { 1 } else { 0 };
unsafe {
super::tt_xetex_set_int_variable(b"shell_escape_enabled\0".as_ptr() as _, v);
}
let mut halt_on_error = self.halt_on_error;
if unstables.continue_on_errors {
halt_on_error = false; }
let v = if halt_on_error { 1 } else { 0 };
unsafe {
super::tt_xetex_set_int_variable(b"halt_on_error_p\0".as_ptr() as _, v);
}
let v = if self.initex_mode { 1 } else { 0 };
unsafe {
super::tt_xetex_set_int_variable(b"in_initex_mode\0".as_ptr() as _, v);
}
let v = if self.synctex_enabled { 1 } else { 0 };
unsafe {
super::tt_xetex_set_int_variable(b"synctex_enabled\0".as_ptr() as _, v);
}
let v = if self.semantic_pagination_enabled {
1
} else {
0
};
unsafe {
super::tt_xetex_set_int_variable(b"semantic_pagination_enabled\0".as_ptr() as _, v);
}
unsafe {
match super::tex_simple_main(
&bridge,
cformat.as_ptr(),
cinput.as_ptr(),
self.build_date
.duration_since(SystemTime::UNIX_EPOCH)
.expect("invalid build date")
.as_secs() as libc::time_t,
) {
0 => Ok(TexResult::Spotless),
1 => Ok(TexResult::Warnings),
2 => Ok(TexResult::Errors),
3 => {
let ptr = super::tt_get_error_message();
let msg = CStr::from_ptr(ptr).to_string_lossy().into_owned();
Err(ErrorKind::Msg(msg).into())
}
x => Err(ErrorKind::Msg(format!(
"internal error: unexpected 'history' value {}",
x
))
.into()),
}
}
}
}