using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Xml;
+
using M17N;
using M17N.Core;
int len = pattern.Length;
int i;
+ M17n.DebugPrint ("Listing {0} in {1} ...", pattern, dirinfo);
for (i = 0; i < len && pattern[i] != sep; i++);
try {
if (i == len)
{
FileInfo[] listing = dirinfo.GetFiles (pattern);
+ i = listing.Length;
foreach (FileInfo elt in listing)
files.Add (elt);
}
string tail = pattern.Substring (i + 1);
pattern = pattern.Substring (0, i);
DirectoryInfo[] listing = dirinfo.GetDirectories (pattern);
+
+ i = listing.Length;
foreach (DirectoryInfo elt in listing)
list (ref files, elt, tail);
}
} catch {
}
+ M17n.DebugPrint (" found {0} files\n", i);
}
}
}
}
- public class MDatabase : IComparable<MDatabase>
+ public partial class MDatabase : IComparable<MDatabase>
{
/// Identifier of a MDatabase.
public struct Tag : IEquatable<Tag>
}
}
- public delegate object Loader (Tag tag, object extra_info);
+ public delegate MPlist Loader (Tag tag, object extra_info);
internal class MDatabaseInfo
{
public MDatabaseInfo (MPlist plist)
{
- Format = MSymbol.plist;
+ Format = MSymbol.nil;
if (plist.IsMText)
{
+ Format = MSymbol.plist;
Filename = plist.Text.ToString ();
plist = plist.Next;
}
MPlist p = plist.Plist;
if (p.IsMText)
- Filename = p.Text.ToString ();
- p = p.Next;
- if (! p.IsEmpty)
{
- if (p.IsSymbol)
- Format = p.Symbol;
+ Filename = p.Text.ToString ();
+ p = p.Next;
+ }
+ if (p.IsSymbol)
+ {
+ Format = p.Symbol;
p = p.Next;
- if (! p.IsEmpty)
- {
- if (p.IsSymbol)
- Schema = p.Symbol;
- p = p.Next;
- if (p.IsMText)
- SchemaFile = p.Text.ToString ();
- }
}
+ if (p.IsSymbol)
+ {
+ Schema = p.Symbol;
+ p = p.Next;
+ }
+ if (p.IsMText)
+ SchemaFile = p.Text.ToString ();
plist = plist.Next;
}
private static DateTime LastUpdateTime = new DateTime (0);
- private static readonly MSymbol Mversion = MSymbol.Of ("version");
- private static readonly MSymbol Mwildcard = MSymbol.Of ("*");
- private static readonly MSymbol Mchar_table = MSymbol.Of ("char-table");
- private static readonly MSymbol Mcharset = MSymbol.Of ("charset");
+ private static readonly MSymbol Mversion = "version";
+ private static readonly MSymbol Mwildcard = "*";
+ private static readonly MSymbol Mchar_table = "char-table";
+ private static readonly MSymbol Mcharset = "charset";
+ private static readonly MSymbol Mxml = "xml";
+
+ private static TimeSpan CheckInterval = new TimeSpan (50000000);
/// Type of database
private enum MDBType
// current system, or the validation was failed.
DISABLED,
// The database is deleted by the modificaiton of mdb.dir, or
- // is overwritten by a new explicit definition..
+ // is overwritten by a new explicit definition.
INVALID,
};
private MDBType DBType;
private MDBStatus DBStatus;
internal MDatabaseInfo Info;
- // File in which the database contents is stored.
+ // File in which the database contents is stored. This is null
+ // when DBStatus is NOT_READY.
internal FileInfo FileInfo;
- // When the database file is checked (or validated).
- internal DateTime CheckedTime;
+ // When the database file is loaded last.
+ internal DateTime LastLoaded = DateTime.Now;
+
+ public enum LoadStatus
+ {
+ None,
+ InvalidLoadMethod,
+ NotAvailable,
+ NotReadable,
+ InvalidContents,
+ };
+
+ public LoadStatus LastLoadStatus = LoadStatus.None;
static MDatabase ()
{
}
DBDirs[2] = new MDatabaseDir (null);
DBDirs[3] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
- update_all ();
+ update_all (true);
}
public static string ApplicationDir
{
get { return (DBDirs[1].Dirname); }
- set { DBDirs[2] = new MDatabaseDir (value); update_all (); }
+ set { DBDirs[2] = new MDatabaseDir (value); update_all (true); }
}
- private static bool update_all ()
+ // Update all listing and directories. Return true iff some are
+ // really updated.
+ private static bool update_all (bool force)
{
- bool updated = false;
+ if (! force && DateTime.Now - LastUpdateTime < CheckInterval)
+ return false;
+ bool updated = false;
for (int i = 1; i < 4; i++)
if (DBDirs[i].Dirname != null)
{
updated = true;
}
}
- LastUpdateTime = DateTime.Now;
+ if (updated)
+ LastUpdateTime = DateTime.Now;
return updated;
}
public static void Dump ()
{
- update_all ();
+ update_all (false);
Console.WriteLine ("[DBDirs]");
for (int i = 1; i < 4; i++)
if (DBDirs[i].Dirname != null)
mdb = mdbs[i];
if (mdb.ListIndex == list_idx && mdb.DirIndex >= dir_idx)
{
- if (mdb.DBStatus == MDBStatus.INVALID)
- M17n.DebugPrint ("registering: {0}\n", mdb);
- else
- M17n.DebugPrint ("updating: {0}\n", mdb);
mdb.DirIndex = dir_idx;
if (dict == wdict)
{
mdb.DBStatus = MDBStatus.READY;
}
mdb.Info = info;
+ if (mdb.DBStatus == MDBStatus.INVALID)
+ M17n.DebugPrint ("registering: {0}\n", mdb);
+ else
+ M17n.DebugPrint ("updating: {0}\n", mdb);
return;
}
}
this.tag = tag;
this.Info = info;
DBType = this.tag.HasWildcard ? MDBType.WILDCARD : MDBType.AUTO;
- if (this.tag[0] == Mchar_table || this.tag[0] == Mcharset)
- Info.Format = this.tag[0];
+ if (tag[0] == Mchar_table || tag[0] == Mcharset)
+ Info.Format = tag[0];
ListIndex = list_idx;
DirIndex = dir_idx;
if (Path.IsPathRooted (Info.Filename))
DBStatus = MDBStatus.READY;
else
DBStatus = MDBStatus.NOT_READY;
+ if (Info.Format == Mchar_table)
+ MCharProp.Define (tag[2], this);
}
public override String ToString () {
if (mdb.DBStatus == MDBStatus.READY)
{
M17n.DebugPrint ("re-expanding: {0}\n", mdb);
- register_files (DBDirs[dir_idx].Dirname, mdb.ListIndex,
- dir_idx, mdb.Info);
+ register_files (DBDirs[dir_idx].Dirname, dir_idx, mdb);
+ }
+ }
+
+ private static bool parse_plist_header (FileInfo fileinfo, MDatabase mdb,
+ out Tag tag, out MDatabaseInfo info)
+ {
+ MPlist plist = null;
+
+ tag = new Tag (MSymbol.nil);
+ info = null;
+ using (FileStream stream = fileinfo.OpenRead ())
+ {
+ try { plist = new MPlist (stream, 1); } catch { }
+ }
+ if (plist == null || ! plist.IsPlist)
+ return false;
+ plist = plist.Plist;
+ tag = new Tag (ref plist);
+ if (tag.HasWildcard || ! tag.Match (mdb.tag))
+ return false;
+ info = new MDatabaseInfo (plist);
+ return true;
+ }
+
+ private static bool parse_xml_header (FileInfo fileinfo, MDatabase mdb,
+ out Tag tag, out MDatabaseInfo info)
+ {
+ tag = new Tag (MSymbol.nil);
+ info = null;
+ using (FileStream stream = fileinfo.OpenRead ())
+ {
+ try {
+ MPlist plist = new MPlist ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ do {
+ reader.Read ();
+ } while (reader.NodeType != XmlNodeType.Element);
+ plist.Add (MSymbol.symbol, (MSymbol) reader.Name);
+ reader.Read ();
+ if (reader.NodeType == XmlNodeType.Element && reader.Name == "tags")
+ {
+ reader.Read ();
+ while (reader.NodeType == XmlNodeType.Element)
+ {
+ reader.Read ();
+ plist.Add (MSymbol.symbol, (MSymbol) reader.Value);
+ reader.Read ();
+ reader.Read ();
+ }
+ tag = new Tag (ref plist);
+ if (tag.HasWildcard || ! tag.Match (mdb.tag))
+ return false;
+ info = new MDatabaseInfo (plist);
+ return true;
}
+ } catch (Exception e) {
+ Console.WriteLine ("error {0}", e);
+ }
+ }
+ return false;
}
- private static void register_files (string dir, int list_idx, int dir_idx,
- MDatabaseInfo base_info)
+ private static void register_files (string dir, int dir_idx, MDatabase mdb)
{
+ int list_idx = mdb.ListIndex;
List<FileInfo> files = new List<FileInfo> ();
- MGlob.FileList (ref files, dir, base_info.Filename);
+ MGlob.FileList (ref files, dir, mdb.Info.Filename);
foreach (FileInfo fileinfo in files)
{
- MPlist plist = null;
- using (FileStream stream = fileinfo.OpenRead ())
- {
- plist = new MPlist (stream, 1);
- }
- if (plist != null && plist.IsPlist)
- {
- plist = plist.Plist;
- Tag tag = new Tag (ref plist);
+ Tag tag;
+ MDatabaseInfo info;
- if (! tag.HasWildcard && tag.Match (tag))
- {
- MDatabaseInfo info = new MDatabaseInfo (plist);
- info.Merge (base_info);
- if (Path.IsPathRooted (base_info.Filename))
- info.Filename = fileinfo.FullName;
- else
- info.Filename = fileinfo.Name;
- register (list_idx, dir_idx, tag, info);
- }
+ if (mdb.Info.Format == MSymbol.plist
+ ? parse_plist_header (fileinfo, mdb, out tag, out info)
+ : parse_xml_header (fileinfo, mdb, out tag, out info))
+ {
+ info.Merge (mdb.Info);
+ if (Path.IsPathRooted (mdb.Info.Filename))
+ info.Filename = fileinfo.FullName;
+ else
+ info.Filename = fileinfo.Name;
+ register (list_idx, dir_idx, tag, info);
}
}
}
M17n.DebugPrint ("expanding: {0}\n", this);
if (DirIndex == 0)
- register_files (null, ListIndex, DirIndex, Info);
+ register_files (null, DirIndex, this);
else
for (int i = 1; i < 4; i++)
if (DBDirs[i].DirInfo != null)
- register_files (DBDirs[i].DirInfo.FullName, ListIndex, i, Info);
+ register_files (DBDirs[i].DirInfo.FullName, i, this);
DBStatus = MDBStatus.READY;
}
}
}
+ // Update the status. Return true iff the database file is
+ // readable but changed.
+
private bool update_status ()
{
if (DBType == MDBType.UNKNOWN)
return true;
+ update_all (false);
if (DBStatus == MDBStatus.INVALID)
return false;
- if (DBStatus == MDBStatus.READY)
+ if (DBStatus != MDBStatus.NOT_READY)
{
- if (DirIndex > 0
- || File.Exists (FileInfo.FullName))
- return true;
- DBStatus = MDBStatus.INVALID;
- return false;
- }
+ try {
+ FileInfo.Refresh ();
+ } catch {
+ DBStatus = MDBStatus.INVALID;
+ return false;
+ }
+ if (LastLoaded >= FileInfo.LastWriteTime)
+ return false;
+ DBStatus = MDBStatus.READY;
+ return true;
+ }
for (int i = 1; i < 4; i++)
if (DBDirs[i] != null && DBDirs[i].Dirname != null)
{
{
FileInfo = new FileInfo (filename);
DirIndex = i;
+ DBStatus = MDBStatus.READY;
return true;
- }
+ }
}
return false;
}
break;
}
}
- if (! update_all () && mdb != null)
+ if (! update_all (false) && mdb != null)
return mdb;
maybe_expand_wildcard (tag);
if (! ndict.TryGetValue (tag, out mdbs))
return null;
for (int i = 0; i < mdbs.Count; i++)
- if ((mdb = mdbs[i]).update_status ())
- return mdb;
+ {
+ mdb = mdbs[i];
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ return mdb;
+ }
return null;
}
{
List<MDatabase> list = new List<MDatabase> ();
- update_all ();
+ update_all (false);
maybe_expand_wildcard (tag);
if (tag.HasWildcard)
foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
if (kv.Key.Match (tag))
foreach (MDatabase mdb in kv.Value)
- if (mdb.update_status ())
- {
- list.Add (mdb);
- break;
- }
+ {
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
}
else
{
List<MDatabase> mdbs;
if (ndict.TryGetValue (tag, out mdbs))
foreach (MDatabase mdb in mdbs)
- if (mdb.update_status ())
- {
- list.Add (mdb);
- break;
- }
+ {
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
}
return list;
}
- public object Load ()
+ private FileStream get_stream ()
+ {
+ if (DBStatus != MDBStatus.READY)
+ {
+ LastLoadStatus = LoadStatus.NotAvailable;
+ return null;
+ }
+
+ FileStream stream = null;
+ try {
+ stream = FileInfo.OpenRead ();
+ } catch {
+ LastLoadStatus = LoadStatus.NotReadable;
+ }
+ return stream;
+ }
+
+ public MPlist Load ()
{
if (loader != null)
return loader (tag, ExtraInfo);
+ if (Info.Format != MSymbol.plist)
+ throw new Exception ("Not a plist database");
- if (Info.Format == Mchar_table)
- return load_char_table ();
- if (Info.Format == Mcharset)
- return load_charset ();
-
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
MPlist plist = null;
- using (FileStream stream = File.OpenRead (FileInfo.FullName))
+ try {
plist = new MPlist (stream);
+ LastLoaded = DateTime.Now;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
return plist;
}
- public object Load (MSymbol key, MSymbol stop)
+ public MPlist Load (MSymbol key, MSymbol stop)
{
- if (loader != null || Info.Format != MSymbol.plist)
- throw new ArgumentException
- ("Key can't be specified for loading this database");
+ if (loader != null)
+ throw new Exception ("Partial load is impossible");
+ if (Info.Format != MSymbol.plist)
+ throw new Exception ("Not a plist database");
- MPlist plist = null;
- using (FileStream stream = File.OpenRead (FileInfo.FullName))
- plist = new MPlist (stream, key, stop);
- return plist;
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
+ try {
+ MPlist plist = new MPlist (stream, key, stop);
+ LastLoaded = DateTime.Now;
+ return plist;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ return null;
+ } finally {
+ stream.Dispose ();
+ }
}
- private object load_charset ()
+ public MPlist Load (MSymbol stop)
{
- return null;
+ if (loader != null)
+ throw new Exception ("Partial load is impossible");
+ if (Info.Format != MSymbol.plist)
+ throw new Exception ("Not a plist database");
+
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
+ try {
+ MPlist plist = new MPlist (stream, stop);
+ LastLoaded = DateTime.Now;
+ return plist;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ return null;
+ } finally {
+ stream.Dispose ();
+ }
}
- private object load_char_table ()
+ private XmlTextReader get_reader (XmlDocument doc)
{
- return null;
+ XmlTextReader reader;
+
+ try {
+ if (doc.NameTable != null)
+ reader = new XmlTextReader (FileInfo.FullName, doc.NameTable);
+ else
+ reader = new XmlTextReader (FileInfo.FullName);
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ } catch {
+ LastLoadStatus = LoadStatus.NotReadable;
+ reader = null;
+ }
+ return reader;
+ }
+
+ public bool Load (XmlDocument doc)
+ {
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML database");
+ XmlTextReader reader = get_reader (doc);
+ if (reader == null)
+ return false;
+ try {
+ doc.Load (reader);
+ LastLoaded = DateTime.Now;
+ return true;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ return false;
+ } finally {
+ reader.Close ();
+ }
+ }
+
+ public bool Load (XmlDocument doc, MSymbol key, MSymbol stop)
+ {
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML database");
+ XmlTextReader reader = get_reader (doc);
+ if (reader == null)
+ return false;
+ try {
+ reader.Read ();
+ while (reader.NodeType != XmlNodeType.Element)
+ reader.Read ();
+ doc.LoadXml ("<" + reader.Name + "></" + reader.Name + ">");
+ reader.Read ();
+ XmlNode node = doc.DocumentElement;
+ while (reader.NodeType == XmlNodeType.Element
+ ? reader.Name != stop.Name
+ : reader.NodeType != XmlNodeType.EndElement)
+ if (reader.NodeType == XmlNodeType.Element
+ && reader.Name == key.Name)
+ node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader),
+ node);
+ return true;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ return false;
+ } finally {
+ reader.Close ();
+ }
+ }
+
+ public bool Load (XmlDocument doc, MSymbol stop)
+ {
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML database");
+ XmlTextReader reader = get_reader (doc);
+ if (reader == null)
+ return false;
+ try {
+ reader.Read ();
+ while (reader.NodeType != XmlNodeType.Element)
+ reader.Read ();
+ doc.LoadXml ("<" + reader.Name + "></" + reader.Name + ">");
+ reader.Read ();
+ XmlNode node = doc.DocumentElement;
+ while (reader.NodeType == XmlNodeType.Element
+ ? reader.Name != stop.Name
+ : reader.NodeType != XmlNodeType.EndElement)
+ node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader), node);
+ return true;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ return false;
+ } finally {
+ reader.Close ();
+ }
+ }
+
+ public XmlNode Load (XmlDocument doc, string id, params string[] nodes)
+ {
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML database");
+ XmlTextReader reader = get_reader (doc);
+ if (reader == null)
+ return null;
+ try {
+ int len = nodes.Length;
+ do {
+ reader.Read ();
+ } while (reader.NodeType != XmlNodeType.Element);
+ if (reader.Name != nodes[0])
+ return null;
+
+ string ns = reader.GetAttribute ("xmlns");
+ XmlNode top = doc.CreateNode (XmlNodeType.Element, nodes[0], ns);
+ XmlNode node = top;
+ int i;
+
+ for (i = 1; i + 1 < len; i++)
+ {
+ if (! reader.ReadToDescendant (nodes[i]))
+ return null;
+ node = node.InsertAfter (doc.CreateNode (XmlNodeType.Element,
+ nodes[i], ns), null);
+ }
+ if (! reader.ReadToDescendant (nodes[i]))
+ return null;
+ XmlNode ref_node = null;
+ while (reader.NodeType != XmlNodeType.EndElement)
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ if (reader.Name == nodes[i]
+ && (id == null || id == reader.GetAttribute ("id")))
+ ref_node = node.InsertAfter (doc.ReadNode (reader), ref_node);
+ else
+ reader.Skip ();
+ }
+ else
+ reader.Read ();
+ }
+ return top;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ return null;
+ } finally {
+ reader.Close ();
+ }
}
/// <summary>Return a list of currently available database
return dirs.ToArray ();
}
+ public MSymbol Format { get { return Info.Format; } }
+
+ public static bool Changed (DateTime time)
+ {
+ update_all (false);
+ return (time < LastUpdateTime);
+ }
+
+ public bool NeedReload ()
+ {
+ return update_status ();
+ }
+
// For IComparable<MDatabase>
public int CompareTo (MDatabase other)
{