diff options
| author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-01-08 15:00:08 +0100 |
|---|---|---|
| committer | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-01-08 18:20:54 +0100 |
| commit | 9cc9b8d81023f39900115bc38eb48c038c5d182f (patch) | |
| tree | cc9c054fddf8a349e0a381fc181595ef5448353c /src | |
| parent | 752afa1c4c5caf59a3b510a7fae3a1995c4b5b02 (diff) | |
Start simple preprocessor, supports variables substitution
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 5 | ||||
| -rw-r--r-- | src/builder.vala | 46 | ||||
| -rw-r--r-- | src/msi.vala | 4 | ||||
| -rw-r--r-- | src/preprocessor.vala | 114 | ||||
| -rw-r--r-- | src/util.vala | 33 | ||||
| -rw-r--r-- | src/wix.vala | 8 | ||||
| -rw-r--r-- | src/wixl.vala | 4 |
7 files changed, 193 insertions, 21 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 3ff0034..83a8fe9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,7 +5,9 @@ AM_CFLAGS = -w AM_VALAFLAGS = \ -H wixl.h --use-header \ - --vapidir=$(srcdir) --pkg config \ + --vapidir=$(srcdir) \ + --vapidir=$(top_srcdir)/vapi \ + --pkg config \ --enable-experimental \ --pkg gio-2.0 \ --pkg libmsi-1.0 \ @@ -17,6 +19,7 @@ AM_VALAFLAGS = \ wixl_SOURCES = \ builder.vala \ msi.vala \ + preprocessor.vala \ util.vala \ wix.vala \ wixl.vala \ diff --git a/src/builder.vala b/src/builder.vala index c29d357..5a441dd 100644 --- a/src/builder.vala +++ b/src/builder.vala @@ -16,10 +16,8 @@ namespace Wixl { } List<WixRoot> roots; - public void load_xml (string data) throws GLib.Error { - var doc = Xml.Parser.read_memory (data, data.length); - - for (var child = doc->children; child != null; child = child->next) { + public void load_doc (Xml.Doc doc) throws GLib.Error { + for (var child = doc.children; child != null; child = child->next) { switch (child->type) { case Xml.ElementType.ELEMENT_NODE: if (child->name != "Wix") @@ -32,6 +30,15 @@ namespace Wixl { } } + public void load_file (File file) throws GLib.Error { + string data; + FileUtils.get_contents (file.get_path (), out data); + + var p = new Preprocessor (); + var doc = p.preprocess (data, file); + load_doc (doc); + } + public G? find_element<G> (string Id) { foreach (var r in roots) { var e = r.find_element<G> (Id); @@ -182,7 +189,9 @@ namespace Wixl { } public override void visit_product (WixProduct product) throws GLib.Error { - db.info.set_codepage (int.parse (product.Codepage)); + if (product.Codepage != null) + db.info.set_codepage (int.parse (product.Codepage)); + db.info.set_author (product.Manufacturer); db.table_property.add ("Manufacturer", product.Manufacturer); @@ -194,9 +203,13 @@ namespace Wixl { } public override void visit_package (WixPackage package) throws GLib.Error { - db.info.set_keywords (package.Keywords); - db.info.set_subject (package.Description); db.info.set_comments (package.Comments); + + if (package.Description != null) + db.info.set_subject (package.Description); + + if (package.Keywords != null) + db.info.set_keywords (package.Keywords); } public override void visit_icon (WixIcon icon) throws GLib.Error { @@ -221,13 +234,15 @@ namespace Wixl { } public override void visit_directory (WixDirectory dir) throws GLib.Error { + var defaultdir = dir.Name ?? "."; + if (dir.parent.get_type () == typeof (WixProduct)) { if (dir.Id != "TARGETDIR") throw new Wixl.Error.FAILED ("Invalid root directory"); - db.table_directory.add (dir.Id, null, dir.Name); + db.table_directory.add (dir.Id, null, defaultdir); } else if (dir.parent.get_type () == typeof (WixDirectory)) { var parent = dir.parent as WixDirectory; - db.table_directory.add (dir.Id, parent.Id, dir.Name); + db.table_directory.add (dir.Id, parent.Id, defaultdir); } else warning ("unhandled parent type %s", dir.parent.name); } @@ -428,14 +443,21 @@ namespace Wixl { } public override void visit_file (WixFile file) throws GLib.Error { - return_if_fail (file.DiskId == "1"); + var diskid = file.DiskId ?? "1"; + return_if_fail (diskid == "1"); + + var name = file.Id; + if (file.Name != null) + name = file.Name; + else if (file.Source != null) + name = Path.get_basename (file.Source); var comp = file.parent as WixComponent; FileInfo info; - file.file = find_file (file.Name, out info); + file.file = find_file (name, out info); var attr = FileAttribute.VITAL; - var rec = db.table_file.add (file.Id, comp.Id, file.Name, (int)info.get_size (), attr); + var rec = db.table_file.add (file.Id, comp.Id, name, (int)info.get_size (), attr); file.record = rec; visit_key_element (file); diff --git a/src/msi.vala b/src/msi.vala index eef4259..5263f47 100644 --- a/src/msi.vala +++ b/src/msi.vala @@ -174,12 +174,12 @@ namespace Wixl { return rec.set_int (2, last_sequence); } - public Libmsi.Record add (string DiskId, string DiskPrompt, string Cabinet) throws GLib.Error { + public Libmsi.Record add (string DiskId, string? DiskPrompt, string Cabinet) throws GLib.Error { var rec = new Libmsi.Record (4); if (!rec.set_int (1, int.parse (DiskId)) || !rec.set_int (2, 0) || - !rec.set_string (3, DiskPrompt) || + (DiskPrompt != null && !rec.set_string (3, DiskPrompt)) || !rec.set_string (4, Cabinet)) throw new Wixl.Error.FAILED ("failed to add record"); diff --git a/src/preprocessor.vala b/src/preprocessor.vala new file mode 100644 index 0000000..e5bfd1b --- /dev/null +++ b/src/preprocessor.vala @@ -0,0 +1,114 @@ +namespace Wixl { + + class Preprocessor: Object { + + HashTable<string, string> variables; + construct { + variables = new HashTable<string, string> (str_hash, str_equal); + } + + public void define_variable (string name, string value) { + variables.insert (name, value); + } + + public string get_variable (string str, File? file) throws GLib.Error { + var var = str.split (".", 2); + if (var.length != 2) + throw new Wixl.Error.FAILED ("invalid variable %s", str); + + switch (var[0]) { + case "var": + return variables.lookup (var[1]); + case "env": + return Environment.get_variable (var[1]); + case "sys": + switch (var[1]) { + case "CURRENTDIR": + return Environment.get_current_dir (); + case "SOURCEFILEDIR": + return file.get_basename (); + case "SOURCEFILEPATH": + return file.get_path (); + } + break; + } + + throw new Wixl.Error.FIXME ("unhandled variable type %s", str); + } + + public string eval (string str, File? file) throws GLib.Error { + var result = ""; + int end = 0; + int pos = 0; + + while ((pos = str.index_of ("$", end)) != -1) { + if (end < pos) + result += str[end:pos]; + end = pos + 1; + var remainder = str[end:str.length]; + if (remainder.has_prefix ("$")) + result += "$"; + else if (remainder.has_prefix ("(")) { + var closing = find_closing_paren (remainder); + if (closing == -1) + throw new Wixl.Error.FAILED ("no matching closing parenthesis"); + var substring = remainder[1:closing]; + if (substring.index_of ("(") != -1) + throw new Wixl.Error.FIXME ("unsupported function"); + result += get_variable (substring, file); + end += closing + 1; + } + } + + return result + str[end:str.length]; + } + + public Xml.Doc preprocess (string data, File? file) throws GLib.Error { + Xml.Doc doc; + var writer = new Xml.TextWriter.doc (out doc); + var reader = new Xml.TextReader.for_doc (data, ""); + + writer.start_document (); + while (reader.read () > 0) { + switch (reader.node_type ()) { + case Xml.ReaderType.PROCESSING_INSTRUCTION: + switch (reader.const_local_name ()) { + case "define": + MatchInfo info; + var r = /^\s*(?P<name>.+?)\s*=\s*(?P<value>.+?)\s*$/; + if (r.match (reader.const_value (), 0, out info)) { + var name = remove_prefix ("var.", info.fetch_named ("name")); + var value = unquote (info.fetch_named ("value")); + define_variable (name, value); + } else + throw new Wixl.Error.FAILED ("invalid define"); + break; + default: + warning ("unhandled preprocessor instruction %s", reader.const_local_name ()); + break; + } + break; + case Xml.ReaderType.ELEMENT: + var empty = reader.is_empty_element () > 0; + + writer.start_element (reader.const_name ()); + while (reader.move_to_next_attribute () > 0) { + var value = eval (reader.const_value (), file); + writer.write_attribute (reader.const_name (), value); + } + + if (empty) + writer.end_element (); + break; + case Xml.ReaderType.END_ELEMENT: + writer.end_element (); + break; + } + } + writer.end_document (); + + doc.dump_format (FileStream.fdopen (1, "w")); + return doc; + } + } +}
\ No newline at end of file diff --git a/src/util.vala b/src/util.vala index a5514a3..7235e3f 100644 --- a/src/util.vala +++ b/src/util.vala @@ -92,4 +92,37 @@ namespace Wixl { return (str[0] == 'Y' || str[0] == 'y'); } + + string unquote (string str) { + if ((str[0] == '\'' && str[str.length-1] == '\'') || + (str[0] == '"' && str[str.length-1] == '"')) + return str[1:-1]; + + return str; + } + + string remove_prefix (string prefix, string str) { + if (str.has_prefix (prefix)) + return str[prefix.length:str.length]; + + return str; + } + + int find_closing_paren (string str) { + return_val_if_fail (str[0] == '(', -1); + + var open_count = 1; + var close_count = 0; + for (var pos = 1; pos < str.length; pos++) { + if (str[pos] == '(') + open_count++; + else if (str[pos] == ')') { + close_count++; + if (open_count == close_count) + return pos; + } + } + + return -1; + } } // Wixl diff --git a/src/wix.vala b/src/wix.vala index d44c8af..ae1dbaa 100644 --- a/src/wix.vala +++ b/src/wix.vala @@ -35,8 +35,10 @@ namespace Wixl { static construct { Value.register_transform_func (typeof (WixElement), typeof (string), (ValueTransform)WixElement.value_to_string); } - - protected class HashTable<string, Type> child_types = null; // FIXME: would be nice if vala always initialize class member to null + + // FIXME: would be nice if vala always initialize class member to null + // GObject copy class init so other class hashtable will be unrefed...?? + protected class HashTable<string, Type> *child_types = null; class construct { child_types = new HashTable<string, Type> (str_hash, str_equal); } @@ -100,7 +102,7 @@ namespace Wixl { case Xml.ElementType.TEXT_NODE: continue; case Xml.ElementType.ELEMENT_NODE: - var t = child_types.lookup (child->name); + var t = child_types->lookup (child->name); if (t != 0) { var elem = Object.new (t) as WixElement; elem.load (child); diff --git a/src/wixl.vala b/src/wixl.vala index db3d3ac..904daf7 100644 --- a/src/wixl.vala +++ b/src/wixl.vala @@ -47,9 +47,7 @@ namespace Wixl { foreach (var arg in files[1:files.length]) { print ("Loading %s...\n", arg); var file = File.new_for_commandline_arg (arg); - string data; - FileUtils.get_contents (file.get_path (), out data); - builder.load_xml (data); + builder.load_file (file); builder.add_path (file.get_parent ().get_path ()); } |
