main.ml 2.5 KB

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