1818
1919use  std:: cell:: { Cell ,  RefCell } ; 
2020use  std:: collections:: { HashMap ,  HashSet } ; 
21+ use  std:: fs; 
2122use  std:: io:: ErrorKind ; 
2223use  std:: path:: { Component ,  Path ,  PathBuf } ; 
2324use  std:: rc:: Rc ; 
2425use  std:: time:: Instant ; 
25- use  std:: { env,  fs} ; 
2626
2727use  html5ever:: tendril:: ByteTendril ; 
2828use  html5ever:: tokenizer:: { 
@@ -110,10 +110,20 @@ macro_rules! t {
110110    } ; 
111111} 
112112
113+ struct  Cli  { 
114+     docs :  PathBuf , 
115+ } 
116+ 
113117fn  main ( )  { 
114-     let  docs = env:: args_os ( ) . nth ( 1 ) . expect ( "doc path should be first argument" ) ; 
115-     let  docs = env:: current_dir ( ) . unwrap ( ) . join ( docs) ; 
116-     let  mut  checker = Checker  {  root :  docs. clone ( ) ,  cache :  HashMap :: new ( )  } ; 
118+     let  cli = match  parse_cli ( )  { 
119+         Ok ( cli)  => cli, 
120+         Err ( err)  => { 
121+             eprintln ! ( "error: {err}" ) ; 
122+             usage_and_exit ( 1 ) ; 
123+         } 
124+     } ; 
125+ 
126+     let  mut  checker = Checker  {  root :  cli. docs . clone ( ) ,  cache :  HashMap :: new ( )  } ; 
117127    let  mut  report = Report  { 
118128        errors :  0 , 
119129        start :  Instant :: now ( ) , 
@@ -125,14 +135,45 @@ fn main() {
125135        intra_doc_exceptions :  0 , 
126136        has_broken_urls :  false , 
127137    } ; 
128-     checker. walk ( & docs,  & mut  report) ; 
138+     checker. walk ( & cli . docs ,  & mut  report) ; 
129139    report. report ( ) ; 
130140    if  report. errors  != 0  { 
131141        println ! ( "found some broken links" ) ; 
132142        std:: process:: exit ( 1 ) ; 
133143    } 
134144} 
135145
146+ fn  parse_cli ( )  -> Result < Cli ,  String >  { 
147+     fn  to_canonical_path ( arg :  & str )  -> Result < PathBuf ,  String >  { 
148+         PathBuf :: from ( arg) . canonicalize ( ) . map_err ( |e| format ! ( "could not canonicalize {arg}: {e}" ) ) 
149+     } 
150+ 
151+     let  mut  verbatim = false ; 
152+     let  mut  docs = None ; 
153+ 
154+     let  mut  args = std:: env:: args ( ) . skip ( 1 ) ; 
155+     while  let  Some ( arg)  = args. next ( )  { 
156+         if  !verbatim && arg == "--"  { 
157+             verbatim = true ; 
158+         }  else  if  !verbatim && ( arg == "-h"  || arg == "--help" )  { 
159+             usage_and_exit ( 0 ) 
160+         }  else  if  !verbatim && arg. starts_with ( '-' )  { 
161+             return  Err ( format ! ( "unknown flag: {arg}" ) ) ; 
162+         }  else  if  docs. is_none ( )  { 
163+             docs = Some ( arg) ; 
164+         }  else  { 
165+             return  Err ( "too many positional arguments" . into ( ) ) ; 
166+         } 
167+     } 
168+ 
169+     Ok ( Cli  {  docs :  to_canonical_path ( & docs. ok_or ( "missing first positional argument" ) ?) ? } ) 
170+ } 
171+ 
172+ fn  usage_and_exit ( code :  i32 )  -> ! { 
173+     eprintln ! ( "usage: linkchecker <path>" ) ; 
174+     std:: process:: exit ( code) 
175+ } 
176+ 
136177struct  Checker  { 
137178    root :  PathBuf , 
138179    cache :  Cache , 
0 commit comments