open Ident let () = State.close ();; let dump = ref None let src = ref [] let args = ref [] let version () = Printf.eprintf "CDuce, version %s\n" Cduce_config.version; Printf.eprintf "built on %s\n" Cduce_config.build_date; Printf.eprintf "using OCaml %s compiler\n" (if Cduce_config.native then "native" else "bytecode"); exit 0 let specs = [ "--dump", Arg.String (fun s -> dump := Some s), " specify filename for persistency"; "--quiet", Arg.Set Cduce.quiet, " suppress normal output (typing, results)"; "-v", Arg.Unit version, " print CDuce version"; "--version", Arg.Unit version, "print CDuce version"; "--license", Arg.Unit (fun () -> Printf.eprintf "\n\ The CDuce interpreter is distributed under the terms of the Q Public \n\ License version 1.0 (included in the sources). The Choice of Law section\n\ been modified from the original Q Public.\n\n "; exit 0), "print CDuce license"; "--arg", Arg.Rest (fun s -> args := s :: !args), " the arguments that follow are passed to the CDuce program (in argv)"; ] let () = Arg.parse specs (fun s -> src := s :: !src) "\nUsage:\ncduce [OPTIONS ...] [FILE ...] [--arg argument ...]\n\nOptions:" let ppf = if !Cduce.quiet then Format.formatter_of_buffer (Buffer.create 1023) else Format.std_formatter let ppf_err = Format.err_formatter let bol = ref true let outflush s = output_string stdout s; flush stdout let toploop () = Cduce.toplevel := true; let tcio = try Unix.tcgetattr Unix.stdin with Unix.Unix_error (_,_,_) -> (* The input is not a terminal *) Location.push_source `Stream; let input = Stream.of_channel stdin in let ok = Cduce.script ppf ppf_err input in if not ok then exit 1 else exit 0 in let restore () = Unix.tcsetattr Unix.stdin Unix.TCSADRAIN tcio in let quit () = outflush "\n"; restore (); exit 0 in Format.fprintf ppf " CDuce version %s\n@." Cduce_config.version; Unix.tcsetattr Unix.stdin Unix.TCSADRAIN { tcio with Unix.c_vquit = '\004' }; Sys.set_signal Sys.sigquit (Sys.Signal_handle (fun _ -> quit ())); Sys.catch_break true; Cduce.toplevel := true; Location.push_source `Stream; let read i = if !bol then outflush "> "; try let c = input_char stdin in bol := c = '\n'; Some c with Sys.Break -> quit () in let input = Stream.from read in let rec loop () = outflush "# "; bol := false; ignore (Cduce.topinput ppf ppf_err input); while (input_char stdin != '\n') do () done; loop () in (try loop () with End_of_file -> ()); restore () let do_file s = let chan = open_in s in Location.push_source (`File s); let input = Stream.of_channel chan in if Stream.peek input = Some '#' then ( let rec count n = match Stream.next input with | '\n' -> n | _ -> count (n + 1) in Wlexer.set_delta_loc (count 1) ); let ok = Cduce.script ppf ppf_err input in close_in chan; if not ok then exit 1 let main () = (match !dump with | Some f -> (try Format.fprintf ppf "Restoring state: "; let chan = open_in_bin f in let s = Marshal.from_channel chan in close_in chan; State.set s; Format.fprintf ppf "done ...@." with Sys_error _ -> Format.fprintf ppf "failed ...@.") | None -> let l = List.rev_map Value.string_latin1 !args in let l = Value.sequence l in let t = Sequence.star Sequence.string in Cduce.enter_global_value (ident (U.mk "argv")) l t ); (match !src with | [] -> toploop () | l -> List.iter do_file l); (match !dump with | Some f -> Format.fprintf ppf "Saving state ...@\n"; let s = State.get () in let chan = open_out_bin f in Marshal.to_channel chan s [ Marshal.Closures ]; close_out chan | None -> ()) let () = main ()