main.ml 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. open Lexing
  2. open Types
  3. type args = {
  4. mutable infiles : string list;
  5. mutable outfile : string option;
  6. mutable verbose : bool;
  7. mutable prune : bool;
  8. mutable unfold : bool;
  9. mutable upto : int option;
  10. }
  11. (* Parse command-line arguments *)
  12. let parse_args () =
  13. let args = {
  14. infiles = [];
  15. outfile = None;
  16. verbose = false;
  17. prune = true;
  18. unfold = true;
  19. upto = None;
  20. } in
  21. let args_spec = [
  22. ("<file> ...", Arg.Rest (fun _ -> ()),
  23. " 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.Unit (fun _ -> args.verbose <- true),
  27. " Verbose mode: show compression rate");
  28. ("-no-prune", Arg.Unit (fun _ -> args.prune <- false),
  29. " Don't prune duplicate properties (skip step 5 below)");
  30. ("-no-unfold", Arg.Unit (fun _ -> args.unfold <- false),
  31. " Only minify whitespace, colors and shorthands \
  32. (skip steps 2-7 below)");
  33. ("-upto", Arg.Int (fun i -> args.upto <- Some i),
  34. "<step> Stop after the specified step (for debugging): \
  35. \n \
  36. 1: parse \n \
  37. 2: unfold shorthands \n \
  38. 3: unfold selectors \n \
  39. 4: unfold blocks \n \
  40. 5: prune duplicates \n \
  41. 6: combine selectors \n \
  42. 7: concatenate blocks \n \
  43. 8: optimize blocks \n \
  44. 9: minify");
  45. ] in
  46. let usage =
  47. "Usage: " ^ Sys.argv.(0) ^ " [-o <file>] [-v] [-no-prune] [-upto <step>] \
  48. [<file> ...] "
  49. in
  50. Arg.parse args_spec (fun f -> args.infiles <- args.infiles @ [f]) usage;
  51. args
  52. let parse_files = function
  53. | [] ->
  54. let input = Util.input_buffered stdin 512 in
  55. (input, Parse.parse_input "<stdin>" input)
  56. | files ->
  57. let rec loop = function
  58. | [] -> []
  59. | filename :: tl ->
  60. let input = Util.input_all (open_in filename) in
  61. let stylesheet = Parse.parse_input filename input in
  62. (input, stylesheet) :: loop tl
  63. in
  64. let inputs, stylesheets = List.split (loop files) in
  65. (String.concat "" inputs, List.concat stylesheets)
  66. let handle_args args =
  67. let steps =
  68. (*let switch flag fn = if flag then fn else fun s -> s in*)
  69. [
  70. (*
  71. switch args.unfold Unfold.unfold_shorthands;
  72. switch args.unfold Unfold.unfold_selectors;
  73. switch args.unfold Unfold.unfold_blocks;
  74. switch (args.unfold && args.prune) Unfold.prune_duplicates;
  75. switch args.unfold Combine.combine_selectors;
  76. switch args.unfold Concat.concat_blocks;
  77. Optimize.optimize_blocks;
  78. *)
  79. ]
  80. in
  81. let write_output =
  82. match args.outfile with
  83. | None -> print_endline
  84. | Some name ->
  85. fun css -> let f = open_out name in output_string f css; close_out f
  86. in
  87. let upto = match args.upto with Some i -> i | None -> 0 in
  88. let input, stylesheet = parse_files args.infiles in
  89. let rec do_steps i stylesheet = function
  90. | _ when i = upto ->
  91. write_output (Stringify.string_of_stylesheet stylesheet)
  92. | [] ->
  93. let output = Stringify.minify_stylesheet stylesheet in
  94. write_output output;
  95. if args.verbose then begin
  96. let il = String.length input in
  97. let ol = String.length output in
  98. Printf.fprintf stderr "compression: %d -> %d bytes (%d%% of original)\n"
  99. il ol (int_of_float (float_of_int ol /. float_of_int il *. 100.))
  100. end
  101. | step :: tl ->
  102. do_steps (i + 1) (step stylesheet) tl
  103. in
  104. do_steps 1 stylesheet steps
  105. (* Main function, returns exit status *)
  106. let main () =
  107. begin
  108. try
  109. handle_args (parse_args ());
  110. exit 0
  111. with
  112. | Loc_error (loc, msg) ->
  113. Util.prerr_loc_msg loc ("Error: " ^ msg);
  114. | Box_error (box, msg) ->
  115. prerr_endline ("Error: " ^ msg ^ ": " ^ Stringify.string_of_box box);
  116. | Failure msg ->
  117. prerr_endline ("Error: " ^ msg);
  118. end;
  119. exit 1
  120. let _ = main ()