@@ -54,6 +54,14 @@ use tectonic_io_base::{
54
54
} ;
55
55
use tectonic_status_base:: { tt_error, tt_warning, MessageKind , StatusBackend } ;
56
56
57
+ /// The ID of an InputHandle, used for Rust core state
58
+ #[ derive( Copy , Clone , PartialEq ) ]
59
+ pub struct InputId ( * mut InputHandle ) ;
60
+
61
+ /// The ID of an OutputHandle, used for Rust core state
62
+ #[ derive( Copy , Clone , PartialEq ) ]
63
+ pub struct OutputId ( * mut OutputHandle ) ;
64
+
57
65
/// Possible failures for "system request" calls to the driver.
58
66
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
59
67
pub enum SystemRequestError {
@@ -473,16 +481,29 @@ impl<'a> CoreBridgeState<'a> {
473
481
error_occurred
474
482
}
475
483
476
- fn output_open ( & mut self , name : & str , is_gz : bool ) -> * mut OutputHandle {
484
+ fn output_to_id ( & self , output : * mut OutputHandle ) -> OutputId {
485
+ OutputId ( output)
486
+ }
487
+
488
+ /// Get a mutable reference to an [`OutputHandle`] associated with an [`OutputId`]
489
+ pub fn get_output ( & mut self , id : OutputId ) -> & mut OutputHandle {
490
+ self . output_handles
491
+ . iter_mut ( )
492
+ . find ( |o| ptr:: addr_eq ( & * * * o, id. 0 ) )
493
+ . unwrap ( )
494
+ }
495
+
496
+ /// Open a new output, provided the output name and whether it is gzipped.
497
+ pub fn output_open ( & mut self , name : & str , is_gz : bool ) -> Option < OutputId > {
477
498
let io = self . hooks . io ( ) ;
478
499
let name = normalize_tex_path ( name) ;
479
500
480
501
let mut oh = match io. output_open_name ( & name) {
481
502
OpenResult :: Ok ( oh) => oh,
482
- OpenResult :: NotAvailable => return ptr :: null_mut ( ) ,
503
+ OpenResult :: NotAvailable => return None ,
483
504
OpenResult :: Err ( e) => {
484
505
tt_warning ! ( self . status, "open of output {} failed" , name; e) ;
485
- return ptr :: null_mut ( ) ;
506
+ return None ;
486
507
}
487
508
} ;
488
509
@@ -495,23 +516,24 @@ impl<'a> CoreBridgeState<'a> {
495
516
}
496
517
497
518
self . output_handles . push ( Box :: new ( oh) ) ;
498
- & mut * * self . output_handles . last_mut ( ) . unwrap ( )
519
+ Some ( OutputId ( & mut * * self . output_handles . last_mut ( ) . unwrap ( ) ) )
499
520
}
500
521
501
- fn output_open_stdout ( & mut self ) -> * mut OutputHandle {
522
+ /// Open a new stdout output.
523
+ pub fn output_open_stdout ( & mut self ) -> Option < OutputId > {
502
524
let io = self . hooks . io ( ) ;
503
525
504
526
let oh = match io. output_open_stdout ( ) {
505
527
OpenResult :: Ok ( oh) => oh,
506
- OpenResult :: NotAvailable => return ptr :: null_mut ( ) ,
528
+ OpenResult :: NotAvailable => return None ,
507
529
OpenResult :: Err ( e) => {
508
530
tt_warning ! ( self . status, "open of stdout failed" ; e) ;
509
- return ptr :: null_mut ( ) ;
531
+ return None ;
510
532
}
511
533
} ;
512
534
513
535
self . output_handles . push ( Box :: new ( oh) ) ;
514
- & mut * * self . output_handles . last_mut ( ) . unwrap ( )
536
+ Some ( OutputId ( & mut * * self . output_handles . last_mut ( ) . unwrap ( ) ) )
515
537
}
516
538
517
539
fn output_write ( & mut self , handle : * mut OutputHandle , buf : & [ u8 ] ) -> bool {
@@ -540,45 +562,57 @@ impl<'a> CoreBridgeState<'a> {
540
562
}
541
563
}
542
564
543
- fn output_close ( & mut self , handle : * mut OutputHandle ) -> bool {
544
- let len = self . output_handles . len ( ) ;
565
+ /// Close the provided output, flushing it and performing any necessary handling.
566
+ pub fn output_close ( & mut self , id : OutputId ) -> bool {
545
567
let mut rv = false ;
546
568
547
- for i in 0 ..len {
548
- let p: * const OutputHandle = & * self . output_handles [ i] ;
549
-
550
- if p == handle {
551
- let mut oh = self . output_handles . swap_remove ( i) ;
552
- if let Err ( e) = oh. flush ( ) {
553
- tt_warning ! ( self . status, "error when closing output {}" , oh. name( ) ; e. into( ) ) ;
554
- rv = true ;
555
- }
556
- let ( name, digest) = oh. into_name_digest ( ) ;
557
- self . hooks . event_output_closed ( name, digest) ;
558
- break ;
569
+ let pos = self
570
+ . output_handles
571
+ . iter ( )
572
+ . position ( |o| ptr:: addr_eq ( & * * o, id. 0 ) ) ;
573
+ if let Some ( pos) = pos {
574
+ let mut oh = self . output_handles . swap_remove ( pos) ;
575
+ if let Err ( e) = oh. flush ( ) {
576
+ tt_warning ! ( self . status, "error when closing output {}" , oh. name( ) ; e. into( ) ) ;
577
+ rv = true ;
559
578
}
579
+ let ( name, digest) = oh. into_name_digest ( ) ;
580
+ self . hooks . event_output_closed ( name, digest) ;
560
581
}
561
582
562
583
rv
563
584
}
564
585
565
- fn input_open ( & mut self , name : & str , format : FileFormat , is_gz : bool ) -> * mut InputHandle {
586
+ fn input_to_id ( & self , input : * mut InputHandle ) -> InputId {
587
+ InputId ( input)
588
+ }
589
+
590
+ /// Get a mutable reference to an [`InputHandle`] associated with an [`InputId`]
591
+ pub fn get_input ( & mut self , input : InputId ) -> & mut InputHandle {
592
+ self . input_handles
593
+ . iter_mut ( )
594
+ . find ( |i| ptr:: addr_eq ( & * * * i, input. 0 ) )
595
+ . unwrap ( )
596
+ }
597
+
598
+ /// Open a new input, provided the input name, the file format, and whether it is gzipped.
599
+ pub fn input_open ( & mut self , name : & str , format : FileFormat , is_gz : bool ) -> Option < InputId > {
566
600
let name = normalize_tex_path ( name) ;
567
601
568
602
let ( ih, path) = match self . input_open_name_format_gz ( & name, format, is_gz) {
569
603
OpenResult :: Ok ( tup) => tup,
570
604
OpenResult :: NotAvailable => {
571
- return ptr :: null_mut ( ) ;
605
+ return None ;
572
606
}
573
607
OpenResult :: Err ( e) => {
574
608
tt_warning ! ( self . status, "open of input {} failed" , name; e) ;
575
- return ptr :: null_mut ( ) ;
609
+ return None ;
576
610
}
577
611
} ;
578
612
579
613
self . input_handles . push ( Box :: new ( ih) ) ;
580
614
self . latest_input_path = path;
581
- & mut * * self . input_handles . last_mut ( ) . unwrap ( )
615
+ Some ( InputId ( & mut * * self . input_handles . last_mut ( ) . unwrap ( ) ) )
582
616
}
583
617
584
618
fn input_open_primary ( & mut self ) -> * mut InputHandle {
@@ -650,32 +684,31 @@ impl<'a> CoreBridgeState<'a> {
650
684
rhandle. ungetc ( byte)
651
685
}
652
686
653
- fn input_close ( & mut self , handle : * mut InputHandle ) -> bool {
654
- let len = self . input_handles . len ( ) ;
655
-
656
- for i in 0 ..len {
657
- let p: * const InputHandle = & * self . input_handles [ i] ;
658
-
659
- if p == handle {
660
- let mut ih = self . input_handles . swap_remove ( i) ;
661
- let mut rv = false ;
662
-
663
- if let Err ( e) = ih. scan_remainder ( ) {
664
- tt_warning ! ( self . status, "error closing out input {}" , ih. name( ) ; e) ;
665
- rv = true ;
666
- }
667
-
668
- let ( name, digest_opt) = ih. into_name_digest ( ) ;
669
- self . hooks . event_input_closed ( name, digest_opt, self . status ) ;
670
- return rv;
687
+ /// Close the provided output, performing any necessary handling.
688
+ pub fn input_close ( & mut self , id : InputId ) -> bool {
689
+ let pos = self
690
+ . input_handles
691
+ . iter ( )
692
+ . position ( |i| ptr:: addr_eq ( & * * i, id. 0 ) ) ;
693
+ if let Some ( pos) = pos {
694
+ let mut ih = self . input_handles . swap_remove ( pos) ;
695
+ let mut rv = false ;
696
+
697
+ if let Err ( e) = ih. scan_remainder ( ) {
698
+ tt_warning ! ( self . status, "error closing out input {}" , ih. name( ) ; e) ;
699
+ rv = true ;
671
700
}
701
+
702
+ let ( name, digest_opt) = ih. into_name_digest ( ) ;
703
+ self . hooks . event_input_closed ( name, digest_opt, self . status ) ;
704
+ return rv;
672
705
}
673
706
674
707
// TODO: Handle the error better. This indicates a bug in the engine.
675
708
tt_error ! (
676
709
self . status,
677
710
"serious internal bug: unexpected handle in input close: {:?}" ,
678
- handle
711
+ id . 0
679
712
) ;
680
713
681
714
true
@@ -900,13 +933,19 @@ pub unsafe extern "C" fn ttbc_output_open(
900
933
let rname = CStr :: from_ptr ( name) . to_string_lossy ( ) ;
901
934
let ris_gz = is_gz != 0 ;
902
935
903
- es. output_open ( & rname, ris_gz)
936
+ match es. output_open ( & rname, ris_gz) {
937
+ Some ( id) => es. get_output ( id) ,
938
+ None => ptr:: null_mut ( ) ,
939
+ }
904
940
}
905
941
906
942
/// Open the general user output stream as a Tectonic output file.
907
943
#[ no_mangle]
908
944
pub extern "C" fn ttbc_output_open_stdout ( es : & mut CoreBridgeState ) -> * mut OutputHandle {
909
- es. output_open_stdout ( )
945
+ match es. output_open_stdout ( ) {
946
+ Some ( id) => es. get_output ( id) ,
947
+ None => ptr:: null_mut ( ) ,
948
+ }
910
949
}
911
950
912
951
/// Write a single character to a Tectonic output file.
@@ -967,7 +1006,7 @@ pub extern "C" fn ttbc_output_close(
967
1006
return 0 ; // This is/was the behavior of close_file() in C.
968
1007
}
969
1008
970
- libc:: c_int:: from ( es. output_close ( handle) )
1009
+ libc:: c_int:: from ( es. output_close ( es . output_to_id ( handle) ) )
971
1010
}
972
1011
973
1012
/// Open a Tectonic file for input.
@@ -984,7 +1023,11 @@ pub unsafe extern "C" fn ttbc_input_open(
984
1023
) -> * mut InputHandle {
985
1024
let rname = CStr :: from_ptr ( name) . to_string_lossy ( ) ;
986
1025
let ris_gz = is_gz != 0 ;
987
- es. input_open ( & rname, format, ris_gz)
1026
+ let id = es. input_open ( & rname, format, ris_gz) ;
1027
+ match id {
1028
+ Some ( id) => es. get_input ( id) ,
1029
+ None => ptr:: null_mut ( ) ,
1030
+ }
988
1031
}
989
1032
990
1033
/// Open the "primary input" file.
@@ -1169,7 +1212,7 @@ pub extern "C" fn ttbc_input_close(
1169
1212
return 0 ; // This is/was the behavior of close_file() in C.
1170
1213
}
1171
1214
1172
- libc:: c_int:: from ( es. input_close ( handle) )
1215
+ libc:: c_int:: from ( es. input_close ( es . input_to_id ( handle) ) )
1173
1216
}
1174
1217
1175
1218
/// A buffer for diagnostic messages. Rust code does not need to use this type.
0 commit comments