@@ -10,12 +10,12 @@ use std::collections::VecDeque;
1010use std:: collections:: hash_map:: Entry ;
1111use std:: ffi:: OsString ;
1212use std:: fs:: File ;
13- use std:: io:: { self , BufRead , BufReader } ;
13+ use std:: io:: { self , BufRead , BufReader , Write } ;
1414use string_interner:: StringInterner ;
1515use string_interner:: backend:: BucketBackend ;
1616use thiserror:: Error ;
1717use uucore:: display:: Quotable ;
18- use uucore:: error:: { UError , UResult , USimpleError } ;
18+ use uucore:: error:: { UError , UResult , USimpleError , strip_errno } ;
1919use uucore:: { format_usage, show, translate} ;
2020
2121// short types for switching interning behavior on the fly.
@@ -102,7 +102,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
102102 process_input ( reader, & mut g) ?;
103103 }
104104
105- g. run_tsort ( ) ;
105+ g. run_tsort ( ) ? ;
106106 Ok ( ( ) )
107107}
108108
@@ -148,9 +148,13 @@ enum TsortError {
148148 #[ error( "{input}: {message}" , input = . 0 , message = translate!( "tsort-error-loop" ) ) ]
149149 Loop ( String ) ,
150150
151- /// Wrapper for bubbling up IO errors
152- #[ error( "{0}" ) ]
153- IO ( #[ from] io:: Error ) ,
151+ /// Read error.
152+ #[ error( "{}" , translate!( "tsort-error-read" , "error" => strip_errno( . 0 ) ) ) ]
153+ Read ( io:: Error ) ,
154+
155+ /// Write error.
156+ #[ error( "{}" , translate!( "tsort-error-write" , "error" => strip_errno( . 0 ) ) ) ]
157+ Write ( io:: Error ) ,
154158}
155159
156160// Auxiliary struct, just for printing loop nodes via show! macro
@@ -173,7 +177,7 @@ fn process_input<R: BufRead>(reader: R, graph: &mut Graph) -> Result<(), TsortEr
173177 if e. kind ( ) == io:: ErrorKind :: IsADirectory {
174178 TsortError :: IsDir ( graph. name ( ) )
175179 } else {
176- e . into ( )
180+ TsortError :: Read ( e )
177181 }
178182 } ) ?;
179183 for token in line. split_whitespace ( ) {
@@ -276,7 +280,7 @@ impl Graph {
276280 }
277281
278282 /// Implementation of algorithm T from TAOCP (Don. Knuth), vol. 1.
279- fn run_tsort ( & mut self ) {
283+ fn run_tsort ( & mut self ) -> Result < ( ) , TsortError > {
280284 let mut independent_nodes_queue: VecDeque < Sym > = self
281285 . nodes
282286 . iter ( )
@@ -289,14 +293,23 @@ impl Graph {
289293 } )
290294 . collect ( ) ;
291295
296+ let stdout = io:: stdout ( ) ;
297+ let mut handle = stdout. lock ( ) ;
298+ let mut res: io:: Result < ( ) > = Ok ( ( ) ) ;
299+
292300 // Sort by resolved string for deterministic output
293301 independent_nodes_queue
294302 . make_contiguous ( )
295303 . sort_unstable_by ( |a, b| self . get_node_name ( * a) . cmp ( self . get_node_name ( * b) ) ) ;
296304
297305 while !self . nodes . is_empty ( ) {
298306 let v = self . find_next_node ( & mut independent_nodes_queue) ;
299- println ! ( "{}" , self . get_node_name( v) ) ;
307+
308+ // Attempt write but continue regardless on error
309+ if res. is_ok ( ) {
310+ res = writeln ! ( handle, "{}" , self . get_node_name( v) ) ;
311+ }
312+
300313 if let Some ( node_to_process) = self . nodes . remove ( & v) {
301314 for successor_name in node_to_process. successor_tokens . into_iter ( ) . rev ( ) {
302315 // we reverse to match GNU tsort order
@@ -311,6 +324,8 @@ impl Graph {
311324 }
312325 }
313326 }
327+
328+ res. map_err ( TsortError :: Write )
314329 }
315330 pub fn indegree ( & self , sym : Sym ) -> Option < usize > {
316331 self . nodes . get ( & sym) . map ( |data| data. predecessor_count )
0 commit comments