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