1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#![deny(missing_docs)]
use kpathsea_sys::*;
use std::env::current_exe;
use std::ffi::{CStr,CString};
pub struct Kpaths(kpathsea);
impl Kpaths {
pub fn new() -> Self {
let kpse = unsafe { kpathsea_new() };
let current_exe_path = current_exe().expect("we need the current executable's path, for kpathsea's bookkeeping");
let mut current_exe_str = current_exe_path.to_string_lossy();
let program_name = CString::new(current_exe_str.to_mut().as_str()).unwrap();
unsafe { kpathsea_set_program_name(kpse, program_name.as_ptr(), program_name.as_ptr()); }
Kpaths(kpse)
}
fn guess_format_from_filename(&self, filename: &str) -> kpse_file_format_type {
for format_type in 0..kpse_file_format_type_kpse_last_format {
let format_info = unsafe { (*self.0).format_info[format_type as usize] };
if format_info.type_.is_null() {
unsafe {
kpathsea_init_format(self.0, format_type as kpse_file_format_type);
}
}
let mut suffix_ptr = format_info.suffix;
while !suffix_ptr.is_null() && !unsafe {*suffix_ptr}.is_null() {
let suffix_cstr = unsafe { CStr::from_ptr(*suffix_ptr) };
let suffix = suffix_cstr.to_str().unwrap();
if filename.get(filename.len()-suffix.len()..) == Some(suffix) {
return format_type as kpse_file_format_type;
}
suffix_ptr = unsafe { suffix_ptr.offset(1) };
}
let mut alt_suffix_ptr = format_info.alt_suffix;
while !alt_suffix_ptr.is_null() && !unsafe {*alt_suffix_ptr}.is_null() {
let alt_suffix_cstr = unsafe { CStr::from_ptr(*alt_suffix_ptr) };
let alt_suffix = alt_suffix_cstr.to_str().unwrap();
if filename.get(filename.len()-alt_suffix.len()..) == Some(alt_suffix) {
return format_type as kpse_file_format_type;
}
alt_suffix_ptr = unsafe { alt_suffix_ptr.offset(1) };
}
}
kpse_file_format_type_kpse_tex_format
}
pub fn find_file(&self, name: &str) -> Option<String> {
let c_name = CString::new(name).unwrap();
let file_format_type = self.guess_format_from_filename(name);
let c_filename_buf = unsafe { kpathsea_find_file(
self.0,
c_name.as_ptr(),
file_format_type,
0
)};
if !c_filename_buf.is_null() {
let c_filepath: &CStr = unsafe { CStr::from_ptr(c_filename_buf) };
let filepath = c_filepath.to_str().unwrap().to_owned();
if filepath.is_empty() {
None
} else {
Some(filepath)
}
} else {
None
}
}
}