1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
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 ();
return doc;
}
}
}
|