/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @software : pluie-yaml * @version : 0.5 * @type : library * @date : 2018 * @licence : GPLv3.0 * @author : a-Sansara <[dev]at[pluie]dot[org]> * @copyright : pluie.org * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of pluie-yaml. * * pluie-yaml is free software (free as in speech) : 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 3 of the License, * or (at your option) any later version. * * pluie-yaml 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 pluie-yaml. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ using GLib; using Gee; using Pluie; extern void yaml_parse_file(string srcPath, string destPath); /** * a Yaml scanner class dealing with libyaml to generate a list of Yaml.Event */ public class Pluie.Yaml.Scanner { /** * Regex pattern use to find EVENT */ const string REG_EVENT = "^([0-9]+), ([0-9]+)(.*)$"; /** * Regex pattern use to find EVENT VERSION */ const string REG_VERSION = "^, ([0-9]+), ([0-9]+)$"; /** * Regex pattern use to find EVENT TAG */ const string REG_TAG = "^, \"([^\"]*)\", \"([^\"]*)\"$"; /** * Regex pattern use to find EVENT ERROR */ const string REG_ERROR = "^, \"([^\"]*)\"$"; /** * Regex pattern use to find EVENT SCALAR */ const string REG_SCALAR = "^, ([0-9]+), \"(.*)\"$"; /** * Regex pattern use to find EVENT ANCHOR */ const string REG_ANCHOR = "^, \"([^\"]*)\"$"; /** * Regex pattern use to find EVENT ALIAS */ const string REG_ALIAS = "^, \"([^\"]*)\"$"; /** * enum linked to MatchInfo REG_EVENT */ enum MIEVT { NONE, LINE, TYPE, DATA } /** * enum linked to MatchInfo REG_VERSION */ enum MIEVT_VERSION { NONE, MAJOR, MINOR } /** * enum linked to MatchInfo REG_SCALAR */ enum MIEVT_SCALAR { NONE, STYLE, DATA } /** * enum linked to MatchInfo REG_TAG */ enum MIEVT_TAG { NONE, HANDLE, SUFFIX } /** * enum linked to MatchInfo REG_ANCHOR */ enum MIEVT_ANCHOR { NONE, ID } /** * enum linked to MatchInfo REG_ERROR */ enum MIEVT_ERROR { NONE, DATA } /** * indicate if file has been sucessfully scanned */ public bool done { get; internal set; } /** * Reader used to load content yaml file */ Io.Reader reader; /** * Yaml Processor used to process events */ Yaml.Processor processor { get; internal set; } /** * @param path the path of file to scan */ public Scanner (string path) { var destPath = Path.build_filename (Environment.get_tmp_dir (), Path.get_basename(path)); yaml_parse_file(path, destPath); this.reader = new Io.Reader (destPath); } /** * return resulting Yaml root node */ public Yaml.Node? get_nodes () { return this.processor.root; } /** * return error Yaml Event */ public Yaml.Event? get_error_event () { return this.processor.error_event; } /** * scan specifiyed file generated throught yaml.c * @param path optional file path to scan */ public bool run (string? path = null) { Dbg.in (Log.METHOD, "path:'%s'".printf (path), Log.LINE, Log.FILE); this.before_run (path); this.processor = new Yaml.Processor (); this.done = false; Yaml.dbg_action ("Scanning events", path); while (this.reader.readable) { this.scan_event (this.reader.read ()); } this.done = true; Yaml.dbg_state (this.done); this.done = this.done && this.processor.run (); Yaml.dbg_state (this.done); Dbg.out (Log.METHOD, "done:%d".printf ((int)done), Log.LINE, Log.FILE); return this.done; } /** * */ private void before_run (string? path) { if (path != null && this.reader.path != path) { this.reader.load (path); } else { this.reader.rewind(new Io.StreamLineMark(0, 0)); } } /** * register event version * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_version(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_VERSION); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("major", mi.fetch (MIEVT_VERSION.MAJOR)); data.set("minor", mi.fetch (MIEVT_VERSION.MINOR)); } this.processor.events.add(new Yaml.Event(EVT.VERSION_DIRECTIVE, line, null, data)); } /** * register event tag * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_tag_directive(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_TAG); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("handle", mi.fetch (MIEVT_TAG.HANDLE)); data.set("prefix", mi.fetch (MIEVT_TAG.SUFFIX)); } this.processor.events.add(new Yaml.Event(EVT.TAG_DIRECTIVE, line, null, data)); } /** * register event tag * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_tag(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_TAG); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("handle", mi.fetch (MIEVT_TAG.HANDLE)); data.set("suffix", mi.fetch (MIEVT_TAG.SUFFIX)); } this.processor.events.add(new Yaml.Event(EVT.TAG, line, null, data)); } /** * register event version * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_error(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_ERROR); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("error", mi.fetch (MIEVT_ERROR.DATA)); } this.processor.events.add(new Yaml.Event(EVT.NONE, line, null, data)); } /** * register event scalar * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_scalar(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_SCALAR); HashMap? data = null; int? style = null; if (reg.match (evtdata, 0, out mi)) { style = int.parse(mi.fetch (MIEVT_SCALAR.STYLE)); data = new HashMap(); data.set("data", mi.fetch (MIEVT_SCALAR.DATA)); } this.processor.events.add(new Yaml.Event(EVT.SCALAR, line, style, data)); } /** * register event anchor * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_anchor(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_ANCHOR); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("id", mi.fetch (MIEVT_ANCHOR.ID)); } this.processor.events.add(new Yaml.Event(EVT.ANCHOR, line, null, data)); } /** * register event alias * @param evtdata the current data event * @param line the current line * @throws GLib.RegexError */ private void register_event_alias(string evtdata, int line) throws GLib.RegexError { MatchInfo mi = null; Regex reg = new Regex (REG_ALIAS); HashMap? data = null; if (reg.match (evtdata, 0, out mi)) { data = new HashMap(); data.set("id", mi.fetch (MIEVT_ANCHOR.ID)); } this.processor.events.add(new Yaml.Event(EVT.ALIAS, line, null, data)); } /** * scan specifiyed line * @param data the current line */ private void scan_event (string? data = null) { Dbg.in (Log.METHOD, null, Log.LINE, Log.FILE); if (data == null) { return; } try { MatchInfo mi = null; Regex reg = new Regex (REG_EVENT); if (reg.match (data, 0, out mi)) { int line = int.parse(mi.fetch (MIEVT.LINE)); int type = int.parse(mi.fetch (MIEVT.TYPE)); string evtdata = mi.fetch (MIEVT.DATA); switch(type) { case EVT.SCALAR : this.register_event_scalar (evtdata, line); break; case EVT.ANCHOR : this.register_event_anchor (evtdata, line); break; case EVT.ALIAS : this.register_event_alias (evtdata, line); break; case EVT.TAG : this.register_event_tag (evtdata, line); break; case EVT.TAG_DIRECTIVE : this.register_event_tag_directive (evtdata, line); break; case EVT.VERSION_DIRECTIVE : this.register_event_version (evtdata, line); break; case EVT.NONE : this.register_event_error (evtdata, line); break; default : this.processor.events.add(new Yaml.Event ((Yaml.EVT) type, line, null, null)); break; } } } catch (GLib.RegexError e) { Dbg.error (e.message, Log.METHOD, Log.LINE, Log.FILE); } Dbg.out (Log.METHOD, null, Log.LINE, Log.FILE); } }