3 * Copyright (c) 2008 Paolo Molaro lupus@oddwiz.org
4 * License: MIT/X11, see the MIT.X11 file.
11 using System
.Collections
.Generic
;
16 static string[] way_types
= new string[] {};
19 static string[] allowed_lowercase = new string[] {
20 "da", "di", "de", "del", "dei", "delle", "degli", "dell", "della", "dello",
21 "sul", "sull", "d", "al", "a", "in", "e"
25 static string[] abbreviations
= new string[] {};
27 static Dictionary
<string,string> wrong_tags_in_nodes
= new Dictionary
<string,string> ();
28 static Dictionary
<string,string> wrong_tags_in_ways
= new Dictionary
<string,string> ();
30 static void LoadRules (string filename
)
33 filename
= Path
.Combine (Environment
.GetFolderPath (Environment
.SpecialFolder
.ApplicationData
), "osm-helpers/osm-check.rules");
34 XmlTextReader reader
= new XmlTextReader (filename
);
35 List
<string> abbrs
= new List
<string> ();
36 List
<string> ways
= new List
<string> ();
38 while (reader
.Read ()) {
39 if (reader
.NodeType
== XmlNodeType
.Element
) {
40 string name
= reader
.Name
;
42 if (name
== "osmrules") {
48 for (int i
= 0; i
< reader
.AttributeCount
; ++i
) {
49 reader
.MoveToAttribute (i
);
50 if (reader
.Name
== "from")
52 else if (reader
.Name
== "to")
55 throw new Exception ("invalid attribute in abbr element");
57 if (from == null || to
== null)
58 throw new Exception ("missing attributes in abbr element");
61 } else if (name
== "way") {
63 for (int i
= 0; i
< reader
.AttributeCount
; ++i
) {
64 reader
.MoveToAttribute (i
);
65 if (reader
.Name
== "name")
68 throw new Exception ("invalid attribute in way element");
71 throw new Exception ("missing name attribute in way element");
73 } else if (name
== "remove") {
77 for (int i
= 0; i
< reader
.AttributeCount
; ++i
) {
78 reader
.MoveToAttribute (i
);
79 if (reader
.Name
== "type")
81 else if (reader
.Name
== "tag")
83 else if (reader
.Name
== "val")
86 throw new Exception ("invalid attribute in remove element");
88 if (type
== null || tag
== null)
89 throw new Exception ("missing type or tag attribute in remove element");
91 wrong_tags_in_ways
[tag
] = val
;
92 else if (type
== "node")
93 wrong_tags_in_nodes
[tag
] = val
;
95 throw new Exception ("invalid type attribute in remove element");
97 throw new Exception ("invalid element");
101 abbreviations
= abbrs
.ToArray ();
102 way_types
= ways
.ToArray ();
105 static XmlTextWriter writer
;
107 static void EmitElement (OsmObject obj
, string tag
, string old
, string newv
)
109 writer
.WriteStartElement (obj
.ObjectType
);
110 writer
.WriteAttributeString ("id", obj
.ID
.ToString ());
111 writer
.WriteAttributeString ("tag", tag
);
112 writer
.WriteAttributeString ("old", old
);
113 writer
.WriteAttributeString ("new", newv
);
114 writer
.WriteAttributeString ("user", obj
.User
);
115 writer
.WriteEndElement ();
118 static string TrimIfNeeded (string tag
, string val
)
120 // we avoid changing note, as this makes it easier to track down
121 // who actually wrote the note and ask them about it
124 if (char.IsWhiteSpace (val
[0]) || char.IsWhiteSpace (val
[val
.Length
- 1]))
126 for (int i
= 0; i
< val
.Length
; ++i
) {
127 if (char.IsWhiteSpace (val
[i
]) && char.IsWhiteSpace (val
[i
+ 1])) {
128 // good enough for the use case
129 val
= val
.Remove (i
+ 1, 1);
136 static string CheckStartWord (string tag
, string val
)
140 foreach (string s
in way_types
) {
141 if (!val
.StartsWith (s
) && val
.StartsWith (s
, StringComparison
.OrdinalIgnoreCase
)) {
142 if (val
.Length
> s
.Length
&& !char.IsWhiteSpace (val
[s
.Length
]))
144 string newv
= s
+ val
.Substring (s
.Length
);
151 static string CheckAbbreviations (string val
)
153 for (int i
= 0; i
< abbreviations
.Length
; i
+= 2) {
154 string s
= abbreviations
[i
];
155 // consider the abbreviation in any case variant
156 if (val
.StartsWith (s
, StringComparison
.OrdinalIgnoreCase
)) {
157 if (val
.Length
> s
.Length
&& !char.IsWhiteSpace (val
[s
.Length
]))
159 string newv
= abbreviations
[i
+ 1] + val
.Substring (s
.Length
);
166 static string CheckAllowedTags (OsmObject obj
, string tag
, string val
)
169 if (wrong_tags_in_nodes
.ContainsKey (tag
)) {
170 string n
= wrong_tags_in_nodes
[tag
];
171 if (n
== "" || n
== val
)
175 } else if (obj
is Way
) {
176 if (wrong_tags_in_ways
.ContainsKey (tag
)) {
177 string n
= wrong_tags_in_ways
[tag
];
178 if (n
== "" || n
== val
)
187 static string CheckAllowedLowercase (OsmObject obj, string tag, string val)
189 // just for names, but we may want to consider only highways as well
190 if (tag != "name" || !(obj is Way))
192 if (obj ["highway"] == null)
194 for (int i = 0; i < val.Length; ++i) {
195 if (char.IsLower (val [i])) {
197 while (j < val.Length && (!char.IsWhiteSpace (val [j]) && val [j] != '\''))
200 string word = val.Substring (i, count);
202 foreach (string allowed in allowed_lowercase) {
203 if (string.CompareOrdinal (word, allowed) == 0) {
209 StringBuilder sb = new StringBuilder (val);
210 sb [i] = char.ToUpper (val [i]);
211 Console.WriteLine ("{0} changed to {1}", val, sb.ToString ());
216 while (i < val.Length && (!char.IsWhiteSpace (val [i]) && val [i] != '\''))
218 while (i < val.Length && (char.IsWhiteSpace (val [i]) || val [i] == '\''))
231 static void Usage_r (int retval
)
233 Console
.WriteLine ("Usage: osm-check [OPTIONS] file.osm");
234 Console
.WriteLine (" osm-check [OPTIONS] lat lon [delta]");
235 Console
.WriteLine (" osm-check --help");
236 Console
.WriteLine ("Options:");
237 Console
.WriteLine ("\t--help Print the help and exit");
238 Console
.WriteLine ("\t--rules rules_file Read the checking rules from rules_file");
239 Console
.WriteLine ("\t--out out_file Output the changes to out_file (default: stdout)");
240 Environment
.Exit (retval
);
243 static int Main (string[] args
)
247 string outfile
= null;
253 for (int i
= 0; i
< args
.Length
; ++i
) {
254 if (args
[i
] == "--help") {
256 } else if (args
[i
] == "--rules") {
257 if (++i
>= args
.Length
)
260 } else if (args
[i
] == "--out") {
261 if (++i
>= args
.Length
)
265 switch (args
.Length
- i
) {
270 delta
= double.Parse (args
[i
+ 2]);
273 lat
= double.Parse (args
[i
+ 0]);
274 lon
= double.Parse (args
[i
+ 1]);
283 if (file
== null && !coords
)
287 } catch (Exception e
) {
288 Console
.WriteLine ("Cannot load rules: {0}", e
.Message
);
292 DataBase db
= new DataBase ();
293 IEnumerable
<OsmObject
> list
;
295 list
= DataBase
.LoadObjects (file
);
297 list
= db
.Load (lon
-delta
, lat
-delta
, lon
+delta
, lat
+delta
);
301 outstream
= Console
.OpenStandardOutput ();
303 outstream
= File
.Create (outfile
);
304 writer
= new XmlTextWriter (outstream
, new UTF8Encoding (false, false));
305 writer
.WriteStartDocument ();
306 writer
.WriteStartElement ("osmchanges");
307 writer
.Formatting
= Formatting
.Indented
;
308 foreach (OsmObject obj
in list
) {
309 foreach (string tag
in obj
.Tags
) {
310 string val
= obj
[tag
];
311 if (val
== null || val
.Length
== 0)
313 string newv
= TrimIfNeeded (tag
, val
);
314 if ((object)val
!= (object)newv
) {
315 EmitElement (obj
, tag
, val
, newv
);
318 newv
= CheckStartWord (tag
, val
);
319 if ((object)val
!= (object)newv
) {
320 EmitElement (obj
, tag
, val
, newv
);
323 newv
= CheckAbbreviations (val
);
324 if ((object)val
!= (object)newv
) {
325 EmitElement (obj
, tag
, val
, newv
);
328 newv
= CheckAllowedTags (obj
, tag
, val
);
329 if ((object)val
!= (object)newv
) {
330 EmitElement (obj
, tag
, val
, newv
);
334 * too much noise for now
335 newv = CheckAllowedLowercase (obj, tag, val);
336 if ((object)val != (object)newv) {
337 EmitElement (obj, tag, val, newv);
342 writer
.WriteEndElement ();
343 writer
.WriteEndDocument ();