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 package uk.ac.rdg.resc.jstyx.infernogrid;
30
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.io.IOException;
34
35 import uk.ac.rdg.resc.jstyx.client.StyxConnection;
36 import uk.ac.rdg.resc.jstyx.client.CStyxFile;
37 import uk.ac.rdg.resc.jstyx.client.CStyxFileInputStream;
38 import uk.ac.rdg.resc.jstyx.client.CStyxFileInputStreamReader;
39 import uk.ac.rdg.resc.jstyx.StyxUtils;
40
41 /***
42 * Class for parsing an InputStream into sets of S-expressions.
43 *
44 * @author Jon Blower
45 * $Revision: 377 $
46 * $Date: 2005-08-31 18:03:19 +0100 (Wed, 31 Aug 2005) $
47 * $Log$
48 * Revision 1.3 2005/08/31 17:03:19 jonblower
49 * Renamed "StyxFile*putStream*" to "CStyxFile*putStream*" for consistency with CStyxFile class
50 *
51 * Revision 1.2 2005/08/10 18:34:28 jonblower
52 * Implemented working S-expression parser
53 *
54 * Revision 1.1 2005/08/08 07:43:03 jonblower
55 * Initial import
56 *
57 */
58 public class SexpParser
59 {
60
61 private InputStreamReader reader;
62
63 private static final char OPEN_PAREN = new Character('(').charValue();
64 private static final char CLOSE_PAREN = new Character(')').charValue();
65 private static final char QUOTES = new Character('"').charValue();
66
67 /*** Creates a new instance of SexpParser */
68 public SexpParser(InputStream is)
69 {
70 this.reader = new InputStreamReader(is, StyxUtils.UTF8);
71 }
72
73 /*** Creates a new instance of SexpParser */
74 public SexpParser(InputStreamReader reader)
75 {
76 this.reader = reader;
77 }
78
79 /***
80 * @return the next Sexpression in the stream, or null if we have reached
81 * the end of the stream
82 * @throws SexpParseException if the input stream does not contain a valid
83 * Sexpression
84 * @throws IOException if there was an error reading the input stream
85 */
86 public Sexpression getNextSexp() throws SexpParseException, IOException
87 {
88 return getChildren(null);
89 }
90
91 /***
92 * Gets the children of the given S-expression. The given S-expression can
93 * be null (when we haven't found an S-expression yet).
94 */
95 private Sexpression getChildren(Sexpression parent)
96 throws SexpParseException, IOException
97 {
98 StringBuffer atomBuf = null;
99 boolean quotesOpen = false;
100
101 while(true)
102 {
103 int ch = this.reader.read();
104
105 if (Character.isWhitespace(ch))
106 {
107 if (quotesOpen)
108 {
109 atomBuf.append((char)ch);
110 }
111 else if (atomBuf != null)
112 {
113
114 parent.add(atomBuf.toString());
115 atomBuf = null;
116 }
117 }
118 else if (ch == OPEN_PAREN)
119 {
120 if (quotesOpen)
121 {
122 atomBuf.append(OPEN_PAREN);
123 }
124 else
125 {
126
127 Sexpression sexp = new Sexpression();
128 getChildren(sexp);
129 if (parent == null)
130 {
131
132 return sexp;
133 }
134 else
135 {
136 parent.add(sexp);
137 }
138 }
139 }
140 else if (ch == CLOSE_PAREN)
141 {
142 if (quotesOpen)
143 {
144 atomBuf.append(CLOSE_PAREN);
145 }
146 else
147 {
148
149 if (parent == null)
150 {
151 throw new SexpParseException("Found end of Sexp with no start");
152 }
153 if (atomBuf != null)
154 {
155 parent.add(atomBuf.toString());
156 atomBuf = null;
157 }
158 return parent;
159 }
160 }
161 else if (ch < 0)
162 {
163 if (parent != null)
164 {
165 throw new SexpParseException("Got EOF in middle of parsing an S-expression");
166 }
167 this.close();
168 return null;
169 }
170 else
171 {
172
173 if (parent == null)
174 {
175 throw new SexpParseException("Format error: atom value found but " +
176 "S-expression not started");
177 }
178 if (ch == QUOTES)
179 {
180
181
182 if (quotesOpen)
183 {
184 quotesOpen = false;
185 parent.add(atomBuf.toString());
186 atomBuf = null;
187 }
188 else
189 {
190 quotesOpen = true;
191 atomBuf = new StringBuffer();
192
193 }
194 }
195 else
196 {
197 if (atomBuf == null)
198 {
199
200 atomBuf = new StringBuffer();
201 }
202 atomBuf.append((char)ch);
203 }
204 }
205 }
206 }
207
208 /***
209 * Closes the underlying InputStream
210 */
211 public void close()
212 {
213 try
214 {
215 this.reader.close();
216 }
217 catch(IOException ioe)
218 {
219 ioe.printStackTrace();
220 }
221 }
222
223 /***
224 * Test function that reads the list of nodes from an Inferno Grid
225 * installation
226 */
227 public static void main(String[] args) throws Exception
228 {
229 StyxConnection conn = new StyxConnection("wagner.rdg.ac.uk", 7777);
230 conn.connect();
231 CStyxFile nodesFile = conn.getFile("admin/nodes");
232 nodesFile.open(StyxUtils.ORDWR | StyxUtils.OTRUNC);
233 nodesFile.setContents("(name ipaddr blacklisted ncompleted)");
234 InputStreamReader reader = new CStyxFileInputStreamReader(new CStyxFileInputStream(nodesFile));
235 SexpParser parser = new SexpParser(reader);
236 Sexpression se;
237 do
238 {
239 se = parser.getNextSexp();
240 if (se != null)
241 {
242 System.out.println(se);
243 }
244 } while (se != null);
245 parser.close();
246 }
247
248 }