/* * log - logging functions * * Copyright (C) 2009--2010 Enrico Zini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using GLib; namespace zavai { namespace log { public class Waypoint : Object { public time_t ts; public double lat; public double lon; public Waypoint() { if (gps.gps.fix_status() != libgps.STATUS_NO_FIX) { lat = gps.gps.info().fix.latitude; lon = gps.gps.info().fix.longitude; ts = (time_t)gps.gps.info().fix.time; } else { // Use 1000 as missing values lat = 1000; lon = 1000; ts = time_t(); } } public void writeInside(FileStream outfd) { var t = Time.gm(ts); outfd.printf(" \n", t.format("%Y-%m-%dT%H:%M:%SZ")); } } public class LogEntry : Waypoint { public string msg; public LogEntry() { base(); } public void write(FileStream outfd) { outfd.printf(" \n", lat, lon); writeInside(outfd); outfd.printf(" %s\n", Markup.escape_text(msg)); outfd.puts(" \n"); } } public class TrackEntry : Waypoint { public TrackEntry() { base(); } public void write(FileStream outfd) { outfd.printf(" \n", lat, lon); writeInside(outfd); outfd.puts(" \n"); } } public class Log : Object { public string tag; public string title; public List entries; public List track; public Log(string tag, string title) { this.tag = tag; this.title = title; entries = null; track = null; } public void add(string msg) { var entry = new LogEntry(); entry.msg = msg; entries.append(entry); } public void add_trackpoint() { track.append(new TrackEntry()); } public void save() { if (entries == null) return; // Directory where we save the log string dir = config.homedir + "/log-" + tag; DirUtils.create(dir, 0777); // First try with a plain name var t = Time.local(entries.data.ts); string basename = dir + "/" + t.format("%Y%m%d-%H%M%S"); string pathname = basename + ".gpx"; // Find a pathname that does not exist already for (int i = 1; FileUtils.test(pathname, FileTest.EXISTS); ++i) pathname = "%s-%d.gpx".printf(basename, i); // Write out var outfd = FileStream.open(pathname, "w"); if (outfd == null) { zavai.log.error("opening " + pathname + ": " + strerror(errno)); return; } write(outfd); outfd.flush(); } protected void writeTrack(FileStream outfd) { outfd.puts(" \n"); outfd.puts(" \n"); for (weak List i = track; i != null; i = i.next) i.data.write(outfd); outfd.puts(" \n"); outfd.puts(" \n"); } protected void writeEntries(FileStream outfd) { outfd.puts(" \n"); for (weak List i = entries; i != null; i = i.next) i.data.write(outfd); outfd.puts(" \n"); } protected void write(FileStream outfd) { outfd.puts("\n"); outfd.puts("\n"); outfd.puts(" \n"); outfd.printf(" %s\n", Markup.escape_text(title)); outfd.puts(" \n"); if (track != null) writeTrack(outfd); if (entries != null) writeEntries(outfd); outfd.puts(" \n"); } } enum LogParserState { NONE, METADATA, TRACK, WPT, } class LogParser: Object { const MarkupParser parser = { // It's a structure, not an object start,// when an element opens end, // when an element closes text, // when text is found null, // when comments are found null // when errors occur }; MarkupParseContext context = null; public Log result = null; LogParserState state = LogParserState.NONE; string cur_text = ""; construct { context = new MarkupParseContext( parser, // the structure with the callbacks 0, // MarkupParseFlags this, // extra argument for the callbacks, methods in this case destroy // when the parsing ends ); } void destroy() { cur_text = ""; } public bool parse(string content, ssize_t len = -1) throws MarkupError { return context.parse(content, len); } /* outfd.puts(" \n"); outfd.printf(" %s\n", Markup.escape_text(title)); outfd.puts(" \n"); if (track != null) writeTrack(outfd); if (entries != null) writeEntries(outfd); outfd.puts(" \n"); */ void start (MarkupParseContext context, string name, string[] attr_names, string[] attr_values) throws MarkupError { if (name == "gpx") { state = LogParserState.NONE; result = new Log("TODO:TAG", "TODO:TITLE"); } else if (name == "metadata") { state = LogParserState.METADATA; } else if (name == "wpt") { state = LogParserState.WPT; } else if (name == "trkseg") { state = LogParserState.TRACK; } cur_text = ""; } void end (MarkupParseContext context, string name) throws MarkupError { if (name == "state") if (state == LogParserState.METADATA) result.title = cur_text; } void text (MarkupParseContext context, string text, size_t text_len) throws MarkupError { cur_text += text; } } public class Logger : Resource, Object { protected List logs; public Logger() { logs = null; zavai.registry.register(this); } protected void start_trace() { gps.gps.pos_changed += on_pos_changed; } protected void end_trace() { gps.gps.pos_changed -= on_pos_changed; } protected void on_pos_changed() { for (weak List i = logs; i != null; i = i.next) i.data.add_trackpoint(); } protected void pop(Log log) { for (weak List i = logs; i != null; i = i.next) if (i.data == log) logs.delete_link(i); } public Log start(string tag, string title) { bool was_empty = (logs == null); Log res = new Log(tag, title); logs.append(res); if (was_empty) start_trace(); return res; } public void end(Log log) { pop(log); log.save(); if (logs == null) end_trace(); } public Log load(string fname) { string contents; size_t length; FileUtils.get_contents(fname, out contents, out length); LogParser parser = new LogParser(); parser.parse(contents, (ssize_t)length); return parser.result; } public void instant(string tag, string msg) { var log = new Log(tag, msg); log.add(msg); log.save(); } public void shutdown() { bool had_logs = (logs != null); while (logs != null) { logs.data.save(); logs.delete_link(logs); } if (had_logs) end_trace(); } } public void error(string s) { stderr.printf("%s\n", s); } public void warning(string s) { stderr.printf("%s\n", s); } public void info(string s) { stderr.printf("%s\n", s); } public void debug(string s) { stderr.printf("%s\n", s); } Logger log = null; public void init() { log = new Logger(); } } }