2 using System.Collections;
9 public class MPlist : IEnumerable
21 public MPlist (FileStream stream)
23 MStreamReader reader = new MStreamReader (stream);
26 bool result = reader.ReadElement (out key, out val);
31 next = new MPlist (reader);
34 public MPlist (FileStream stream, int count)
36 MStreamReader reader = new MStreamReader (stream);
39 bool result = reader.ReadElement (out key, out val);
43 if (result && --count > 0)
44 next = new MPlist (reader, count);
49 public MPlist (FileStream stream, MSymbol target, MSymbol stop)
51 MStreamReader reader = new MStreamReader (stream);
60 result = reader.ReadElement (out key, out val);
63 if (key == MSymbol.plist)
65 MPlist plist = (MPlist) val;
69 if (plist.Symbol == stop)
71 if (plist.Symbol == target)
83 internal MPlist (MStreamReader reader)
87 bool result = reader.ReadElement (out key, out val);
92 next = new MPlist (reader);
95 private MPlist (MStreamReader reader, int count)
99 bool result = reader.ReadElement (out key, out val);
103 if (result && --count > 0)
104 next = new MPlist (reader, count);
106 next = new MPlist ();
109 private MPlist (MStreamReader reader, MSymbol target, MSymbol stop)
119 result = reader.ReadElement (out key, out val);
122 if (key == MSymbol.plist)
124 MPlist plist = (MPlist) val;
128 if (plist.Symbol == stop)
130 if (plist.Symbol == target)
134 next = new MPlist ();
142 private MPlist (MSymbol key, object val)
148 public bool IsEmpty { get { return next == null; } }
149 public MPlist Next { get { return next; } }
151 internal bool IsSymbol { get { return Key == MSymbol.symbol; } }
152 internal bool IsMText { get { return Key == MSymbol.mtext; } }
153 internal bool IsPlist { get { return Key == MSymbol.plist; } }
154 internal bool IsInteger { get { return Key == MSymbol.integer; } }
156 internal MSymbol Symbol { get { return (MSymbol) Val; } }
157 internal MText Text { get { return (MText) Val; } }
158 internal MPlist Plist { get { return (MPlist) Val; } }
159 internal int Integer { get { return (int) Val; } }
167 for (MPlist p = this; p.next != null; i++, p = p.next);
172 public MPlist Clone ()
174 MPlist plist = new MPlist (), pl = plist;
176 for (MPlist p = this; p.next != null; p = p.next)
177 pl = pl.Add (p.Key, p.Val);
181 public override string ToString ()
185 for (MPlist p = this; ! p.IsEmpty; p = p.next)
189 if (p.Key != MSymbol.symbol
190 && p.Key != MSymbol.integer
191 && p.Key != MSymbol.plist
192 && p.Key != MSymbol.mtext)
194 if (p.Key == MSymbol.mtext)
195 str += "\"" + p.Val + "\"";
202 private MPlist find (MSymbol key)
206 for (p = this; ! p.IsEmpty; p = p.next)
212 public MPlist Find (MSymbol key)
214 MPlist p = find (key);
216 return (p.IsEmpty ? null : p);
219 public object Get (MSymbol key)
221 return find (key).Val;
224 internal MPlist Assq (MSymbol key)
226 foreach (MPlist p in this)
227 if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key)
232 private delegate MPlist MPlistDelegate (MSymbol key, object val);
234 private MPlist mplist_op (MPlistDelegate op, object val)
236 Type type = val.GetType ();
238 if (Object.ReferenceEquals (type, typeof (MSymbol)))
239 return op (MSymbol.symbol, val);
240 if (Object.ReferenceEquals (type, typeof (MText)))
241 return op (MSymbol.mtext, val);
242 if (Object.ReferenceEquals (type, typeof (MPlist)))
243 return op (MSymbol.plist, val);
244 if (Object.ReferenceEquals (type, typeof (int)))
245 return op (MSymbol.integer, val);
246 return op (MSymbol.t, val);
249 public MPlist Set (MSymbol key, object val)
258 public MPlist Set (object val)
260 return mplist_op (Set, val);
263 public MPlist Put (MSymbol key, object val)
265 return find (key).Set (key, val);
268 public MPlist Put (object val)
270 return mplist_op (Put, val);
273 public MPlist Push (MSymbol key, object val)
275 MPlist p = new MPlist (Key, Val);
284 public MPlist Push (object val)
286 return mplist_op (Push, val);
289 public object Pop (out MSymbol key)
306 return Pop (out key);
309 public MPlist Add (MSymbol key, object val)
313 for (p = this; ! p.IsEmpty; p = p.next);
314 return p.Push (key, val);
317 public MPlist Clear ()
325 // Implement IEnumerable interface.
326 // foreach (MPlist p in plist) { ... }
328 public virtual IEnumerator GetEnumerator ()
330 return new Enumerator (this);
333 private class Enumerator : IEnumerator
335 private MPlist plist;
336 private MPlist current;
338 internal Enumerator (MPlist plist)
343 public object Current
346 if (current == null || current.IsEmpty)
347 throw new InvalidOperationException ();
357 public bool MoveNext ()
362 current = current.next;
363 return (! current.IsEmpty);
368 public class MStreamReader : StreamReader
370 private static char[] escaped_char = new char[128];
371 private static int[] hexadecimal = new int[128];
372 private char comment_start;
373 private bool line_oriented;
375 public MStreamReader (Stream stream) : base (stream)
378 line_oriented = false;
381 public MStreamReader (Stream stream, char comment_start,
382 bool line_oriented) : base (stream)
384 this.comment_start = comment_start;
385 this.line_oriented = line_oriented;
388 static MStreamReader ()
390 for (int i = 0; i < 128; i++)
391 escaped_char[i] = (char) i;
392 escaped_char['0'] = (char) 0;
393 escaped_char['e'] = (char) 27;
394 escaped_char['a'] = '\a';
395 escaped_char['b'] = '\b';
396 escaped_char['f'] = '\f';
397 escaped_char['n'] = '\n';
398 escaped_char['r'] = '\r';
399 escaped_char['t'] = '\t';
400 escaped_char['v'] = '\v';
401 for (int i = 0; i < 128; i++)
403 for (int i = '0'; i <= '9'; i++)
404 hexadecimal[i] = i - '0';
405 for (int i = 'A'; i <= 'F'; i++)
406 hexadecimal[i] = hexadecimal[i + 'a' - 'A'] = i -'A' + 10;
409 private int ReadHexadecimal (int max)
413 while ((c = Peek ()) >= 0 && c < 128 && (c = hexadecimal[c]) >= 0)
415 if (max >= 0 && (i * 16) + c >= max)
423 public bool ForwardLine ()
426 while ((c = Read ()) >=0 && c != '\n');
430 public bool SkipSpace (out int c)
432 while ((c = Peek ()) == ' ' && c == '\t' && c == '\f')
437 public bool PeekChar (out int c)
439 while ((c = Peek ()) != -1)
441 if (c == comment_start)
443 else if (c != ' ' && c != '\t' && c != '\n')
445 else if (c == '\n' && line_oriented)
453 public bool ReadInteger (out int i)
467 i = ReadHexadecimal (-1);
471 while ((c = Peek ()) >= '0' && c <= '9')
472 i = (i * 10) + (Read () - '0');
476 public bool ReadChar (out int c)
479 if (c < 0 || (line_oriented && c == '\n'))
485 return ReadChar (out c);
488 else if (c == 'x' || c == 'u' || c == 'U')
489 c = ReadHexadecimal (0x10FFFF);
496 private bool read_string (out string str, int prefix, bool for_symbol)
498 char[] buf = new char[256];
504 buf[i++] = (char) prefix;
505 while ((c = Peek ()) >= 0
508 || (c != '(' && c != ')' && c != ' ' && c != '\t' && c != '\n')))
510 if (! ReadChar (out c))
518 buf[i++] = (char) (0xD800 + ((c - 0x10000) >> 10));
519 buf[i++] = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
524 str = new string (buf, 0, i);
526 str += new string (buf, 0, i);
530 if (c == '\"' && ! for_symbol)
535 str = new string (buf, 0, i);
537 str += new string (buf, 0, i);
539 return (str != null);
542 public bool ReadString (out string str)
544 return read_string (out str, -1, false);
547 public bool ReadMText (out MText mt)
556 if (read_string (out str, -1, false))
557 mt = new MText (str);
565 while ((c = Peek ()) == '\\')
572 mt.Cat (ReadHexadecimal (0x10FFFF));
579 public bool ReadSymbol (out MSymbol sym, int prefix)
583 if (read_string (out str, prefix, true))
585 sym = MSymbol.Of (str);
592 internal bool ReadElement (out MSymbol key, out object val)
596 if (! PeekChar (out c))
606 val = new MPlist (this);
609 else if (c == '"' || c == '\\')
616 else if (c >= '0' && c <= '9')
621 key = MSymbol.integer;
627 if (c >= '0' && c <= '9')
632 key = MSymbol.integer;
638 ReadSymbol (out sym, '-');
640 key = MSymbol.symbol;
646 if (ReadChar (out c))
649 key = MSymbol.integer;
660 if ((c = Peek ()) == 'x' || c == 'u')
663 val = ReadHexadecimal (-1);
664 key = MSymbol.integer;
670 ReadSymbol (out sym, '#');
672 key = MSymbol.symbol;
686 ReadSymbol (out sym, -1);
688 key = MSymbol.symbol;