main.ml 3.4 KB

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