2 * log - logging functions
4 * Copyright (C) 2009--2010 Enrico Zini <enrico@enricozini.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 public class Waypoint : Object
34 if (gps.gps.fix_status() != libgps.STATUS_NO_FIX)
36 lat = gps.gps.info().fix.latitude;
37 lon = gps.gps.info().fix.longitude;
38 ts = (time_t)gps.gps.info().fix.time;
40 // Use 1000 as missing values
47 public void writeInside(FileStream outfd)
50 outfd.printf(" <time>%s</time>\n", t.format("%Y-%m-%dT%H:%M:%S%z"));
55 public class LogEntry : Waypoint
64 public void write(FileStream outfd)
66 outfd.printf(" <wpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
68 outfd.printf(" <name>%s</name>\n", Markup.escape_text(msg));
69 outfd.puts(" </wpt>\n");
73 public class TrackEntry : Waypoint
80 public void write(FileStream outfd)
82 outfd.printf(" <trkpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
84 outfd.puts(" </trkpt>\n");
89 public class Log : Object
94 public List<LogEntry> entries;
95 public List<TrackEntry> track;
97 public Log(string tag, string title, bool acked=false)
106 public void add(string msg)
108 var entry = new LogEntry();
110 entries.append(entry);
113 public void add_trackpoint()
115 track.append(new TrackEntry());
120 if (entries == null) return;
122 // Directory where we save the log
125 dir = config.homedir + "/archive";
127 dir = config.homedir + "/log";
128 DirUtils.create(dir, 0777);
130 // First try with a plain name
131 var t = Time.local(entries.data.ts);
132 string basename = dir + "/" + t.format("%Y%m%d-%H%M%S") + "-" + tag;
134 string pathname = basename + ".gpx";
136 // Find a pathname that does not exist already
137 for (int i = 1; FileUtils.test(pathname, FileTest.EXISTS); ++i)
138 pathname = "%s-%d.gpx".printf(basename, i);
141 var outfd = FileStream.open(pathname, "w");
144 zavai.log.error("opening " + pathname + ": " + strerror(errno));
157 protected void writeTrack(FileStream outfd)
159 outfd.puts(" <trk>\n");
160 outfd.puts(" <trkseg>\n");
161 for (weak List<TrackEntry> i = track; i != null; i = i.next)
163 outfd.puts(" </trkseg>\n");
164 outfd.puts(" </trk>\n");
167 protected void writeEntries(FileStream outfd)
169 for (weak List<LogEntry> i = entries; i != null; i = i.next)
173 protected void write(FileStream outfd)
175 outfd.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
176 outfd.puts("<gpx version=\"1.0\"\n");
177 outfd.printf(" creator=\"zavai %s\"\n", zavai.config.version);
178 outfd.puts(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
179 outfd.puts(" xmlns=\"http://www.topografix.com/GPX/1/0\"\n");
180 outfd.puts(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
181 outfd.puts(" <metadata>\n");
182 outfd.printf(" <name>%s</name>\n", Markup.escape_text(title));
183 outfd.puts(" </metadata>\n");
184 if (track != null) writeTrack(outfd);
185 if (entries != null) writeEntries(outfd);
186 outfd.puts(" </gpx>\n");
190 enum LogParserState {
197 class LogParser: Object
199 const MarkupParser parser = { // It's a structure, not an object
200 start,// when an element opens
201 end, // when an element closes
202 text, // when text is found
203 null, // when comments are found
204 null // when errors occur
207 MarkupParseContext context = null;
208 public Log result = null;
209 LogParserState state = LogParserState.NONE;
210 string cur_text = "";
211 LogEntry cur_logentry = null;
212 TrackEntry cur_trackentry = null;
216 context = new MarkupParseContext(
217 parser, // the structure with the callbacks
218 0, // MarkupParseFlags
219 this, // extra argument for the callbacks, methods in this case
220 destroy // when the parsing ends
228 cur_trackentry = null;
231 public bool parse(string content, ssize_t len = -1) throws MarkupError
233 string oldtz = Environment.get_variable("TZ");
234 Environment.set_variable("TZ", "UTC", true);
235 bool res = context.parse(content, len);
237 Environment.unset_variable("TZ");
239 Environment.set_variable("TZ", oldtz, true);
243 void parse_attrs(Waypoint w, string[] attr_names, string[] attr_values)
247 for (int i = 0; attr_names[i] != null; ++i)
249 if (attr_names[i] == "lat")
250 w.lat = attr_values[i].to_double();
251 else if (attr_names[i] == "lon")
252 w.lon = attr_values[i].to_double();
256 void start (MarkupParseContext context, string name,
257 string[] attr_names, string[] attr_values) throws MarkupError
261 state = LogParserState.NONE;
262 result = new Log("TODO:TAG", "TODO:TITLE");
263 } else if (name == "metadata") {
264 state = LogParserState.METADATA;
265 } else if (name == "wpt") {
266 cur_logentry = new LogEntry();
267 parse_attrs(cur_logentry, attr_names, attr_values);
268 result.entries.append(cur_logentry);
269 state = LogParserState.WPT;
270 } else if (name == "trkpt") {
271 cur_trackentry = new TrackEntry();
272 parse_attrs(cur_trackentry, attr_names, attr_values);
273 result.track.append(cur_trackentry);
274 state = LogParserState.TRACK;
279 void end (MarkupParseContext context, string name) throws MarkupError
285 case LogParserState.METADATA:
286 result.title = cur_text;
288 case LogParserState.WPT:
289 cur_logentry.msg = cur_text;
293 else if (name == "time")
296 t.strptime(cur_text, "%Y-%m-%dT%H:%M:%S%z");
297 if (state == LogParserState.WPT)
298 cur_logentry.ts = t.mktime();
299 else if (state == LogParserState.TRACK)
300 cur_trackentry.ts = t.mktime();
304 void text (MarkupParseContext context,
305 string text, size_t text_len) throws MarkupError
311 public class Logger : Resource, Object
313 protected List<Log> logs;
318 zavai.registry.register(this);
321 protected void start_trace()
323 gps.gps.pos_changed += on_pos_changed;
326 protected void end_trace()
328 gps.gps.pos_changed -= on_pos_changed;
331 protected void on_pos_changed()
333 for (weak List<Log> i = logs; i != null; i = i.next)
334 i.data.add_trackpoint();
337 protected void pop(Log log)
339 for (weak List<Log> i = logs; i != null; i = i.next)
344 public Log start(string tag, string title)
346 bool was_empty = (logs == null);
347 Log res = new Log(tag, title);
349 if (was_empty) start_trace();
353 public void end(Log log)
357 if (logs == null) end_trace();
360 public Log load(string fname)
364 FileUtils.get_contents(fname, out contents, out length);
365 LogParser parser = new LogParser();
366 parser.parse(contents, (ssize_t)length);
367 return parser.result;
370 protected size_t list_dir(string dir, ref List<string> res)
373 var d = File.new_for_path(dir);
374 var enumerator = d.enumerate_children(FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
376 while ((file_info = enumerator.next_file(null)) != null)
378 if (!file_info.get_name().has_suffix(".gpx")) continue;
379 res.append(file_info.get_name());
385 public string[] list_entries(bool only_unacked=true)
388 List<string> entries = new List<string>();
390 count += list_dir(config.homedir + "/archive", ref entries);
391 count += list_dir(config.homedir + "/log", ref entries);
392 string[] res = new string[count+1];
394 for (weak List<string> i = entries; i != null; i = i.next)
400 public void instant(string tag, string msg)
402 var log = new Log(tag, msg);
407 public void shutdown()
409 bool had_logs = (logs != null);
413 logs.delete_link(logs);
415 if (had_logs) end_trace();
419 public void error(string s)
421 stderr.printf("%s\n", s);
423 public void warning(string s)
425 stderr.printf("%s\n", s);
427 public void info(string s)
429 stderr.printf("%s\n", s);
431 public void debug(string s)
433 stderr.printf("%s\n", s);