public void writeInside(FileStream outfd)
{
var t = Time.gm(ts);
- outfd.printf(" <time>%s</time>\n", t.format("%Y-%m-%dT%H:%M:%SZ"));
+ outfd.printf(" <time>%s</time>\n", t.format("%Y-%m-%dT%H:%M:%S%z"));
}
}
public class Log : Object
{
- public uint id;
public string tag;
public string title;
+ public bool acked;
public List<LogEntry> entries;
public List<TrackEntry> track;
- public Log(uint id, string tag, string title)
+ public Log(string tag, string title, bool acked=false)
{
- this.id = id;
this.tag = tag;
this.title = title;
+ this.acked = acked;
entries = null;
track = null;
}
if (entries == null) return;
// Directory where we save the log
- string dir = config.homedir + "/log-" + tag;
+ string dir;
+ if (acked)
+ dir = config.homedir + "/archive";
+ else
+ dir = config.homedir + "/log";
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 basename = dir + "/" + t.format("%Y%m%d-%H%M%S") + "-" + tag;
string pathname = basename + ".gpx";
outfd.flush();
}
+ public void dump()
+ {
+ write(stderr);
+ }
+
protected void writeTrack(FileStream outfd)
{
outfd.puts(" <trk>\n");
protected void writeEntries(FileStream outfd)
{
- outfd.puts(" <wpt>\n");
for (weak List<LogEntry> i = entries; i != null; i = i.next)
i.data.write(outfd);
- outfd.puts(" </wpt>\n");
}
protected void write(FileStream outfd)
}
}
+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 = "";
+ LogEntry cur_logentry = null;
+ TrackEntry cur_trackentry = null;
+
+ 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 = "";
+ cur_logentry = null;
+ cur_trackentry = null;
+ }
+
+ public bool parse(string content, ssize_t len = -1) throws MarkupError
+ {
+ string oldtz = Environment.get_variable("TZ");
+ Environment.set_variable("TZ", "UTC", true);
+ bool res = context.parse(content, len);
+ if (oldtz == null)
+ Environment.unset_variable("TZ");
+ else
+ Environment.set_variable("TZ", oldtz, true);
+ return res;
+ }
+
+ void parse_attrs(Waypoint w, string[] attr_names, string[] attr_values)
+ {
+ w.lat = 1000;
+ w.lon = 1000;
+ for (int i = 0; attr_names[i] != null; ++i)
+ {
+ if (attr_names[i] == "lat")
+ w.lat = attr_values[i].to_double();
+ else if (attr_names[i] == "lon")
+ w.lon = attr_values[i].to_double();
+ }
+ }
+
+ 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") {
+ cur_logentry = new LogEntry();
+ parse_attrs(cur_logentry, attr_names, attr_values);
+ result.entries.append(cur_logentry);
+ state = LogParserState.WPT;
+ } else if (name == "trkpt") {
+ cur_trackentry = new TrackEntry();
+ parse_attrs(cur_trackentry, attr_names, attr_values);
+ result.track.append(cur_trackentry);
+ state = LogParserState.TRACK;
+ }
+ cur_text = "";
+ }
+
+ void end (MarkupParseContext context, string name) throws MarkupError
+ {
+ if (name == "name")
+ {
+ switch (state)
+ {
+ case LogParserState.METADATA:
+ result.title = cur_text;
+ break;
+ case LogParserState.WPT:
+ cur_logentry.msg = cur_text;
+ break;
+ }
+ }
+ else if (name == "time")
+ {
+ Time t = Time();
+ t.strptime(cur_text, "%Y-%m-%dT%H:%M:%S%z");
+ if (state == LogParserState.WPT)
+ cur_logentry.ts = t.mktime();
+ else if (state == LogParserState.TRACK)
+ cur_trackentry.ts = t.mktime();
+ }
+ }
+
+ void text (MarkupParseContext context,
+ string text, size_t text_len) throws MarkupError
+ {
+ cur_text += text;
+ }
+}
+
public class Logger : Resource, Object
{
protected List<Log> logs;
- protected uint seq;
public Logger()
{
logs = null;
- seq = 0;
-
zavai.registry.register(this);
}
i.data.add_trackpoint();
}
- protected uint gen_seq()
+ protected void pop(Log log)
{
- // Increase avoiding 0 on rollover
- while (true)
- {
- if (++seq == 0) ++seq;
- bool found = false;
- for (weak List<Log> i = logs; i != null; i = i.next)
- {
- if (i.data.id == seq)
- {
- found = true;
- break;
- }
- }
- if (!found) break;
- }
- return seq;
+ for (weak List<Log> i = logs; i != null; i = i.next)
+ if (i.data == log)
+ logs.delete_link(i);
}
- protected weak Log? find(uint id)
+ public Log start(string tag, string title)
{
- for (weak List<Log> i = logs; i != null; i = i.next)
- if (i.data.id == id)
- return i.data;
- return null;
+ bool was_empty = (logs == null);
+ Log res = new Log(tag, title);
+ logs.append(res);
+ if (was_empty) start_trace();
+ return res;
}
- protected Log? pop(uint id)
+ public void end(Log log)
{
- for (weak List<Log> i = logs; i != null; i = i.next)
- if (i.data.id == id)
- {
- Log res = i.data;
- logs.delete_link(i);
- return res;
- }
- return null;
+ pop(log);
+ log.save();
+ if (logs == null) end_trace();
}
- public uint start(string tag, string title)
+ public Log load(string fname)
{
- bool was_empty = (logs == null);
- uint id = gen_seq();
- logs.append(new Log(id, tag, title));
- if (was_empty) start_trace();
- return id;
+ 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 add(uint id, string msg)
+ protected size_t list_dir(string dir, ref List<string> res)
{
- Log log = find(id);
- if (log == null) return;
- log.add(msg);
+ size_t count = 0;
+ var d = File.new_for_path(dir);
+ var enumerator = d.enumerate_children(FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
+ FileInfo file_info;
+ while ((file_info = enumerator.next_file(null)) != null)
+ {
+ if (!file_info.get_name().has_suffix(".gpx")) continue;
+ res.append(file_info.get_name());
+ ++count;
+ }
+ return count;
}
- public void end(uint id)
+ public string[] list_entries(bool only_unacked=true)
{
- Log log = pop(id);
- log.save();
- if (log == null) end_trace();
+ size_t count = 0;
+ List<string> entries = new List<string>();
+ if (!only_unacked)
+ count += list_dir(config.homedir + "/archive", ref entries);
+ count += list_dir(config.homedir + "/log", ref entries);
+ string[] res = new string[count+1];
+ size_t cur = 0;
+ for (weak List<string> i = entries; i != null; i = i.next)
+ res[cur++] = i.data;
+ res[cur] = null;
+ return res;
}
public void instant(string tag, string msg)
{
- var log = new Log(0, tag, msg);
+ var log = new Log(tag, msg);
log.add(msg);
log.save();
}
public void shutdown()
{
+ bool had_logs = (logs != null);
while (logs != null)
{
- var log = pop(logs.data.id);
- log.save();
+ logs.data.save();
+ logs.delete_link(logs);
}
+ if (had_logs) end_trace();
}
}