--- /dev/null
+#!/usr/bin/env python
+
+import sys
+import types
+import re
+
+key_pattern = re.compile('^[A-Za-z0-9_-]+$')
+
+class MoeMetaInvalid(Exception):
+ pass
+
+class MoeMeta:
+ """Moe meta-file."""
+
+ def __init__(self):
+ self.meta = {}
+
+ def __getitem__(self, k):
+ if not self.meta.has_key(k): return None
+ v = self.meta[k]
+ if type(v) == types.ListType:
+ if len(v) > 0: return v[0]
+ else: return None
+ else: return v
+
+ def __setitem__(self, k, v):
+ self.meta[k] = v
+
+ def get_list(self, k):
+ m = self.meta
+ if not m.has_key(k):
+ m[k] = []
+ elif type(m[k]) != types.ListType:
+ m[k] = [m[k]]
+ return m[k]
+
+ def write(self, file=None, name=None):
+ if file is None:
+ if name is not None:
+ file = open(name, 'w')
+ else:
+ file = sys.stdout
+ self.write_nested(file, 0)
+
+ def write_nested(self, file, indent):
+ for k,v in self.meta.items():
+ if type(v) == types.ListType: vals = v
+ else: vals = [v]
+ for w in vals:
+ if isinstance(w, MoeMeta):
+ file.write("\t" * indent + k + "(\n")
+ w.write_nested(file, indent+1);
+ file.write("\t" * indent + ")\n")
+ else:
+ file.write("\t" * indent + k + ':' + str(w) + "\n")
+
+ def read(self, file=None, name=None):
+ if file is None:
+ if name is not None:
+ file = open(name, 'r')
+ else:
+ file = sys.stdin
+ self.meta = {}
+ self.do_read(file)
+
+ def read_val(self, k, v):
+ if not key_pattern.match(k):
+ raise MoeMetaInvalid, "Parse error: invalid key syntax"
+ m = self.meta
+ if not m.has_key(k):
+ m[k] = v
+ else:
+ self.get_list(k).append(v)
+
+ def do_read(self, file):
+ stk = []
+ this = self
+ for x in file.readlines():
+ x = x.rstrip("\n").lstrip(" \t")
+ if x=='' or x.startswith('#'):
+ pass
+ else:
+ sep = x.find(':')
+ if sep >= 0:
+ k = x[:sep]
+ v = x[sep+1:]
+ this.read_val(k, v)
+ elif x.endswith('('):
+ k = x[:-1]
+ new = MoeMeta()
+ this.read_val(k, new)
+ stk.append(this)
+ this = new
+ elif x == ')':
+ if len(stk) == 0:
+ raise MoeMetaInvalid, "Parse error: incorrect nesting"
+ else:
+ this = stk.pop()
+ else:
+ raise MoeMetaInvalid, "Parse error: malformed line"