From 8cf10abaac56c183c9b000414068b1d9fcc1abbd Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 17 Oct 2019 15:17:18 +0200 Subject: [PATCH 01/34] implement PlainStatusBackend --- src/status/mod.rs | 4 +++ src/status/plain.rs | 55 +++++++++++++++++++++++++++++++++++++++++ src/status/termcolor.rs | 12 ++++----- 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 src/status/plain.rs diff --git a/src/status/mod.rs b/src/status/mod.rs index 0a7454a42..be5f4f25d 100644 --- a/src/status/mod.rs +++ b/src/status/mod.rs @@ -4,6 +4,7 @@ //! A framework for showing status messages to the user. +pub mod plain; pub mod termcolor; use std::cmp; @@ -77,6 +78,8 @@ pub trait StatusBackend { None, ) } + + fn dump_to_stderr(&mut self, output: &[u8]); } /// Report a formatted informational message to the user. @@ -133,4 +136,5 @@ impl NoopStatusBackend { impl StatusBackend for NoopStatusBackend { fn report(&mut self, _kind: MessageKind, _args: Arguments, _err: Option<&Error>) {} + fn dump_to_stderr(&mut self, _output: &[u8]) {} } diff --git a/src/status/plain.rs b/src/status/plain.rs new file mode 100644 index 000000000..0cb9f00f0 --- /dev/null +++ b/src/status/plain.rs @@ -0,0 +1,55 @@ +use std::fmt::Arguments; + +use super::{ChatterLevel, MessageKind, StatusBackend}; +use crate::errors::Error; +use std::io::{self, Write}; + +pub struct PlainStatusBackend { + chatter: ChatterLevel, +} + +impl PlainStatusBackend { + pub fn new(chatter: ChatterLevel) -> Self { + PlainStatusBackend { chatter } + } +} + +impl StatusBackend for PlainStatusBackend { + fn report(&mut self, kind: MessageKind, args: Arguments, err: Option<&Error>) { + let prefix = match kind { + MessageKind::Note => "note:", + MessageKind::Warning => "warning:", + MessageKind::Error => "error:", + }; + if kind == MessageKind::Note { + println!("{} {}", prefix, args); + } else { + eprintln!("{} {}", prefix, args); + } + if let Some(e) = err { + for item in e.iter() { + eprintln!("caused by: {}", item); + } + if let Some(backtrace) = e.backtrace() { + eprintln!("debugging: backtrace follows:"); + eprintln!("{:?}", backtrace); + } + } + } + + fn note_highlighted(&mut self, before: &str, highlighted: &str, after: &str) { + if self.chatter > ChatterLevel::Minimal { + self.report( + MessageKind::Note, + format_args!("{}{}{}", before, highlighted, after), + None, + ); + } + } + + fn dump_to_stderr(&mut self, output: &[u8]) { + io::stderr() + .write_all(output) + .expect("write to stderr failed"); + } +} diff --git a/src/status/termcolor.rs b/src/status/termcolor.rs index 36a54e2ce..f25489ca6 100644 --- a/src/status/termcolor.rs +++ b/src/status/termcolor.rs @@ -137,12 +137,6 @@ impl TermcolorStatusBackend { }); } } - - pub fn dump_to_stderr(&mut self, output: &[u8]) { - self.stderr - .write_all(output) - .expect("write to stderr failed"); - } } /// Show formatted text to the user, styled as an error message. @@ -185,4 +179,10 @@ impl StatusBackend for TermcolorStatusBackend { writeln!(self.stdout, "{}", after).expect("write to stdout failed"); } } + + fn dump_to_stderr(&mut self, output: &[u8]) { + self.stderr + .write_all(output) + .expect("write to stderr failed"); + } } From d18a6196efd216299dbcbb163e15cdf71208ed63 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 17 Oct 2019 15:18:10 +0200 Subject: [PATCH 02/34] driver: use dynamic dispatch for StatusBackend This avoids monomorphization and sipmlifies the API a bit. --- src/driver.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 4427d6554..0f53bf3ec 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -633,7 +633,7 @@ impl ProcessingSession { /// Assess whether we need to rerun an engine. This is the case if there /// was a file that the engine read and then rewrote, and the rewritten /// version is different than the version that it read in. - fn is_rerun_needed(&self, status: &mut S) -> Option { + fn is_rerun_needed(&self, status: &mut dyn StatusBackend) -> Option { // TODO: we should probably wire up diagnostics since I expect this // stuff could get finicky and we're going to want to be able to // figure out why rerun detection is breaking. @@ -664,7 +664,7 @@ impl ProcessingSession { } #[allow(dead_code)] - fn _dump_access_info(&self, status: &mut S) { + fn _dump_access_info(&self, status: &mut dyn StatusBackend) { for (name, info) in &self.events.0 { if info.access_pattern != AccessPattern::Read { let r = match info.read_digest { @@ -697,7 +697,7 @@ impl ProcessingSession { /// - run BibTeX, if it seems to be required /// - repeat the last two steps as often as needed /// - write the output files to disk, including a Makefile if it was requested. - pub fn run(&mut self, status: &mut S) -> Result<()> { + pub fn run(&mut self, status: &mut dyn StatusBackend) -> Result<()> { // Do we need to generate the format file? let generate_format = if self.output_format == OutputFormat::Format { @@ -817,10 +817,10 @@ impl ProcessingSession { Ok(()) } - fn write_files( + fn write_files( &mut self, mut mf_dest_maybe: Option<&mut File>, - status: &mut S, + status: &mut dyn StatusBackend, only_logs: bool, ) -> Result { let root = match self.output_path { @@ -909,11 +909,7 @@ impl ProcessingSession { /// The "default" pass really runs a bunch of sub-passes. It is a "Do What /// I Mean" operation. - fn default_pass( - &mut self, - bibtex_first: bool, - status: &mut S, - ) -> Result { + fn default_pass(&mut self, bibtex_first: bool, status: &mut dyn StatusBackend) -> Result { // If `bibtex_first` is true, we start by running bibtex, and run // proceed with the standard rerun logic. Otherwise, we run TeX, // auto-detect whether we need to run bibtex, possibly run it, and @@ -1011,7 +1007,7 @@ impl ProcessingSession { } /// Use the TeX engine to generate a format file. - fn make_format_pass(&mut self, status: &mut S) -> Result { + fn make_format_pass(&mut self, status: &mut dyn StatusBackend) -> Result { if self.io.bundle.is_none() { return Err( ErrorKind::Msg("cannot create formats without using a bundle".to_owned()).into(), @@ -1089,10 +1085,10 @@ impl ProcessingSession { } /// Run one pass of the TeX engine. - fn tex_pass( + fn tex_pass( &mut self, rerun_explanation: Option<&str>, - status: &mut S, + status: &mut dyn StatusBackend, ) -> Result> { let result = { let mut stack = self.io.as_stack(); @@ -1131,7 +1127,7 @@ impl ProcessingSession { Ok(warnings) } - fn bibtex_pass(&mut self, status: &mut S) -> Result { + fn bibtex_pass(&mut self, status: &mut dyn StatusBackend) -> Result { let result = { let mut stack = self.io.as_stack(); let mut engine = BibtexEngine::new(); @@ -1167,7 +1163,7 @@ impl ProcessingSession { Ok(0) } - fn xdvipdfmx_pass(&mut self, status: &mut S) -> Result { + fn xdvipdfmx_pass(&mut self, status: &mut dyn StatusBackend) -> Result { { let mut stack = self.io.as_stack(); let mut engine = XdvipdfmxEngine::new().with_date(self.build_date); @@ -1185,7 +1181,7 @@ impl ProcessingSession { Ok(0) } - fn spx2html_pass(&mut self, status: &mut S) -> Result { + fn spx2html_pass(&mut self, status: &mut dyn StatusBackend) -> Result { { let mut stack = self.io.as_stack(); let mut engine = Spx2HtmlEngine::new(); From 39f680ef56e30753b4e519e37ebb4c4206e68508 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Thu, 17 Oct 2019 15:19:46 +0200 Subject: [PATCH 03/34] cli: implement --color={always,auto,never} --- Cargo.lock | 1 + Cargo.toml | 1 + src/bin/tectonic.rs | 41 ++++++++++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8be6fd972..63c3b8922 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1632,6 +1632,7 @@ name = "tectonic" version = "0.0.0-dev.0" dependencies = [ "app_dirs2", + "atty", "byte-unit", "cc", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index ce859b17c..5506df6b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ tectonic_xdv = { path = "xdv", version = "0.0.0-dev.0" } termcolor = "^1.1" toml = { version = "^0.5", optional = true } zip = { version = "^0.5", default-features = false, features = ["deflate"] } +atty = "0.2.14" [features] default = ["serialization"] diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index dc229533e..be3cd5f67 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -13,10 +13,10 @@ use std::time; use tectonic::config::PersistentConfig; use tectonic::driver::{OutputFormat, PassSetting, ProcessingSessionBuilder}; use tectonic::errors::{ErrorKind, Result}; +use tectonic::status::plain::PlainStatusBackend; use tectonic::status::termcolor::TermcolorStatusBackend; use tectonic::status::{ChatterLevel, StatusBackend}; - -use tectonic::{errmsg, tt_error, tt_error_styled, tt_note}; +use tectonic::{errmsg, tt_error, tt_note}; #[derive(Debug, StructOpt)] #[structopt(name = "Tectonic", about = "Process a (La)TeX document")] @@ -37,11 +37,14 @@ struct CliOptions { /// How much chatter to print when running #[structopt(long = "chatter", short, name = "level", default_value = "default", possible_values(&["default", "minimal"]))] chatter_level: String, + /// Enable/disable colorful log output. + #[structopt(long, name = "color", default_value = "auto", possible_values(&["always", "auto", "never"]))] + color: String, /// Use only resource files cached locally #[structopt(short = "C", long)] only_cached: bool, /// The kind of output to generate - #[structopt(long, name = "format", default_value = "pdf", possible_values(&["pdf", "html", "xdv", "aux", "format"]))] + #[structopt(long, name = "format", default_value = "pdf", possible_values(&["pdf", "html", "xdv", "aux", "fmt"]))] outfmt: String, /// Write Makefile-format rules expressing the dependencies of this run to #[structopt(long, name = "dest_path")] @@ -71,11 +74,7 @@ struct CliOptions { #[structopt(name = "outdir", short, long, parse(from_os_str))] outdir: Option, } -fn inner( - args: CliOptions, - config: PersistentConfig, - status: &mut TermcolorStatusBackend, -) -> Result<()> { +fn inner(args: CliOptions, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<()> { let mut sess_builder = ProcessingSessionBuilder::default(); let format_path = args.format; sess_builder @@ -187,10 +186,11 @@ fn inner( "something bad happened inside {}; its output follows:\n", engine ); - tt_error_styled!(status, "==============================================================================="); + + tt_error!(status, "==============================================================================="); status.dump_to_stderr(&output); - tt_error_styled!(status, "==============================================================================="); - tt_error_styled!(status, ""); + tt_error!(status, "==============================================================================="); + tt_error!(status, ""); } } } @@ -235,8 +235,19 @@ fn main() { // something I'd be relatively OK with since it'd only affect the progam // UI, not the processing results). - let mut status = - TermcolorStatusBackend::new(ChatterLevel::from_str(&args.chatter_level).unwrap()); + let chatter_level = ChatterLevel::from_str(&args.chatter_level).unwrap(); + let use_color = match &*args.color { + "always" => true, + "auto" => atty::is(atty::Stream::Stdout), + "never" => false, + _ => unreachable!(), + }; + + let mut status = if use_color { + Box::new(TermcolorStatusBackend::new(chatter_level)) as Box + } else { + Box::new(PlainStatusBackend::new(chatter_level)) as Box + }; // For now ... @@ -249,8 +260,8 @@ fn main() { // function ... all so that we can print out the word "error:" in red. // This code parallels various bits of the `error_chain` crate. - if let Err(ref e) = inner(args, config, &mut status) { - status.bare_error(e); + if let Err(ref e) = inner(args, config, &mut *status) { + tt_error!(status, ""; e); process::exit(1) } } From cd90bc26e60baad4da42c71f83d53adcf7ce0f24 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Sun, 20 Oct 2019 18:12:16 +0200 Subject: [PATCH 04/34] rename --color to --cli-color --- src/bin/tectonic.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index be3cd5f67..2db8a2d7b 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -39,7 +39,7 @@ struct CliOptions { chatter_level: String, /// Enable/disable colorful log output. #[structopt(long, name = "color", default_value = "auto", possible_values(&["always", "auto", "never"]))] - color: String, + cli_color: String, /// Use only resource files cached locally #[structopt(short = "C", long)] only_cached: bool, @@ -236,14 +236,14 @@ fn main() { // UI, not the processing results). let chatter_level = ChatterLevel::from_str(&args.chatter_level).unwrap(); - let use_color = match &*args.color { + let use_cli_color = match &*args.cli_color { "always" => true, "auto" => atty::is(atty::Stream::Stdout), "never" => false, _ => unreachable!(), }; - let mut status = if use_color { + let mut status = if use_cli_color { Box::new(TermcolorStatusBackend::new(chatter_level)) as Box } else { Box::new(PlainStatusBackend::new(chatter_level)) as Box From d0ec0f6f19773fc0fe0876d99f4a9236bcf31f9a Mon Sep 17 00:00:00 2001 From: ralismark Date: Wed, 9 Sep 2020 20:05:11 +1000 Subject: [PATCH 05/34] Rework dump_to_stderr --- src/bin/tectonic.rs | 5 +---- src/status/mod.rs | 6 ++++-- src/status/plain.rs | 10 +++++++++- src/status/termcolor.rs | 12 +++++++++++- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index 2db8a2d7b..3edb97045 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -187,10 +187,7 @@ fn inner(args: CliOptions, config: PersistentConfig, status: &mut dyn StatusBack engine ); - tt_error!(status, "==============================================================================="); - status.dump_to_stderr(&output); - tt_error!(status, "==============================================================================="); - tt_error!(status, ""); + status.dump_error_logs(&output); } } } diff --git a/src/status/mod.rs b/src/status/mod.rs index be5f4f25d..663dc9f02 100644 --- a/src/status/mod.rs +++ b/src/status/mod.rs @@ -79,7 +79,9 @@ pub trait StatusBackend { ) } - fn dump_to_stderr(&mut self, output: &[u8]); + /// This is used to print TeX engine logs after it encountered errors. This prints the log, + /// surrounded by lines of equal signs. + fn dump_error_logs(&mut self, output: &[u8]); } /// Report a formatted informational message to the user. @@ -136,5 +138,5 @@ impl NoopStatusBackend { impl StatusBackend for NoopStatusBackend { fn report(&mut self, _kind: MessageKind, _args: Arguments, _err: Option<&Error>) {} - fn dump_to_stderr(&mut self, _output: &[u8]) {} + fn dump_error_logs(&mut self, _output: &[u8]) {} } diff --git a/src/status/plain.rs b/src/status/plain.rs index 0cb9f00f0..4c3921779 100644 --- a/src/status/plain.rs +++ b/src/status/plain.rs @@ -47,9 +47,17 @@ impl StatusBackend for PlainStatusBackend { } } - fn dump_to_stderr(&mut self, output: &[u8]) { + fn dump_error_logs(&mut self, output: &[u8]) { + eprintln!( + "===============================================================================" + ); + io::stderr() .write_all(output) .expect("write to stderr failed"); + + eprintln!( + "===============================================================================" + ); } } diff --git a/src/status/termcolor.rs b/src/status/termcolor.rs index f25489ca6..7099a1c1b 100644 --- a/src/status/termcolor.rs +++ b/src/status/termcolor.rs @@ -180,9 +180,19 @@ impl StatusBackend for TermcolorStatusBackend { } } - fn dump_to_stderr(&mut self, output: &[u8]) { + fn dump_error_logs(&mut self, output: &[u8]) { + tt_error_styled!( + self, + "===============================================================================" + ); + self.stderr .write_all(output) .expect("write to stderr failed"); + + tt_error_styled!( + self, + "===============================================================================" + ); } } From 6c0617665e4aab6f683fabb8375cb2c86075f16d Mon Sep 17 00:00:00 2001 From: ralismark Date: Wed, 9 Sep 2020 20:06:01 +1000 Subject: [PATCH 06/34] Clean up atty dependency entry --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5506df6b8..53cf34e68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ vcpkg = "0.2.10" [dependencies] app_dirs = { version = "2", package = "app_dirs2" } +atty = "0.2" byte-unit = "^4.0" cfg-if = "0.1" structopt = "0.3" @@ -61,7 +62,6 @@ tectonic_xdv = { path = "xdv", version = "0.0.0-dev.0" } termcolor = "^1.1" toml = { version = "^0.5", optional = true } zip = { version = "^0.5", default-features = false, features = ["deflate"] } -atty = "0.2.14" [features] default = ["serialization"] From af12d368655bd007b7b1a6dcf1dfc74d1a23e57b Mon Sep 17 00:00:00 2001 From: ralismark Date: Wed, 9 Sep 2020 20:12:36 +1000 Subject: [PATCH 07/34] Respect chatter setting --- src/status/plain.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/status/plain.rs b/src/status/plain.rs index 4c3921779..af5090b88 100644 --- a/src/status/plain.rs +++ b/src/status/plain.rs @@ -16,6 +16,10 @@ impl PlainStatusBackend { impl StatusBackend for PlainStatusBackend { fn report(&mut self, kind: MessageKind, args: Arguments, err: Option<&Error>) { + if kind == MessageKind::Note && self.chatter <= ChatterLevel::Minimal { + return; + } + let prefix = match kind { MessageKind::Note => "note:", MessageKind::Warning => "warning:", From 2584c123a62b229d9a7dee0b68d0a3c8faf1b482 Mon Sep 17 00:00:00 2001 From: ralismark Date: Wed, 9 Sep 2020 20:21:15 +1000 Subject: [PATCH 08/34] Rename --cli-color to --color --- src/bin/tectonic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index 3edb97045..fc301b143 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -38,7 +38,7 @@ struct CliOptions { #[structopt(long = "chatter", short, name = "level", default_value = "default", possible_values(&["default", "minimal"]))] chatter_level: String, /// Enable/disable colorful log output. - #[structopt(long, name = "color", default_value = "auto", possible_values(&["always", "auto", "never"]))] + #[structopt(long = "color", name = "when", default_value = "auto", possible_values(&["always", "auto", "never"]))] cli_color: String, /// Use only resource files cached locally #[structopt(short = "C", long)] From bf9dc3f1ffdc03a5af2d94e417a01cd8545cedd8 Mon Sep 17 00:00:00 2001 From: ralismark Date: Thu, 10 Sep 2020 10:32:06 +1000 Subject: [PATCH 09/34] Test color=never and color=auto --- tests/executable.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/executable.rs b/tests/executable.rs index ffd33540f..80c9b1aa9 100644 --- a/tests/executable.rs +++ b/tests/executable.rs @@ -355,3 +355,33 @@ fn test_keep_logs_on_error() { assert!(log.contains(r"job aborted, no legal \end found")); } + +#[test] +fn test_no_color() { + if env::var("RUNNING_COVERAGE").is_ok() { + return; + } + + // No input files here, but output files are created. + let fmt_arg = get_plain_format_arg(); + + let tempdir = setup_and_copy_files(&[]); + let output_nocolor = run_tectonic_with_stdin( + tempdir.path(), + &[&fmt_arg, "-", "--color=never"], + "no end to this file", + ); + + // Output is not a terminal, so these two should be the same + let tempdir = setup_and_copy_files(&[]); + let output_autocolor = run_tectonic_with_stdin( + tempdir.path(), + &[&fmt_arg, "-", "--color=auto"], + "no end to this file", + ); + + assert_eq!(output_nocolor, output_autocolor); + + error_or_panic(output_nocolor); + error_or_panic(output_autocolor); +} From a1ac78d1ba124e2eb1f6b6063f5e385a20c8395b Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Wed, 9 Sep 2020 23:35:24 -0400 Subject: [PATCH 10/34] dist: fix a sequencing bug in dist --- dist/azure-deployment.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dist/azure-deployment.yml b/dist/azure-deployment.yml index 506f3ac26..da32c5e43 100644 --- a/dist/azure-deployment.yml +++ b/dist/azure-deployment.yml @@ -36,7 +36,7 @@ jobs: set -xeuo pipefail cranko github delete-release continuous git tag -f continuous HEAD - git push -f --tags origin continuous + git push -f origin refs/tags/continuous cranko github create-custom-release \ --name "Continuous Deployment" \ --prerelease \ @@ -88,6 +88,7 @@ jobs: CARGO_REGISTRY_TOKEN: $(CARGO_REGISTRY_TOKEN) - job: github_releases + dependsOn: branch_and_tag # otherwise, GitHub will create the tag itself pool: vmImage: ubuntu-20.04 variables: @@ -160,7 +161,7 @@ jobs: GITHUB_TOKEN: $(GITHUB_TOKEN) - job: update_arch_linux - dependsOn: cargo_publish # <= note! + dependsOn: cargo_publish # need to download the crate file and calc its digest pool: vmImage: ubuntu-20.04 variables: From 765db4e0ffa9e2a3fc158edae3caa350edc32327 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 10 Sep 2020 12:30:20 -0400 Subject: [PATCH 11/34] Attempt to gather coverage from executable tests Some of these failed due to a missing environment variable, but if I fix that the tests at least seem to run, in my local testing. --- dist/azure-coverage.yml | 2 +- tests/executable.rs | 62 ++++++----------------------------------- 2 files changed, 9 insertions(+), 55 deletions(-) diff --git a/dist/azure-coverage.yml b/dist/azure-coverage.yml index 0f216fbfe..612c10ab0 100644 --- a/dist/azure-coverage.yml +++ b/dist/azure-coverage.yml @@ -50,7 +50,7 @@ steps: git show HEAD displayName: Make release commit -- bash: RUNNING_COVERAGE=1 cargo kcov --no-clean-rebuild +- bash: cargo kcov --no-clean-rebuild displayName: cargo kcov - bash: | diff --git a/tests/executable.rs b/tests/executable.rs index 80c9b1aa9..c6c925f98 100644 --- a/tests/executable.rs +++ b/tests/executable.rs @@ -102,8 +102,14 @@ fn setup_and_copy_files(files: &[&str]) -> TempDir { .prefix("tectonic_executable_test") .tempdir() .unwrap(); - let executable_test_dir = - PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("tests/executable"); + + // `cargo kcov` (0.5.2) does not set this variable: + let executable_test_dir = if let Some(v) = env::var_os("CARGO_MANIFEST_DIR") { + PathBuf::from(v) + } else { + PathBuf::new() + } + .join("tests/executable"); for file in files { // Create parent directories, if the file is not at the root of `tests/executable/` @@ -165,60 +171,36 @@ fn check_file(tempdir: &TempDir, rest: &str) { #[test] fn bad_chatter_1() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let output = run_tectonic(&PathBuf::from("."), &["-", "--chatter=reticent"]); error_or_panic(output); } #[test] fn bad_input_path_1() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let output = run_tectonic(&PathBuf::from("."), &["/"]); error_or_panic(output); } #[test] fn bad_input_path_2() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let output = run_tectonic(&PathBuf::from("."), &["somedir/.."]); error_or_panic(output); } #[test] fn bad_outfmt_1() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let output = run_tectonic(&PathBuf::from("."), &["-", "--outfmt=dd"]); error_or_panic(output); } #[test] fn help_flag() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let output = run_tectonic(&PathBuf::from("."), &["-h"]); success_or_panic(output); } #[test] // GitHub #31 fn relative_include() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&[ "subdirectory/relative_include.tex", @@ -235,10 +217,6 @@ fn relative_include() { #[test] fn stdin_content() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - // No input files here, but output files are created. let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&[]); @@ -253,10 +231,6 @@ fn stdin_content() { // Regression #36 #[test] fn test_space() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&["test space.tex"]); @@ -266,10 +240,6 @@ fn test_space() { #[test] fn test_outdir() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&["subdirectory/content/1.tex"]); @@ -290,10 +260,6 @@ fn test_outdir() { // panic unwinding broken: https://github.com/rust-embedded/cross/issues/343 #[cfg(not(all(target_arch = "arm", target_env = "musl")))] fn test_bad_outdir() { - if env::var("RUNNING_COVERAGE").is_ok() { - panic!() - } - let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&["subdirectory/content/1.tex"]); @@ -313,10 +279,6 @@ fn test_bad_outdir() { // panic unwinding broken: https://github.com/rust-embedded/cross/issues/343 #[cfg(not(all(target_arch = "arm", target_env = "musl")))] fn test_outdir_is_file() { - if env::var("RUNNING_COVERAGE").is_ok() { - panic!() - } - let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&["test space.tex", "subdirectory/content/1.tex"]); @@ -333,10 +295,6 @@ fn test_outdir_is_file() { #[test] fn test_keep_logs_on_error() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - // No input files here, but output files are created. let fmt_arg = get_plain_format_arg(); let tempdir = setup_and_copy_files(&[]); @@ -358,10 +316,6 @@ fn test_keep_logs_on_error() { #[test] fn test_no_color() { - if env::var("RUNNING_COVERAGE").is_ok() { - return; - } - // No input files here, but output files are created. let fmt_arg = get_plain_format_arg(); From 0dbaf2a205b71ab007b6d5aeaac644261cd50f14 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 10 Sep 2020 12:38:53 -0400 Subject: [PATCH 12/34] dist/azure-coverage.yml: remove now-unneeded command and more fail-paranoia --- dist/azure-coverage.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dist/azure-coverage.yml b/dist/azure-coverage.yml index 612c10ab0..43e19dfe6 100644 --- a/dist/azure-coverage.yml +++ b/dist/azure-coverage.yml @@ -29,6 +29,7 @@ steps: displayName: Set up code coverage - bash: | + set -xeuo pipefail # As of Rust 1.44, test executables land in target/debug/deps/ instead of # target/debug/, which messes up current cargo-kcov (0.5.2) because it tries # to search for those executables. Work around with `cp`. One of the @@ -38,13 +39,13 @@ steps: # a search based on the hardlink count. Hacky and fragile but this should # get us going. Hopefully kcov will get fixed where this will become # unneccessary anyway. - rm target/debug/deps/tectonic-???????????????? cargo test --no-run find target/debug/deps/tectonic-???????????????? -links 2 -print -delete cp -vp target/debug/deps/*-???????????????? target/debug/ displayName: cargo test --no-run - bash: | + set -xeuo pipefail git add . cranko release-workflow commit git show HEAD @@ -54,5 +55,6 @@ steps: displayName: cargo kcov - bash: | + set -xeuo pipefail bash <(curl -s https://codecov.io/bash) displayName: Report coverage results From 913c8d807ab4ff5ed74eb876f5f1524784fa02fd Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Fri, 11 Sep 2020 14:10:13 -0400 Subject: [PATCH 13/34] tests: attempt to gather code coverage info in the executable tests It turns out that our tests of the built `tectonic` executable weren't gathering code coverage information about the code paths exercised in those tests. I *think* that it's not so hard to hack in some support to gather that information, so let's give it a try. --- dist/azure-coverage.yml | 38 +++++++++++++++++++++++++++++--------- tests/executable.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/dist/azure-coverage.yml b/dist/azure-coverage.yml index 43e19dfe6..21a71b720 100644 --- a/dist/azure-coverage.yml +++ b/dist/azure-coverage.yml @@ -28,17 +28,16 @@ steps: cargo install --force cargo-kcov displayName: Set up code coverage +# As of Rust 1.44, test executables land in target/debug/deps/ instead of +# target/debug/, which messes up current cargo-kcov (0.5.2) because it tries to +# search for those executables. Work around with `cp`. One of the `tectonic-*` +# binaries is the debug executable, which is hard-linked to +# `target/debug/tectonic`. kcov will erroneously try to run this as a test if we +# copy it, so we have to make not to do that, which we accomplish with a search +# based on the hardlink count. Hacky and fragile but this should get us going. +# Hopefully kcov will get fixed where this will become unneccessary anyway. - bash: | set -xeuo pipefail - # As of Rust 1.44, test executables land in target/debug/deps/ instead of - # target/debug/, which messes up current cargo-kcov (0.5.2) because it tries - # to search for those executables. Work around with `cp`. One of the - # `tectonic-*` binaries is the debug executable, which is hard-linked to - # `target/debug/tectonic`. kcov will erroneously try to run this as a test - # if we copy it, so we have to make not to do that, which we accomplish with - # a search based on the hardlink count. Hacky and fragile but this should - # get us going. Hopefully kcov will get fixed where this will become - # unneccessary anyway. cargo test --no-run find target/debug/deps/tectonic-???????????????? -links 2 -print -delete cp -vp target/debug/deps/*-???????????????? target/debug/ @@ -54,6 +53,27 @@ steps: - bash: cargo kcov --no-clean-rebuild displayName: cargo kcov +# Our "executable" test executes the actual Tectonic binary. In order to collect +# coverage information about what happens in those executions, we have special +# support in the test harness to wrap the invocations in `kcov` calls. +- bash: | + set -xeuo pipefail + export TECTONIC_EXETEST_KCOV_RUNNER="kcov --exclude-pattern=$HOME/.cargo --verify" + cargo test --test executable + displayName: Special-case executable tests + +# Now, merge all of the coverage reports. `cargo kcov` does this automatically, +# but it uses an explicit list of coverage runs, so there's no way to get it to +# include our special executable tests. We just glob everything, which means we +# have to delete the preexisting merged report. +- bash: | + set -xeou pipefail + cd target/cov + rm -rf amber.png bcov.css data glass.png index.html index.json \ + kcov-merged merged-kcov-output + kcov --merge . * + displayName: Merge coverage reports + - bash: | set -xeuo pipefail bash <(curl -s https://codecov.io/bash) diff --git a/tests/executable.rs b/tests/executable.rs index c6c925f98..3dc1358fa 100644 --- a/tests/executable.rs +++ b/tests/executable.rs @@ -23,6 +23,7 @@ lazy_static! { root.push("tests"); root }; + static ref TARGET_RUNNER_WORDS: Vec = { // compile-time environment variable from build.rs: let target = env!("TARGET").to_owned(); @@ -36,6 +37,17 @@ lazy_static! { vec![] } }; + + // Special coverage-collection mode. This implementation is quite tuned for + // the Tectonic CI/CD system, so if you're trying to use it manually, expect + // some rough edges. + static ref KCOV_WORDS: Vec = { + if let Ok(runtext) = env::var("TECTONIC_EXETEST_KCOV_RUNNER") { + runtext.split_whitespace().map(|x| x.to_owned()).collect() + } else { + vec![] + } + }; } fn get_plain_format_arg() -> String { @@ -61,10 +73,32 @@ fn prep_tectonic(cwd: &Path, args: &[&str]) -> Command { println!("using tectonic binary at {:?}", tectonic); println!("using cwd {:?}", cwd); + // We may need to wrap the Tectonic invocation. If we're cross-compiling, we + // might need to use something like QEMU to actually be able to run the + // executable. If we're collecting code coverage information with kcov, we + // need to wrap the invocation with that program. let mut command = if TARGET_RUNNER_WORDS.len() > 0 { let mut cmd = Command::new(&TARGET_RUNNER_WORDS[0]); cmd.args(&TARGET_RUNNER_WORDS[1..]).arg(tectonic); cmd + } else if KCOV_WORDS.len() > 0 { + let mut cmd = Command::new(&KCOV_WORDS[0]); + cmd.args(&KCOV_WORDS[1..]); + + // Give kcov a directory into which to put its output. We use + // mktemp-like functionality to automatically create such directories + // uniquely so that we don't have to manually bookkeep. This does mean + // that successive runs will build up new data directories indefinitely. + let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + root.push("target"); + root.push("cov"); + root.push("exetest."); + let tempdir = tempfile::Builder::new().prefix(&root).tempdir().unwrap(); + let tempdir = tempdir.into_path(); + cmd.arg(tempdir); + + cmd.arg(tectonic); + cmd } else { Command::new(tectonic) }; From 3b100e42437a7ee7c6e904f6f08ad18e1ff2c2dd Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Fri, 11 Sep 2020 14:45:14 -0400 Subject: [PATCH 14/34] dist/azure-coverage.yml: some kcovs have index.js, it seems --- dist/azure-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/azure-coverage.yml b/dist/azure-coverage.yml index 21a71b720..0600cb969 100644 --- a/dist/azure-coverage.yml +++ b/dist/azure-coverage.yml @@ -69,7 +69,7 @@ steps: - bash: | set -xeou pipefail cd target/cov - rm -rf amber.png bcov.css data glass.png index.html index.json \ + rm -rf amber.png bcov.css data glass.png index.html index.js* \ kcov-merged merged-kcov-output kcov --merge . * displayName: Merge coverage reports From 74d2549b1fb0b9b0e5d94c5858fe33e26ef5574b Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 13 Sep 2020 23:06:25 -0400 Subject: [PATCH 15/34] dist/azure-coverage.yml: try to only include main code in coverage stats --- dist/azure-coverage.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dist/azure-coverage.yml b/dist/azure-coverage.yml index 0600cb969..2248afd69 100644 --- a/dist/azure-coverage.yml +++ b/dist/azure-coverage.yml @@ -50,7 +50,10 @@ steps: git show HEAD displayName: Make release commit -- bash: cargo kcov --no-clean-rebuild +- bash: | + set -xeuo pipefail + p="$(pwd)" + cargo kcov --no-clean-rebuild -- --include-pattern="$p/src,$p/tectonic,$p/xdv" displayName: cargo kcov # Our "executable" test executes the actual Tectonic binary. In order to collect @@ -58,7 +61,8 @@ steps: # support in the test harness to wrap the invocations in `kcov` calls. - bash: | set -xeuo pipefail - export TECTONIC_EXETEST_KCOV_RUNNER="kcov --exclude-pattern=$HOME/.cargo --verify" + p="$(pwd)" + export TECTONIC_EXETEST_KCOV_RUNNER="kcov --include-pattern=$p/src,$p/tectonic,$p/xdv" cargo test --test executable displayName: Special-case executable tests From ae34db7c9e5cec9b1eeef770bd250cde0c052733 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 07:12:24 +0000 Subject: [PATCH 16/34] build(deps): bump libc from 0.2.76 to 0.2.77 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.76 to 0.2.77. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.76...0.2.77) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63c3b8922..244404061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -770,9 +770,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.76" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "libz-sys" From ecb5ec3b5eed99a4e1b111dbdf6fafbecee7ccb0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 07:12:49 +0000 Subject: [PATCH 17/34] build(deps): bump serde from 1.0.115 to 1.0.116 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.115 to 1.0.116. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.115...v1.0.116) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63c3b8922..9d594dd4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1484,18 +1484,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", From bc4f6f7a547c91e95fb2d5515f6e70e9f7dcb22f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2020 07:13:11 +0000 Subject: [PATCH 18/34] build(deps): bump zip from 0.5.7 to 0.5.8 Bumps [zip](https://github.com/mvdnes/zip-rs) from 0.5.7 to 0.5.8. - [Release notes](https://github.com/mvdnes/zip-rs/releases) - [Commits](https://github.com/mvdnes/zip-rs/compare/v0.5.7...v0.5.8) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63c3b8922..22277d6b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2196,9 +2196,9 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" [[package]] name = "zip" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d30de6e58104bb7b9a94f34b52a2bdabb8a40b678a64201cd0069e3d7119b5ff" +checksum = "543adf038106b64cfca4711c82c917d785e3540e04f7996554488f988ec43124" dependencies = [ "byteorder", "crc32fast", From d0d450ed56afc64729f3ee51abb06aced92fd398 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 00:26:19 +1000 Subject: [PATCH 19/34] Setup cbindgen & build method --- .gitignore | 1 + Cargo.lock | 19 +++++++++++++++++++ Cargo.toml | 1 + build.rs | 12 ++++++++++++ cbindgen.toml | 15 +++++++++++++++ 5 files changed, 48 insertions(+) create mode 100644 cbindgen.toml diff --git a/.gitignore b/.gitignore index 5ad584b56..56c424cbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/tectonic/core-bindgen.h /cross /target /tests/plain.fmt diff --git a/Cargo.lock b/Cargo.lock index d213db5ae..41ba8a946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,24 @@ dependencies = [ "iovec", ] +[[package]] +name = "cbindgen" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e783d38a7700989e0209d0b0ed224c34ade92d3603da0cf15dc502ebada685a6" +dependencies = [ + "clap", + "heck", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml", +] + [[package]] name = "cc" version = "1.0.59" @@ -1634,6 +1652,7 @@ dependencies = [ "app_dirs2", "atty", "byte-unit", + "cbindgen", "cc", "cfg-if", "error-chain", diff --git a/Cargo.toml b/Cargo.toml index 53cf34e68..a80da29a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ regex = "^1.3" sha2 = "^0.9" tectonic_cfg_support = { path = "cfg_support", version = "0.0.0-dev.0" } vcpkg = "0.2.10" +cbindgen = "0.14.4" [dependencies] app_dirs = { version = "2", package = "app_dirs2" } diff --git a/build.rs b/build.rs index 771c737a2..df30e2659 100644 --- a/build.rs +++ b/build.rs @@ -9,6 +9,8 @@ /// TODO: this surely needs to become much smarter and more flexible. use tectonic_cfg_support::*; +extern crate cbindgen; + use std::env; use std::path::{Path, PathBuf}; @@ -184,6 +186,16 @@ fn main() { let target = env::var("TARGET").unwrap(); let rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + // Generate C bindings + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + cbindgen::generate(&crate_dir) + .unwrap() + .write_to_file("tectonic/core-bindgen.h"); + + // Most of `core-bindgen.h` comes from this file, so this should catch most of the changes. + // TODO better detect when cbindgen needs to be run, or we need to rebuild. + println!("cargo:rerun-if-changed=src/engines/mod.rs"); + // Re-export $TARGET during the build so that our executable tests know // what environment variable CARGO_TARGET_@TARGET@_RUNNER to check when // they want to spawn off executables. diff --git a/cbindgen.toml b/cbindgen.toml new file mode 100644 index 000000000..155826e62 --- /dev/null +++ b/cbindgen.toml @@ -0,0 +1,15 @@ +include_guard = "tectonic_core_bindgen_h" +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +include_version = true + +language = "C" + +# typedef Name struct {} Name +style = "both" + +# Table of name conversions to apply to item names +[export.rename] +TectonicBridgeApi = "tt_bridge_api_t" + +[fn] +sort_by = "None" # Make cbindgen not mess with our declaration order From 8b79d62caf867cabab3319ca3dc66cd1d37fa194 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 00:46:01 +1000 Subject: [PATCH 20/34] Integrate generated bindings Had to fix a few constness issues. --- build.rs | 1 + cbindgen.toml | 6 ++++++ src/engines/mod.rs | 6 +++++- tectonic/core-bridge.c | 8 ++++---- tectonic/core-bridge.h | 9 +-------- tectonic/xetex-engine-interface.c | 7 ++----- tectonic/xetex-ini.c | 2 +- tectonic/xetex-xetexd.h | 2 +- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/build.rs b/build.rs index df30e2659..8298e9991 100644 --- a/build.rs +++ b/build.rs @@ -186,6 +186,7 @@ fn main() { let target = env::var("TARGET").unwrap(); let rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + // TODO make this be always run // Generate C bindings let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); cbindgen::generate(&crate_dir) diff --git a/cbindgen.toml b/cbindgen.toml index 155826e62..8397aec56 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -1,3 +1,6 @@ +# Hack to not generate tt_bridge_api_t +after_includes = "typedef struct tt_bridge_api_t tt_bridge_api_t;" + include_guard = "tectonic_core_bindgen_h" autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" include_version = true @@ -7,6 +10,9 @@ language = "C" # typedef Name struct {} Name style = "both" +[export] +exclude = [ "DIGEST_LEN", "TectonicBridgeApi" ] + # Table of name conversions to apply to item names [export.rename] TectonicBridgeApi = "tt_bridge_api_t" diff --git a/src/engines/mod.rs b/src/engines/mod.rs index e9796189e..db6d5fba0 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -494,7 +494,11 @@ struct TectonicBridgeApi { extern "C" { fn tt_get_error_message() -> *const libc::c_char; fn tt_xetex_set_int_variable(var_name: *const libc::c_char, value: libc::c_int) -> libc::c_int; - //fn tt_xetex_set_string_variable(var_name: *const libc::c_char, value: *const libc::c_char) -> libc::c_int; + #[allow(dead_code)] // currently unused + fn tt_xetex_set_string_variable( + var_name: *const libc::c_char, + value: *const libc::c_char, + ) -> libc::c_int; fn tex_simple_main( api: *const TectonicBridgeApi, dump_name: *const libc::c_char, diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index 71c510865..f7962bde3 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -20,7 +20,7 @@ /* The global variable that represents the Rust API. Some fine day we'll get * rid of all of the globals ... */ -static tt_bridge_api_t *tectonic_global_bridge = NULL; +static const tt_bridge_api_t *tectonic_global_bridge = NULL; /* Highest-level abort/error handling. */ @@ -52,7 +52,7 @@ tt_get_error_message(void) * setjmp aborts and error message extraction. */ int -tex_simple_main(tt_bridge_api_t *api, char *dump_name, char *input_file_name, time_t build_date) +tex_simple_main(const tt_bridge_api_t *api, const char *dump_name, const char *input_file_name, time_t build_date) { int rv; @@ -70,7 +70,7 @@ tex_simple_main(tt_bridge_api_t *api, char *dump_name, char *input_file_name, ti int -dvipdfmx_simple_main(tt_bridge_api_t *api, char *dviname, char *pdfname, bool compress, bool deterministic_tags, time_t build_date) +dvipdfmx_simple_main(const tt_bridge_api_t *api, const char *dviname, const char *pdfname, bool compress, bool deterministic_tags, time_t build_date) { int rv; @@ -89,7 +89,7 @@ dvipdfmx_simple_main(tt_bridge_api_t *api, char *dviname, char *pdfname, bool co int -bibtex_simple_main(tt_bridge_api_t *api, char *aux_file_name) +bibtex_simple_main(const tt_bridge_api_t *api, const char *aux_file_name) { int rv; diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 293816138..da46fab4a 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -7,6 +7,7 @@ #define TECTONIC_CORE_BRIDGE_H #include "core-foundation.h" +#include "core-bindgen.h" /* Both XeTeX and bibtex use this enum: */ @@ -88,14 +89,6 @@ typedef struct tt_bridge_api_t { BEGIN_EXTERN_C -/* These functions are not meant to be used in the C/C++ code. They define the - * API that we expose to the Rust side of things. */ - -const char *tt_get_error_message(void); -int tex_simple_main(tt_bridge_api_t *api, char *dump_name, char *input_file_name, time_t build_date); -int dvipdfmx_simple_main(tt_bridge_api_t *api, char *dviname, char *pdfname, bool compress, bool deterministic_tags, time_t build_date); -int bibtex_simple_main(tt_bridge_api_t *api, char *aux_file_name); - /* The internal, C/C++ interface: */ NORETURN PRINTF_FUNC(1,2) int _tt_abort(const char *format, ...); diff --git a/tectonic/xetex-engine-interface.c b/tectonic/xetex-engine-interface.c index 903749c3b..2aa23264f 100644 --- a/tectonic/xetex-engine-interface.c +++ b/tectonic/xetex-engine-interface.c @@ -12,11 +12,8 @@ /* These functions aren't used within the C/C++ library, but are called * by the Rust code to configure the XeTeX engine before launching it. */ -int tt_xetex_set_int_variable (char *var_name, int value); -int tt_xetex_set_string_variable (char *var_name, char *value); - int -tt_xetex_set_int_variable (char *var_name, int value) +tt_xetex_set_int_variable (const char *var_name, int value) { if (streq_ptr(var_name, "halt_on_error_p")) halt_on_error_p = value; @@ -34,7 +31,7 @@ tt_xetex_set_int_variable (char *var_name, int value) int -tt_xetex_set_string_variable (char *var_name, char *value) +tt_xetex_set_string_variable (const char *var_name, const char *value) { /* Currently unused; see Git history for how we used to set output_comment */ return 1; diff --git a/tectonic/xetex-ini.c b/tectonic/xetex-ini.c index 274b64fc5..ca3484396 100644 --- a/tectonic/xetex-ini.c +++ b/tectonic/xetex-ini.c @@ -3942,7 +3942,7 @@ tt_cleanup(void) { } tt_history_t -tt_run_engine(char *dump_name, char *input_file_name, time_t build_date) +tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_date) { int32_t font_k; diff --git a/tectonic/xetex-xetexd.h b/tectonic/xetex-xetexd.h index 10abab7c6..af14c2ec7 100644 --- a/tectonic/xetex-xetexd.h +++ b/tectonic/xetex-xetexd.h @@ -1136,7 +1136,7 @@ cur_length(void) { /* Tectonic related functions */ void tt_cleanup(void); -tt_history_t tt_run_engine(char *dump_name, char *input_file_name, time_t build_date); +tt_history_t tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_date); /* formerly xetex.h: */ From 0d65a7b0fd15133afb0ec4982b619571c99c6dfd Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 00:54:33 +1000 Subject: [PATCH 21/34] Add FORMAT_SERIAL to cbindgen --- src/lib.rs | 6 +++++- tectonic/xetex-constants.h | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a0651ac06..5954d43e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,11 @@ pub use crate::engines::tex::{TexEngine, TexResult}; pub use crate::engines::xdvipdfmx::XdvipdfmxEngine; pub use crate::errors::{Error, ErrorKind, Result}; -const FORMAT_SERIAL: u32 = 28; // keep synchronized with tectonic/xetex-constants.h!! +// Increase this whenever the engine internals change such that the contents +// of the "format" files must be regenerated -- this includes changes to the +// string pool. + +pub const FORMAT_SERIAL: u32 = 28; /// Compile LaTeX text to a PDF. /// diff --git a/tectonic/xetex-constants.h b/tectonic/xetex-constants.h index f6f0f9412..ad858d20b 100644 --- a/tectonic/xetex-constants.h +++ b/tectonic/xetex-constants.h @@ -1030,10 +1030,4 @@ #define MOV_D_FIXED 6 #define MOV_Z_SEEN 12 -/* Increase this whenever the engine internals change such that the contents - * of the "format" files must be regenerated -- this includes changes to the - * string pool. KEEP SYNCHRONIZED WITH src/lib.rs!!! */ - -#define FORMAT_SERIAL 28 - #endif /* not TECTONIC_CONSTANTS_H */ From fafcc4dcbdd46576a12a77728ea2144c10ee0e0a Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 16:51:45 +1000 Subject: [PATCH 22/34] Make ExecutionState a concrete type --- src/engines/mod.rs | 136 ++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 82 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index db6d5fba0..4de72c3c9 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -122,8 +122,8 @@ lazy_static! { /// The methods on ExecutionState pretty much all work to implement for the /// "bridge" API (C/C++ => Rust) defined below. -struct ExecutionState<'a, I: 'a + IoProvider> { - io: &'a mut I, +struct ExecutionState<'a> { + io: &'a mut dyn IoProvider, events: &'a mut dyn IoEventBackend, status: &'a mut dyn StatusBackend, #[allow(clippy::vec_box)] @@ -132,12 +132,12 @@ struct ExecutionState<'a, I: 'a + IoProvider> { output_handles: Vec>, } -impl<'a, I: 'a + IoProvider> ExecutionState<'a, I> { +impl<'a> ExecutionState<'a> { pub fn new( - io: &'a mut I, + io: &'a mut dyn IoProvider, events: &'a mut dyn IoEventBackend, status: &'a mut dyn StatusBackend, - ) -> ExecutionState<'a, I> { + ) -> ExecutionState<'a> { ExecutionState { io, events, @@ -542,10 +542,7 @@ extern "C" fn diag_error_begin() -> *mut Diagnostic { Box::into_raw(warning) } -extern "C" fn diag_finish<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - diag: *mut Diagnostic, -) { +extern "C" fn diag_finish(es: *mut ExecutionState, diag: *mut Diagnostic) { let rdiag = unsafe { Box::from_raw(diag as *mut Diagnostic) }; let es = unsafe { &mut *es }; @@ -560,28 +557,22 @@ extern "C" fn diag_append(diag: *mut Diagnostic, text: *const libc::c_char) { rdiag.message.push_str(&rtext.to_string_lossy()); } -extern "C" fn issue_warning<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - text: *const libc::c_char, -) { +extern "C" fn issue_warning(es: *mut ExecutionState, text: *const libc::c_char) { let es = unsafe { &mut *es }; let rtext = unsafe { CStr::from_ptr(text) }; tt_warning!(es.status, "{}", rtext.to_string_lossy()); } -extern "C" fn issue_error<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - text: *const libc::c_char, -) { +extern "C" fn issue_error(es: *mut ExecutionState, text: *const libc::c_char) { let es = unsafe { &mut *es }; let rtext = unsafe { CStr::from_ptr(text) }; tt_error!(es.status, "{}", rtext.to_string_lossy()); } -extern "C" fn get_file_md5<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn get_file_md5( + es: *mut ExecutionState, path: *const libc::c_char, digest: *mut u8, ) -> libc::c_int { @@ -596,8 +587,8 @@ extern "C" fn get_file_md5<'a, I: 'a + IoProvider>( } } -extern "C" fn get_data_md5<'a, I: 'a + IoProvider>( - _es: *mut ExecutionState<'a, I>, +extern "C" fn get_data_md5( + _es: *mut ExecutionState, data: *const u8, len: libc::size_t, digest: *mut u8, @@ -614,8 +605,8 @@ extern "C" fn get_data_md5<'a, I: 'a + IoProvider>( 0 } -extern "C" fn output_open<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn output_open( + es: *mut ExecutionState, name: *const libc::c_char, is_gz: libc::c_int, ) -> *const libc::c_void { @@ -626,16 +617,14 @@ extern "C" fn output_open<'a, I: 'a + IoProvider>( es.output_open(&rname, ris_gz) as *const _ } -extern "C" fn output_open_stdout<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, -) -> *const libc::c_void { +extern "C" fn output_open_stdout(es: *mut ExecutionState) -> *const libc::c_void { let es = unsafe { &mut *es }; es.output_open_stdout() as *const _ } -extern "C" fn output_putc<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn output_putc( + es: *mut ExecutionState, handle: *mut libc::c_void, c: libc::c_int, ) -> libc::c_int { @@ -650,8 +639,8 @@ extern "C" fn output_putc<'a, I: 'a + IoProvider>( } } -extern "C" fn output_write<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn output_write( + es: *mut ExecutionState, handle: *mut libc::c_void, data: *const u8, len: libc::size_t, @@ -669,10 +658,7 @@ extern "C" fn output_write<'a, I: 'a + IoProvider>( } } -extern "C" fn output_flush<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - handle: *mut libc::c_void, -) -> libc::c_int { +extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; let rhandle = handle as *mut OutputHandle; @@ -683,10 +669,7 @@ extern "C" fn output_flush<'a, I: 'a + IoProvider>( } } -extern "C" fn output_close<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - handle: *mut libc::c_void, -) -> libc::c_int { +extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; if handle.is_null() { @@ -702,8 +685,8 @@ extern "C" fn output_close<'a, I: 'a + IoProvider>( } } -extern "C" fn input_open<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn input_open( + es: *mut ExecutionState, name: *const libc::c_char, format: libc::c_int, is_gz: libc::c_int, @@ -719,26 +702,21 @@ extern "C" fn input_open<'a, I: 'a + IoProvider>( } } -extern "C" fn input_open_primary<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, -) -> *const libc::c_void { +extern "C" fn input_open_primary(es: *mut ExecutionState) -> *const libc::c_void { let es = unsafe { &mut *es }; es.input_open_primary() as *const _ } -extern "C" fn input_get_size<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - handle: *mut libc::c_void, -) -> libc::size_t { +extern "C" fn input_get_size(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::size_t { let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; es.input_get_size(rhandle) } -extern "C" fn input_seek<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn input_seek( + es: *mut ExecutionState, handle: *mut libc::c_void, offset: libc::ssize_t, whence: libc::c_int, @@ -774,10 +752,7 @@ extern "C" fn input_seek<'a, I: 'a + IoProvider>( } } -extern "C" fn input_getc<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - handle: *mut libc::c_void, -) -> libc::c_int { +extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; @@ -796,8 +771,8 @@ extern "C" fn input_getc<'a, I: 'a + IoProvider>( } } -extern "C" fn input_ungetc<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn input_ungetc( + es: *mut ExecutionState, handle: *mut libc::c_void, ch: libc::c_int, ) -> libc::c_int { @@ -813,8 +788,8 @@ extern "C" fn input_ungetc<'a, I: 'a + IoProvider>( } } -extern "C" fn input_read<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, +extern "C" fn input_read( + es: *mut ExecutionState, handle: *mut libc::c_void, data: *mut u8, len: libc::size_t, @@ -832,10 +807,7 @@ extern "C" fn input_read<'a, I: 'a + IoProvider>( } } -extern "C" fn input_close<'a, I: 'a + IoProvider>( - es: *mut ExecutionState<'a, I>, - handle: *mut libc::c_void, -) -> libc::c_int { +extern "C" fn input_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; if handle.is_null() { @@ -854,31 +826,31 @@ extern "C" fn input_close<'a, I: 'a + IoProvider>( // All of these entry points are used to populate the bridge API struct: impl TectonicBridgeApi { - fn new<'a, I: 'a + IoProvider>(exec_state: &ExecutionState<'a, I>) -> TectonicBridgeApi { + fn new(exec_state: &ExecutionState) -> TectonicBridgeApi { TectonicBridgeApi { - context: (exec_state as *const ExecutionState<'a, I>) as *const libc::c_void, + context: (exec_state as *const ExecutionState) as *const libc::c_void, diag_warn_begin: diag_warn_begin as *const libc::c_void, diag_error_begin: diag_error_begin as *const libc::c_void, - diag_finish: diag_finish::<'a, I> as *const libc::c_void, + diag_finish: diag_finish as *const libc::c_void, diag_append: diag_append as *const libc::c_void, - issue_warning: issue_warning::<'a, I> as *const libc::c_void, - issue_error: issue_error::<'a, I> as *const libc::c_void, - get_file_md5: get_file_md5::<'a, I> as *const libc::c_void, - get_data_md5: get_data_md5::<'a, I> as *const libc::c_void, - output_open: output_open::<'a, I> as *const libc::c_void, - output_open_stdout: output_open_stdout::<'a, I> as *const libc::c_void, - output_putc: output_putc::<'a, I> as *const libc::c_void, - output_write: output_write::<'a, I> as *const libc::c_void, - output_flush: output_flush::<'a, I> as *const libc::c_void, - output_close: output_close::<'a, I> as *const libc::c_void, - input_open: input_open::<'a, I> as *const libc::c_void, - input_open_primary: input_open_primary::<'a, I> as *const libc::c_void, - input_get_size: input_get_size::<'a, I> as *const libc::c_void, - input_seek: input_seek::<'a, I> as *const libc::c_void, - input_read: input_read::<'a, I> as *const libc::c_void, - input_getc: input_getc::<'a, I> as *const libc::c_void, - input_ungetc: input_ungetc::<'a, I> as *const libc::c_void, - input_close: input_close::<'a, I> as *const libc::c_void, + issue_warning: issue_warning as *const libc::c_void, + issue_error: issue_error as *const libc::c_void, + get_file_md5: get_file_md5 as *const libc::c_void, + get_data_md5: get_data_md5 as *const libc::c_void, + output_open: output_open as *const libc::c_void, + output_open_stdout: output_open_stdout as *const libc::c_void, + output_putc: output_putc as *const libc::c_void, + output_write: output_write as *const libc::c_void, + output_flush: output_flush as *const libc::c_void, + output_close: output_close as *const libc::c_void, + input_open: input_open as *const libc::c_void, + input_open_primary: input_open_primary as *const libc::c_void, + input_get_size: input_get_size as *const libc::c_void, + input_seek: input_seek as *const libc::c_void, + input_read: input_read as *const libc::c_void, + input_getc: input_getc as *const libc::c_void, + input_ungetc: input_ungetc as *const libc::c_void, + input_close: input_close as *const libc::c_void, } } } From 8576f0a9c949980b2fef16f8295af152ac93fc9f Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 17:53:42 +1000 Subject: [PATCH 23/34] Export some bridge functions --- src/engines/mod.rs | 31 +++++++++++++++++++++---------- tectonic/core-bridge.c | 20 +++++++++++--------- tectonic/core-bridge.h | 2 +- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 4de72c3c9..8d045c71d 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -12,6 +12,9 @@ //! substantial private API that defines the interface between Tectonic's Rust //! code and the C/C++ code that the backends are (currently) implemented in. +// Mostly for the bridge functions +#![allow(clippy::not_unsafe_ptr_arg_deref)] + use flate2::read::GzDecoder; use flate2::{Compression, GzBuilder}; use lazy_static::lazy_static; @@ -122,7 +125,7 @@ lazy_static! { /// The methods on ExecutionState pretty much all work to implement for the /// "bridge" API (C/C++ => Rust) defined below. -struct ExecutionState<'a> { +pub struct ExecutionState<'a> { io: &'a mut dyn IoProvider, events: &'a mut dyn IoEventBackend, status: &'a mut dyn StatusBackend, @@ -521,12 +524,13 @@ extern "C" { // Entry points for the C/C++ API functions. -struct Diagnostic { +pub struct Diagnostic { message: String, kind: MessageKind, } -extern "C" fn diag_warn_begin() -> *mut Diagnostic { +#[no_mangle] +pub extern "C" fn diag_warn_begin() -> *mut Diagnostic { let warning = Box::new(Diagnostic { message: String::new(), kind: MessageKind::Warning, @@ -534,7 +538,8 @@ extern "C" fn diag_warn_begin() -> *mut Diagnostic { Box::into_raw(warning) } -extern "C" fn diag_error_begin() -> *mut Diagnostic { +#[no_mangle] +pub extern "C" fn diag_error_begin() -> *mut Diagnostic { let warning = Box::new(Diagnostic { message: String::new(), kind: MessageKind::Error, @@ -542,7 +547,8 @@ extern "C" fn diag_error_begin() -> *mut Diagnostic { Box::into_raw(warning) } -extern "C" fn diag_finish(es: *mut ExecutionState, diag: *mut Diagnostic) { +#[no_mangle] +pub extern "C" fn diag_finish(es: *mut ExecutionState, diag: *mut Diagnostic) { let rdiag = unsafe { Box::from_raw(diag as *mut Diagnostic) }; let es = unsafe { &mut *es }; @@ -550,28 +556,32 @@ extern "C" fn diag_finish(es: *mut ExecutionState, diag: *mut Diagnostic) { .report(rdiag.kind, format_args!("{}", rdiag.message), None); } -extern "C" fn diag_append(diag: *mut Diagnostic, text: *const libc::c_char) { +#[no_mangle] +pub extern "C" fn diag_append(diag: *mut Diagnostic, text: *const libc::c_char) { let rdiag = unsafe { &mut *diag }; let rtext = unsafe { CStr::from_ptr(text) }; rdiag.message.push_str(&rtext.to_string_lossy()); } -extern "C" fn issue_warning(es: *mut ExecutionState, text: *const libc::c_char) { +#[no_mangle] +pub extern "C" fn issue_warning(es: *mut ExecutionState, text: *const libc::c_char) { let es = unsafe { &mut *es }; let rtext = unsafe { CStr::from_ptr(text) }; tt_warning!(es.status, "{}", rtext.to_string_lossy()); } -extern "C" fn issue_error(es: *mut ExecutionState, text: *const libc::c_char) { +#[no_mangle] +pub extern "C" fn issue_error(es: *mut ExecutionState, text: *const libc::c_char) { let es = unsafe { &mut *es }; let rtext = unsafe { CStr::from_ptr(text) }; tt_error!(es.status, "{}", rtext.to_string_lossy()); } -extern "C" fn get_file_md5( +#[no_mangle] +pub extern "C" fn get_file_md5( es: *mut ExecutionState, path: *const libc::c_char, digest: *mut u8, @@ -587,7 +597,8 @@ extern "C" fn get_file_md5( } } -extern "C" fn get_data_md5( +#[no_mangle] +pub extern "C" fn get_data_md5( _es: *mut ExecutionState, data: *const u8, len: libc::size_t, diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index f7962bde3..ebb803b21 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -113,32 +113,32 @@ bibtex_simple_main(const tt_bridge_api_t *api, const char *aux_file_name) diagnostic_t ttstub_diag_warn_begin(void) { - return TGB->diag_warn_begin(); + return diag_warn_begin(); } diagnostic_t ttstub_diag_error_begin(void) { - return TGB->diag_error_begin(); + return diag_error_begin(); } void ttstub_diag_finish(diagnostic_t diag) { - TGB->diag_finish(TGB->context, diag); + diag_finish(TGB->context, diag); } void ttstub_diag_append(diagnostic_t diag, char const *text) { - TGB->diag_append(diag, text); + diag_append(diag, text); } PRINTF_FUNC(2,0) void ttstub_diag_vprintf(diagnostic_t diag, const char *format, va_list ap) { vsnprintf(error_buf, BUF_SIZE, format, ap); /* Not ideal to (ab)use error_buf here */ - TGB->diag_append(diag, error_buf); + ttstub_diag_append(diag, error_buf); } PRINTF_FUNC(2,3) void @@ -159,7 +159,7 @@ ttstub_issue_warning(const char *format, ...) va_start(ap, format); vsnprintf(error_buf, BUF_SIZE, format, ap); /* Not ideal to (ab)use error_buf here */ va_end(ap); - TGB->issue_warning(TGB->context, error_buf); + issue_warning(TGB->context, error_buf); } PRINTF_FUNC(1,2) void @@ -170,7 +170,7 @@ ttstub_issue_error(const char *format, ...) va_start(ap, format); vsnprintf(error_buf, BUF_SIZE, format, ap); /* Not ideal to (ab)use error_buf here */ va_end(ap); - TGB->issue_error(TGB->context, error_buf); + issue_error(TGB->context, error_buf); } PRINTF_FUNC(2,3) int @@ -197,13 +197,15 @@ ttstub_fprintf(rust_output_handle_t handle, const char *format, ...) int ttstub_get_file_md5(char const *path, char *digest) { - return TGB->get_file_md5(TGB->context, path, digest); + // TODO change uses of ttstub_get_file_md5 to pass uint8_t* + return get_file_md5(TGB->context, path, (uint8_t*) digest); } int ttstub_get_data_md5(char const *data, size_t len, char *digest) { - return TGB->get_data_md5(TGB->context, data, len, digest); + // TODO change uses of ttstub_get_data_md5 to pass uint8_t* + return get_data_md5(TGB->context, (uint8_t const*) data, len, (uint8_t*) digest); } rust_output_handle_t diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index da46fab4a..1b71833d6 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -51,7 +51,7 @@ typedef enum typedef void *rust_output_handle_t; typedef void *rust_input_handle_t; -typedef void *diagnostic_t; +typedef Diagnostic *diagnostic_t; /* Bridge API. Keep synchronized with src/engines/mod.rs. */ From 06ecd4bea72a361361d1da364f82f56bec4f19bd Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 17:59:12 +1000 Subject: [PATCH 24/34] Export output bridge functions --- src/engines/mod.rs | 40 +++++++++++++++++++++++----------------- tectonic/core-bridge.c | 12 ++++++------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 8d045c71d..5af5b168e 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -284,13 +284,13 @@ impl<'a> ExecutionState<'a> { error_occurred } - fn output_open(&mut self, name: &OsStr, is_gz: bool) -> *const OutputHandle { + fn output_open(&mut self, name: &OsStr, is_gz: bool) -> *mut OutputHandle { let mut oh = match self.io.output_open_name(name) { OpenResult::Ok(oh) => oh, - OpenResult::NotAvailable => return ptr::null(), + OpenResult::NotAvailable => return ptr::null_mut(), OpenResult::Err(e) => { tt_warning!(self.status, "open of output {} failed", name.to_string_lossy(); e); - return ptr::null(); + return ptr::null_mut(); } }; @@ -304,22 +304,22 @@ impl<'a> ExecutionState<'a> { self.events.output_opened(oh.name()); self.output_handles.push(Box::new(oh)); - &*self.output_handles[self.output_handles.len() - 1] + &mut **self.output_handles.last_mut().unwrap() } - fn output_open_stdout(&mut self) -> *const OutputHandle { + fn output_open_stdout(&mut self) -> *mut OutputHandle { let oh = match self.io.output_open_stdout() { OpenResult::Ok(oh) => oh, - OpenResult::NotAvailable => return ptr::null(), + OpenResult::NotAvailable => return ptr::null_mut(), OpenResult::Err(e) => { tt_warning!(self.status, "open of stdout failed"; e); - return ptr::null(); + return ptr::null_mut(); } }; self.events.stdout_opened(); self.output_handles.push(Box::new(oh)); - &*self.output_handles[self.output_handles.len() - 1] + &mut **self.output_handles.last_mut().unwrap() } fn output_write(&mut self, handle: *mut OutputHandle, buf: &[u8]) -> bool { @@ -616,25 +616,28 @@ pub extern "C" fn get_data_md5( 0 } -extern "C" fn output_open( +#[no_mangle] +pub extern "C" fn output_open( es: *mut ExecutionState, name: *const libc::c_char, is_gz: libc::c_int, -) -> *const libc::c_void { +) -> *mut libc::c_void { let es = unsafe { &mut *es }; let rname = osstr_from_cstr(&unsafe { CStr::from_ptr(name) }); let ris_gz = is_gz != 0; - es.output_open(&rname, ris_gz) as *const _ + es.output_open(&rname, ris_gz) as *mut _ } -extern "C" fn output_open_stdout(es: *mut ExecutionState) -> *const libc::c_void { +#[no_mangle] +pub extern "C" fn output_open_stdout(es: *mut ExecutionState) -> *mut libc::c_void { let es = unsafe { &mut *es }; - es.output_open_stdout() as *const _ + es.output_open_stdout() as *mut _ } -extern "C" fn output_putc( +#[no_mangle] +pub extern "C" fn output_putc( es: *mut ExecutionState, handle: *mut libc::c_void, c: libc::c_int, @@ -650,7 +653,8 @@ extern "C" fn output_putc( } } -extern "C" fn output_write( +#[no_mangle] +pub extern "C" fn output_write( es: *mut ExecutionState, handle: *mut libc::c_void, data: *const u8, @@ -669,7 +673,8 @@ extern "C" fn output_write( } } -extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +#[no_mangle] +pub extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; let rhandle = handle as *mut OutputHandle; @@ -680,7 +685,8 @@ extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_void) - } } -extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +#[no_mangle] +pub extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; if handle.is_null() { diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index ebb803b21..4191658f1 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -211,37 +211,37 @@ ttstub_get_data_md5(char const *data, size_t len, char *digest) rust_output_handle_t ttstub_output_open(char const *path, int is_gz) { - return TGB->output_open(TGB->context, path, is_gz); + return output_open(TGB->context, path, is_gz); } rust_output_handle_t ttstub_output_open_stdout(void) { - return TGB->output_open_stdout(TGB->context); + return output_open_stdout(TGB->context); } int ttstub_output_putc(rust_output_handle_t handle, int c) { - return TGB->output_putc(TGB->context, handle, c); + return output_putc(TGB->context, handle, c); } size_t ttstub_output_write(rust_output_handle_t handle, const char *data, size_t len) { - return TGB->output_write(TGB->context, handle, data, len); + return output_write(TGB->context, handle, (const uint8_t*) data, len); } int ttstub_output_flush(rust_output_handle_t handle) { - return TGB->output_flush(TGB->context, handle); + return output_flush(TGB->context, handle); } int ttstub_output_close(rust_output_handle_t handle) { - return TGB->output_close(TGB->context, handle); + return output_close(TGB->context, handle); } rust_input_handle_t From 14a8fc51957079a05d280337ff8a0cdf5613ae16 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 18:08:14 +1000 Subject: [PATCH 25/34] Export input bridge functions --- src/engines/mod.rs | 51 +++++++++++++++++++++++++----------------- tectonic/core-bridge.c | 16 ++++++------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 5af5b168e..b875e9aa3 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -370,41 +370,41 @@ impl<'a> ExecutionState<'a> { rv } - fn input_open(&mut self, name: &OsStr, format: FileFormat, is_gz: bool) -> *const InputHandle { + fn input_open(&mut self, name: &OsStr, format: FileFormat, is_gz: bool) -> *mut InputHandle { let ih = match self.input_open_name_format_gz(name, format, is_gz) { OpenResult::Ok(ih) => ih, OpenResult::NotAvailable => { self.events.input_not_available(name); - return ptr::null(); + return ptr::null_mut(); } OpenResult::Err(e) => { tt_warning!(self.status, "open of input {} failed", name.to_string_lossy(); e); - return ptr::null(); + return ptr::null_mut(); } }; // the file name may have had an extension added, so we use ih.name() here: self.events.input_opened(ih.name(), ih.origin()); self.input_handles.push(Box::new(ih)); - &*self.input_handles[self.input_handles.len() - 1] + &mut **self.input_handles.last_mut().unwrap() } - fn input_open_primary(&mut self) -> *const InputHandle { + fn input_open_primary(&mut self) -> *mut InputHandle { let ih = match self.io.input_open_primary(self.status) { OpenResult::Ok(ih) => ih, OpenResult::NotAvailable => { tt_error!(self.status, "primary input not available (?!)"); - return ptr::null(); + return ptr::null_mut(); } OpenResult::Err(e) => { tt_error!(self.status, "open of primary input failed"; e); - return ptr::null(); + return ptr::null_mut(); } }; self.events.primary_input_opened(ih.origin()); self.input_handles.push(Box::new(ih)); - &*self.input_handles[self.input_handles.len() - 1] + &mut **self.input_handles.last_mut().unwrap() } fn input_get_size(&mut self, handle: *mut InputHandle) -> usize { @@ -702,37 +702,44 @@ pub extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_voi } } -extern "C" fn input_open( +#[no_mangle] +pub extern "C" fn input_open( es: *mut ExecutionState, name: *const libc::c_char, format: libc::c_int, is_gz: libc::c_int, -) -> *const libc::c_void { +) -> *mut libc::c_void { let es = unsafe { &mut *es }; let rname = osstr_from_cstr(unsafe { CStr::from_ptr(name) }); let rformat = c_format_to_rust(format); let ris_gz = is_gz != 0; match rformat { - Some(fmt) => es.input_open(&rname, fmt, ris_gz) as *const _, - None => ptr::null(), + Some(fmt) => es.input_open(&rname, fmt, ris_gz) as *mut _, + None => ptr::null_mut(), } } -extern "C" fn input_open_primary(es: *mut ExecutionState) -> *const libc::c_void { +#[no_mangle] +pub extern "C" fn input_open_primary(es: *mut ExecutionState) -> *mut libc::c_void { let es = unsafe { &mut *es }; - es.input_open_primary() as *const _ + es.input_open_primary() as *mut _ } -extern "C" fn input_get_size(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::size_t { +#[no_mangle] +pub extern "C" fn input_get_size( + es: *mut ExecutionState, + handle: *mut libc::c_void, +) -> libc::size_t { let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; es.input_get_size(rhandle) } -extern "C" fn input_seek( +#[no_mangle] +pub extern "C" fn input_seek( es: *mut ExecutionState, handle: *mut libc::c_void, offset: libc::ssize_t, @@ -769,7 +776,8 @@ extern "C" fn input_seek( } } -extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +#[no_mangle] +pub extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; @@ -788,7 +796,8 @@ extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) -> } } -extern "C" fn input_ungetc( +#[no_mangle] +pub extern "C" fn input_ungetc( es: *mut ExecutionState, handle: *mut libc::c_void, ch: libc::c_int, @@ -805,7 +814,8 @@ extern "C" fn input_ungetc( } } -extern "C" fn input_read( +#[no_mangle] +pub extern "C" fn input_read( es: *mut ExecutionState, handle: *mut libc::c_void, data: *mut u8, @@ -824,7 +834,8 @@ extern "C" fn input_read( } } -extern "C" fn input_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +#[no_mangle] +pub extern "C" fn input_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let es = unsafe { &mut *es }; if handle.is_null() { diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index 4191658f1..353d4ce1e 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -247,26 +247,26 @@ ttstub_output_close(rust_output_handle_t handle) rust_input_handle_t ttstub_input_open(char const *path, tt_input_format_type format, int is_gz) { - return TGB->input_open(TGB->context, path, format, is_gz); + return input_open(TGB->context, path, format, is_gz); } rust_input_handle_t ttstub_input_open_primary(void) { - return TGB->input_open_primary(TGB->context); + return input_open_primary(TGB->context); } size_t ttstub_input_get_size(rust_input_handle_t handle) { - return TGB->input_get_size(TGB->context, handle); + return input_get_size(TGB->context, handle); } size_t ttstub_input_seek(rust_input_handle_t handle, ssize_t offset, int whence) { int internal_error = 0; - size_t rv = TGB->input_seek(TGB->context, handle, offset, whence, &internal_error); + size_t rv = input_seek(TGB->context, handle, offset, whence, &internal_error); if (internal_error) { // Nonzero indicates a serious internal error. longjmp(jump_buffer, 1); @@ -277,25 +277,25 @@ ttstub_input_seek(rust_input_handle_t handle, ssize_t offset, int whence) ssize_t ttstub_input_read(rust_input_handle_t handle, char *data, size_t len) { - return TGB->input_read(TGB->context, handle, data, len); + return input_read(TGB->context, handle, (uint8_t*) data, len); } int ttstub_input_getc(rust_input_handle_t handle) { - return TGB->input_getc(TGB->context, handle); + return input_getc(TGB->context, handle); } int ttstub_input_ungetc(rust_input_handle_t handle, int ch) { - return TGB->input_ungetc(TGB->context, handle, ch); + return input_ungetc(TGB->context, handle, ch); } int ttstub_input_close(rust_input_handle_t handle) { - if (TGB->input_close(TGB->context, handle)) { + if (input_close(TGB->context, handle)) { // Nonzero return value indicates a serious internal error. longjmp(jump_buffer, 1); } From f028b221f936d5cdd27f6de83d0cfa9d21e13e47 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 19:06:19 +1000 Subject: [PATCH 26/34] Clean up TectonicBridgeApi --- cbindgen.toml | 5 +--- src/engines/bibtex.rs | 4 +-- src/engines/mod.rs | 65 ++++++++++------------------------------ src/engines/tex.rs | 4 +-- src/engines/xdvipdfmx.rs | 4 +-- tectonic/core-bridge.h | 34 --------------------- 6 files changed, 23 insertions(+), 93 deletions(-) diff --git a/cbindgen.toml b/cbindgen.toml index 8397aec56..167a6037c 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -1,6 +1,3 @@ -# Hack to not generate tt_bridge_api_t -after_includes = "typedef struct tt_bridge_api_t tt_bridge_api_t;" - include_guard = "tectonic_core_bindgen_h" autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" include_version = true @@ -11,7 +8,7 @@ language = "C" style = "both" [export] -exclude = [ "DIGEST_LEN", "TectonicBridgeApi" ] +exclude = [ "DIGEST_LEN" ] # Table of name conversions to apply to item names [export.rename] diff --git a/src/engines/bibtex.rs b/src/engines/bibtex.rs index a7895627e..32cc64b8f 100644 --- a/src/engines/bibtex.rs +++ b/src/engines/bibtex.rs @@ -29,8 +29,8 @@ impl BibtexEngine { let caux = CString::new(aux)?; - let /*mut*/ state = ExecutionState::new(io, events, status); - let bridge = TectonicBridgeApi::new(&state); + let mut state = ExecutionState::new(io, events, status); + let bridge = TectonicBridgeApi::new(&mut state); unsafe { match super::bibtex_simple_main(&bridge, caux.as_ptr()) { diff --git a/src/engines/mod.rs b/src/engines/mod.rs index b875e9aa3..479371ed4 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -468,46 +468,33 @@ impl<'a> ExecutionState<'a> { // call back into our code. Keep synchronized with **tectonic/core-bridge.h**. #[repr(C)] -struct TectonicBridgeApi { - context: *const libc::c_void, - diag_warn_begin: *const libc::c_void, - diag_error_begin: *const libc::c_void, - diag_finish: *const libc::c_void, - diag_append: *const libc::c_void, - issue_warning: *const libc::c_void, - issue_error: *const libc::c_void, - get_file_md5: *const libc::c_void, - get_data_md5: *const libc::c_void, - output_open: *const libc::c_void, - output_open_stdout: *const libc::c_void, - output_putc: *const libc::c_void, - output_write: *const libc::c_void, - output_flush: *const libc::c_void, - output_close: *const libc::c_void, - input_open: *const libc::c_void, - input_open_primary: *const libc::c_void, - input_get_size: *const libc::c_void, - input_seek: *const libc::c_void, - input_read: *const libc::c_void, - input_getc: *const libc::c_void, - input_ungetc: *const libc::c_void, - input_close: *const libc::c_void, +pub struct TectonicBridgeApi<'a> { + context: *mut ExecutionState<'a>, } +// This silences the warning that ExecutionState is not FFI-safe. The C side only passes the +// pointer around and doesn't actually look into the struct, so we can ignore this warning. + +#[allow(improper_ctypes)] extern "C" { + fn tt_get_error_message() -> *const libc::c_char; + fn tt_xetex_set_int_variable(var_name: *const libc::c_char, value: libc::c_int) -> libc::c_int; + #[allow(dead_code)] // currently unused fn tt_xetex_set_string_variable( var_name: *const libc::c_char, value: *const libc::c_char, ) -> libc::c_int; + fn tex_simple_main( api: *const TectonicBridgeApi, dump_name: *const libc::c_char, input_file_name: *const libc::c_char, build_date: libc::time_t, ) -> libc::c_int; + fn dvipdfmx_simple_main( api: *const TectonicBridgeApi, dviname: *const libc::c_char, @@ -516,10 +503,12 @@ extern "C" { deterministic_tags: bool, build_date: libc::time_t, ) -> libc::c_int; + fn bibtex_simple_main( api: *const TectonicBridgeApi, aux_file_name: *const libc::c_char, ) -> libc::c_int; + } // Entry points for the C/C++ API functions. @@ -853,32 +842,10 @@ pub extern "C" fn input_close(es: *mut ExecutionState, handle: *mut libc::c_void // All of these entry points are used to populate the bridge API struct: -impl TectonicBridgeApi { - fn new(exec_state: &ExecutionState) -> TectonicBridgeApi { +impl TectonicBridgeApi<'_> { + fn new<'a>(exec_state: &'a mut ExecutionState<'a>) -> TectonicBridgeApi<'a> { TectonicBridgeApi { - context: (exec_state as *const ExecutionState) as *const libc::c_void, - diag_warn_begin: diag_warn_begin as *const libc::c_void, - diag_error_begin: diag_error_begin as *const libc::c_void, - diag_finish: diag_finish as *const libc::c_void, - diag_append: diag_append as *const libc::c_void, - issue_warning: issue_warning as *const libc::c_void, - issue_error: issue_error as *const libc::c_void, - get_file_md5: get_file_md5 as *const libc::c_void, - get_data_md5: get_data_md5 as *const libc::c_void, - output_open: output_open as *const libc::c_void, - output_open_stdout: output_open_stdout as *const libc::c_void, - output_putc: output_putc as *const libc::c_void, - output_write: output_write as *const libc::c_void, - output_flush: output_flush as *const libc::c_void, - output_close: output_close as *const libc::c_void, - input_open: input_open as *const libc::c_void, - input_open_primary: input_open_primary as *const libc::c_void, - input_get_size: input_get_size as *const libc::c_void, - input_seek: input_seek as *const libc::c_void, - input_read: input_read as *const libc::c_void, - input_getc: input_getc as *const libc::c_void, - input_ungetc: input_ungetc as *const libc::c_void, - input_close: input_close as *const libc::c_void, + context: exec_state, } } } diff --git a/src/engines/tex.rs b/src/engines/tex.rs index a3646a9da..f55d896e9 100644 --- a/src/engines/tex.rs +++ b/src/engines/tex.rs @@ -115,8 +115,8 @@ impl TexEngine { 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(&state); + let mut state = ExecutionState::new(io, events, status); + let bridge = TectonicBridgeApi::new(&mut state); // initialize globals let v = if self.halt_on_error { 1 } else { 0 }; diff --git a/src/engines/xdvipdfmx.rs b/src/engines/xdvipdfmx.rs index c141d4aa0..45ab2a686 100644 --- a/src/engines/xdvipdfmx.rs +++ b/src/engines/xdvipdfmx.rs @@ -57,8 +57,8 @@ impl XdvipdfmxEngine { let cdvi = CString::new(dvi)?; let cpdf = CString::new(pdf)?; - let /*mut*/ state = ExecutionState::new(io, events, status); - let bridge = TectonicBridgeApi::new(&state); + let mut state = ExecutionState::new(io, events, status); + let bridge = TectonicBridgeApi::new(&mut state); unsafe { match super::dvipdfmx_simple_main( diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 1b71833d6..6b853d173 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -53,40 +53,6 @@ typedef void *rust_output_handle_t; typedef void *rust_input_handle_t; typedef Diagnostic *diagnostic_t; -/* Bridge API. Keep synchronized with src/engines/mod.rs. */ - -typedef struct tt_bridge_api_t { - void *context; - - diagnostic_t (*diag_warn_begin)(void); - diagnostic_t (*diag_error_begin)(void); - void (*diag_finish)(void *context, diagnostic_t diag); - void (*diag_append)(diagnostic_t diag, char const *text); - - void (*issue_warning)(void *context, char const *text); - void (*issue_error)(void *context, char const *text); - - int (*get_file_md5)(void *context, char const *path, char *digest); - int (*get_data_md5)(void *context, char const *data, size_t len, char *digest); - - rust_output_handle_t (*output_open)(void *context, char const *path, int is_gz); - rust_output_handle_t (*output_open_stdout)(void *context); - int (*output_putc)(void *context, rust_output_handle_t handle, int c); - size_t (*output_write)(void *context, rust_output_handle_t handle, const char *data, size_t len); - int (*output_flush)(void *context, rust_output_handle_t handle); - int (*output_close)(void *context, rust_output_handle_t handle); - - rust_input_handle_t (*input_open)(void *context, char const *path, tt_input_format_type format, int is_gz); - rust_input_handle_t (*input_open_primary)(void *context); - size_t (*input_get_size)(void *context, rust_input_handle_t handle); - size_t (*input_seek)(void *context, rust_input_handle_t handle, ssize_t offset, int whence, int* internal_error); - ssize_t (*input_read)(void *context, rust_input_handle_t handle, char *data, size_t len); - int (*input_getc)(void *context, rust_input_handle_t handle); - int (*input_ungetc)(void *context, rust_input_handle_t handle, int ch); - int (*input_close)(void *context, rust_input_handle_t handle); -} tt_bridge_api_t; - - BEGIN_EXTERN_C /* The internal, C/C++ interface: */ From 8e9c3d06aecbfed8edb2ddbf39bbeab6646b86c1 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 19:07:56 +1000 Subject: [PATCH 27/34] Remove unnecessary dereferences cbindgen translates references to pointers, so this doesn't affect the actual bridge api. --- src/engines/mod.rs | 66 +++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 479371ed4..c756f55ec 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -537,33 +537,29 @@ pub extern "C" fn diag_error_begin() -> *mut Diagnostic { } #[no_mangle] -pub extern "C" fn diag_finish(es: *mut ExecutionState, diag: *mut Diagnostic) { +pub extern "C" fn diag_finish(es: &mut ExecutionState, diag: *mut Diagnostic) { let rdiag = unsafe { Box::from_raw(diag as *mut Diagnostic) }; - let es = unsafe { &mut *es }; es.status .report(rdiag.kind, format_args!("{}", rdiag.message), None); } #[no_mangle] -pub extern "C" fn diag_append(diag: *mut Diagnostic, text: *const libc::c_char) { - let rdiag = unsafe { &mut *diag }; +pub extern "C" fn diag_append(diag: &mut Diagnostic, text: *const libc::c_char) { let rtext = unsafe { CStr::from_ptr(text) }; - rdiag.message.push_str(&rtext.to_string_lossy()); + diag.message.push_str(&rtext.to_string_lossy()); } #[no_mangle] -pub extern "C" fn issue_warning(es: *mut ExecutionState, text: *const libc::c_char) { - let es = unsafe { &mut *es }; +pub extern "C" fn issue_warning(es: &mut ExecutionState, text: *const libc::c_char) { let rtext = unsafe { CStr::from_ptr(text) }; tt_warning!(es.status, "{}", rtext.to_string_lossy()); } #[no_mangle] -pub extern "C" fn issue_error(es: *mut ExecutionState, text: *const libc::c_char) { - let es = unsafe { &mut *es }; +pub extern "C" fn issue_error(es: &mut ExecutionState, text: *const libc::c_char) { let rtext = unsafe { CStr::from_ptr(text) }; tt_error!(es.status, "{}", rtext.to_string_lossy()); @@ -571,11 +567,10 @@ pub extern "C" fn issue_error(es: *mut ExecutionState, text: *const libc::c_char #[no_mangle] pub extern "C" fn get_file_md5( - es: *mut ExecutionState, + es: &mut ExecutionState, path: *const libc::c_char, digest: *mut u8, ) -> libc::c_int { - let es = unsafe { &mut *es }; let rpath = osstr_from_cstr(unsafe { CStr::from_ptr(path) }); let rdest = unsafe { slice::from_raw_parts_mut(digest, 16) }; @@ -588,12 +583,11 @@ pub extern "C" fn get_file_md5( #[no_mangle] pub extern "C" fn get_data_md5( - _es: *mut ExecutionState, + _es: &mut ExecutionState, data: *const u8, len: libc::size_t, digest: *mut u8, ) -> libc::c_int { - //let es = unsafe { &mut *es }; let rdata = unsafe { slice::from_raw_parts(data, len) }; let rdest = unsafe { slice::from_raw_parts_mut(digest, 16) }; @@ -607,11 +601,10 @@ pub extern "C" fn get_data_md5( #[no_mangle] pub extern "C" fn output_open( - es: *mut ExecutionState, + es: &mut ExecutionState, name: *const libc::c_char, is_gz: libc::c_int, ) -> *mut libc::c_void { - let es = unsafe { &mut *es }; let rname = osstr_from_cstr(&unsafe { CStr::from_ptr(name) }); let ris_gz = is_gz != 0; @@ -619,19 +612,16 @@ pub extern "C" fn output_open( } #[no_mangle] -pub extern "C" fn output_open_stdout(es: *mut ExecutionState) -> *mut libc::c_void { - let es = unsafe { &mut *es }; - +pub extern "C" fn output_open_stdout(es: &mut ExecutionState) -> *mut libc::c_void { es.output_open_stdout() as *mut _ } #[no_mangle] pub extern "C" fn output_putc( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, c: libc::c_int, ) -> libc::c_int { - let es = unsafe { &mut *es }; let rhandle = handle as *mut OutputHandle; let rc = c as u8; @@ -644,12 +634,11 @@ pub extern "C" fn output_putc( #[no_mangle] pub extern "C" fn output_write( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, data: *const u8, len: libc::size_t, ) -> libc::size_t { - let es = unsafe { &mut *es }; let rhandle = handle as *mut OutputHandle; let rdata = unsafe { slice::from_raw_parts(data, len) }; @@ -663,8 +652,7 @@ pub extern "C" fn output_write( } #[no_mangle] -pub extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let es = unsafe { &mut *es }; +pub extern "C" fn output_flush(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let rhandle = handle as *mut OutputHandle; if es.output_flush(rhandle) { @@ -675,9 +663,7 @@ pub extern "C" fn output_flush(es: *mut ExecutionState, handle: *mut libc::c_voi } #[no_mangle] -pub extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let es = unsafe { &mut *es }; - +pub extern "C" fn output_close(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { if handle.is_null() { return 0; // This is/was the behavior of close_file() in C. } @@ -693,12 +679,11 @@ pub extern "C" fn output_close(es: *mut ExecutionState, handle: *mut libc::c_voi #[no_mangle] pub extern "C" fn input_open( - es: *mut ExecutionState, + es: &mut ExecutionState, name: *const libc::c_char, format: libc::c_int, is_gz: libc::c_int, ) -> *mut libc::c_void { - let es = unsafe { &mut *es }; let rname = osstr_from_cstr(unsafe { CStr::from_ptr(name) }); let rformat = c_format_to_rust(format); let ris_gz = is_gz != 0; @@ -710,18 +695,15 @@ pub extern "C" fn input_open( } #[no_mangle] -pub extern "C" fn input_open_primary(es: *mut ExecutionState) -> *mut libc::c_void { - let es = unsafe { &mut *es }; - +pub extern "C" fn input_open_primary(es: &mut ExecutionState) -> *mut libc::c_void { es.input_open_primary() as *mut _ } #[no_mangle] pub extern "C" fn input_get_size( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, ) -> libc::size_t { - let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; es.input_get_size(rhandle) @@ -729,13 +711,12 @@ pub extern "C" fn input_get_size( #[no_mangle] pub extern "C" fn input_seek( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, offset: libc::ssize_t, whence: libc::c_int, internal_error: *mut libc::c_int, ) -> libc::size_t { - let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; let rwhence = match whence { @@ -766,8 +747,7 @@ pub extern "C" fn input_seek( } #[no_mangle] -pub extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let es = unsafe { &mut *es }; +pub extern "C" fn input_getc(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { let rhandle = handle as *mut InputHandle; // If we couldn't fill the whole (1-byte) buffer, that's boring old EOF. @@ -787,11 +767,10 @@ pub extern "C" fn input_getc(es: *mut ExecutionState, handle: *mut libc::c_void) #[no_mangle] pub extern "C" fn input_ungetc( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, ch: libc::c_int, ) -> libc::c_int { - let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; match es.input_ungetc(rhandle, ch as u8) { @@ -805,12 +784,11 @@ pub extern "C" fn input_ungetc( #[no_mangle] pub extern "C" fn input_read( - es: *mut ExecutionState, + es: &mut ExecutionState, handle: *mut libc::c_void, data: *mut u8, len: libc::size_t, ) -> libc::ssize_t { - let es = unsafe { &mut *es }; let rhandle = handle as *mut InputHandle; let rdata = unsafe { slice::from_raw_parts_mut(data, len) }; @@ -824,9 +802,7 @@ pub extern "C" fn input_read( } #[no_mangle] -pub extern "C" fn input_close(es: *mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let es = unsafe { &mut *es }; - +pub extern "C" fn input_close(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { if handle.is_null() { return 0; // This is/was the behavior of close_file() in C. } From 45b7a7743a7e67130fd5e40f0077204f3e154b16 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 19:17:00 +1000 Subject: [PATCH 28/34] Change output function signatures to avoid casts --- src/engines/mod.rs | 30 ++++++++++++------------------ tectonic/core-bridge.h | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index c756f55ec..f3ce1cf74 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -604,28 +604,27 @@ pub extern "C" fn output_open( es: &mut ExecutionState, name: *const libc::c_char, is_gz: libc::c_int, -) -> *mut libc::c_void { +) -> *mut OutputHandle { let rname = osstr_from_cstr(&unsafe { CStr::from_ptr(name) }); let ris_gz = is_gz != 0; - es.output_open(&rname, ris_gz) as *mut _ + es.output_open(&rname, ris_gz) } #[no_mangle] -pub extern "C" fn output_open_stdout(es: &mut ExecutionState) -> *mut libc::c_void { - es.output_open_stdout() as *mut _ +pub extern "C" fn output_open_stdout(es: &mut ExecutionState) -> *mut OutputHandle { + es.output_open_stdout() } #[no_mangle] pub extern "C" fn output_putc( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut OutputHandle, c: libc::c_int, ) -> libc::c_int { - let rhandle = handle as *mut OutputHandle; let rc = c as u8; - if es.output_write(rhandle, &[rc]) { + if es.output_write(handle, &[rc]) { libc::EOF } else { c @@ -635,16 +634,15 @@ pub extern "C" fn output_putc( #[no_mangle] pub extern "C" fn output_write( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut OutputHandle, data: *const u8, len: libc::size_t, ) -> libc::size_t { - let rhandle = handle as *mut OutputHandle; let rdata = unsafe { slice::from_raw_parts(data, len) }; // NOTE: we use f.write_all() so partial writes are not gonna be a thing. - if es.output_write(rhandle, rdata) { + if es.output_write(handle, rdata) { 0 } else { len @@ -652,10 +650,8 @@ pub extern "C" fn output_write( } #[no_mangle] -pub extern "C" fn output_flush(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let rhandle = handle as *mut OutputHandle; - - if es.output_flush(rhandle) { +pub extern "C" fn output_flush(es: &mut ExecutionState, handle: *mut OutputHandle) -> libc::c_int { + if es.output_flush(handle) { 1 } else { 0 @@ -663,14 +659,12 @@ pub extern "C" fn output_flush(es: &mut ExecutionState, handle: *mut libc::c_voi } #[no_mangle] -pub extern "C" fn output_close(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +pub extern "C" fn output_close(es: &mut ExecutionState, handle: *mut OutputHandle) -> libc::c_int { if handle.is_null() { return 0; // This is/was the behavior of close_file() in C. } - let rhandle = handle as *mut OutputHandle; - - if es.output_close(rhandle) { + if es.output_close(handle) { 1 } else { 0 diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 6b853d173..46cf6a025 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -49,7 +49,7 @@ typedef enum TTIF_TECTONIC_PRIMARY = 59, /* quasi-hack to get the primary input */ } tt_input_format_type; -typedef void *rust_output_handle_t; +typedef OutputHandle *rust_output_handle_t; typedef void *rust_input_handle_t; typedef Diagnostic *diagnostic_t; From 5fe8f8e0dc996c8a7a2304da3d2cdb94c0a42a55 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 19:20:39 +1000 Subject: [PATCH 29/34] Change input function signatures to avoid ptr cast --- src/engines/mod.rs | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index f3ce1cf74..5a292a213 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -677,42 +677,38 @@ pub extern "C" fn input_open( name: *const libc::c_char, format: libc::c_int, is_gz: libc::c_int, -) -> *mut libc::c_void { +) -> *mut InputHandle { let rname = osstr_from_cstr(unsafe { CStr::from_ptr(name) }); let rformat = c_format_to_rust(format); let ris_gz = is_gz != 0; match rformat { - Some(fmt) => es.input_open(&rname, fmt, ris_gz) as *mut _, + Some(fmt) => es.input_open(&rname, fmt, ris_gz), None => ptr::null_mut(), } } #[no_mangle] -pub extern "C" fn input_open_primary(es: &mut ExecutionState) -> *mut libc::c_void { - es.input_open_primary() as *mut _ +pub extern "C" fn input_open_primary(es: &mut ExecutionState) -> *mut InputHandle { + es.input_open_primary() } #[no_mangle] pub extern "C" fn input_get_size( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut InputHandle, ) -> libc::size_t { - let rhandle = handle as *mut InputHandle; - - es.input_get_size(rhandle) + es.input_get_size(handle) } #[no_mangle] pub extern "C" fn input_seek( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut InputHandle, offset: libc::ssize_t, whence: libc::c_int, internal_error: *mut libc::c_int, ) -> libc::size_t { - let rhandle = handle as *mut InputHandle; - let rwhence = match whence { libc::SEEK_SET => SeekFrom::Start(offset as u64), libc::SEEK_CUR => SeekFrom::Current(offset as i64), @@ -730,7 +726,7 @@ pub extern "C" fn input_seek( } }; - match es.input_seek(rhandle, rwhence) { + match es.input_seek(handle, rwhence) { Ok(pos) => pos as libc::size_t, Err(e) => { // TODO: Handle the error better. Report the error properly to the caller? @@ -741,13 +737,11 @@ pub extern "C" fn input_seek( } #[no_mangle] -pub extern "C" fn input_getc(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { - let rhandle = handle as *mut InputHandle; - +pub extern "C" fn input_getc(es: &mut ExecutionState, handle: *mut InputHandle) -> libc::c_int { // If we couldn't fill the whole (1-byte) buffer, that's boring old EOF. // No need to complain. Fun match statement here. - match es.input_getc(rhandle) { + match es.input_getc(handle) { Ok(b) => libc::c_int::from(b), Err(Error(ErrorKind::Io(ref ioe), _)) if ioe.kind() == io::ErrorKind::UnexpectedEof => { libc::EOF @@ -762,12 +756,10 @@ pub extern "C" fn input_getc(es: &mut ExecutionState, handle: *mut libc::c_void) #[no_mangle] pub extern "C" fn input_ungetc( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut InputHandle, ch: libc::c_int, ) -> libc::c_int { - let rhandle = handle as *mut InputHandle; - - match es.input_ungetc(rhandle, ch as u8) { + match es.input_ungetc(handle, ch as u8) { Ok(_) => 0, Err(e) => { tt_warning!(es.status, "ungetc() failed"; e); @@ -779,14 +771,13 @@ pub extern "C" fn input_ungetc( #[no_mangle] pub extern "C" fn input_read( es: &mut ExecutionState, - handle: *mut libc::c_void, + handle: *mut InputHandle, data: *mut u8, len: libc::size_t, ) -> libc::ssize_t { - let rhandle = handle as *mut InputHandle; let rdata = unsafe { slice::from_raw_parts_mut(data, len) }; - match es.input_read(rhandle, rdata) { + match es.input_read(handle, rdata) { Ok(_) => len as isize, Err(e) => { tt_warning!(es.status, "{}-byte read failed", len; e); @@ -796,14 +787,12 @@ pub extern "C" fn input_read( } #[no_mangle] -pub extern "C" fn input_close(es: &mut ExecutionState, handle: *mut libc::c_void) -> libc::c_int { +pub extern "C" fn input_close(es: &mut ExecutionState, handle: *mut InputHandle) -> libc::c_int { if handle.is_null() { return 0; // This is/was the behavior of close_file() in C. } - let rhandle = handle as *mut InputHandle; - - if es.input_close(rhandle) { + if es.input_close(handle) { 1 } else { 0 From 090dfa04c736d28abbd5f4b049fc0ac565566c97 Mon Sep 17 00:00:00 2001 From: ralismark Date: Sun, 20 Sep 2020 19:30:06 +1000 Subject: [PATCH 30/34] Fix input handle type issues --- tectonic/core-bridge.h | 2 +- tectonic/dpx-cidtype0.c | 2 +- tectonic/dpx-epdf.c | 2 +- tectonic/dpx-epdf.h | 2 +- tectonic/dpx-otl_conf.c | 2 +- tectonic/dpx-pdfdoc.c | 2 +- tectonic/dpx-spc_dvips.c | 2 +- tectonic/dpx-spc_pdfm.c | 2 +- tectonic/dpx-subfont.c | 8 ++++---- tectonic/dpx-tfm.c | 2 +- tectonic/dpx-truetype.c | 4 ++-- tectonic/dpx-tt_cmap.c | 2 +- tectonic/dpx-type1c.c | 4 ++-- 13 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 46cf6a025..0f50f7d31 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -50,7 +50,7 @@ typedef enum } tt_input_format_type; typedef OutputHandle *rust_output_handle_t; -typedef void *rust_input_handle_t; +typedef InputHandle *rust_input_handle_t; typedef Diagnostic *diagnostic_t; BEGIN_EXTERN_C diff --git a/tectonic/dpx-cidtype0.c b/tectonic/dpx-cidtype0.c index 61326acbe..28adfd09e 100644 --- a/tectonic/dpx-cidtype0.c +++ b/tectonic/dpx-cidtype0.c @@ -1321,7 +1321,7 @@ t1_load_UnicodeCMap (const char *font_name, { int cmap_id = -1; cff_font *cffont; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; if (!font_name) return -1; diff --git a/tectonic/dpx-epdf.c b/tectonic/dpx-epdf.c index beb581789..ec102779e 100644 --- a/tectonic/dpx-epdf.c +++ b/tectonic/dpx-epdf.c @@ -578,7 +578,7 @@ static struct operator int -pdf_copy_clip (FILE *image_file, int pageNo, double x_user, double y_user) +pdf_copy_clip (rust_input_handle_t image_file, int pageNo, double x_user, double y_user) { pdf_obj *page_tree, *contents; int depth = 0, top = -1; diff --git a/tectonic/dpx-epdf.h b/tectonic/dpx-epdf.h index 32b443c2d..3e128af63 100644 --- a/tectonic/dpx-epdf.h +++ b/tectonic/dpx-epdf.h @@ -37,7 +37,7 @@ #define pdfbox_trim 4 #define pdfbox_art 5 -int pdf_copy_clip (FILE *image_file, int page_index, +int pdf_copy_clip (rust_input_handle_t image_file, int page_index, double x_user, double y_user); int pdf_include_page (pdf_ximage * ximage, rust_input_handle_t handle, diff --git a/tectonic/dpx-otl_conf.c b/tectonic/dpx-otl_conf.c index b3d8b0c57..8ad4d04bd 100644 --- a/tectonic/dpx-otl_conf.c +++ b/tectonic/dpx-otl_conf.c @@ -457,7 +457,7 @@ otl_read_conf (const char *conf_name) { pdf_obj *rule; pdf_obj *gclass; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; char *filename, *wbuf, *p, *endptr; const char *pp; int size, len; diff --git a/tectonic/dpx-pdfdoc.c b/tectonic/dpx-pdfdoc.c index 5a88bd742..0ce6832f1 100644 --- a/tectonic/dpx-pdfdoc.c +++ b/tectonic/dpx-pdfdoc.c @@ -76,7 +76,7 @@ read_thumbnail (const char *thumb_filename) { pdf_obj *image_ref; int xobj_id; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; load_options options = {1, 0, NULL}; handle = ttstub_input_open(thumb_filename, TTIF_PICT, 0); diff --git a/tectonic/dpx-spc_dvips.c b/tectonic/dpx-spc_dvips.c index ee97d37fc..5f5af717f 100644 --- a/tectonic/dpx-spc_dvips.c +++ b/tectonic/dpx-spc_dvips.c @@ -60,7 +60,7 @@ static int spc_handler_ps_header (struct spc_env *spe, struct spc_arg *args) { char *pro; - rust_input_handle_t *ps_header; + rust_input_handle_t ps_header; skip_white(&args->curptr, args->endptr); if (args->curptr + 1 >= args->endptr || args->curptr[0] != '=') { diff --git a/tectonic/dpx-spc_pdfm.c b/tectonic/dpx-spc_pdfm.c index 3ebff2b9d..a6df8e6ff 100644 --- a/tectonic/dpx-spc_pdfm.c +++ b/tectonic/dpx-spc_pdfm.c @@ -1349,7 +1349,7 @@ spc_handler_pdfm_stream_with_type (struct spc_env *spe, struct spc_arg *args, in ssize_t nb_read; char *ident, *instring, *fullname; pdf_obj *tmp; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; skip_white(&args->curptr, args->endptr); diff --git a/tectonic/dpx-subfont.c b/tectonic/dpx-subfont.c index c167f75cc..913189b56 100644 --- a/tectonic/dpx-subfont.c +++ b/tectonic/dpx-subfont.c @@ -115,7 +115,7 @@ static char line_buf[LINE_BUF_SIZE]; * for line-continuation. */ static char * -readline (char *buf, int buf_len, rust_input_handle_t *handle) +readline (char *buf, int buf_len, rust_input_handle_t handle) { char *r, *q, *p = buf; int n = 0, c = 0; @@ -239,7 +239,7 @@ read_sfd_record (struct sfd_rec_ *rec, const char *lbuf) /* Scan for subfont IDs */ static int -scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t *handle) +scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) { char *id; char *q, *p; @@ -308,7 +308,7 @@ find_sfd_file (const char *sfd_name) if (id < 0) { struct sfd_file_ *sfd = NULL; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; if (num_sfd_files >= max_sfd_files) { max_sfd_files += 8; @@ -362,7 +362,7 @@ sfd_load_record (const char *sfd_name, const char *subfont_id) { int rec_id = -1; struct sfd_file_ *sfd; - rust_input_handle_t *handle; + rust_input_handle_t handle; int sfd_id, i, error = 0; char *p, *q; diff --git a/tectonic/dpx-tfm.c b/tectonic/dpx-tfm.c index 29cec97eb..cbf7e9b07 100644 --- a/tectonic/dpx-tfm.c +++ b/tectonic/dpx-tfm.c @@ -927,7 +927,7 @@ tfm_get_design_size (int font_id) bool tfm_exists (const char *tfm_name) { - rust_input_handle_t *handle; + rust_input_handle_t handle; handle = ttstub_input_open(tfm_name, TTIF_OFM, 0); if (handle) { diff --git a/tectonic/dpx-truetype.c b/tectonic/dpx-truetype.c index b807d4b6c..deb091145 100644 --- a/tectonic/dpx-truetype.c +++ b/tectonic/dpx-truetype.c @@ -59,7 +59,7 @@ pdf_font_open_truetype (pdf_font *font) pdf_obj *fontdict, *descriptor; sfnt *sfont; int embedding = 1; /* Must be embedded. */ - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; int length, error = 0; assert( font ); @@ -875,7 +875,7 @@ pdf_font_load_truetype (pdf_font *font) int index = pdf_font_get_index(font); char **enc_vec; pdf_obj *fontfile; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; sfnt *sfont; int i, error = 0; diff --git a/tectonic/dpx-tt_cmap.c b/tectonic/dpx-tt_cmap.c index 8112cfd12..8dfce4cb9 100644 --- a/tectonic/dpx-tt_cmap.c +++ b/tectonic/dpx-tt_cmap.c @@ -1361,7 +1361,7 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon sfnt *sfont; ULONG offset = 0; char *base_name = NULL, *cmap_name = NULL; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; otl_gsub *gsub_vert = NULL, *gsub_list = NULL; tt_cmap *ttcmap; CIDSysInfo csi = {NULL, NULL, 0}; diff --git a/tectonic/dpx-type1c.c b/tectonic/dpx-type1c.c index 774d8c667..dacb38d1d 100644 --- a/tectonic/dpx-type1c.c +++ b/tectonic/dpx-type1c.c @@ -64,7 +64,7 @@ pdf_font_open_type1c (pdf_font *font) { char *fontname; char *ident; - rust_input_handle_t *handle = NULL; + rust_input_handle_t handle = NULL; sfnt *sfont; cff_font *cffont; pdf_obj *descriptor, *tmp; @@ -230,7 +230,7 @@ pdf_font_load_type1c (pdf_font *font) pdf_obj *pdfcharset; /* Actually string object */ char *usedchars; char *fontname, *uniqueTag, *ident, *fullname; - rust_input_handle_t *handle; + rust_input_handle_t handle; int encoding_id; pdf_obj *fontfile, *stream_dict; char **enc_vec; From 8f95ab9529ec1f019192ab664aef5a06270a0ed8 Mon Sep 17 00:00:00 2001 From: ralismark Date: Mon, 21 Sep 2020 10:38:40 +1000 Subject: [PATCH 31/34] Clean up things --- src/engines/mod.rs | 24 +++++++++--------------- tectonic/core-bridge.c | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 5a292a213..82e766711 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -462,10 +462,9 @@ impl<'a> ExecutionState<'a> { } } -// Now, here' the actual C API. There are two parts to this: the functions in -// the backing C/C++ code that *we* call, and the API bridge -- a struct of -// function pointers that we pass to the C/C++ entry points so that they can -// call back into our code. Keep synchronized with **tectonic/core-bridge.h**. +// The bridge only contains the ExecutionState now. It used to hold pointers to the below bridge +// api functions (which would allow the C code to call back into our code), but those are now +// exported using cbindgen. #[repr(C)] pub struct TectonicBridgeApi<'a> { @@ -489,14 +488,14 @@ extern "C" { ) -> libc::c_int; fn tex_simple_main( - api: *const TectonicBridgeApi, + api: &TectonicBridgeApi, dump_name: *const libc::c_char, input_file_name: *const libc::c_char, build_date: libc::time_t, ) -> libc::c_int; fn dvipdfmx_simple_main( - api: *const TectonicBridgeApi, + api: &TectonicBridgeApi, dviname: *const libc::c_char, pdfname: *const libc::c_char, enable_compression: bool, @@ -505,7 +504,7 @@ extern "C" { ) -> libc::c_int; fn bibtex_simple_main( - api: *const TectonicBridgeApi, + api: &TectonicBridgeApi, aux_file_name: *const libc::c_char, ) -> libc::c_int; @@ -582,12 +581,7 @@ pub extern "C" fn get_file_md5( } #[no_mangle] -pub extern "C" fn get_data_md5( - _es: &mut ExecutionState, - data: *const u8, - len: libc::size_t, - digest: *mut u8, -) -> libc::c_int { +pub extern "C" fn get_data_md5(data: *const u8, len: libc::size_t, digest: *mut u8) -> libc::c_int { let rdata = unsafe { slice::from_raw_parts(data, len) }; let rdest = unsafe { slice::from_raw_parts_mut(digest, 16) }; @@ -799,8 +793,6 @@ pub extern "C" fn input_close(es: &mut ExecutionState, handle: *mut InputHandle) } } -// All of these entry points are used to populate the bridge API struct: - impl TectonicBridgeApi<'_> { fn new<'a>(exec_state: &'a mut ExecutionState<'a>) -> TectonicBridgeApi<'a> { TectonicBridgeApi { @@ -812,6 +804,8 @@ impl TectonicBridgeApi<'_> { // Finally, some support -- several of the C API functions pass arguments that // are "file format" enumerations. This code bridges the two. See the // `tt_input_format_type` enum in . +// +// TODO use cbindgen to export this so we don't need to synchronise definitions #[derive(Clone, Copy, Debug)] enum FileFormat { diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index 353d4ce1e..992506754 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -205,7 +205,7 @@ int ttstub_get_data_md5(char const *data, size_t len, char *digest) { // TODO change uses of ttstub_get_data_md5 to pass uint8_t* - return get_data_md5(TGB->context, (uint8_t const*) data, len, (uint8_t*) digest); + return get_data_md5((uint8_t const*) data, len, (uint8_t*) digest); } rust_output_handle_t From 3baa43dbfb44e43af74843570c774ebdae75d794 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2020 07:16:28 +0000 Subject: [PATCH 32/34] build(deps): bump structopt from 0.3.17 to 0.3.18 Bumps [structopt](https://github.com/TeXitoi/structopt) from 0.3.17 to 0.3.18. - [Release notes](https://github.com/TeXitoi/structopt/releases) - [Changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md) - [Commits](https://github.com/TeXitoi/structopt/compare/v0.3.17...v0.3.18) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d213db5ae..7dfa5b305 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1582,9 +1582,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +checksum = "a33f6461027d7f08a13715659b2948e1602c31a3756aeae9378bfe7518c72e82" dependencies = [ "clap", "lazy_static", @@ -1593,9 +1593,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +checksum = "c92e775028122a4b3dd55d58f14fc5120289c69bee99df1d117ae30f84b225c9" dependencies = [ "heck", "proc-macro-error", From 47dd4bf664465db1d0bb473c7e713ddf9a39d673 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 1 Oct 2020 18:57:52 -0400 Subject: [PATCH 33/34] Place the cbindgen header in $OUT_DIR rather than the source tree --- .gitignore | 5 +---- build.rs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 56c424cbb..cb81b5d43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,7 @@ -/tectonic/core-bindgen.h /cross +/docs/book/* /target /tests/plain.fmt /tests/00*00-latex-*.fmt /tests/00*00-plain-*.fmt /tests/xenia/paper.pdf - -# ignore mdbook compiled output (HTML) -docs/book/* diff --git a/build.rs b/build.rs index 8298e9991..706c8ac68 100644 --- a/build.rs +++ b/build.rs @@ -1,19 +1,16 @@ // build.rs -- build helper script for Tectonic. -// Copyright 2016-2019 the Tectonic Project +// Copyright 2016-2020 the Tectonic Project // Licensed under the MIT License. /// The Tectonic build script. Not only do we have internal C/C++ code, we /// also depend on several external C/C++ libraries, so there's a lot to do /// here. It would be great to streamline things. -/// -/// TODO: this surely needs to become much smarter and more flexible. +use std::{ + env, + path::{Path, PathBuf}, +}; use tectonic_cfg_support::*; -extern crate cbindgen; - -use std::env; -use std::path::{Path, PathBuf}; - #[cfg(not(target_os = "macos"))] const PKGCONFIG_LIBS: &str = "fontconfig harfbuzz >= 1.4 harfbuzz-icu icu-uc freetype2 graphite2 libpng zlib"; @@ -186,15 +183,16 @@ fn main() { let target = env::var("TARGET").unwrap(); let rustflags = env::var("RUSTFLAGS").unwrap_or_default(); - // TODO make this be always run - // Generate C bindings - let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - cbindgen::generate(&crate_dir) + // Generate bindings for the C/C++ code to interface with backend Rust code. + // As a heuristic we trigger rebuilds on changes to src/engines/mod.rs since + // most of `core-bindgen.h` comes from this file. + let mut cbindgen_header_path: PathBuf = env::var("OUT_DIR").unwrap().into(); + cbindgen_header_path.push("core-bindgen.h"); + + cbindgen::generate(env::var("CARGO_MANIFEST_DIR").unwrap()) .unwrap() - .write_to_file("tectonic/core-bindgen.h"); + .write_to_file(&cbindgen_header_path); - // Most of `core-bindgen.h` comes from this file, so this should catch most of the changes. - // TODO better detect when cbindgen needs to be run, or we need to rebuild. println!("cargo:rerun-if-changed=src/engines/mod.rs"); // Re-export $TARGET during the build so that our executable tests know @@ -378,6 +376,7 @@ fn main() { .define("HAVE_ZLIB", "1") .define("HAVE_ZLIB_COMPRESS2", "1") .define("ZLIB_CONST", "1") + .include(env::var("OUT_DIR").unwrap()) .include("."); let cppflags = [ @@ -426,6 +425,7 @@ fn main() { .file("tectonic/xetex-XeTeXFontMgr.cpp") .file("tectonic/xetex-XeTeXLayoutInterface.cpp") .file("tectonic/xetex-XeTeXOTMath.cpp") + .include(env::var("OUT_DIR").unwrap()) .include("."); dep_state.foreach_include_path(|p| { From 6b29ab69b202d0d4dcc71b85dc9bbfbc5b00bf1d Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 1 Oct 2020 18:58:51 -0400 Subject: [PATCH 34/34] .config/cranko/config.toml: define Cranko upstream URLs --- .config/cranko/config.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .config/cranko/config.toml diff --git a/.config/cranko/config.toml b/.config/cranko/config.toml new file mode 100644 index 000000000..b1e133d54 --- /dev/null +++ b/.config/cranko/config.toml @@ -0,0 +1,5 @@ +[repo] +upstream_urls = [ + 'git@github.com:tectonic-typesetting/tectonic.git', + 'https://github.com/tectonic-typesetting/tectonic.git', +]