@@ -11,6 +11,17 @@ use yaml_rust::yaml::Yaml;
11
11
use regex:: Regex ;
12
12
use lazy_static:: lazy_static;
13
13
14
+ macro_rules! fatalerr {
15
+ ( ) => ( {
16
+ eprintln!( ) ;
17
+ std:: process:: exit( 1 ) ;
18
+ } ) ;
19
+ ( $( $arg: tt) * ) => ( {
20
+ eprintln!( $( $arg) * ) ;
21
+ std:: process:: exit( 1 ) ;
22
+ } ) ;
23
+ }
24
+
14
25
struct Table < ' a > {
15
26
path : String ,
16
27
file : RefCell < Box < dyn Write > > ,
@@ -25,9 +36,9 @@ impl<'a> Table<'a> {
25
36
None => RefCell :: new ( Box :: new ( stdout ( ) ) ) ,
26
37
Some ( ref file) => RefCell :: new ( Box :: new (
27
38
match filemode {
28
- "truncate" => File :: create ( & Path :: new ( file) ) . unwrap ( ) ,
29
- "append" => OpenOptions :: new ( ) . append ( true ) . create ( true ) . open ( & Path :: new ( file) ) . unwrap ( ) ,
30
- mode => panic ! ( "Invalid 'mode' setting in configuration file: {}" , mode)
39
+ "truncate" => File :: create ( & Path :: new ( file) ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to create output file '{}': {}" , file , err ) ) ,
40
+ "append" => OpenOptions :: new ( ) . append ( true ) . create ( true ) . open ( & Path :: new ( file) ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to open output file '{}': {}" , file , err ) ) ,
41
+ mode => fatalerr ! ( "Error: invalid 'mode' setting in configuration file: {}" , mode)
31
42
}
32
43
) )
33
44
} ,
@@ -36,7 +47,7 @@ impl<'a> Table<'a> {
36
47
}
37
48
}
38
49
fn write ( & self , text : & str ) {
39
- self . file . borrow_mut ( ) . write_all ( text. as_bytes ( ) ) . expect ( "Write error encountered; exiting..." ) ;
50
+ self . file . borrow_mut ( ) . write_all ( text. as_bytes ( ) ) . unwrap_or_else ( |err| fatalerr ! ( "Error: IO error encountered while writing table: {}" , err ) ) ;
40
51
}
41
52
fn clear_columns ( & self ) {
42
53
for col in & self . columns {
@@ -114,7 +125,7 @@ fn gml_to_ewkb(cell: &RefCell<String>, coll: &[Geometry], bbox: Option<&BBox>, m
114
125
// println!("{:?}", geom);
115
126
let code = match geom. dims {
116
127
2 => 32 , // Indicate EWKB where the srid follows this byte
117
- 3 => 32 | 128 , // Add bit to indicate the presense of Z values
128
+ 3 => 32 | 128 , // Add bit to indicate the presence of Z values
118
129
_ => {
119
130
eprintln ! ( "GML number of dimensions {} not supported" , geom. dims) ;
120
131
32
@@ -169,20 +180,20 @@ fn gml_to_ewkb(cell: &RefCell<String>, coll: &[Geometry], bbox: Option<&BBox>, m
169
180
fn add_table < ' a > ( rowpath : & str , outfile : Option < & str > , filemode : & str , skip : Option < & ' a str > , colspec : & ' a [ Yaml ] ) -> Table < ' a > {
170
181
let mut table = Table :: new ( rowpath, outfile, filemode, skip) ;
171
182
for col in colspec {
172
- let name = col[ "name" ] . as_str ( ) . expect ( "Column has no 'name' entry in configuration file") ;
173
- let colpath = col[ "path" ] . as_str ( ) . expect ( "Column has no 'path' entry in configuration file") ;
183
+ let name = col[ "name" ] . as_str ( ) . unwrap_or_else ( || fatalerr ! ( "Error: column has no 'name' entry in configuration file") ) ;
184
+ let colpath = col[ "path" ] . as_str ( ) . unwrap_or_else ( || fatalerr ! ( "Error: column has no 'path' entry in configuration file") ) ;
174
185
let mut path = String :: from ( rowpath) ;
175
186
path. push_str ( colpath) ;
176
187
let subtable: Option < Table > = match col[ "cols" ] . is_badvalue ( ) {
177
188
true => None ,
178
189
false => {
179
- let file = col[ "file" ] . as_str ( ) . expect ( "Subtable has no 'file' entry") ;
180
- Some ( add_table ( & path, Some ( file) , filemode, skip, col[ "cols" ] . as_vec ( ) . expect ( "Subtable 'cols' entry is not an array") ) )
190
+ let file = col[ "file" ] . as_str ( ) . unwrap_or_else ( || fatalerr ! ( "Error: subtable has no 'file' entry") ) ;
191
+ Some ( add_table ( & path, Some ( file) , filemode, skip, col[ "cols" ] . as_vec ( ) . unwrap_or_else ( || fatalerr ! ( "Error: subtable 'cols' entry is not an array") ) ) )
181
192
}
182
193
} ;
183
194
let hide = col[ "hide" ] . as_bool ( ) . unwrap_or ( false ) ;
184
- let include: Option < Regex > = col[ "incl" ] . as_str ( ) . map ( |str| Regex :: new ( str) . expect ( "Invalid regex in 'incl' entry in configuration file" ) ) ;
185
- let exclude: Option < Regex > = col[ "excl" ] . as_str ( ) . map ( |str| Regex :: new ( str) . expect ( "Invalid regex in 'excl' entry in configuration file" ) ) ;
195
+ let include: Option < Regex > = col[ "incl" ] . as_str ( ) . map ( |str| Regex :: new ( str) . unwrap_or_else ( |err| fatalerr ! ( "Error: invalid regex in 'incl' entry in configuration file: {}" , err ) ) ) ;
196
+ let exclude: Option < Regex > = col[ "excl" ] . as_str ( ) . map ( |str| Regex :: new ( str) . unwrap_or_else ( |err| fatalerr ! ( "Error: invalid regex in 'excl' entry in configuration file: {}" , err ) ) ) ;
186
197
let attr = col[ "attr" ] . as_str ( ) ;
187
198
let convert = col[ "conv" ] . as_str ( ) ;
188
199
let find = col[ "find" ] . as_str ( ) ;
@@ -191,12 +202,17 @@ fn add_table<'a>(rowpath: &str, outfile: Option<&str>, filemode: &str, skip: Opt
191
202
let bbox = col[ "bbox" ] . as_str ( ) . and_then ( BBox :: from) ;
192
203
let multitype = col[ "mult" ] . as_bool ( ) . unwrap_or ( false ) ;
193
204
194
- if convert. is_some ( ) && !vec ! ( "xml-to-text" , "gml-to-ewkb" ) . contains ( & convert. unwrap ( ) ) {
195
- panic ! ( "Option 'convert' contains invalid value {}" , convert. unwrap( ) ) ;
205
+ if let Some ( val) = convert {
206
+ if !vec ! ( "xml-to-text" , "gml-to-ewkb" ) . contains ( & val) {
207
+ fatalerr ! ( "Error: option 'convert' contains invalid value: {}" , val) ;
208
+ }
209
+ if val == "gml-to-ewkb" {
210
+ eprintln ! ( "Warning: gml-to-ewkb conversion is experimental and in no way complete or standards compliant; use at your own risk" ) ;
211
+ }
196
212
}
197
213
if include. is_some ( ) || exclude. is_some ( ) {
198
214
if convert. is_some ( ) {
199
- panic ! ( "Filtering (incl/excl) and 'conv' cannot be used together on a single column" ) ;
215
+ fatalerr ! ( "Error: filtering (incl/excl) and 'conv' cannot be used together on a single column" ) ;
200
216
}
201
217
if find. is_some ( ) {
202
218
eprintln ! ( "Notice: when using filtering (incl/excl) and find/replace on a single column, the filter is checked before replacements" ) ;
@@ -215,24 +231,22 @@ fn add_table<'a>(rowpath: &str, outfile: Option<&str>, filemode: &str, skip: Opt
215
231
table
216
232
}
217
233
218
- fn main ( ) -> std :: io :: Result < ( ) > {
234
+ fn main ( ) {
219
235
let args: Vec < _ > = env:: args ( ) . collect ( ) ;
220
236
let bufread: Box < dyn BufRead > ;
221
237
if args. len ( ) == 2 {
222
238
bufread = Box :: new ( BufReader :: new ( stdin ( ) ) ) ;
223
239
}
224
240
else if args. len ( ) == 3 {
225
- bufread = Box :: new ( BufReader :: new ( File :: open ( & args[ 2 ] ) ?) ) ;
226
- }
227
- else {
228
- eprintln ! ( "usage: {} <configfile> [xmlfile]" , args[ 0 ] ) ;
229
- return Ok ( ( ) ) ;
241
+ bufread = Box :: new ( BufReader :: new ( File :: open ( & args[ 2 ] ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to open input file '{}': {}" , args[ 2 ] , err) ) ) ) ;
230
242
}
243
+ else { fatalerr ! ( "Usage: {} <configfile> [xmlfile]" , args[ 0 ] ) ; }
231
244
232
245
let config = {
233
246
let mut config_str = String :: new ( ) ;
234
- File :: open ( & args[ 1 ] ) . unwrap ( ) . read_to_string ( & mut config_str) . unwrap ( ) ;
235
- & YamlLoader :: load_from_str ( & config_str) . unwrap_or_else ( |err| { eprintln ! ( "Syntax error in configuration file: {}" , err) ; std:: process:: exit ( 0 ) ; } ) [ 0 ]
247
+ let mut file = File :: open ( & args[ 1 ] ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to open configuration file '{}': {}" , args[ 1 ] , err) ) ;
248
+ file. read_to_string ( & mut config_str) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to read configuration file '{}': {}" , args[ 1 ] , err) ) ;
249
+ & YamlLoader :: load_from_str ( & config_str) . unwrap_or_else ( |err| fatalerr ! ( "Error: invalid syntax in configuration file: {}" , err) ) [ 0 ]
236
250
} ;
237
251
238
252
let mut reader;
@@ -246,12 +260,12 @@ fn main() -> std::io::Result<()> {
246
260
let mut filtercount = 0 ;
247
261
let mut skipcount = 0 ;
248
262
249
- let rowpath = config[ "path" ] . as_str ( ) . expect ( "No valid 'path' entry in configuration file") ;
250
- let colspec = config[ "cols" ] . as_vec ( ) . expect ( "No valid 'cols' array in configuration file") ;
263
+ let rowpath = config[ "path" ] . as_str ( ) . unwrap_or_else ( || fatalerr ! ( "Error: no valid 'path' entry in configuration file") ) ;
264
+ let colspec = config[ "cols" ] . as_vec ( ) . unwrap_or_else ( || fatalerr ! ( "Error: no valid 'cols' array in configuration file") ) ;
251
265
let outfile = config[ "file" ] . as_str ( ) ;
252
266
let filemode = match config[ "mode" ] . is_badvalue ( ) {
253
267
true => "truncate" ,
254
- false => config[ "mode" ] . as_str ( ) . expect ( "Invalid 'mode' entry in configuration file")
268
+ false => config[ "mode" ] . as_str ( ) . unwrap_or_else ( || fatalerr ! ( "Error: invalid 'mode' entry in configuration file") )
255
269
} ;
256
270
let skip = config[ "skip" ] . as_str ( ) ;
257
271
let maintable = add_table ( rowpath, outfile, filemode, skip, colspec) ;
@@ -270,14 +284,14 @@ fn main() -> std::io::Result<()> {
270
284
match reader. read_event ( & mut buf) {
271
285
Ok ( Event :: Start ( ref e) ) => {
272
286
path. push ( '/' ) ;
273
- path. push_str ( reader. decode ( e. name ( ) ) . unwrap ( ) ) ;
287
+ path. push_str ( reader. decode ( e. name ( ) ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML tag '{}': {}" , String :: from_utf8_lossy ( e . name ( ) ) , err ) ) ) ;
274
288
if filtered || skipped { continue ; }
275
289
if path == table. skip {
276
290
skipped = true ;
277
291
continue ;
278
292
}
279
293
else if xmltotext {
280
- text. push_str ( & format ! ( "<{}>" , & e. unescape_and_decode( & reader) . unwrap ( ) ) ) ;
294
+ text. push_str ( & format ! ( "<{}>" , & e. unescape_and_decode( & reader) . unwrap_or_else ( |err| fatalerr! ( "Error: failed to decode XML tag '{}': {}" , String :: from_utf8_lossy ( e . name ( ) ) , err ) ) ) ) ;
281
295
continue ;
282
296
}
283
297
else if gmltoewkb {
@@ -307,7 +321,7 @@ fn main() -> std::io::Result<()> {
307
321
let key = reader. decode ( attr. key ) ;
308
322
match key {
309
323
Ok ( "srsName" ) => {
310
- let mut value = String :: from ( reader. decode ( & attr. value ) . unwrap ( ) ) ;
324
+ let mut value = String :: from ( reader. decode ( & attr. value ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML attribute '{}': {}" , String :: from_utf8_lossy ( & attr . value ) , err ) ) ) ;
311
325
if let Some ( i) = value. rfind ( "::" ) {
312
326
value = value. split_off ( i+2 ) ;
313
327
}
@@ -319,7 +333,7 @@ fn main() -> std::io::Result<()> {
319
333
}
320
334
} ,
321
335
Ok ( "srsDimension" ) => {
322
- let value = reader. decode ( & attr. value ) . unwrap ( ) ;
336
+ let value = reader. decode ( & attr. value ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML attribute '{}': {}" , String :: from_utf8_lossy ( & attr . value ) , err ) ) ;
323
337
match value. parse :: < u8 > ( ) {
324
338
Ok ( int) => {
325
339
if let Some ( geom) = gmlcoll. last_mut ( ) { geom. dims = int } ;
@@ -397,14 +411,14 @@ fn main() -> std::io::Result<()> {
397
411
Ok ( Event :: Text ( ref e) ) => {
398
412
if filtered || skipped { continue ; }
399
413
if xmltotext {
400
- text. push_str ( & e. unescape_and_decode ( & reader) . unwrap ( ) ) ;
414
+ text. push_str ( & e. unescape_and_decode ( & reader) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML text node '{}': {}" , String :: from_utf8_lossy ( e ) , err ) ) ) ;
401
415
continue ;
402
416
}
403
417
else if gmltoewkb {
404
418
if gmlpos {
405
- let value = String :: from ( & e. unescape_and_decode ( & reader) . unwrap ( ) ) ;
419
+ let value = String :: from ( & e. unescape_and_decode ( & reader) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML gmlpos '{}': {}" , String :: from_utf8_lossy ( e ) , err ) ) ) ;
406
420
for pos in value. split ( ' ' ) {
407
- gmlcoll. last_mut ( ) . unwrap ( ) . rings . last_mut ( ) . unwrap ( ) . push ( pos. parse ( ) . unwrap ( ) ) ;
421
+ gmlcoll. last_mut ( ) . unwrap ( ) . rings . last_mut ( ) . unwrap ( ) . push ( pos. parse ( ) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to parse GML pos '{}' into float: {}" , pos , err ) ) ) ;
408
422
}
409
423
}
410
424
continue ;
@@ -430,7 +444,7 @@ fn main() -> std::io::Result<()> {
430
444
break ;
431
445
}
432
446
}
433
- table. columns [ i] . value . borrow_mut ( ) . push_str ( & e. unescape_and_decode ( & reader) . unwrap ( ) . replace ( "\\ " , "\\ \\ " ) ) ;
447
+ table. columns [ i] . value . borrow_mut ( ) . push_str ( & e. unescape_and_decode ( & reader) . unwrap_or_else ( |err| fatalerr ! ( "Error: failed to decode XML text node '{}': {}" , String :: from_utf8_lossy ( e ) , err ) ) . replace ( "\\ " , "\\ \\ " ) ) ;
434
448
if let Some ( re) = & table. columns [ i] . include {
435
449
if !re. is_match ( & table. columns [ i] . value . borrow ( ) ) {
436
450
filtered = true ;
@@ -514,7 +528,7 @@ fn main() -> std::io::Result<()> {
514
528
}
515
529
} ,
516
530
Ok ( Event :: Eof ) => break ,
517
- Err ( e) => panic ! ( "Error at position {}: {:? }" , reader. buffer_position( ) , e) ,
531
+ Err ( e) => fatalerr ! ( "Error: failed to parse XML at position {}: {}" , reader. buffer_position( ) , e) ,
518
532
_ => ( )
519
533
}
520
534
buf. clear ( ) ;
@@ -525,5 +539,4 @@ fn main() -> std::io::Result<()> {
525
539
match filtercount { 0 => "" . to_owned( ) , n => format!( " ({} excluded)" , n) } ,
526
540
match skipcount { 0 => "" . to_owned( ) , n => format!( " ({} skipped)" , n) }
527
541
) ;
528
- Ok ( ( ) )
529
542
}
0 commit comments