signature EsisOptions = sig val O_SILENT : bool ref val O_ERROR_DEVICE : TextIO.outstream ref val O_ERROR_LINEWIDTH : int ref val O_OUTPUT_FILE : string ref val O_NON_DIRECT : UniChar.Char ref val setEsisDefaults : unit -> unit val setEsisOptions : Options.Option list * (string -> unit) -> bool * bool * string option * string option val esisUsage : Options.Usage end structure EsisOptions : EsisOptions = struct open Options val O_SILENT = ref false val O_ERROR_DEVICE = ref TextIO.stdErr val O_ERROR_LINEWIDTH = ref 80 val O_OUTPUT_FILE = ref "-" val O_NON_DIRECT = ref (0wx100 : UniChar.Char) fun setEsisDefaults () = let val _ = O_SILENT := false val _ = O_ERROR_DEVICE := TextIO.stdErr val _ = O_OUTPUT_FILE := "-" val _ = O_NON_DIRECT := 0wx100 in () end val esisUsage = [U_ITEM(["-o ","--output="],"Write output to file (stdout)"), U_ITEM(["-s","--silent"],"Suppress reporting of errors and warnings"), U_ITEM(["-e ","--error-output="],"Redirect errors to file (stderr)"), U_SEP, U_ITEM(["-7","--ascii"],"Produce output in ASCII (7 bit) encoding"), U_ITEM(["-8","--latin1"],"Produce output in LATIN1 (8 bit) encoding (default)"), U_SEP, U_ITEM(["--version"],"Print the version number and exit"), U_ITEM(["-?","--help"],"Print this text and exit"), U_ITEM(["--"],"Do not recognize remaining arguments as options") ] fun setEsisOptions (opts,optError) = let fun onlyOne what = "at most one "^what^" may be specified" fun unknown pre opt = String.concat ["unknown option ",pre,opt] fun hasNoArg pre key = String.concat ["option ",pre,key," expects no argument"] fun mustHave pre key = String.concat ["option ",pre,key," must have an argument"] fun check_noarg(key,valOpt) = if isSome valOpt then optError (hasNoArg "--" key) else () fun do_long (pars as (v,h,e,f)) (key,valOpt) = case key of "help" => (v,true,e,f) before check_noarg(key,valOpt) | "version" => (true,h,e,f) before check_noarg(key,valOpt) | "silent" => pars before O_SILENT := true before check_noarg(key,valOpt) | "ascii" => pars before O_NON_DIRECT := 0wx80 before check_noarg(key,valOpt) | "latin1" => pars before O_NON_DIRECT := 0wx100 before check_noarg(key,valOpt) | "output" => (case valOpt of NONE => pars before optError (mustHave "--" key) | SOME s => pars before O_OUTPUT_FILE := s) | "error-output" => (case valOpt of NONE => pars before optError (mustHave "--" key) | SOME s => (v,h,SOME s,f)) | _ => pars before optError(unknown "--" key) fun do_short (pars as (v,h,e,f)) (cs,opts) = case cs of nil => doit pars opts | [#"o"] => (case opts of OPT_STRING s::opts1 => (O_OUTPUT_FILE := s; doit pars opts1) | _ => (optError (mustHave "-" "o"); doit pars opts)) | [#"e"] => (case opts of OPT_STRING s::opts1 => doit (v,h,SOME s,f) opts1 | _ => (optError (mustHave "-" "e"); doit pars opts)) | cs => doit (foldr (fn (c,pars) => case c of #"s" => pars before O_SILENT := true | #"7" => pars before O_NON_DIRECT := 0wx80 | #"8" => pars before O_NON_DIRECT := 0wx100 | #"o" => pars before optError (mustHave "-" "o") | #"e" => pars before optError (mustHave "-" "e") | #"?" => (v,true,e,f) | c => pars before optError(unknown "-" (String.implode [c]))) pars cs) opts and doit pars nil = pars | doit (pars as (v,h,e,f)) (opt::opts) = case opt of OPT_LONG(key,valOpt) => doit (do_long pars (key,valOpt)) opts | OPT_SHORT cs => do_short pars (cs,opts) | OPT_STRING s => if isSome f then let val _ = optError(onlyOne "input file") in doit pars opts end else doit (v,h,e,SOME s) opts | OPT_NOOPT => doit pars opts | OPT_NEG cs => let val _ = if null cs then () else app (fn c => optError (unknown "-n" (String.implode[c]))) cs in doit pars opts end in doit (false,false,NONE,NONE) opts end end