Quellcode durchsuchen

Switch to Getopt for parsing cli args

Taddeus Kroes vor 10 Jahren
Ursprung
Commit
83d43b9619
3 geänderte Dateien mit 84 neuen und 90 gelöschten Zeilen
  1. 5 1
      Makefile
  2. 6 4
      README.md
  3. 73 85
      main.ml

+ 5 - 1
Makefile

@@ -10,6 +10,7 @@ OCAMLLDLIBS  := str.cmxa
 
 OCAMLLEX  := ocamllex
 OCAMLYACC := menhir --infer --explain --dump
+OCAMLOPT_GETOPT := ocamlfind opt -linkpkg -package getopt
 
 .PHONY: all clean
 .PRECIOUS: $(addprefix .cmi,$(ALL_NAMES))
@@ -28,8 +29,11 @@ all: $(RESULT)
 %.cmx: %.ml
 	ocamlopt -c $(OCAMLCFLAGS) -o $@ $(<:.cmi=.ml)
 
+main.cmx: main.ml
+	$(OCAMLOPT_GETOPT) -c $(OCAMLCFLAGS) -o $@ $(<:.cmi=.ml)
+
 $(RESULT): $(addsuffix .cmx,$(ALL_NAMES))
-	ocamlopt -o $@ $(OCAMLLDFLAGS) $(OCAMLLDLIBS) $^
+	$(OCAMLOPT_GETOPT) -o $@ $(OCAMLLDFLAGS) $(OCAMLLDLIBS) $^
 
 # module dependencies
 lexer.cmi: lexer.ml

+ 6 - 4
README.md

@@ -96,12 +96,13 @@ Output of `mincss -h`:
 Building mincss
 ===============
 
