using System;
+using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Xml;
+
using M17N;
using M17N.Core;
namespace M17N.Core
{
+ internal class MGlob
+ {
+ static readonly char sep = Path.DirectorySeparatorChar;
+
+ public static void FileList (ref List<FileInfo> files,
+ string dir, string pattern)
+ {
+ int len = pattern.Length;
+
+ if (Path.IsPathRooted (pattern))
+ {
+ int headsep = 0;
+ int i;
+
+ for (i = 1; i < len && (pattern[i] != '*' && pattern[i] != '?'); i++)
+ if (pattern[i] == sep)
+ headsep = i;
+ if (i == len)
+ {
+ if (File.Exists (pattern))
+ files.Add (new FileInfo (pattern));
+ return;
+ }
+ dir = pattern.Substring (0, headsep);
+ pattern = pattern.Substring (headsep + 1);
+ }
+ else
+ {
+ if (dir == null)
+ dir = Directory.GetCurrentDirectory ();
+ }
+ if (Directory.Exists (dir))
+ list (ref files, new DirectoryInfo (dir), pattern);
+ }
+
+ private static void list (ref List<FileInfo> files,
+ DirectoryInfo dirinfo, string pattern)
+ {
+ 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);
+ }
+ else
+ {
+ 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);
+ }
+ }
+
internal class MDatabaseDir
{
private const string ListFileName = "mdb.dir";
public string Dirname;
public DirectoryInfo DirInfo;
+ public DateTime DirChangeTime;
public FileInfo ListInfo;
- public DateTime LastScanned;
+ public DateTime ListChangeTime;
public MDatabaseDir (string dirname)
{
Dirname = dirname;
- if (dirname != null)
- {
- try {
- DirInfo = new DirectoryInfo (dirname);
- try {
- ListInfo = DirInfo.GetFiles (ListFileName)[0];
- } catch {
- ListInfo = null;
- }
- } catch {
- DirInfo = null;
- ListInfo = null;
- }
- }
+ DirChangeTime = ListChangeTime = DateTime.Now;
}
- public bool CheckStatus ()
+ public void Refresh ()
{
if (DirInfo != null)
{
- try {
- DirInfo.Refresh ();
- } catch {
- DirInfo = null;
- ListInfo = null;
- LastScanned = new DateTime (0);
- return true;
- }
- if (ListInfo != null)
- try {
- ListInfo.Refresh ();
- } catch {
- ListInfo = null;
- return true;
+ if (Dirname != null && Directory.Exists (Dirname))
+ {
+ DirInfo.Refresh ();
+ if (DirChangeTime < DirInfo.LastWriteTime)
+ DirChangeTime = DirInfo.LastWriteTime;
}
else
{
- try {
- ListInfo = DirInfo.GetFiles (ListFileName)[0];
- return true;
- } catch {
- ListInfo = null;
- }
+ DirInfo = null;
+ DirChangeTime = DateTime.Now;
}
- return (LastScanned < DirInfo.LastWriteTime
- || (ListInfo != null
- && LastScanned < ListInfo.LastWriteTime));
}
else
{
if (Dirname != null && Directory.Exists (Dirname))
{
DirInfo = new DirectoryInfo (Dirname);
+ DirChangeTime = DateTime.Now;
+ }
+ }
+ if (DirInfo == null)
+ {
+ if (ListInfo != null)
+ {
+ ListInfo = null;
+ ListChangeTime = DateTime.Now;
+ }
+ }
+ else
+ {
+ if (ListInfo != null)
+ {
+ ListInfo.Refresh ();
+ if (ListChangeTime < ListInfo.LastWriteTime)
+ ListChangeTime = ListInfo.LastWriteTime;
+ }
+ else
+ {
try {
ListInfo = DirInfo.GetFiles (ListFileName)[0];
+ ListChangeTime = DateTime.Now;
} catch {
- ListInfo = null;
}
- return true;
}
- return false;
}
}
-
- public void UpdateStatus ()
- {
- if (DirInfo != null)
- LastScanned = DateTime.UtcNow;
- }
-
- public FileInfo[] Scan (string filename)
- {
- if (DirInfo == null)
- return null;
- DirInfo.Refresh ();
- return DirInfo.GetFiles (filename);
- }
}
- public class MDatabase
+ public partial class MDatabase : IComparable<MDatabase>
{
- /// Tags to identify a MDatabase.
- public struct Tag
+ /// Identifier of a MDatabase.
+ public struct Tag : IEquatable<Tag>
{
- public MSymbol[] Tags;
+ private MSymbol[] Tags;
public Tag (MSymbol tag0)
{
Tags[0] = tag0; Tags[1] = tag1; Tags[2] = tag2; Tags[3] = tag3;
}
- public bool Match (Tag tag)
+ public Tag (ref MPlist plist)
+ {
+ Tags = new MSymbol[4];
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (plist.IsSymbol)
+ {
+ Tags[i] = plist.Symbol;
+ plist = plist.Next;
+ }
+ else
+ Tags[i] = MSymbol.nil;
+ }
+ }
+
+ public bool Equals (Tag tag)
{
for (int i = 0; i < 4; i++)
- {
- if (tag.Tags[i] == Mwildcard || Tags[i] == Mwildcard)
- return true;
- if (tag.Tags[i] != Tags[i])
- return false;
- }
+ if (tag[i] != Tags[i])
+ return false;
return true;
}
+ public override int GetHashCode ()
+ {
+ return (Tags[0].GetHashCode () ^ Tags[1].GetHashCode ()
+ ^ Tags[2].GetHashCode () ^ Tags[3].GetHashCode ());
+ }
+
public override string ToString ()
{
return ("<"
+ Tags[0] + "," + Tags[1] + "," + Tags[2] + "," + Tags[3]
+ ">");
}
+
+ public MSymbol this[int i]
+ {
+ set { Tags[i] = value; }
+ get { return Tags[i]; }
+ }
+
+ public bool Match (Tag tag)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (tag[i] == Mwildcard || Tags[i] == Mwildcard)
+ return true;
+ if (tag[i] != Tags[i])
+ return false;
+ }
+ return true;
+ }
+
+ public bool HasWildcard {
+ get {
+ for (int i = 0; i < 4; i++)
+ if (Tags[i] == Mwildcard)
+ return true;
+ return false;
+ }
+ }
}
public delegate object Loader (Tag tag, object extra_info);
- internal class MDatabaseInfo {
- // -2: absolute, -1: unknown 0: DBDirs[0], 1: DBDirs[1], 2: DBDirs[2]
- internal int DirIndex;
+ internal class MDatabaseInfo
+ {
+ // These come from the declartion plist of the database.
internal string Description;
internal string Filename;
- internal FileInfo FileInfo;
internal FileInfo Validater;
internal int Version;
internal MSymbol Format;
internal MSymbol Schema;
internal string SchemaFile;
- internal DateTime ModifiedTime;
internal MPlist Props;
public MDatabaseInfo ()
{
Format = Schema = MSymbol.nil;
- DirIndex = -1;
+ }
+
+ private static int parse_version (MPlist plist)
+ {
+ string[] str;
+ int major, minor, release;
+
+ if (! plist.IsMText)
+ return 0xFFFFFF;
+ str = plist.Text.ToString ().Split ('.');
+ if (str.Length != 3)
+ return 0xFFFFFF;
+ try { major = int.Parse (str[0]); } catch { return 0xFFFFFF; }
+ try { minor = int.Parse (str[1]); } catch { return 0xFFFFFF; }
+ try { release = int.Parse (str[2]); } catch { return 0xFFFFFF; }
+ return ((major << 16) | (minor << 8) | release);
+ }
+
+ public MDatabaseInfo (MPlist plist)
+ {
+ Format = MSymbol.nil;
+ if (plist.IsMText)
+ {
+ Format = MSymbol.plist;
+ Filename = plist.Text.ToString ();
+ plist = plist.Next;
+ }
+ else if (plist.IsPlist)
+ {
+ MPlist p = plist.Plist;
+
+ if (p.IsMText)
+ {
+ Filename = p.Text.ToString ();
+ p = p.Next;
+ }
+ if (p.IsSymbol)
+ {
+ Format = p.Symbol;
+ p = p.Next;
+ }
+ if (p.IsSymbol)
+ {
+ Schema = p.Symbol;
+ p = p.Next;
+ }
+ if (p.IsMText)
+ SchemaFile = p.Text.ToString ();
+ plist = plist.Next;
+ }
+
+ Version = 0;
+ Props = new MPlist ();
+ foreach (MPlist pl in plist)
+ {
+ if (pl.IsPlist)
+ {
+ MPlist p = pl.Plist;
+
+ if (p.IsSymbol && p.Symbol == Mversion)
+ Version = parse_version (p.Next);
+ else
+ Props.Put (pl.Key, pl.Val);
+ }
+ else if (pl.IsSymbol)
+ {
+ MPlist p = new MPlist ();
+ p.Add (MSymbol.symbol, pl.Symbol);
+ p.Add (MSymbol.symbol, MSymbol.t);
+ Props.Put (MSymbol.plist, p);
+ }
+ }
+ }
+
+ public void Merge (MDatabaseInfo src)
+ {
+ if (Validater == null)
+ Validater = src.Validater;
+ if (Version == 0)
+ Version = src.Version;
+ if (Format == MSymbol.nil)
+ Format = src.Format;
+ if (Schema == MSymbol.nil)
+ Schema = src.Schema;
+ if (SchemaFile == null)
+ SchemaFile = src.SchemaFile;
+ foreach (MPlist p in src.Props)
+ if (Props.Assq (p.Plist.Symbol) == null)
+ Props.Push (p.Key, p.Val);
}
public override string ToString ()
{
- string str = ("#<Info " + Format + " \"" + Filename
- + "\" (" + DirIndex + ")");
+ string str = ("#<Info " + Format + " \"" + Filename + "\"");
if (Schema != MSymbol.nil)
str += " " + Schema;
return str + ">";
}
}
- private static Dictionary<MDatabase.Tag, MDatabase[]> DBDict
- = new Dictionary<MDatabase.Tag, MDatabase[]> ();
+ // Dictionaries for normal databases.
+ private static Dictionary<MDatabase.Tag, List<MDatabase>> ndict
+ = new Dictionary<MDatabase.Tag, List<MDatabase>> ();
+
+ // Dictionaries for databases of DBType WILDCARD
+ private static Dictionary<MDatabase.Tag, List<MDatabase>> wdict
+ = new Dictionary<MDatabase.Tag, List<MDatabase>> ();
- private static Dictionary<MDatabase.Tag, MDatabase[]> DBDictMulti
- = new Dictionary<MDatabase.Tag, MDatabase[]> ();
+ private static MDatabaseDir[] DBDirs = new MDatabaseDir[4];
- private static MDatabaseDir[] DBDirs = new MDatabaseDir[3];
+ private static DateTime LastUpdateTime = new DateTime (0);
- private static readonly MSymbol Mversion = MSymbol.Of ("version");
+ 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 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 TimeSpan CheckInterval = new TimeSpan (50000000);
/// Type of database
private enum MDBType
/// Status of database
private enum MDBStatus
{
- // The database file is currently disabled. It means that the
- // database file is not readable or the database is deleted by
- // the modification of "mdb.dir".
+ // The database file has not yet been decided, or is not yet
+ // expanded if DBType is WILDCARD.
+ NOT_READY,
+ // The database file was decided, or has been expanded if
+ // DBType is WILDCARD.
+ READY,
+ // The database is disabled. It means that the database file
+ // is not readable, the version is not supported by the
+ // current system, or the validation was failed.
DISABLED,
- // The database file has not yet been loaded, or was modified
- // after the previous loading.
- OUTDATED,
- // The database file has not been modified after the previous
- // loading.
- UPDATED,
- // The database file is updated but the validation was failed
- // or the version is not supported by the current system.
+ // The database is deleted by the modificaiton of mdb.dir, or
+ // is overwritten by a new explicit definition.
INVALID,
};
public Tag tag;
private Loader loader;
private object ExtraInfo;
+ // Directory of the database file.
+ // -1:unknown, 0:absolute, 1:DBDirs[1], 2:DBDirs[2], 3:DBDirs[3]
+ private int DirIndex;
+ // Directory of the mdb.dir defining the database file.
+ // 0: EXPLICIT or UNKNOWN, 1:DBDirs[1], 2:DBDirs[2], 3:DBDirs[3]
+ private int ListIndex;
private MDBType DBType;
private MDBStatus DBStatus;
- internal DateTime LoadedTime;
internal MDatabaseInfo Info;
+ // File in which the database contents is stored. This is null
+ // when DBStatus is NOT_READY.
+ internal FileInfo FileInfo;
+ // 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 ()
{
(Environment.SpecialFolder.ApplicationData));
try {
- DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, ".m17n.d"));
- } catch (ArgumentException) {
- DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n_d"));
+ string dir = Environment.GetEnvironmentVariable ("M17NDIR");
+ DBDirs[1] = new MDatabaseDir (dir);
+ } catch {
+ try {
+ DBDirs[1] = new MDatabaseDir (Path.Combine (usr_dir, ".m17n.d"));
+ } catch (ArgumentException) {
+ DBDirs[1] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n_d"));
+ }
}
- DBDirs[1] = new MDatabaseDir (null);
- DBDirs[2] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
+ DBDirs[2] = new MDatabaseDir (null);
+ DBDirs[3] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
+ update_all (true);
}
public static string ApplicationDir
- { get { return (DBDirs[1].Dirname); }
- set { DBDirs[1].Dirname = value; DBDirs[1].CheckStatus (); } }
+ {
+ get { return (DBDirs[1].Dirname); }
+ set { DBDirs[2] = new MDatabaseDir (value); update_all (true); }
+ }
- private static bool update_database_directories ()
+ // Update all listing and directories. Return true iff some are
+ // really updated.
+ private static bool update_all (bool force)
{
+ if (! force && DateTime.Now - LastUpdateTime < CheckInterval)
+ return false;
+
bool updated = false;
- for (int i = 0; i < 3; i++)
- if (DBDirs[i].CheckStatus ())
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].Dirname != null)
{
- delete_databases (i);
- if (DBDirs[i].ListInfo != null)
- update_databases (i);
- updated = true;
+ DBDirs[i].Refresh ();
+ if (LastUpdateTime < DBDirs[i].ListChangeTime)
+ {
+ update_list (i);
+ updated = true;
+ }
+ if (LastUpdateTime < DBDirs[i].DirChangeTime)
+ {
+ update_dir (i);
+ updated = true;
+ }
}
+ if (updated)
+ LastUpdateTime = DateTime.Now;
return updated;
}
- public static void ListDirs ()
+ public static void Dump ()
{
- update_database_directories ();
- for (int i = 0; i < 3; i++)
+ update_all (false);
+ Console.WriteLine ("[DBDirs]");
+ for (int i = 1; i < 4; i++)
if (DBDirs[i].Dirname != null)
{
- Console.Write ("{0}:{1}", i, DBDirs[i].Dirname);
if (DBDirs[i].DirInfo != null)
{
+ Console.Write ("{0}:{1}", i, DBDirs[i].DirInfo.FullName);
if (DBDirs[i].ListInfo != null)
Console.WriteLine (" {0}", DBDirs[i].ListInfo);
else
- Console.WriteLine (".. no mdb.dir");
+ Console.WriteLine (" .. no mdb.dir");
}
else
- Console.WriteLine (".. not exist");
+ Console.WriteLine ("{0}:{1} .. not exist", i, DBDirs[i].Dirname);
}
+
+ Console.WriteLine ("[WDICT]");
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in wdict)
+ foreach (MDatabase mdb in kv.Value)
+ Console.WriteLine (mdb);
+
+ Console.WriteLine ("[NDICT]");
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+ foreach (MDatabase mdb in kv.Value)
+ Console.WriteLine (mdb);
+ }
+
+ private static void register (MDatabase mdb)
+ {
+ Dictionary<MDatabase.Tag, List<MDatabase>> dict
+ = mdb.DBType == MDBType.WILDCARD ? wdict : ndict;
+ List<MDatabase> mdbs;
+
+ if (dict.TryGetValue (mdb.tag, out mdbs))
+ {
+ for (int i = 0; i < mdbs.Count; i++)
+ if (mdbs[i].ListIndex == mdb.ListIndex)
+ {
+ mdbs[i].DBStatus = MDBStatus.INVALID;
+ mdbs[i] = mdb;
+ return;
+ }
+ mdbs.Add (mdb);
+ }
+ else
+ {
+ mdbs = new List<MDatabase> (1);
+ mdbs.Add (mdb);
+ dict.Add (mdb.tag, mdbs);
+ }
}
- private void register (int priority)
+ private static void register (int list_idx, int dir_idx,
+ Tag tag, MDatabaseInfo info)
{
- Dictionary<MDatabase.Tag, MDatabase[]> dict
- = DBType == MDBType.WILDCARD ? DBDictMulti : DBDict;
- MDatabase[] mdbs;
+ Dictionary<MDatabase.Tag, List<MDatabase>> dict
+ = tag.HasWildcard ? wdict : ndict;
+ List<MDatabase> mdbs;
+ MDatabase mdb;
- if (! dict.TryGetValue (tag, out mdbs))
+ if (dict.TryGetValue (tag, out mdbs))
+ for (int i = 0; i < mdbs.Count; i++)
+ {
+ mdb = mdbs[i];
+ if (mdb.ListIndex == list_idx && mdb.DirIndex >= dir_idx)
+ {
+ mdb.DirIndex = dir_idx;
+ if (dict == wdict)
+ {
+ mdb.DBType = MDBType.WILDCARD;
+ mdb.DBStatus = MDBStatus.NOT_READY;
+ }
+ else if (dir_idx == -1)
+ {
+ mdb.DBType = MDBType.AUTO;
+ mdb.DBStatus = MDBStatus.NOT_READY;
+ }
+ else
+ {
+ mdb.DBType = MDBType.MULTIPLE;
+ 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;
+ }
+ }
+ else
{
- mdbs = new MDatabase[4];
+ mdbs = new List<MDatabase> (1);
dict.Add (tag, mdbs);
}
- mdbs[priority] = this;
+ mdb = new MDatabase (list_idx, dir_idx, tag, info);
+ M17n.DebugPrint ("registering: {0}\n", mdb);
+ mdbs.Add (mdb);
}
public MDatabase (Tag tag, Loader loader, object extra_info)
this.tag = tag;
this.loader = loader;
DBType = MDBType.UNKNOWN;
- DBStatus = MDBStatus.UPDATED;
+ DBStatus = MDBStatus.READY;
+ DirIndex = 0;
+ ListIndex = 0;
ExtraInfo = extra_info;
- this.register (0);
+ register (this);
}
public MDatabase (Tag tag, string filename)
{
this.tag = tag;
DBType = MDBType.EXPLICIT;
- DBStatus = MDBStatus.OUTDATED;
- Info = new MDatabaseInfo ();
- Info.Filename = filename;
- Info.DirIndex = Path.IsPathRooted (filename) ? -2 : -1;
- this.register (0);
- }
-
- private MDatabase (MPlist plist, int priority)
- {
- tag = new Tag (MSymbol.nil);
- DBType = MDBType.AUTO;
- DBStatus = MDBStatus.OUTDATED;
- for (int i = 0; plist.IsSymbol; i++, plist = plist.Next)
+ if (Path.IsPathRooted (filename))
{
- if (DBType == MDBType.WILDCARD)
- tag.Tags[i] = MSymbol.nil;
+ DirIndex = 0;
+ if (File.Exists (filename))
+ DBStatus = MDBStatus.READY;
else
- {
- tag.Tags[i] = plist.Symbol;
- if (tag.Tags[i] == Mwildcard)
- DBType = MDBType.WILDCARD;
- }
+ DBStatus = MDBStatus.INVALID;
}
-
- Info = new MDatabaseInfo ();
- if (tag.Tags[0] == Mchar_table || tag.Tags[0] == Mcharset)
- Info.Format = tag.Tags[0];
else
- Info.Format = MSymbol.plist;
- if (plist.IsMText)
{
- Info.Filename = plist.Text.ToString ();
- plist = plist.Next;
+ DirIndex = -1;
+ DBStatus = MDBStatus.NOT_READY;
}
- else if (plist.IsPlist)
- {
- MPlist p = plist.Plist;
+ ListIndex = 0;
+ Info = new MDatabaseInfo ();
+ Info.Filename = filename;
+ register (this);
+ }
- if (p.IsMText)
- Info.Filename = plist.Text.ToString ();
- p = p.Next;
- if (! p.IsEmpty)
- {
- if (p.IsSymbol)
- Info.Format = p.Symbol;
- p = p.Next;
- if (! p.IsEmpty)
- {
- if (p.IsSymbol)
- Info.Schema = p.Symbol;
- p = p.Next;
- if (p.IsMText)
- Info.SchemaFile = p.Text.ToString ();
- }
- }
- plist = plist.Next;
- }
+ private MDatabase (int list_idx, int dir_idx, Tag tag, MDatabaseInfo info)
+ {
+ this.tag = tag;
+ this.Info = info;
+ DBType = this.tag.HasWildcard ? MDBType.WILDCARD : MDBType.AUTO;
+ 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
- throw new Exception ("Invalid source definition:" + plist);
-
- Info.DirIndex = Path.IsPathRooted (Info.Filename) ? -2 : -1;
- Info.Version = 0;
- Info.Props = new MPlist ();
- foreach (MPlist pl in plist)
- {
- if (pl.IsPlist)
- {
- MPlist p = pl.Plist;
-
- if (p.IsSymbol && p.Symbol == Mversion)
- {
- Info.Version = parse_version (p.Next);
- if (M17n.Version < Info.Version)
- DBStatus = MDBStatus.DISABLED;
- }
- }
- Info.Props.Put (pl.Key, pl.Val);
- }
- this.register (priority);
+ DBStatus = MDBStatus.NOT_READY;
+ if (Info.Format == Mchar_table)
+ MCharProp.Define (tag[2], this);
}
public override String ToString () {
- string str = "#<MDataBase " + tag + " " + DBType + " " + DBStatus;
+ string str = ("#<MDataBase (" + ListIndex + "," + DirIndex + ") "
+ + tag + " " + DBType + " " + DBStatus);
if (DBType != MDBType.EXPLICIT && DBType != MDBType.UNKNOWN)
str += " " + Info;
return str + ">";
}
- private static int parse_version (MPlist plist)
+ // Update (or disable) databases defined by "mdb.dir" in
+ // DBDirs[list_idx].
+ private static void update_list (int list_idx)
{
- string[] str;
- int major, minor, release;
+ M17n.DebugPrint ("Updating list: {0}\n", list_idx);
+ // At first disable all target databases.
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in wdict)
+ foreach (MDatabase mdb in kv.Value)
+ if (mdb.ListIndex == list_idx)
+ {
+ M17n.DebugPrint ("deleting: {0}\n", mdb);
+ mdb.DBStatus = MDBStatus.INVALID;
+ break;
+ }
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+ foreach (MDatabase mdb in kv.Value)
+ if (mdb.ListIndex == list_idx)
+ {
+ M17n.DebugPrint ("deleting: {0}\n", mdb);
+ mdb.DBStatus = MDBStatus.INVALID;
+ break;
+ }
+
+ FileInfo dblist = DBDirs[list_idx].ListInfo;
+ if (dblist == null)
+ return;
- if (! plist.IsMText)
- return 0xFFFFFF;
- str = plist.Text.ToString ().Split ('.');
- if (str.Length != 3)
- return 0xFFFFFF;
- try { major = int.Parse (str[0]); } catch { return 0xFFFFFF; }
- try { minor = int.Parse (str[1]); } catch { return 0xFFFFFF; }
- try { release = int.Parse (str[2]); } catch { return 0xFFFFFF; }
- return ((major << 16) | (minor << 8) | release);
+ MPlist plist = null;
+ using (FileStream stream = File.OpenRead (dblist.FullName))
+ {
+ plist = new MPlist (stream);
+ }
+ if (plist == null)
+ return;
+ foreach (MPlist pl in plist)
+ if (pl.IsPlist)
+ {
+ try
+ {
+ MPlist p = pl.Plist;
+ Tag tag = new Tag (ref p);
+ MDatabaseInfo info = new MDatabaseInfo (p);
+ int dir_idx = Path.IsPathRooted (info.Filename) ? 0 : -1;
+ register (list_idx, dir_idx, tag, info);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine (e.Message + ": " + pl.Plist);
+ }
+ }
}
- private static void delete_databases (int list_idx)
+ // Update (or disable) databases in DBDirs[dir_idx].
+ private static void update_dir (int dir_idx)
{
- foreach (KeyValuePair<Tag, MDatabase[]> item in DBDict)
- item.Value[list_idx + 1] = null;
- foreach (KeyValuePair<Tag, MDatabase[]> item in DBDictMulti)
- item.Value[list_idx + 1] = null;
+ M17n.DebugPrint ("Updating dir: {0}\n", dir_idx);
+ // Reset all databases in DBDirs[dir_idx].
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+ foreach (MDatabase mdb in kv.Value)
+ if (mdb.DirIndex >= dir_idx)
+ {
+ M17n.DebugPrint ("disabling: {0}\n", mdb);
+ mdb.DBStatus = MDBStatus.NOT_READY;
+ mdb.DirIndex = -1;
+ }
+ // Re-expand all WILDCARD databases in DBDirs[dir_idx].
+ if (DBDirs[dir_idx].DirInfo != null)
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in wdict)
+ foreach (MDatabase mdb in kv.Value)
+ if (mdb.DBStatus == MDBStatus.READY)
+ {
+ M17n.DebugPrint ("re-expanding: {0}\n", mdb);
+ register_files (DBDirs[dir_idx].Dirname, dir_idx, mdb);
+ }
}
- private static void update_databases (int list_idx)
+ private static bool parse_plist_header (FileInfo fileinfo, MDatabase mdb,
+ out Tag tag, out MDatabaseInfo info)
{
- MDatabaseDir dbdir = DBDirs[list_idx];
- FileInfo dblist = dbdir.ListInfo;
MPlist plist = null;
- using (FileStream stream = File.OpenRead (dblist.FullName))
+ tag = new Tag (MSymbol.nil);
+ info = null;
+ using (FileStream stream = fileinfo.OpenRead ())
{
- MStreamReader reader = new MStreamReader (stream);
- plist = new MPlist (reader);
+ try { plist = new MPlist (stream, 1); } catch { }
}
- if (plist == null)
- return;
- foreach (MPlist pl in plist)
+ 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 ())
{
- if (! pl.IsPlist)
- continue;
- try
- {
- new MDatabase (pl.Plist, list_idx + 1);
- }
- catch (Exception e)
- {
- Console.WriteLine (e.Message);
- }
+ 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 void expand_wildcard (int priority)
+ private static void register_files (string dir, int dir_idx, MDatabase mdb)
{
- if (Info.DirIndex == -2)
+ int list_idx = mdb.ListIndex;
+ List<FileInfo> files = new List<FileInfo> ();
+ MGlob.FileList (ref files, dir, mdb.Info.Filename);
+ foreach (FileInfo fileinfo in files)
{
-
+ Tag tag;
+ MDatabaseInfo 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);
+ }
}
+ }
+
+ private void expand_wildcard ()
+ {
+ M17n.DebugPrint ("expanding: {0}\n", this);
+ if (DirIndex == 0)
+ register_files (null, DirIndex, this);
+ else
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].DirInfo != null)
+ register_files (DBDirs[i].DirInfo.FullName, i, this);
+ DBStatus = MDBStatus.READY;
}
- private void update_status ()
+ private static void maybe_expand_wildcard (Tag tag)
{
- if (Info.DirIndex == -2)
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in wdict)
{
+ M17n.DebugPrint ("expand check: {0}\n", kv.Key);
+ if (kv.Key.Match (tag))
+ {
+ foreach (MDatabase mdb in kv.Value)
+ {
+ if (mdb.DBStatus == MDBStatus.NOT_READY)
+ mdb.expand_wildcard ();
+ }
+ }
}
}
+ // 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.NOT_READY)
+ {
+ 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)
+ {
+ string filename = Path.Combine (DBDirs[i].Dirname, Info.Filename);
+ if (File.Exists (filename))
+ {
+ FileInfo = new FileInfo (filename);
+ DirIndex = i;
+ DBStatus = MDBStatus.READY;
+ return true;
+ }
+ }
+ return false;
+ }
+
public static MDatabase Find (Tag tag)
{
- MDatabase[] mdbs;
+ List<MDatabase> mdbs;
MDatabase mdb = null;
- if (DBDict.TryGetValue (tag, out mdbs))
+ if (tag.HasWildcard)
+ throw new ArgumentException ("Wildcard not allowed: " + tag);
+
+ if (ndict.TryGetValue (tag, out mdbs))
{
- if (mdbs[0] != null)
- return mdbs[0];
- for (int i = 1; i < 4; i++)
- if ((mdb = mdbs[i]) != null)
- break;
+ mdbs.Sort ();
+ for (int i = 0; i < mdbs.Count; i++)
+ {
+ mdb = mdbs[i];
+ if (mdb.ListIndex == 0)
+ return mdb;
+ if (mdb.DBStatus == MDBStatus.READY)
+ break;
+ }
}
- if (! update_database_directories ())
+ if (! update_all (false) && mdb != null)
return mdb;
- if (! DBDict.TryGetValue (tag, out mdbs))
+ maybe_expand_wildcard (tag);
+ if (! ndict.TryGetValue (tag, out mdbs))
return null;
- for (int i = 1; i < 4; i++)
- if (mdbs[i] != null)
- return mdbs[i];
+ for (int i = 0; i < mdbs.Count; i++)
+ {
+ mdb = mdbs[i];
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ return mdb;
+ }
return null;
}
{
List<MDatabase> list = new List<MDatabase> ();
- update_database_directories ();
- foreach (KeyValuePair<Tag, MDatabase[]> item in DBDictMulti)
- if (item.Key.Match (tag))
- for (j = 0; j < 4; j++)
- if (item.Value[j] != null)
- if (item.Value[j].DBStatus == MDBStatus.OUTDATED)
- item.Value[j].expand_wildcard (j);
+ update_all (false);
+ maybe_expand_wildcard (tag);
- for (int i = 0; i < 4 && tag.Tags[i] == Mwildcard; i++);
- if (i == 4)
+ if (tag.HasWildcard)
{
- // No wildcard.
- if (DBDict.TryGetValue (tag, out mdbs))
- for (int j = 0; j < 4; j++)
- if (mdbs[j] != null)
+ foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+ if (kv.Key.Match (tag))
+ foreach (MDatabase mdb in kv.Value)
{
- mdbs[j].update_status ();
- if (mdbs[j].DBStatus != MDBStatus.DISABLED)
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
{
- list.Add (mdbs[j]);
+ list.Add (mdb);
break;
}
}
}
else
{
- // With wildcard. We must scan all databases.
- foreach (KeyValuePair<Tag, MDatabase[]> item in DBDict)
- if (item.Key.Match (tag))
- for (int j = 0; j < 4; j++)
- if (item.Value[j] != null)
+ List<MDatabase> mdbs;
+ if (ndict.TryGetValue (tag, out mdbs))
+ foreach (MDatabase mdb in mdbs)
+ {
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
{
- MDatabase mdb = item.Value[j];
- mdb.update_status ();
- if (mdb.DBStatus != MDBStatus.DISABLED)
- {
- list.Add (mdb);
- break;
- }
+ list.Add (mdb);
+ break;
}
+ }
}
return list;
}
+ private FileStream get_stream ()
+ {
+ if (loader != null
+ || (Info.Format != MSymbol.plist && Info.Format != Mxml))
+ {
+ LastLoadStatus = LoadStatus.InvalidLoadMethod;
+ return null;
+ }
+ if (DBStatus != MDBStatus.READY)
+ {
+ LastLoadStatus = LoadStatus.NotAvailable;
+ return null;
+ }
+
+ FileStream stream = null;
+ try {
+ stream = FileInfo.OpenRead ();
+ } catch {
+ LastLoadStatus = LoadStatus.NotReadable;
+ }
+ return stream;
+ }
+
public object Load ()
{
- return (loader != null ? loader (tag, ExtraInfo)
- : load (MSymbol.nil, MSymbol.nil));
+ if (loader != null)
+ return loader (tag, ExtraInfo);
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ try {
+ XmlReader reader = XmlReader.Create (FileInfo.FullName);
+ doc.Load (reader);
+ LastLoaded = DateTime.Now;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ }
+ return doc;
+ }
+
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
+ MPlist plist = null;
+ try {
+ plist = new MPlist (stream);
+ LastLoaded = DateTime.Now;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
+ return plist;
}
public object Load (MSymbol key, MSymbol stop)
{
- if (loader != null)
+ FileStream stream = get_stream ();
+
+ if (stream == null)
return null;
- return load (key, stop);
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ 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);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return doc;
+ }
+
+ MPlist plist = null;
+ try {
+ plist = new MPlist (stream, key, stop);
+ LastLoaded = DateTime.Now;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
+ return plist;
}
- private object load (MSymbol key, MSymbol stop)
+ public object Load (MSymbol stop)
{
- LoadedTime = DateTime.UtcNow;
+ FileStream stream = get_stream ();
- return null;
+ if (stream == null)
+ return null;
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ try {
+ reader.Read ();
+ while (reader.NodeType != XmlNodeType.Element)
+ reader.Read ();
+ doc.LoadXml ("<" + reader.Name + "></" + reader.Name + ">");
+ reader.Read ();
+ XmlNode node = null;
+ while (reader.NodeType == XmlNodeType.Element
+ ? reader.Name != stop.Name
+ : reader.NodeType != XmlNodeType.EndElement)
+ if (reader.NodeType == XmlNodeType.Element)
+ node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader),
+ node);
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return doc;
+ }
+
+ MPlist plist = null;
+ try {
+ plist = new MPlist (stream, stop);
+ LastLoaded = DateTime.Now;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
+ return plist;
+ }
+
+ public XmlNode Load (string id, params string[] nodes)
+ {
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML format");
+
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+ int len = nodes.Length;
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ 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;
+
+ try {
+ 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 ();
+ }
+
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return top;
+ }
+
+ /// <summary>Return a list of currently available database
+ /// directory names</summary>.
+ public static string[] DirectoryList ()
+ {
+ List<string> dirs = new List<string> ();
+
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].Dirname != null)
+ dirs.Add (DBDirs[i].Dirname);
+ 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)
+ {
+ return (ListIndex == other.ListIndex
+ ? DirIndex - other.DirIndex
+ : ListIndex - other.ListIndex);
}
}
-}
\ No newline at end of file
+}