|
3 | 3 | * License: MIT |
4 | 4 | *) |
5 | 5 |
|
6 | | -type options = {ignoreCase: bool, passThrough: bool} |
| 6 | +exception Encoding of string |
7 | 7 |
|
8 | | -fun idOptions (opts: options) : Id.options = {ignoreCase = #ignoreCase opts} |
| 8 | +val unsupportedEncoding = "unsupported encoding: " |
| 9 | + |
| 10 | +fun checkWrongEncoding (lines: string list) = |
| 11 | + let |
| 12 | + val _ = |
| 13 | + case lines of |
| 14 | + [first] => |
| 15 | + (case map Char.ord (String.explode first) of |
| 16 | + 0x00 :: 0x00 :: 0xFE :: 0xFF :: _ => |
| 17 | + raise Encoding (unsupportedEncoding ^ "UTF-32 BE") |
| 18 | + | 0xFF :: 0xFE :: 0x00 :: 0x00 :: _ => |
| 19 | + raise Encoding (unsupportedEncoding ^ "UTF-32 LE") |
| 20 | + | 0xFE :: 0xFF :: _ => |
| 21 | + raise Encoding (unsupportedEncoding ^ "UTF-16 BE") |
| 22 | + | 0xFF :: 0xFE :: _ => |
| 23 | + raise Encoding (unsupportedEncoding ^ "UTF-16 LE") |
| 24 | + | _ => ()) |
| 25 | + | _ => () |
| 26 | + in |
| 27 | + lines |
| 28 | + end |
9 | 29 |
|
10 | 30 | fun readLines (filename: string) : string list = |
11 | 31 | let |
@@ -44,7 +64,8 @@ datatype result = Output of string | FailureOutput of string | Error of string |
44 | 64 |
|
45 | 65 | fun processFileCustom quiet passThrough successFn filterFn filename = |
46 | 66 | let |
47 | | - val parsed = Ini.parse passThrough (readLines filename) |
| 67 | + val parsed = |
| 68 | + ((Ini.parse passThrough) o checkWrongEncoding o readLines) filename |
48 | 69 | val filtered = filterFn parsed |
49 | 70 | val success = successFn (parsed, filtered) |
50 | 71 | val output = if quiet then "" else Ini.stringify filtered |
@@ -100,13 +121,17 @@ fun helpCommand [] = Output allUsage |
100 | 121 | Error (invalidUsage ^ (formatArgs (cmd :: rest)) ^ "\n" ^ usage ^ cmd) |
101 | 122 |
|
102 | 123 | fun versionCommand [] = |
103 | | - let val version = "0.15.0" |
| 124 | + let val version = "0.16.0" |
104 | 125 | in Output (version ^ "\n") |
105 | 126 | end |
106 | 127 | | versionCommand [_] = versionCommand [] |
107 | 128 | | versionCommand (cmd :: rest) = |
108 | 129 | Error (invalidUsage ^ (formatArgs (cmd :: rest)) ^ "\n" ^ usage ^ cmd) |
109 | 130 |
|
| 131 | +type options = {ignoreCase: bool, passThrough: bool} |
| 132 | + |
| 133 | +fun idOptions (opts: options) : Id.options = {ignoreCase = #ignoreCase opts} |
| 134 | + |
110 | 135 | fun getCommand (opts: options) [_, filename] = |
111 | 136 | processFile (#passThrough opts) (fn _ => true) (fn x => x) filename |
112 | 137 | | getCommand opts [_, filename, section] = |
@@ -139,7 +164,7 @@ fun getCommand (opts: options) [_, filename] = |
139 | 164 | val q = Ini.SelectProperty {section = section, key = key} |
140 | 165 | val parsed = |
141 | 166 | ((Ini.select (idOptions opts) q) o (Ini.parse (#passThrough opts)) |
142 | | - o readLines) filename |
| 167 | + o checkWrongEncoding o readLines) filename |
143 | 168 | val allItems = List.concat |
144 | 169 | (List.map (fn {name = _, contents = xs} => xs) parsed) |
145 | 170 | val values = |
@@ -275,11 +300,16 @@ fun processArgs (opts: options) [] = helpCommand [] |
275 | 300 | | processArgs opts (cmd :: _) = |
276 | 301 | Error (unknownCommand ^ (formatArgs [cmd]) ^ "\n" ^ availableCommands) |
277 | 302 |
|
| 303 | +fun handleException (message: string) = |
| 304 | + exitWithError "" ("Error: " ^ message) |
| 305 | + |
278 | 306 | val args = CommandLine.arguments () |
279 | 307 |
|
280 | 308 | val result = |
281 | 309 | processArgs {ignoreCase = false, passThrough = false} args |
282 | | - handle Ini.Tokenization (message) => exitWithError "" ("Error: " ^ message) |
| 310 | + handle |
| 311 | + Encoding message => handleException message |
| 312 | + | Ini.Tokenization message => handleException message |
283 | 313 | val _ = |
284 | 314 | case result of |
285 | 315 | Output s => printFlush TextIO.stdOut s |
|
0 commit comments