Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge pull request #1 from mquinson/master
[simgrid.git] / contrib / psg / src / peersim / config / ParsedProperties.java
1 /*
2  * Copyright (c) 2003-2005 The BISON Project
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  */
18                 
19 package peersim.config;
20
21 import java.io.*;
22 import java.util.*;
23
24 /**
25 * Extends the class {@link ConfigProperties} with basic parsing capabilities.
26 * @see #load
27 */
28 public class ParsedProperties extends ConfigProperties {
29
30 //================= variables ======================================
31 //==================================================================
32
33 // ================= initialization =================================
34 // ==================================================================
35
36 /**
37 * Calls super constructor.
38 * @see ConfigProperties#ConfigProperties(String[])
39 */
40 public  ParsedProperties( String[] pars ) {
41
42         super( pars );
43 }
44
45 // ------------------------------------------------------------------
46
47 /**
48 * Calls super constructor.
49 * @see ConfigProperties#ConfigProperties(String)
50 */
51 public  ParsedProperties( String filename ) throws IOException {
52
53         super( filename );
54 }
55
56
57 // =========== Public methods ========================================
58 // ===================================================================
59
60
61 /**
62 * Loads given file. It works exactly as <code>Properties.load</code>
63 * with a file input stream to the given file, except that the file is parsed
64 * the following way allowing to compress some property names
65 * using <code>{</code> and <code>}</code>.
66   
67   When a bracket is present, it must
68   be the only non-space element of a line. The last property defined 
69   before the opening bracket define the prefix that is added to all the 
70   properties defined included between brackets.
71   In other words, a construct like this:
72   <pre>
73   control.degree GraphObserver 
74   {
75     protocol newscast
76     undir
77   }
78   </pre>
79   is equivalent to the definition of these three properties:
80   <pre>
81   control.degree GraphObserver 
82   control.degree.protocol newscast
83   control.degree.undir
84   </pre>
85   
86   Nested brackets are possible. The rule of the last property before 
87   the opening bracket applies also to the inside brackets, with
88   the prefix being the complete property definition (so, including
89   the prefix observed before). Example:
90   <pre>
91         control.1 DynamicNetwork
92         {
93           add CRASH
94           substitute
95           init.0 WireKOut 
96           {
97             degree DEGREE
98             protocol 0
99           }
100         }
101   </pre>
102   defines the following properties:
103   <pre>
104         control.1 DynamicNetwork
105         control.1.add CRASH
106         control.1.substitute
107         control.1.init.0 WireKOut 
108         control.1.init.0.degree DEGREE
109         control.1.init.0.protocol 0
110   </pre>
111   
112   <p>
113   Know limitations: 
114   The parsing mechanism is very simple; no complex error messages
115   are provided. In case of missing closing brackets, the method
116   will stop reporting the number of missing brackets. Additional
117   closing brackets (i.e., missing opening brackets) produce an
118   error messages reporting the line where the closing bracket
119   is present. Misplaced brackets (included in lines that
120   contains other characters) are ignored, thus may indirectly produce
121   the previous error messages.
122 */
123 public void load( String fileName ) throws IOException {
124
125         /* This set is used to store prefixes that have been associated
126          * to brackets blocks. If a prefix is inserted twice, this means
127          * that there are two blocks referring to the same prefix - 
128          * which may be caused by a commented prefix in the config
129          * file, something like this:
130          * 
131          *  prefix1
132          *  {
133          *    property 1
134          *  }
135          *  #prefix2
136          *  {
137          *    property 2
138          *  }
139          *
140          */
141         Set<String> prefixes = new HashSet<String>();
142         
143         BufferedReader f = 
144                 new BufferedReader(new FileReader( fileName ));
145         int lines = 0;
146         parseStream(f, "", 0, lines, prefixes);
147
148         f.close();
149 }
150
151 // --------------------------------------------------------------------
152
153 private int parseStream(BufferedReader f, String prefix, int pars, 
154                 int lines, Set prefixes)
155 throws IOException {
156
157         if (prefix.equals(".")) {
158                 System.err.println("Error at line " + lines + ": bracket block not " +
159                                 "associated with any configuration entry");
160                 System.exit(1);
161         }
162         if (prefixes.contains(prefix)) {
163                 System.err.println("Error at line " + lines + ": multiple bracket " +
164                                 "blocks referring to the same configuration entry " + prefix);
165                 System.exit(1);
166         } else {
167                 prefixes.add(prefix);
168         }
169         
170         boolean complete = true;
171         String part;
172         String line = "";
173         String last = "";
174         while ((part = f.readLine()) != null)
175         {
176                 lines++;
177                 
178                 // Reset line
179                 if (complete) line = "";
180                 
181                 // Check if the line is a comment line
182                 // If so, remove the comment
183                 int index = part.indexOf('#');
184                 if (index >= 0)
185                 {
186                         part = part.substring(0, index);
187                 } 
188
189                 // Check if the line is empty
190                 part = part.trim();
191                 if ("".equals(part)) continue;
192
193                 complete = (part.charAt(part.length()-1) != '\\'); 
194                 if (!complete)
195                 {  
196                         line = line + part.substring(0, part.length()-2) + " ";
197                         continue;
198                 }
199                 
200                 // Complete the line
201                 line = line + part;
202                 if (line.equals("{"))
203                 {
204                         lines = parseStream(f, last+".", pars+1, lines, prefixes);
205                 } 
206                 else if (line.equals("}"))
207                 {
208                         if (pars == 0)
209                         {
210                                 System.err.println(
211                                         "Error: Additional } at line " + lines + 
212                                         " when parsing the configuration file");
213                                 System.exit(1);
214                         }
215                         return lines;
216                 }
217                 else
218                 {
219                         // Search the first token
220                         String[] tokens = line.split("[\\s:=]+", 2);
221                         if (tokens.length == 1)
222                         {
223                                 setProperty(prefix+tokens[0], "");
224                         }
225                         else
226                         {
227                                 setProperty(prefix+tokens[0], tokens[1]);
228                         }
229                         last = prefix + tokens[0];
230                 }
231         }
232         if (pars == 1)
233         {
234                 System.err.println("Error: One closing bracket ('}') is missing");
235                 System.exit(1);
236         } 
237         else if (pars > 1)
238         {
239                 System.err.println("Error: " + pars+" closing brackets ('}') are missing");
240                 System.exit(1);
241         }
242         return lines;
243 }
244
245 // --------------------------------------------------------------------
246
247 /*
248 public static void main(String[] args)
249 {
250         java.util.Properties prop = new ParsedProperties(args);
251 }
252 */
253 }
254