main.ml 5.97 KB
Newer Older
bguillaum's avatar
bguillaum committed
1
open Printf
pj2m's avatar
pj2m committed
2
open Log
bguillaum's avatar
bguillaum committed
3
open Conll
bguillaum's avatar
bguillaum committed
4
open Dep2pict
bguillaum's avatar
bguillaum committed
5

bguillaum's avatar
New gui  
bguillaum committed
6 7
open Global

pj2m's avatar
pj2m committed
8 9
let version = VERSION

10
let _ =
bguillaum's avatar
bguillaum committed
11
  Log.set_active_levels [`INFO; `WARNING];
bguillaum's avatar
bguillaum committed
12 13 14
  Log.set_info_label "DEP2PICT";
  Log.set_critical_label "DEP2PICT";
  Log.set_write_to_log_file false;
15
  Log.set_info_foreground Log.f_green;
bguillaum's avatar
bguillaum committed
16 17 18 19
  Log.set_critical_foreground Log.f_red;
  Log.set_critical_background Log.b_default;
  Log.set_show_time true

bguillaum's avatar
bguillaum committed
20
let usage = String.concat "\n" [
bguillaum's avatar
bguillaum committed
21
  "================================================================================";
bguillaum's avatar
bguillaum committed
22
  "=-=-=-=-= dep2pict: a tool to draw dependency graphs =-=-=-=-=";
bguillaum's avatar
bguillaum committed
23
  "";
bguillaum's avatar
bguillaum committed
24
  "Usage:";
25
  "  * dep2pict <options> input_file output_file    convert input_file into output_file";
bguillaum's avatar
bguillaum committed
26 27 28
  "  * dep2pict (-h | --help)                       display this help";
  "  * dep2pict (-v | --version)                    display version number ("^version^")";

bguillaum's avatar
bguillaum committed
29 30
  "";
  "Formats are guessed from file extension:";
bguillaum's avatar
bguillaum committed
31 32
  "  * accepted input formats are: dep, conll, xml";
  "  * accepted output formats are: png, svg, pdf, dep";
bguillaum's avatar
bguillaum committed
33
  "";
bguillaum's avatar
bguillaum committed
34
  "Options:";
bguillaum's avatar
New gui  
bguillaum committed
35
  "  -s | --sentid    <string> identifier of the sentence to display (incompatible with -p | --position)";
bguillaum's avatar
bguillaum committed
36
  "  -p | --position  <int> number of the dep structure to display when input file contains sequence (incompatible with -s | --sentid)";
37
  "  -d | --debug     add on_mouse_over tips in svg output and set verbose mode for font utilities";
38
  "  -b | --batch     Unformated error message that can be used in a pipeline or a web app";
39
  "  --special_chars  <file> give a set of chars (one char by line) that are considered as 1.5 width of 'X' (for korean chars for instance)";
bguillaum's avatar
bguillaum committed
40
  "================================================================================";
bguillaum's avatar
bguillaum committed
41
]
bguillaum's avatar
bguillaum committed
42

bguillaum's avatar
bguillaum committed
43

bguillaum's avatar
bguillaum committed
44
let first = ref true
45
let rec parse_arg = function
bguillaum's avatar
bguillaum committed
46 47 48
  | [] -> ()
  | "-v"::_ | "--version"::_ -> printf "%s\n%!" version; exit 0
  | "-h"::_ | "--help"::_ -> printf "%s\n%!" usage; exit 0
bguillaum's avatar
bguillaum committed
49

50
  | "-p"::i::tail
51
  | "--position"::i::tail -> current_position := ((int_of_string i)-1); parse_arg tail
bguillaum's avatar
bguillaum committed
52

53
  | "-s"::s::tail
bguillaum's avatar
bguillaum committed
54
  | "--sentid"::s::tail -> requested_sentid := Some s; parse_arg tail
bguillaum's avatar
New gui  
bguillaum committed
55

Bruno Guillaume's avatar
Bruno Guillaume committed
56 57 58
  (* does nothing (allow to pyqt to check for existence of the program) *)
  | "--check"::_ -> exit 0

59 60
  | "--special_chars"::s::tail -> special_chars := Some s; parse_arg tail

bguillaum's avatar
New gui  
bguillaum committed
61
  | "-d"::tail | "--debug"::tail -> debug := true; parse_arg tail
bguillaum's avatar
bguillaum committed
62

63
  | "-b"::tail | "--batch"::tail -> Log.set_active_levels []; batch := true; parse_arg tail
64

65
  | "-rtl":: tail | "--right_to_left":: tail -> rtl := true; parse_arg tail
