@@ -5,6 +5,7 @@ use std::io::{Read, Write, stdout};
5
5
use std:: fs:: File ;
6
6
use std:: path:: Path ;
7
7
use std:: env;
8
+ use std:: cell:: RefCell ;
8
9
use std:: time:: Instant ;
9
10
use quick_xml:: Reader ;
10
11
use quick_xml:: events:: Event ;
@@ -13,30 +14,34 @@ use yaml_rust::yaml::Yaml;
13
14
14
15
struct Table < ' a > {
15
16
path : String ,
16
- file : Box < dyn Write > ,
17
+ file : RefCell < Box < dyn Write > > ,
17
18
columns : Vec < Column < ' a > >
18
19
}
19
20
impl < ' a > Table < ' a > {
20
- fn new < ' b > ( path : & str , file : Option < & str > ) -> Table < ' b > {
21
+ fn new ( path : & str , file : Option < & str > ) -> Table < ' a > {
21
22
Table {
22
23
path : String :: from ( path) ,
23
24
file : match file {
24
- None => Box :: new ( stdout ( ) ) ,
25
- Some ( ref file) => Box :: new ( File :: create ( & Path :: new ( file) ) . unwrap ( ) )
25
+ None => RefCell :: new ( Box :: new ( stdout ( ) ) ) ,
26
+ Some ( ref file) => RefCell :: new ( Box :: new ( File :: create ( & Path :: new ( file) ) . unwrap ( ) ) )
26
27
} ,
27
28
columns : Vec :: new ( )
28
29
}
29
30
}
31
+ fn write ( & self , text : & str ) {
32
+ self . file . borrow_mut ( ) . write_all ( & text. as_bytes ( ) ) . expect ( "Write error encountered; exiting..." ) ;
33
+ }
30
34
}
31
35
32
36
struct Column < ' a > {
33
37
name : String ,
34
38
path : String ,
35
- value : String ,
39
+ value : RefCell < String > ,
36
40
convert : Option < & ' a str > ,
37
41
search : Option < & ' a str > ,
38
42
replace : Option < & ' a str > ,
39
- consol : Option < & ' a str >
43
+ consol : Option < & ' a str > ,
44
+ subtable : Option < Table < ' a > >
40
45
}
41
46
42
47
struct Geometry {
@@ -57,7 +62,7 @@ impl Geometry {
57
62
}
58
63
}
59
64
60
- fn gml_to_ewkb ( value : & mut String , geom : & Geometry ) {
65
+ fn gml_to_ewkb ( cell : & RefCell < String > , geom : & Geometry ) {
61
66
let mut ewkb = vec ! [ 1 , geom. gtype, 0 , 0 ] ;
62
67
let code = match geom. dims {
63
68
2 => 32 ,
@@ -76,25 +81,33 @@ fn gml_to_ewkb(value: &mut String, geom: &Geometry) {
76
81
ewkb. extend_from_slice ( & pos. to_le_bytes ( ) ) ;
77
82
}
78
83
}
84
+ let mut value = cell. borrow_mut ( ) ;
79
85
for byte in ewkb. iter ( ) {
80
86
value. push_str ( & format ! ( "{:02X}" , byte) ) ;
81
87
}
82
88
}
83
89
84
- fn add_table < ' a > ( tables : & mut Vec < Table < ' a > > , rowpath : & str , outfile : Option < & str > , colspec : & ' a Vec < Yaml > ) {
85
- tables. push ( Table :: new ( rowpath, outfile) ) ;
86
- let table = tables. last_mut ( ) . unwrap ( ) ;
90
+ fn add_table < ' a > ( rowpath : & str , outfile : Option < & str > , colspec : & ' a Vec < Yaml > ) -> Table < ' a > {
91
+ let mut table = Table :: new ( rowpath, outfile) ;
87
92
for col in colspec {
88
93
let name = col[ "name" ] . as_str ( ) . expect ( "Column has no 'name' entry in configuration file" ) ;
89
94
let colpath = col[ "path" ] . as_str ( ) . expect ( "Column has no 'path' entry in configuration file" ) ;
95
+ let mut path = String :: from ( rowpath) ;
96
+ path. push_str ( colpath) ;
97
+ let subtable: Option < Table > = match col[ "cols" ] . is_badvalue ( ) {
98
+ true => None ,
99
+ false => {
100
+ let file = col[ "file" ] . as_str ( ) . expect ( "Subtable has no 'file' entry" ) ;
101
+ Some ( add_table ( & path, Some ( & file) , col[ "cols" ] . as_vec ( ) . expect ( "Subtable 'cols' entry is not an array" ) ) )
102
+ }
103
+ } ;
90
104
let convert = col[ "convert" ] . as_str ( ) ;
91
105
let search = col[ "search" ] . as_str ( ) ;
92
106
let replace = col[ "replace" ] . as_str ( ) ;
93
107
let consol = col[ "consol" ] . as_str ( ) ;
94
- let mut path = String :: from ( rowpath) ;
95
- path. push_str ( colpath) ;
96
- table. columns . push ( Column { name : name. to_string ( ) , path, value : String :: new ( ) , convert, search, replace, consol } ) ;
108
+ table. columns . push ( Column { name : name. to_string ( ) , path, value : RefCell :: new ( String :: new ( ) ) , convert, search, replace, consol, subtable } ) ;
97
109
}
110
+ table
98
111
}
99
112
100
113
fn main ( ) -> std:: io:: Result < ( ) > {
@@ -104,9 +117,11 @@ fn main() -> std::io::Result<()> {
104
117
return Ok ( ( ) ) ;
105
118
}
106
119
107
- let mut config_str = String :: new ( ) ;
108
- File :: open ( & args[ 1 ] ) . unwrap ( ) . read_to_string ( & mut config_str) . unwrap ( ) ;
109
- let config = & YamlLoader :: load_from_str ( & config_str) . unwrap ( ) [ 0 ] ;
120
+ let config = {
121
+ let mut config_str = String :: new ( ) ;
122
+ File :: open ( & args[ 1 ] ) . unwrap ( ) . read_to_string ( & mut config_str) . unwrap ( ) ;
123
+ & YamlLoader :: load_from_str ( & config_str) . unwrap ( ) [ 0 ]
124
+ } ;
110
125
111
126
let mut reader;
112
127
reader = Reader :: from_file ( & args[ 2 ] ) . unwrap ( ) ;
@@ -119,9 +134,9 @@ fn main() -> std::io::Result<()> {
119
134
let rowpath = config[ "path" ] . as_str ( ) . expect ( "No valid 'rowpath' entry in configuration file" ) ;
120
135
let colspec = config[ "cols" ] . as_vec ( ) . expect ( "No valid 'columns' array in configuration file" ) ;
121
136
let outfile = config[ "file" ] . as_str ( ) ;
122
- let mut tables : Vec < Table > = Vec :: new ( ) ;
123
- add_table ( & mut tables, rowpath , outfile , colspec ) ;
124
- let table = tables . first_mut ( ) . unwrap ( ) ;
137
+ let maintable = add_table ( rowpath , outfile , colspec ) ;
138
+ let mut tables: Vec < & Table > = Vec :: new ( ) ;
139
+ let mut table = & maintable ;
125
140
126
141
let mut xmltotext = false ;
127
142
let mut text = String :: new ( ) ;
@@ -188,6 +203,11 @@ fn main() -> std::io::Result<()> {
188
203
else if path. len ( ) > table. path . len ( ) {
189
204
for i in 0 ..table. columns . len ( ) {
190
205
if path == table. columns [ i] . path {
206
+ if table. columns [ i] . subtable . is_some ( ) {
207
+ tables. push ( table) ;
208
+ table = & table. columns [ i] . subtable . as_ref ( ) . unwrap ( ) ;
209
+ break ;
210
+ }
191
211
match table. columns [ i] . convert {
192
212
None => ( ) ,
193
213
Some ( "xml-to-text" ) => xmltotext = true ,
@@ -217,38 +237,44 @@ fn main() -> std::io::Result<()> {
217
237
if path == table. columns [ i] . path {
218
238
match table. columns [ i] . consol {
219
239
None => {
220
- if !table. columns [ i] . value . is_empty ( ) {
240
+ if !table. columns [ i] . value . borrow ( ) . is_empty ( ) {
221
241
eprintln ! ( "Column '{}' has multiple occurrences without a consolidation method; using 'first'" , table. columns[ i] . name) ;
222
242
break ;
223
243
}
224
244
} ,
225
245
Some ( "append" ) => {
226
- if !table. columns [ i] . value . is_empty ( ) { table. columns [ i] . value . push ( ',' ) ; }
246
+ if !table. columns [ i] . value . borrow ( ) . is_empty ( ) { table. columns [ i] . value . borrow_mut ( ) . push ( ',' ) ; }
227
247
} ,
228
248
Some ( s) => {
229
249
eprintln ! ( "Column '{}' has invalid consolidation method {}" , table. columns[ i] . name, s) ;
230
250
break ;
231
251
}
232
252
}
233
- table. columns [ i] . value . push_str ( & e. unescape_and_decode ( & reader) . unwrap ( ) . replace ( "\\ " , "\\ \\ " ) ) ;
253
+ table. columns [ i] . value . borrow_mut ( ) . push_str ( & e. unescape_and_decode ( & reader) . unwrap ( ) . replace ( "\\ " , "\\ \\ " ) ) ;
234
254
break ;
235
255
}
236
256
}
237
257
} ,
238
258
Ok ( Event :: End ( _) ) => {
239
259
if path == table. path {
260
+ if !tables. is_empty ( ) {
261
+ table. write ( & tables. last ( ) . unwrap ( ) . columns [ 0 ] . value . borrow ( ) ) ;
262
+ table. write ( "\t " ) ;
263
+ }
240
264
for i in 0 ..table. columns . len ( ) {
241
- if i > 0 { write ! ( table. file , "\t " ) ? ; }
242
- if table. columns [ i] . value . is_empty ( ) { write ! ( table. file , "\\ N" ) ? ; }
265
+ if i > 0 { table. write ( "\t " ) ; }
266
+ if table. columns [ i] . value . borrow ( ) . is_empty ( ) { table. write ( "\\ N" ) ; }
243
267
else {
244
268
if let ( Some ( s) , Some ( r) ) = ( table. columns [ i] . search , table. columns [ i] . replace ) {
245
- table. columns [ i] . value = table. columns [ i] . value . replace ( s, r) ;
269
+ let mut value = table. columns [ i] . value . borrow_mut ( ) ;
270
+ * value = value. replace ( s, r) ;
246
271
}
247
- write ! ( table. file , "{}" , table . columns[ i] . value) ? ;
248
- table. columns [ i] . value . clear ( ) ;
272
+ table . write ( & table. columns [ i] . value . borrow ( ) ) ;
273
+ table. columns [ i] . value . borrow_mut ( ) . clear ( ) ;
249
274
}
250
275
}
251
- writeln ! ( table. file) ?;
276
+ table. write ( "\n " ) ;
277
+ if !tables. is_empty ( ) { table = tables. pop ( ) . unwrap ( ) ; }
252
278
}
253
279
let i = path. rfind ( '/' ) . unwrap ( ) ;
254
280
let tag = path. split_off ( i) ;
@@ -260,7 +286,7 @@ fn main() -> std::io::Result<()> {
260
286
if let ( Some ( s) , Some ( r) ) = ( table. columns [ i] . search , table. columns [ i] . replace ) {
261
287
text = text. replace ( s, r) ;
262
288
}
263
- table. columns [ i] . value . push_str ( & text) ;
289
+ table. columns [ i] . value . borrow_mut ( ) . push_str ( & text) ;
264
290
text. clear ( ) ;
265
291
break ;
266
292
}
@@ -270,7 +296,7 @@ fn main() -> std::io::Result<()> {
270
296
for i in 0 ..table. columns . len ( ) {
271
297
if path == table. columns [ i] . path {
272
298
gmltoewkb = false ;
273
- gml_to_ewkb ( & mut table. columns [ i] . value , & gmlgeom) ;
299
+ gml_to_ewkb ( & table. columns [ i] . value , & gmlgeom) ;
274
300
gmlgeom. reset ( ) ;
275
301
break ;
276
302
}
0 commit comments