root/trunk/bevutils/PropertyFile.d

Revision 20, 6.7 kB (checked in by teales, 1 year ago)

Bevutils files initial check-in.

Line 
1 /**
2  * Authors: Steve Teale - steve.teale@britseyeview.com
3  *
4  * Date: 2007/05/19
5  * History: V0.1
6  * License: Use freely for any purpose.
7  */
8 module bevutils.propertyfile;
9
10 import std.string;
11 import std.stdio;
12 import std.stream;
13 import std.regexp;
14 import bevutils.tinyxml;
15
16 /**
17  * A class to facilitate reading of XML property files.
18  *
19  * Currently supports string, int, string[] and int[] properties.
20  *
21  * Two styles of XML are supported:
22  * ------------------------------------------------------
23 <?xml version="1.0" ?>
24    <Properties layout="1">
25       <constr type="string">Driver=SQL Server;DSN=MySQL1</constr>
26       <logpath type="string">d:\logs</logpath>
27       <numlogs type="int">10</numlogs>
28       <maxlogsize type="int">1000000</maxlogsize>
29       <watchdirs type="string[]">
30          <item>d:\A</item>
31          <item>d:\B</item>
32          <item>d:\C</item>
33       </watchdirs>
34       <thingie type="int[]">
35          <item>1</item>
36          <item>2</item>
37          <item>3</item>
38       </thingie>
39    </Properties>
40  * ------------------------------------------------------
41  * and:
42  * ------------------------------------------------------
43 <?xml version="1.0" ?>
44 <Properties layout="2">
45    <constr type="string" value="Driver=SQL Server;DSN=MySQL1" />
46    <logpath type="string" value="d:\logs" />
47    <numlogs type="int" value="10" />
48    <maxlogsize type="int" value="1000000" />
49    <watchdirs type="string[]">
50       <item value="d:\A" />
51       <item value="d:\B" />
52       <item value="d:\C" />
53    </watchdirs>
54    <thingie type="int[]">
55       <item value="1" />
56       <item value="2" />
57       <item value="3" />
58    </thingie>
59 </Properties>
60  * ------------------------------------------------------
61  */
62 class PropertyFile
63 {
64 private:
65    struct Property
66    {
67       int type;
68       union
69       {
70          char[] s;
71          int i;
72          char[][] as;
73          int[] ai;
74       }
75    }
76
77    Property [char[]] _props;
78    static RegExp irex;
79
80 public:
81    static this()
82    {
83       irex = RegExp("-?[0-9]{1,10}");
84    }
85
86    /**
87     * Constructor from a file name
88     *
89     * Params:
90     *   filepath = Fully qualified file name.
91     */
92    this(char[] filepath)
93    {
94       File file = new File(filepath);
95       char[] text = file.toString();
96       TinyXML tx = new TinyXML(text);
97       Tag t = tx.Context;
98       char[] layout = t.getValue("layout");
99       int lt = (layout == "1")? 1: 2;
100       int n = t.Tags;
101       for (int i = 0; i < n; i++)
102       {
103          Tag x = cast(Tag) t[i, TinyXML.TAG];
104          char[] type = x.getValue("type");
105          char[] name = x.Name;
106          char[] val;
107
108          Property p;
109          switch (type)
110          {
111             case "int":
112                val = (lt == 1)? x.FirstText: x.getValue("value");
113                int m = irex.find(val);
114                if (m != 0 || irex.post.length > 0)
115                   throw new Exception(name ~ " Value " ~ val ~ " does not match the specified type.");
116                p.i = cast(int) std.string.atoi(val);
117                p.type = 1;
118                _props[name] = p;
119                break;
120             case "int[]":
121                handleIntArray(x, name, lt);
122                break;
123             case "string[]":
124                handleStringArray(x, name, lt);
125                break;
126             default:
127                val = (lt == 1)? x.FirstText: x.getValue("value");
128                p.s = val;
129                p.type = 0;
130                _props[name] = p;
131                break;
132          }
133       }
134    }
135
136    /**
137     * Determine if a property is present by name.
138     *
139     * Params:
140     *   s = Popery name.
141     */
142    bool opCall(char[] s) { return !((s in _props) is null); }
143
144    /**
145     * Get an integer property value.
146     *
147     * Params:
148     *   name = Property name.
149     */
150    int getInt(char[] name)
151    {
152      if (!(name in _props))
153         throw new Exception("No such property");
154      Property p = _props[name];
155      if (p.type != 1)
156         throw new Exception("Property " ~ name ~ " is not of type int");
157      return p.i;
158    }
159
160    /**
161     * Get a string property value.
162     *
163     * Params:
164     *   name = Property name.
165     */
166    char[] getString(char[] name)
167    {
168      if (!(name in _props))
169         throw new Exception("No such property");
170      Property p = _props[name];
171      if (p.type != 0)
172         throw new Exception("Property " ~ name ~ " is not of type string");
173      return p.s;
174    }
175
176    /**
177     * Get an int array property value.
178     *
179     * Params:
180     *   name = Property name.
181     */
182    int[] getIntArray(char[] name)
183    {
184      if (!(name in _props))
185         throw new Exception("No such property");
186      Property p = _props[name];
187      if (p.type != 3)
188         throw new Exception("Property " ~ name ~ " is not of type int[]");
189      return p.ai;
190    }
191
192    /**
193     * Get an string array property value.
194     *
195     * Params:
196     *   name = Property name.
197     */
198    char[][] getStringArray(char[] name)
199    {
200      if (!(name in _props))
201         throw new Exception("No such property");
202      Property p = _props[name];
203      if (p.type != 2)
204         throw new Exception("Property " ~ name ~ " is not of type string[]");
205      return p.as;
206    }
207
208 private:
209    private void handleIntArray(Tag x, char[] name, int lt)
210    {
211       Property p;
212       int tc = x.Tags;
213       int[] a;
214       a.length = tc;
215       for (int i = 0; i < tc; i++)
216       {
217          Tag t = cast(Tag) x[i, TinyXML.TAG];
218          char[] s = (lt == 1)? t.FirstText: t.getValue("value");
219          int n = irex.find(s);
220          if (n != 0 || irex.post.length > 0)
221             throw new Exception(name ~ " array element " ~ s ~ " does not match the specified type.");
222          n = cast(int) std.string.atoi(s);
223          a[i] = n;
224       }
225       p.ai = a;
226       p.type = 3;
227       _props[name] = p;
228    }
229
230    private void handleStringArray(Tag x, char[] name, int lt)
231    {
232       Property p;
233       int tc = x.Tags;
234       char[][] a;
235       a.length = tc;
236       for (int i = 0; i < tc; i++)
237       {
238          Tag t = cast(Tag) x[i, TinyXML.TAG];
239          a[i] = (lt == 1)? t.FirstText: t.getValue("value");
240       }
241       p.as = a;
242       p.type = 2;
243       _props[name] = p;
244    }
245 }
246
247 /+
248 void main(char[][] args)
249 {
250    PropertyFile pf = new PropertyFile("d:\\d\\test2.xml");
251    writefln(pf.getString("constr"));
252    writefln(pf.getString("logpath"));
253    int n = pf.getInt("numlogs");
254    writefln("%d", n);
255    n = pf.getInt("maxlogsize");
256    writefln("%d", n);
257    char[][] as = pf.getStringArray("watchdirs");
258    for (int i = 0; i < as.length; i++)
259       writefln(as[i]);
260    int[] ai = pf.getIntArray("thingie");
261    for (int i = 0; i < ai.length; i++)
262       writefln("%d", ai[i]);
263 }
264 +/
Note: See TracBrowser for help on using the browser.