bguillaum's avatar
bguillaum committed
66 67
  | s::_ when s.[0] = '-' -> Log.fcritical "Unknwon option \"%s\"" s

68
  | anon :: tail ->
bguillaum's avatar
bguillaum committed
69
    begin
bguillaum's avatar
bguillaum committed
70 71 72
      if !first
      then (input_file := anon; first := false)
      else
73 74 75
        match !output_file with
        | None -> output_file := Some anon
        | Some _ -> Log.fcritical "At most two anonymous arguments are allowed, don't know what to do with \"%s\"" anon
bguillaum's avatar
bguillaum committed
76 77 78
    end;
    parse_arg tail

Bruno Guillaume's avatar
Bruno Guillaume committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
let json_apply json_in json_out =
  match json_in with
  | `List l ->
    let (new_json : Yojson.Basic.json) = `List (List.map (
      function
      | `Assoc item ->
      begin
         match List.assoc_opt "dep_file" item with
         | Some (`String dep_file) ->
          let out_file = (Filename.chop_extension dep_file) ^ ".svg" in
          let dep = Dep2pict.from_dep (File.read dep_file) in
          Dep2pict.save_svg ~filename:out_file dep;
          let new_fields =
            match Dep2pict.highlight_shift () with
            | Some f -> [("svg_file", `String out_file); ("shift", `Float f)]
            | None -> [("svg_file", `String out_file)] in
          `Assoc (item @ new_fields)
         | _ -> Log.warning "Json items should contain a \"del_file\" field"; exit 0
      end
      | _ -> Log.warning "Json input file should be a list of Assoc list"; exit 0
      ) l) in
      let out_ch = open_out json_out in
      Printf.fprintf out_ch "%s\n" (Yojson.Basic.pretty_to_string (new_json));
      close_out out_ch
  | _ -> Log.warning "Json input file should be a list"; exit 0
  (* (Yojson.Basic.pretty_to_string json) *)

106
(* -------------------------------------------------------------------------------- *)
107
let main () =
108
  let () = parse_arg (List.tl (Array.to_list Sys.argv)) in
109

110 111 112 113 114 115 116 117
  if !debug then Dep2pict.set_verbose ();

  begin
    match !special_chars with
    | None -> ()
    | Some filename -> Dep2pict.load_special_chars filename
  end;

118
  (* check for input_file and load file if any *)
bguillaum's avatar
bguillaum committed
119
    match !output_file with
Bruno Guillaume's avatar
Bruno Guillaume committed
120
    | None -> failwith "TODO call gui"
121
    | Some out_file ->
122 123 124 125
      if (Format.get !input_file) = Format.Json
      then json_apply (Yojson.Basic.from_file !input_file) out_file
      else
      try
bguillaum's avatar
bguillaum committed
126
        load !input_file;
Bruno Guillaume's avatar
Bruno Guillaume committed
127
          set_position ();
bguillaum's avatar
bguillaum committed
128 129
          let graph = match (!current_data, !current_position) with
          | (Dep g,_) -> g
130 131 132
          | (Conll [||],_) -> error ~file: !input_file "Empty Conll file"
          | (Conll arr, pos) ->
          Dep2pict.from_conll ~rtl:!rtl ~conll:(snd arr.(pos)) in
bguillaum's avatar
bguillaum committed
133 134 135 136 137 138 139 140 141 142 143 144 145
          begin
            match Format.get out_file with
            | Format.Svg -> Dep2pict.save_svg ~filename:out_file graph
            | Format.Pdf -> Dep2pict.save_pdf ~filename:out_file graph
            | Format.Png -> Dep2pict.save_png ~filename:out_file graph
            | Format.Dep -> (
              match (!current_data, !current_position) with
              | (Conll arr, p) -> File.write out_file (Dep2pict.conll_to_dep ~conll:(snd arr.(p)))
              | _ -> critical "<dep> output format is available only for <conll> inputs"
            )
            | f -> critical "<%s> is not a valid output format" (Format.to_string f)
          end;
          Log.finfo "File %s generated." out_file
146 147 148 149 150 151 152 153 154 155
      with
      | Error json -> raise (Error json)
      | Dep2pict.Error json -> raise (Error json)
      | Conll_types.Error json -> raise (Error json)
      | Sys_error data -> error ~file: !input_file ~data "Sys_error"
      | exc -> error ~file: !input_file ~data:(Printexc.to_string exc) "Unexpected exception, please report"

let _ =
  try main ()
  with Error json -> critical "%s" (Yojson.Basic.pretty_to_string json)