package jsonxt
Source file writer_file.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146module type Intf = sig val json_to_file : string -> 'a Json_internal.constrained -> (unit, string) result val json_to_file_exn : string -> 'a Json_internal.constrained -> unit val json_to_channel : out_channel -> 'a Json_internal.constrained -> (unit, string) result val json_to_channel_exn : out_channel -> 'a Json_internal.constrained -> unit val json_to_file_hum : string -> 'a Json_internal.constrained -> (unit, string) result val json_to_file_hum_exn : string -> 'a Json_internal.constrained -> unit val json_to_channel_hum : out_channel -> 'a Json_internal.constrained -> (unit, string) result val json_to_channel_hum_exn : out_channel -> 'a Json_internal.constrained -> unit val to_file : string -> 'a Json_internal.constrained -> unit val to_file_hum : string -> 'a Json_internal.constrained -> unit val to_channel : out_channel -> 'a Json_internal.constrained -> unit val to_channel_hum : out_channel -> 'a Json_internal.constrained -> unit val stream_to_channel : out_channel -> 'a Json_internal.constrained Stream.t -> unit val stream_to_file : string -> 'a Json_internal.constrained Stream.t -> unit end module Make (Compliance : Compliance.S) : Intf = struct let nibble_to_hex i = char_of_int (if i > 9 then 65 + i - 10 else 48 + i) let add_hex_byte oc i = output_char oc (nibble_to_hex ((i lsr 4) land 0x0f)); output_char oc (nibble_to_hex (i land 0x0f)) let escape oc s = let add_char = output_char oc in let add_string = output_string oc in let l = String.length s in for i = 0 to l - 1 do match s.[i] with | '"' -> add_string "\\\"" | '\\' -> add_string "\\\\" | '\b' -> add_string "\\b" | '\012' -> add_string "\\f" | '\n' -> add_string "\\n" | '\r' -> add_string "\\r" | '\t' -> add_string "\\t" | '\x00'..'\x1F' | '\x7F' as c -> add_string "\\u00"; add_hex_byte oc (int_of_char c) | _ -> add_char s.[i] done let json_to_channel_fmt oc json ~eol ~incr ~psep = let add_char = output_char oc in let add_string = output_string oc in let add_quote_string s = add_char '"'; escape oc s; add_char '"' in let add_int i = add_string (string_of_int i) in let add_float f = add_string (Compliance.number_to_string f) in let psep = ":" ^ psep in let rec fmt off value = match value with | `Assoc o -> let ldr = String.make off ' ' in add_char '{'; add_string eol; json_assoc (off + incr) o; add_string eol; add_string ldr; add_char '}' | `List l -> let ldr = String.make off ' ' in add_char '['; add_string eol; json_list (off + incr) l; add_string eol; add_string ldr; add_char ']' | `Null -> add_string "null" | `Bool b -> add_string (string_of_bool b) | `Int i -> add_int i | `Intlit s -> add_string s | `Float f -> add_float f | `Floatlit s -> add_string s | `String s -> add_quote_string s | `Stringlit s -> add_string s | `Tuple t -> let ldr = String.make off ' ' in add_char '('; add_string eol; json_list (off + incr) t; add_string eol; add_string ldr; add_char ')' | `Variant v -> let ldr = String.make off ' ' in add_char '<'; add_string eol; variant (off + incr) v; add_string eol; add_string ldr; add_char '>' and json_assoc off o = let ldr = String.make off ' ' in let sep = ref ldr in let newsep = "," ^ eol ^ ldr in List.iter (fun v -> add_string !sep; sep := newsep; pair off v ) o and pair off (k, v) = add_quote_string k; add_string psep; fmt off v and json_list off l = let ldr = String.make off ' ' in let sep = ref ldr in let newsep = "," ^ eol ^ ldr in List.iter (fun v -> add_string !sep; sep := newsep; fmt off v ) l and variant off (k, j) = add_quote_string k; match j with | Some j -> add_string psep; fmt (off + incr) j | None -> () in fmt 0 json; add_string eol let json_to_channel' = json_to_channel_fmt ~eol:"" ~incr:0 ~psep:"" let json_to_channel_hum' = json_to_channel_fmt ~eol:"\n" ~incr:2 ~psep:" " let json_to_channel oc json = try Ok (json_to_channel' oc json) with | Failure err -> Error err let json_to_channel_hum oc json = try Ok (json_to_channel_hum' oc json) with | Failure err -> Error err let json_to_channel_exn = json_to_channel' let json_to_channel_hum_exn = json_to_channel_hum' let json_to_file file json = let oc = open_out file in let res = json_to_channel oc json in close_out oc; res let json_to_file_hum file json = let oc = open_out file in let res = json_to_channel_hum oc json in close_out oc; res let json_to_file_exn file json = let oc = open_out file in try (json_to_channel' oc json; close_out oc) with | exn -> close_out oc; raise exn let json_to_file_hum_exn file json = let oc = open_out file in try (json_to_channel_hum' oc json; close_out oc) with | exn -> close_out oc; raise exn let to_file = json_to_file_exn let to_file_hum = json_to_file_hum_exn let to_channel = json_to_channel_exn let to_channel_hum = json_to_channel_hum_exn let stream_to_channel oc stream = Stream.iter (fun json -> json_to_channel_exn oc json; output_char oc '\n') stream let stream_to_file file stream = let oc = open_out file in try (stream_to_channel oc stream; close_out oc) with | exn -> close_out oc; raise exn end