1- use std:: error:: Error ;
2- use clap:: { Arg , ArgAction , Command } ;
3- use std:: fs:: File ;
4- use std:: io:: { self , stdin, BufRead , BufReader } ;
5-
6- #[ allow( unused) ]
7- #[ derive( Debug ) ]
8- pub struct Config {
9- files : Vec < String > ,
10- number_lines : bool ,
11- number_nonblank_lines : bool ,
12- }
13-
14- type MyResult < T > = Result < T , Box < dyn Error > > ;
15-
16- fn open ( filename : & str ) -> MyResult < Box < dyn BufRead > > {
17- match filename {
18- "-" => Ok ( Box :: new ( BufReader :: new ( io:: stdin ( ) ) ) ) ,
19- _ => Ok ( Box :: new ( BufReader :: new ( File :: open ( filename) ?) ) ) ,
20- }
21- }
22-
23- pub fn run ( config : Config ) -> MyResult < ( ) > {
24- // dbg!(config);
25- for filename in config. files {
26- // println!("{}", filename);
27- match open ( & filename) {
28- Err ( err) => eprintln ! ( "Failed to open {}: {}" , filename, err) ,
29- Ok ( _) => println ! ( "Opened {}" , filename) ,
30- }
31- }
32- Ok ( ( ) )
33- }
34-
35- pub fn get_args ( ) -> MyResult < Config > {
36- let matches = Command :: new ( "ch03_catr" )
37- . version ( "0.1.0" )
38- . author ( "Rakuram <[email protected] >" ) 39- . about ( "Rust cat Command" )
40- . help_template (
41- "{name} {version} \n \
42- {author} \n \
43- {about} \n \n \
44- USAGE: \n {usage}\n \n \
45- {all-args}" ,
46- )
47- . arg (
48- Arg :: new ( "files" )
49- . value_name ( "FILE" )
50- . help ( "Input files" )
51- // .required(true) // reason why required is not used is because we are using default value
52- . num_args ( 1 ..)
53- . default_value ( "-" )
54- . action ( ArgAction :: Append ) ,
55- )
56- . arg (
57- Arg :: new ( "number_lines" )
58- . short ( 'n' )
59- . long ( "number" )
60- . help ( "number all output lines" )
61- . action ( ArgAction :: SetTrue )
62- . conflicts_with ( "number_nonblank" ) ,
63- )
64- . arg (
65- Arg :: new ( "number_nonblank" )
66- . short ( 'b' )
67- . long ( "number-nonblank" )
68- . help ( "number nonempty output lines, overrides -n" )
69- . action ( ArgAction :: SetTrue ) ,
70- )
71- . get_matches ( ) ;
72-
73- // let text: Vec<String> = matches
74- // .get_many("files")
75- // .expect("filename is required")
76- // .cloned()
77- // .collect();
78-
79- // println!("{:#?}", text);
80-
81- // let number_lines = matches.get_flag("number_lines");
82-
83- // let number_nonblank_lines = matches.get_flag("number_nonblank_lines");
84-
85- // println!("text: {:#?}", text);
86- // println!("number_lines: {:#?}", number_lines);
87- // println!("number_nonblank_lines: {:#?}", number_nonblank_lines);
88-
89- Ok ( Config {
90- files : matches. get_many ( "files" ) . unwrap ( ) . cloned ( ) . collect ( ) ,
91- number_lines : matches. get_flag ( "number_lines" ) ,
92- number_nonblank_lines : matches. get_flag ( "number_nonblank" ) ,
93- } )
94- }
1+ use clap:: { Arg , ArgAction , Command } ;
2+ use std:: error:: Error ;
3+ use std:: fs:: File ;
4+ use std:: io:: { self , BufRead , BufReader } ;
5+
6+ #[ allow( unused) ]
7+ #[ derive( Debug ) ]
8+ pub struct Config {
9+ files : Vec < String > ,
10+ number_lines : bool ,
11+ number_nonblank_lines : bool ,
12+ }
13+
14+ type MyResult < T > = Result < T , Box < dyn Error > > ;
15+
16+ fn open ( filename : & str ) -> MyResult < Box < dyn BufRead > > {
17+ match filename {
18+ "-" => Ok ( Box :: new ( BufReader :: new ( io:: stdin ( ) ) ) ) ,
19+ _ => Ok ( Box :: new ( BufReader :: new ( File :: open ( filename) ?) ) ) ,
20+ }
21+ }
22+
23+ // method 1
24+ // pub fn run(config: Config) -> MyResult<()> {
25+ // // dbg!(config);
26+ // for filename in config.files {
27+ // // println!("{}", filename);
28+ // match open(&filename) {
29+ // Err(err) => eprintln!("Failed to open {}: {}", filename, err),
30+ // // Ok(_) => println!("Opened {}", filename),
31+ // Ok(file) => {
32+ // let mut line_number = 0;
33+ // for line_result in file.lines() {
34+ // let line = line_result?;
35+ // line_number += 1;
36+
37+ // if config.number_lines {
38+ // println!("{:>6}\t{}", line_number, line);
39+ // } else {
40+ // println!("{}", line);
41+ // }
42+
43+ // if config.number_nonblank_lines {
44+ // if line.is_empty() {
45+ // line_number -= 1;
46+ // continue;
47+ // } else {
48+ // println!("{:>6}\t{}", line_number, line);
49+ // }
50+ // }
51+ // }
52+ // }
53+ // }
54+ // }
55+ // Ok(())
56+ // }
57+
58+ // method 2 - Idomatic way
59+ pub fn run ( config : Config ) -> MyResult < ( ) > {
60+ for filename in config. files {
61+ match open ( & filename) {
62+ Err ( err) => eprintln ! ( "Failed to open {}: {}" , filename, err) ,
63+ Ok ( file) => {
64+ let mut last_num = 0 ;
65+ for ( line_num, line) in file. lines ( ) . enumerate ( ) {
66+ let line = line?; // unwrapping from Result
67+ if config. number_lines {
68+ println ! ( "{:6}\t {}" , line_num + 1 , line) ;
69+ } else if config. number_nonblank_lines {
70+ if !line. is_empty ( ) {
71+ last_num += 1 ;
72+ println ! ( "{:6}\t {}" , last_num, line) ;
73+ } else {
74+ println ! ( ) ;
75+ }
76+ } else {
77+ println ! ( "{}" , line) ;
78+ }
79+ }
80+ }
81+ }
82+ }
83+ Ok ( ( ) )
84+ }
85+
86+ pub fn get_args ( ) -> MyResult < Config > {
87+ let matches = Command :: new ( "ch03_catr" )
88+ . version ( "0.1.0" )
89+ . author ( "Rakuram <[email protected] >" ) 90+ . about ( "Rust cat Command" )
91+ . help_template (
92+ "{name} {version} \n \
93+ {author} \n \
94+ {about} \n \n \
95+ USAGE: \n {usage}\n \n \
96+ {all-args}",
97+ )
98+ . arg (
99+ Arg :: new ( "files" )
100+ . value_name ( "FILE" )
101+ . help ( "Input files" )
102+ // .required(true) // reason why required is not used is because we are using default value
103+ . num_args ( 1 ..)
104+ . default_value ( "-" )
105+ . action ( ArgAction :: Append ) ,
106+ )
107+ . arg (
108+ Arg :: new ( "number_lines" )
109+ . short ( 'n' )
110+ . long ( "number" )
111+ . help ( "number all output lines" )
112+ . action ( ArgAction :: SetTrue )
113+ . conflicts_with ( "number_nonblank" ) ,
114+ )
115+ . arg (
116+ Arg :: new ( "number_nonblank" )
117+ . short ( 'b' )
118+ . long ( "number-nonblank" )
119+ . help ( "number nonempty output lines, overrides -n" )
120+ . action ( ArgAction :: SetTrue ) ,
121+ )
122+ . get_matches ( ) ;
123+
124+ // let text: Vec<String> = matches
125+ // .get_many("files")
126+ // .expect("filename is required")
127+ // .cloned()
128+ // .collect();
129+
130+ // println!("{:#?}", text);
131+
132+ // let number_lines = matches.get_flag("number_lines");
133+
134+ // let number_nonblank_lines = matches.get_flag("number_nonblank_lines");
135+
136+ // println!("text: {:#?}", text);
137+ // println!("number_lines: {:#?}", number_lines);
138+ // println!("number_nonblank_lines: {:#?}", number_nonblank_lines);
139+
140+ Ok ( Config {
141+ files : matches. get_many ( "files" ) . unwrap ( ) . cloned ( ) . collect ( ) ,
142+ number_lines : matches. get_flag ( "number_lines" ) ,
143+ number_nonblank_lines : matches. get_flag ( "number_nonblank" ) ,
144+ } )
145+ }
0 commit comments