-Dependencies are [OCaml](https://ocaml.org/docs/install.html) 4.0 and
-[menhir](http://cristal.inria.fr/~fpottier/menhir/).
+Dependencies are [OCaml](https://ocaml.org/docs/install.html) 4.02.0,
+[menhir](http://cristal.inria.fr/~fpottier/menhir/) and
+[Getopt](https://forge.ocamlcore.org/projects/ocaml-getopt/).
 
 Bootstrapping on a Debian system can be done as follows:
 
-    $ sudo apt-get install ocaml menhir git
+    $ sudo apt-get install ocaml menhir libgetopt-ocaml-dev git
     $ git clone git@github.com:taddeus/mincss.git
     $ cd mincss
     $ make
@@ -115,7 +116,7 @@ flexibility:
     $ eval `opam config env`
     $ opam switch 4.02.0
     $ opam update
-    $ opam install menhir
+    $ opam install menhir getopt
 
 
 TODO / bugs
@@ -132,3 +133,4 @@ TODO / bugs
 - `border:none` could be `border:0`, or in general any shorthand that has both
   a `style` and `width` property should be transformed from `none` into `0`.
 - Automated test suite: auto-diff css files and expected minified versions.
+- `mincss -s test/duplicates.css` gets stuck in an infinite loop.

+ 73 - 85
main.ml

@@ -9,103 +9,88 @@ type args = {
   simple     : bool;
   shorthands : bool;
   duplicates : bool;
-  echo       : bool;
   sort       : bool;
 }
 
-let parse_args () =
-  let usage =
-    "Usage: " ^ Sys.argv.(0) ^
-    " [<options>] [<file> ...]\n\
-     \n\
-     Generic options:\n \
-     -h, --help        Show this help message\n \
-     -v, --verbose     Verbose mode: show compression rate\n \
-     -o <file>         Output file (defaults to stdout)\n \
-     <file> ...        Input files (default is to read from stdin)\n\
-     \n\
-     Optimization flags (default is -w -c -s -d):\n \
-     -w, --whitespace  Eliminate unnecessary whitespaces (has the greatest \
-                       effect, omit for pretty-printing)\n \
-     -c, --simple      Shorten colors, font weights and nth-child\n \
-     -s, --shorthands  Generate shorthand properties\n \
-     -d, --duplicates  Prune duplicate properties (WARNING: may affect \
-                       cross-browser hacks)\n \
-     -p, --pretty      Shorthand for -c -s -d\n \
-     \n\
-     Formatting options:\n \
-     -r, --sort        Sort declarations in each ruleset (always on when \
-                       --shorthands is enabled)\n \
-     -e, --echo        Just parse and pretty-print, no optimizations\n\
-     "
-  in
+let usage =
+  "Usage: " ^ Sys.argv.(0) ^
+  " [<options>] [<file> ...]\n\
+   \n\
+   Generic options:\n \
+   -h, --help        Show this help message\n \
+   -v, --verbose     Verbose mode: show compression rate\n \
+   -o <file>\n \
+   --output=<file>   Output file (defaults to stdout)\n \
+   <file> ...        Input files (defaults to stdin or \"-\")\n\
+   \n\
+   Optimization flags (default is -w -c -s -d):\n \
+   -w, --whitespace  Eliminate unnecessary whitespaces (has the greatest \
+                     effect, omit for pretty-printing)\n \
+   -c, --simple      Shorten colors, font weights and nth-child\n \
+   -s, --shorthands  Generate shorthand properties\n \
+   -d, --duplicates  Prune duplicate properties (WARNING: may affect \
+                     cross-browser hacks)\n \
+   -p, --pretty      Shorthand for -c -s -d\n \
+   \n\
+   Formatting options:\n \
+   -r, --sort        Sort declarations in each ruleset (always on when \
+                     --shorthands is enabled)\n \
+   -e, --echo        Just parse and pretty-print, no optimizations\n\
+   "
 
-  let default_args = {
-    infiles    = [];
-    outfile    = None;
-    verbose    = false;
-    whitespace = false;
-    simple     = false;
-    shorthands = false;
-    duplicates = false;
-    echo       = false;
-    sort       = false;
-  } in
-
-  let rec handle args = function
-    | ("-v" | "--verbose") :: tl ->
-      handle {args with verbose = true} tl
-    | ("-w" | "--whitespace") :: tl ->
-      handle {args with whitespace = true} tl
-    | ("-c" | "--simple") :: tl ->
-      handle {args with simple = true} tl
-    | ("-s" | "--shorthands") :: tl ->
-      handle {args with shorthands = true} tl
-    | ("-d" | "-duplicates") :: tl ->
-      handle {args with duplicates = true} tl
-    | ("-p" | "--pretty") :: tl ->
-      handle {args with simple = true; shorthands = true; duplicates = true} tl
-    | ("-e" | "--echo") :: tl ->
-      handle {args with echo = true} tl
-    | ("-r" | "--sort") :: tl ->
-      handle {args with sort = true} tl
-
-    | ("-h" | "--help") :: tl ->
-      prerr_string usage;
-      raise Exit_success
-
-    | ["-o"] ->
-      raise (Failure ("missing output file name"))
-    | "-o" :: next :: tl when next.[0] = '-' ->
-      raise (Failure ("missing output file name"))
-    | "-o" :: filename :: tl ->
-      handle {args with outfile = Some filename} tl
-
-    | arg :: tl when String.length arg > 2 && arg.[0] = '-' && arg.[1] <> '-' ->
-      let rec handle_opts args = function
-        | i when i = String.length arg -> args
-        | i -> handle_opts (handle args ["-" ^ String.make 1 arg.[i]]) (i + 1)
-      in
-      handle (handle_opts args 1) tl
-
-    | arg :: tl when arg.[0] = '-' ->
-      prerr_endline usage;
-      raise (Failure ("unknown option " ^ arg))
-
-    | filename :: tl ->
-      handle {args with infiles = args.infiles @ [filename]} tl
-
-    | [] -> args
+let parse_args () =
+  let infiles    = ref [] in
+  let outfile    = ref None in
+  let verbose    = ref false in
+  let whitespace = ref false in
+  let simple     = ref false in
+  let shorthands = ref false in
+  let duplicates = ref false in
+  let sort       = ref false in
+  let echo       = ref false in
+
+  let show_usage () = prerr_string usage; raise Exit_success in
+  let set_pretty () = simple := true; shorthands := true; duplicates := true in
+  let add_infile  = function
+    | "-"      -> infiles := []
+    | filename -> infiles := filename :: !infiles
   in
 
-  match handle default_args (List.tl (Array.to_list Sys.argv)) with
-  | { echo = true; _ } as args ->
+  let specs = [
+    ('h', "help",       Some show_usage, None);
+    ('v', "verbose",    Getopt.set verbose true, None);
+    ('o', "output",     None, Some (fun file -> outfile := Some file));
+    ('w', "whitespace", Getopt.set whitespace true, None);
+    ('c', "simple",     Getopt.set simple true, None);
+    ('s', "shorthands", Getopt.set shorthands true, None);
+    ('d', "duplicates", Getopt.set duplicates true, None);
+    ('p', "pretty",     Some set_pretty, None);
+    ('r', "sort",       Getopt.set sort true, None);
+    ('e', "echo",       Getopt.set echo true, None);
+  ] in
+
+  Getopt.parse_cmdline specs add_infile;
+
+  match {
+    infiles    = List.rev !infiles;
+    outfile    = !outfile;
+    verbose    = !verbose;
+    whitespace = !whitespace;
+    simple     = !simple;
+    shorthands = !shorthands;
+    duplicates = !duplicates;
+    sort       = !sort;
+  } with
+
+  (* disable optimizations when --echo is specified *)
+  | args when !echo = true ->
     { args with
       whitespace = false;
       simple     = false;
       shorthands = false;
       duplicates = false }
 
+  (* enable all optimizations by default *)
   | { whitespace = false;
       simple     = false;
       shorthands = false;
@@ -181,6 +166,9 @@ let main () =
       Util.prerr_loc_msg loc ("Error: " ^ msg);
     | Box_error (box, msg) ->
       prerr_endline ("Error: " ^ msg ^ ": " ^ Stringify.string_of_box box);
+    | Getopt.Error msg ->
+      prerr_endline ("Error: " ^ msg ^ "\n");
+      prerr_string usage;
     | Failure msg ->
       prerr_endline ("Error: " ^ msg);
     | Exit_success ->