Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #713: Properties.d

File Properties.d, 8.3 kB (added by schveiguy, 1 year ago)

updated version of Properties.d

Line 
1 /*******************************************************************************
2
3         copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
4
5         license:        BSD style: $(LICENSE)
6
7         version:        Initial release: May 2004
8                         Oct 2007: change to use a Map interface to store
9                         properties.
10
11         author:         Kris, Steven Schveighoffer
12
13 *******************************************************************************/
14
15 module tango.text.Properties;
16
17 private import  tango.io.Buffer,
18                 tango.io.FilePath,
19                 tango.io.FileConst,
20                 tango.io.FileConduit;
21
22 private import  Text = tango.text.Util;
23
24 private import  tango.text.stream.LineIterator;
25
26 /*******************************************************************************
27
28         Provides an interface for using properties.  This is mainly used by
29         the Properties object to load/save properties to a stream.
30
31 *******************************************************************************/
32
33 interface PropertyMap(T)
34 {
35         /***********************************************************************
36
37                 Add a property.  If a property already exists with that name,
38                 the value is replaced.
39
40         ***********************************************************************/
41
42         void add(T[] name, T[] value);
43
44         /***********************************************************************
45
46                 Remove a property.  If the property with the given name
47                 doesn't exist, this function does nothing.
48
49         ***********************************************************************/
50
51         void remove(T[] name);
52
53         /***********************************************************************
54
55                 Index operator.  This is how you get a property value given
56                 the name.  If the name is not in the map, this returns null.
57
58         ***********************************************************************/
59
60         T[] opIndex(T[] name);
61
62         /***********************************************************************
63
64                 Add a value to the property map, using the index operator.  E.g.:
65                 ---
66                 properties["file"] = "test.txt";
67                 ---
68
69                 Calling this is equivalent to add(name, value);
70
71                 This returns value.
72
73         ***********************************************************************/
74
75         T[] opIndexAssign(T[] value, T[] name);
76
77         /***********************************************************************
78
79                 Used to iterate over the keys and values in the map.
80
81         ***********************************************************************/
82
83         int opApply(int delegate(ref T[] name, ref T[] value) dg);
84
85         /***********************************************************************
86
87                 Remove all properties from the map.
88
89         ***********************************************************************/
90
91         void clear();
92
93         /***********************************************************************
94
95                 Returns true if the named property exists in the map
96
97         ***********************************************************************/
98
99         bool contains(T[] name);
100 }
101
102 /*******************************************************************************
103
104         Provides load facilities for a properties file. That is, a file
105         or other medium containing lines of text with a name=value layout.
106
107 *******************************************************************************/
108
109 class Properties(T)
110 {
111         alias PropertyMap!(T) Map;
112
113         /***********************************************************************
114
115                 Load properties from the named file, and pass each of them
116                 to the provided delegate.
117
118         ***********************************************************************/
119
120         static void load (FilePath path, Map properties)
121         {
122                 auto fc = new FileConduit (path);
123                 scope (exit)
124                        fc.close;
125
126                 load (fc, properties);
127         }
128
129         /***********************************************************************
130
131                 Load properties from the provided buffer, and pass them to
132                 the specified Map object.
133
134                 We use an iterator to sweep text lines, and extract lValue
135                 and rValue pairs from each one, The expected file format is
136                 as follows:
137
138                 ---
139                 x = y
140                 abc = 123
141                 x.y.z = this is a single property
142
143                 # this is a comment line
144                 ---
145
146         ***********************************************************************/
147
148         static void load (InputStream stream, Map properties)
149         {
150                 foreach (line; new LineIterator!(T) (stream))
151                         {
152                         auto text = Text.trim (line);
153
154                         // comments require '#' as the first non-whitespace char
155                         if (text.length && (text[0] != '#'))
156                            {
157                            // find the '=' char
158                            auto i = Text.locate (text, '=');
159
160                            // ignore if not found ...
161                            if (i < text.length)
162                                    // Note that we dup here so further lines
163                                    // read from the file do not corrupt the
164                                    // keys/values.
165                                    properties.add(Text.trim(text[0 .. i]).dup, Text.trim(text[i+1 .. $]).dup);
166                            }
167                         }
168         }
169
170         /***********************************************************************
171
172                 Write properties to the provided filepath
173
174         ***********************************************************************/
175
176         static void save (FilePath path, Map properties)
177         {
178                 auto fc = new FileConduit (path, FileConduit.WriteCreate);
179                 scope (exit)
180                        fc.close;
181                 save (fc, properties);
182         }
183
184         /***********************************************************************
185
186                 Write properties to the provided conduit
187
188         ***********************************************************************/
189
190         static void save (IConduit conduit, Map properties)
191         {
192                 save (new Buffer(conduit), properties).flush;
193         }
194
195         /***********************************************************************
196
197                 Write properties to the provided buffer
198
199         ***********************************************************************/
200
201         static IBuffer save (IBuffer emit, Map properties)
202         {
203                 const T[] equals = " = ";
204                 version (Win32)
205                          const T[] NL = "\r\n";
206                 version (Posix)
207                          const T[] NL = "\n";
208
209                 foreach (key, value; properties)
210                          emit (key) (equals) (value) (NL);
211                 return emit;
212         }
213 }
214
215
216 debug (Properties)
217 {
218         import tango.io.Buffer;
219         import tango.io.Console;
220         import tango.text.SimplePropertyMap;
221
222         void main()
223         {
224                 auto aa = new SimplePropertyMap!(char);
225                 aa ["foo"] = "something";
226                 aa ["bar"] = "something else";
227                 aa ["wumpus"] = "";
228
229                 // write Hash map to a buffer; could use a file
230                 auto props = new Properties!(char);
231                 auto buffer = new Buffer (256);
232                 props.save (buffer, aa);
233
234                 // reset and repopulate hash map from the buffer
235                 aa.clear();
236                 props.load (buffer, aa);
237
238                 // display result
239                 foreach (name, value; aa)
240                          Cout (name) (" = ") (value).newline;
241         }
242 }