summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-01-08 15:00:08 +0100
committerMarc-André Lureau <marcandre.lureau@gmail.com>2013-01-08 18:20:54 +0100
commit9cc9b8d81023f39900115bc38eb48c038c5d182f (patch)
treecc9c054fddf8a349e0a381fc181595ef5448353c /src
parent752afa1c4c5caf59a3b510a7fae3a1995c4b5b02 (diff)
Start simple preprocessor, supports variables substitution
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/builder.vala46
-rw-r--r--src/msi.vala4
-rw-r--r--src/preprocessor.vala114
-rw-r--r--src/util.vala33
-rw-r--r--src/wix.vala8
-rw-r--r--src/wixl.vala4
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 ());
}