main.ml 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. open Lexing
  2. open Types
  3. type args = {
  4. mutable infiles : string list;
  5. mutable outfile : string option;
  6. mutable verbose : int;
  7. mutable echo : bool;
  8. mutable pretty : bool;
  9. }
  10. (* Parse command-line arguments *)
  11. let parse_args () =
  12. let args = {
  13. infiles = [];
  14. outfile = None;
  15. verbose = 1;
  16. echo = false;
  17. pretty = false;
  18. } in
  19. let args_spec = [
  20. ("<file> ...", Arg.Rest (fun _ -> ()),
  21. " Optional input files (default is to read from stdin)");
  22. ("-o", Arg.String (fun s -> args.outfile <- Some s),
  23. "<file> Output file (defaults to stdout)");
  24. ("-v", Arg.Int (fun i -> args.verbose <- i),
  25. "<num> Set verbosity (0: nothing, 1: errors (default), \
  26. 2: compression rate, 3: debug)");
  27. ("--echo", Arg.Unit (fun _ -> args.echo <- true),
  28. " Don't minify, just pretty-print the parsed CSS");
  29. ("--pretty", Arg.Unit (fun _ -> args.pretty <- true),
  30. " Minify, but pretty-print the parsed CSS (for debugging)");
  31. ] in
  32. let usage =
  33. "Usage: " ^ Sys.argv.(0) ^ " [-o <file>] [-v <verbosity>] [<file> ...] " ^
  34. "[--pretty | --echo]"
  35. in
  36. Arg.parse args_spec (fun f -> args.infiles <- args.infiles @ [f]) usage;
  37. args
  38. let parse_files = function
  39. | [] ->
  40. let input = Util.input_buffered stdin 512 in
  41. (input, Parse.parse_input "<stdin>" input)
  42. | files ->
  43. let rec loop = function
  44. | [] -> []
  45. | filename :: tl ->
  46. let input = Util.input_all (open_in filename) in
  47. let stylesheet = Parse.parse_input filename input in
  48. (input, stylesheet) :: loop tl
  49. in
  50. let inputs, stylesheets = List.split (loop files) in
  51. (String.concat "" inputs, List.concat stylesheets)
  52. let handle_args args =
  53. let input, stylesheet = parse_files args.infiles in
  54. let write_output =
  55. match args.outfile with
  56. | None -> print_endline
  57. | Some name ->
  58. fun css -> let f = open_out name in output_string f css; close_out f
  59. in
  60. match args with
  61. | {echo = true} ->
  62. write_output (Stringify.string_of_stylesheet stylesheet)
  63. | _ ->
  64. let stylesheet = Color.compress stylesheet in
  65. let stylesheet = Shorthand.compress stylesheet in
  66. let stringify =
  67. if args.pretty
  68. then Stringify.string_of_stylesheet
  69. else Stringify.minify_stylesheet
  70. in
  71. let output = stringify stylesheet in
  72. write_output output;
  73. if args.verbose >= 2 then begin
  74. let il = String.length input in
  75. let ol = String.length output in
  76. Printf.fprintf stderr "compression: %d -> %d bytes (%d%% of original)\n"
  77. il ol (int_of_float (float_of_int ol /. float_of_int il *. 100.))
  78. end
  79. (* Main function, returns exit status *)
  80. let main () =
  81. let args = parse_args () in
  82. begin
  83. try
  84. handle_args args;
  85. exit 0
  86. with
  87. | Loc_error (loc, msg) ->
  88. Util.prerr_loc_msg (args.verbose >= 1) loc ("Error: " ^ msg);
  89. | Failure err ->
  90. prerr_endline ("Error: " ^ err);
  91. end;
  92. exit 1
  93. let _ = main ()