using System;
+using System.Collections;
using System.Collections.Generic;
using System.IO;
using M17N;
namespace M17N.Core
{
- public delegate object MDatabaseLoader (MDatabaseTag tag,
- object extra_info);
-
- public struct MDatabaseTag
+ internal class MGlob
{
- public MSymbol Tag0, Tag1, Tag2, Tag3;
+ static readonly char sep = Path.DirectorySeparatorChar;
- public MDatabaseTag (MSymbol tag0)
- {
- Tag0 = tag0; Tag1 = Tag2 = Tag3 = MSymbol.nil;
- }
+ public static void FileList (ref List<FileInfo> files,
+ string dir, string pattern)
+ {
+ int len = pattern.Length;
- public MDatabaseTag (MSymbol tag0, MSymbol tag1)
- {
- Tag0 = tag0; Tag1 = tag1; Tag2 = Tag3 = MSymbol.nil;
- }
+ if (Path.IsPathRooted (pattern))
+ {
+ int headsep = 0;
+ int i;
- public MDatabaseTag (MSymbol tag0, MSymbol tag1, MSymbol tag2)
- {
- Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = MSymbol.nil;
- }
+ 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);
+ }
- public MDatabaseTag (MSymbol tag0, MSymbol tag1,
- MSymbol tag2, MSymbol tag3)
- {
- Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = tag3;
+ private static void list (ref List<FileInfo> files,
+ DirectoryInfo dirinfo, string pattern)
+ {
+ int len = pattern.Length;
+ int i;
+
+ for (i = 0; i < len && pattern[i] != sep; i++);
+ try {
+ if (i == len)
+ {
+ FileInfo[] listing = dirinfo.GetFiles (pattern);
+ 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);
+ foreach (DirectoryInfo elt in listing)
+ list (ref files, elt, tail);
+ }
+ } catch {
}
+ }
}
- public class MDatabase
+ internal class MDatabaseDir
{
- private class MDatabaseDir
- {
- public string Dirname;
- public DirectoryInfo Info;
- public DateTime LastScanned;
+ private const string ListFileName = "mdb.dir";
- public MDatabaseDir (string dirname)
- {
- Dirname = dirname;
- try {
- Info = new DirectoryInfo (dirname);
- } finally {
- Info = null;
- }
- }
+ public string Dirname;
+ public DirectoryInfo DirInfo;
+ public DateTime DirChangeTime;
+ public FileInfo ListInfo;
+ public DateTime ListChangeTime;
- public bool StatusChanged {
- get {
- bool exists = Directory.Exists (Dirname);
+ public MDatabaseDir (string dirname)
+ {
+ Dirname = dirname;
+ DirChangeTime = ListChangeTime = DateTime.Now;
+ }
- if (Info != null)
+ public void Refresh ()
+ {
+ if (DirInfo != null)
+ {
+ if (Dirname != null && Directory.Exists (Dirname))
{
- if (! exists)
- {
- Info = null;
- return true;
- }
- Info.Refresh ();
- return (LastScanned < Info.LastWriteTime);
+ DirInfo.Refresh ();
+ if (DirChangeTime < DirInfo.LastWriteTime)
+ DirChangeTime = DirInfo.LastWriteTime;
+ }
+ else
+ {
+ DirInfo = null;
+ DirChangeTime = DateTime.Now;
+ }
+ }
+ 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
{
- if (exists)
+ try {
+ ListInfo = DirInfo.GetFiles (ListFileName)[0];
+ ListChangeTime = DateTime.Now;
+ } catch {
+ }
+ }
+ }
+ }
+ }
+
+ public partial class MDatabase : IComparable<MDatabase>
+ {
+ /// Identifier of a MDatabase.
+ public struct Tag : IEquatable<Tag>
+ {
+ private MSymbol[] Tags;
+
+ public Tag (MSymbol tag0)
+ {
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = Tags[2] = Tags[3] = MSymbol.nil;
+ }
+
+ public Tag (MSymbol tag0, MSymbol tag1)
+ {
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = tag1; Tags[2] = Tags[3] = MSymbol.nil;
+ }
+
+ public Tag (MSymbol tag0, MSymbol tag1, MSymbol tag2)
+ {
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = tag1; Tags[2] = tag2; Tags[3] = MSymbol.nil;
+ }
+
+ public Tag (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
+ {
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = tag1; Tags[2] = tag2; Tags[3] = tag3;
+ }
+
+ public Tag (ref MPlist plist)
+ {
+ Tags = new MSymbol[4];
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (plist.IsSymbol)
{
- Info = new DirectoryInfo (Dirname);
- return true;
+ Tags[i] = plist.Symbol;
+ plist = plist.Next;
}
- return false;
+ else
+ Tags[i] = MSymbol.nil;
}
}
+
+ public bool Equals (Tag tag)
+ {
+ for (int i = 0; i < 4; i++)
+ 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 void UpdateStatus ()
+ public override string ToString ()
{
- LastScanned = DateTime.Now;
+ 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;
+ }
}
}
- private class MDatabaseDefinition
+ public delegate object Loader (Tag tag, object extra_info);
+
+ internal class MDatabaseInfo
{
- private static readonly MSymbol Mversion;
- public MDatabaseTag Tag;
- public string Description;
- public MText Filename;
- public bool IsWildcard;
- public MSymbol Format;
- public MSymbol Schema;
- public MText SchemaFile;
- public MPlist props;
- public bool Supported;
-
- static MDatabaseDefinition ()
+ // These come from the declartion plist of the database.
+ internal string Description;
+ internal string Filename;
+ internal FileInfo Validater;
+ internal int Version;
+ internal MSymbol Format;
+ internal MSymbol Schema;
+ internal string SchemaFile;
+ internal MPlist Props;
+
+ public MDatabaseInfo ()
{
- Mversion = new MSymbol ("version");
+ Format = Schema = MSymbol.nil;
}
- public MDatabaseDefinition (MPlist plist)
+ private static int parse_version (MPlist plist)
{
- MSymbol[] tags = new MSymbol[4];
- int i;
-
- for (i = 0; plist.IsSymbol; i++, plist = plist.Next)
- tags[i] = plist.Symbol;
- while (i < 4)
- tags[i++] = MSymbol.nil;
- Tag = new MDatabaseTag (tags[0], tags[1], tags[2], tags[3]);
+ 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.plist;
if (plist.IsMText)
{
- Filename = plist.Text;
+ Filename = plist.Text.ToString ();
plist = plist.Next;
}
else if (plist.IsPlist)
MPlist p = plist.Plist;
if (p.IsMText)
- Filename = plist.Text;
+ Filename = p.Text.ToString ();
p = p.Next;
if (! p.IsEmpty)
{
Schema = p.Symbol;
p = p.Next;
if (p.IsMText)
- SchemaFile = p.Text;
+ SchemaFile = p.Text.ToString ();
}
}
plist = plist.Next;
}
- Supported = true;
- props = new MPlist ();
+
+ Version = 0;
+ Props = new MPlist ();
foreach (MPlist pl in plist)
{
if (pl.IsPlist)
{
MPlist p = pl.Plist;
- if (p.IsSymbol && p.Symbol == Mversion
- && ! check_version (p.Next))
- Supported = false;
- props.Put (pl);
+ 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);
}
}
}
- private bool check_version (MPlist plist)
+ public void Merge (MDatabaseInfo src)
{
- string[] str;
- int major, minor, release;
+ 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);
+ }
- if (! plist.IsMText)
- return false;
- str = plist.Text.ToString ().Split ('.');
- if (str.Length != 3)
- return false;
- try { major = int.Parse (str[0]); } catch { return false; }
- try { minor = int.Parse (str[1]); } catch { return false; }
- try { release = int.Parse (str[2]); } catch { return false; }
- return (M17N.MajorVersion > major
- || (M17N.MajorVersion == major
- && (M17N.MinorVersion > minor
- || (M17N.MinorVersion == minor
- && M17N.ReleaseNumber >= release))));
+ public override string ToString ()
+ {
+ string str = ("#<Info " + Format + " \"" + Filename + "\"");
+ if (Schema != MSymbol.nil)
+ str += " " + Schema;
+ return str + ">";
}
}
- private static MDatabaseDir[] DBDirs = new MDatabaseDir[3];
+ // 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 MDatabaseDir[] DBDirs = new MDatabaseDir[4];
- private const string SystemDirectory = "/usr/share/m17n";
+ private static DateTime LastUpdateTime = new DateTime (0);
- private static Dictionary<MDatabaseTag, MDatabase> DBDict
- = new Dictionary<MDatabaseTag, MDatabase> ();
+ 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");
/// Type of database
private enum MDBType
{
- /// The database was defined automatically (from mdb.dir
- /// file(s)) with no wildcard tag.
+ /// The database was defined automatically from one of mdb.dir
+ /// files with no wildcard tag.
AUTO,
- /// The database was defined automatically (from mdb.dir
- /// file(s)) with a wildcard tag to define multiple databases
+ /// The database was defined automatically from one of mdb.dir
+ /// files with a wildcard tag to define multiple databases
/// of the same kind.
- AUTO_WILDCARD,
- /// The database was defined explicitely (by MDatabaseDefine).
- EXPLICIT
+ MULTIPLE,
+ /// The database was defined explicitely by MDatabase.Define
+ /// to use the normal loader.
+ EXPLICIT,
+ /// The database was defined explicitely by MDatabase.Define
+ /// to use a special loader.
+ UNKNOWN,
+ /// The database is for defining multiple databases of the
+ /// same kind with a wildcard tag.
+ WILDCARD,
};
/// 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.
- // If this is for a database directory, the directory is
- // readable but "mdb.dir" doesn't exist in it.
- INVALID
+ // The database is deleted by the modificaiton of mdb.dir, or
+ // is overwritten by a new explicit definition..
+ INVALID,
};
- public readonly MDatabaseTag Tag;
- private MDatabaseLoader Loader;
+ public Tag tag;
+ private Loader loader;
private object ExtraInfo;
-
- private bool IsSystemDatabase;
- private DirectoryInfo Dir;
- private MText Filename;
- private FileInfo FileInfo;
- private FileInfo Validater;
- private int MajorVersion, MinorVersion, ReleaseNumber;
+ // 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;
- private MSymbol Format;
- private MSymbol Schema;
- private DateTime Mtime;
- private DateTime Ltime;
- private MPlist Props;
+ internal MDatabaseInfo Info;
+ // File in which the database contents is stored.
+ internal FileInfo FileInfo;
+ // When the database file is checked (or validated).
+ internal DateTime CheckedTime;
- public static string ApplicationDirectory;
+ static MDatabase ()
+ {
+ string share_dir = (Environment.GetFolderPath
+ (Environment.SpecialFolder.CommonApplicationData));
+ string usr_dir = (Environment.GetFolderPath
+ (Environment.SpecialFolder.ApplicationData));
- private MDatabase (MDatabaseTag tag, MDatabaseLoader loader,
- object extra_info)
+ try {
+ 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[2] = new MDatabaseDir (null);
+ DBDirs[3] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
+ update_all ();
+ }
+
+ public static string ApplicationDir
{
- Tag = tag;
- Loader = loader;
- ExtraInfo = extra_info;
+ get { return (DBDirs[1].Dirname); }
+ set { DBDirs[2] = new MDatabaseDir (value); update_all (); }
}
- private MDatabase (MDatabaseTag tag, string filename)
+ private static bool update_all ()
{
- Tag = tag;
- Filename = new MText (filename);
+ bool updated = false;
+
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].Dirname != null)
+ {
+ DBDirs[i].Refresh ();
+ if (LastUpdateTime < DBDirs[i].ListChangeTime)
+ {
+ update_list (i);
+ updated = true;
+ }
+ if (LastUpdateTime < DBDirs[i].DirChangeTime)
+ {
+ update_dir (i);
+ updated = true;
+ }
+ }
+ LastUpdateTime = DateTime.Now;
+ return updated;
}
- public static MDatabase Define (MDatabaseTag tag, MDatabaseLoader loader,
- object extra_info)
+ public static void Dump ()
{
- MDatabase db = MDatabase.Find (tag);
+ update_all ();
+ Console.WriteLine ("[DBDirs]");
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].Dirname != null)
+ {
+ 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");
+ }
+ else
+ Console.WriteLine ("{0}:{1} .. not exist", i, DBDirs[i].Dirname);
+ }
- if (db != null)
+ 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
{
- db.Loader = loader;
- db.ExtraInfo = extra_info;
- return db;
+ mdbs = new List<MDatabase> (1);
+ mdbs.Add (mdb);
+ dict.Add (mdb.tag, mdbs);
}
- return new MDatabase (tag, loader, extra_info);
}
- public static MDatabase Define (MDatabaseTag tag, string filename)
+ private static void register (int list_idx, int dir_idx,
+ Tag tag, MDatabaseInfo info)
{
- MDatabase db = MDatabase.Find (tag);
+ Dictionary<MDatabase.Tag, List<MDatabase>> dict
+ = tag.HasWildcard ? wdict : ndict;
+ List<MDatabase> mdbs;
+ MDatabase mdb;
- if (db != null)
+ 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)
+ {
+ 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.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;
+ return;
+ }
+ }
+ else
{
- db.Loader = null;
- db.Filename = new MText (filename);
- return db;
+ mdbs = new List<MDatabase> (1);
+ dict.Add (tag, mdbs);
}
- return new MDatabase (tag, filename);
+ mdb = new MDatabase (list_idx, dir_idx, tag, info);
+ M17n.DebugPrint ("registering: {0}\n", mdb);
+ mdbs.Add (mdb);
}
- static MDatabase ()
+ public MDatabase (Tag tag, Loader loader, object extra_info)
{
- string share_dir = (Environment.GetFolderPath
- (Environment.SpecialFolder.CommonApplicationData));
- string usr_dir = (Environment.GetFolderPath
- (Environment.SpecialFolder.ApplicationData));
+ this.tag = tag;
+ this.loader = loader;
+ DBType = MDBType.UNKNOWN;
+ DBStatus = MDBStatus.READY;
+ DirIndex = 0;
+ ListIndex = 0;
+ ExtraInfo = extra_info;
+ register (this);
+ }
- try {
- DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, ".m17n.d"));
- } catch (ArgumentException) {
- DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n.d"));
- }
- DBDirs[1] = null;
- DBDirs[2] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
+ public MDatabase (Tag tag, string filename)
+ {
+ this.tag = tag;
+ DBType = MDBType.EXPLICIT;
+ if (Path.IsPathRooted (filename))
+ {
+ DirIndex = 0;
+ if (File.Exists (filename))
+ DBStatus = MDBStatus.READY;
+ else
+ DBStatus = MDBStatus.INVALID;
+ }
+ else
+ {
+ DirIndex = -1;
+ DBStatus = MDBStatus.NOT_READY;
+ }
+ ListIndex = 0;
+ Info = new MDatabaseInfo ();
+ Info.Filename = filename;
+ register (this);
}
- internal static void Update ()
+ 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
+ DBStatus = MDBStatus.NOT_READY;
+ if (Info.Format == Mchar_table)
+ MCharProp.Define (tag[2], this);
+ }
+ public override String ToString () {
+ string str = ("#<MDataBase (" + ListIndex + "," + DirIndex + ") "
+ + tag + " " + DBType + " " + DBStatus);
+
+ if (DBType != MDBType.EXPLICIT && DBType != MDBType.UNKNOWN)
+ str += " " + Info;
+ return str + ">";
}
+ // Update (or disable) databases defined by "mdb.dir" in
+ // DBDirs[list_idx].
+ private static void update_list (int list_idx)
+ {
+ 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;
+
+ 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);
+ }
+ }
+ }
- public static MDatabase Find (MDatabaseTag tag)
+ // Update (or disable) databases in DBDirs[dir_idx].
+ private static void update_dir (int dir_idx)
{
- MDatabase db;
+ 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, mdb.ListIndex,
+ dir_idx, mdb.Info);
+ }
+ }
+
+ private static void register_files (string dir, int list_idx, int dir_idx,
+ MDatabaseInfo base_info)
+ {
+ List<FileInfo> files = new List<FileInfo> ();
+ MGlob.FileList (ref files, dir, base_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);
- return (DBDict.TryGetValue (tag, out db) ? db : null);
+ 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);
+ }
+ }
+ }
}
- public object Load ()
+ private void expand_wildcard ()
{
- return (Loader != null ? Loader (Tag, ExtraInfo)
- : load (MSymbol.nil, MSymbol.nil));
+ M17n.DebugPrint ("expanding: {0}\n", this);
+
+ if (DirIndex == 0)
+ register_files (null, ListIndex, DirIndex, Info);
+ else
+ for (int i = 1; i < 4; i++)
+ if (DBDirs[i].DirInfo != null)
+ register_files (DBDirs[i].DirInfo.FullName, ListIndex, i, Info);
+ DBStatus = MDBStatus.READY;
}
- public object Load (MSymbol key, MSymbol stop)
+ private static void maybe_expand_wildcard (Tag tag)
{
- if (Loader != null)
- return null;
- return load (key, stop);
+ 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 ();
+ }
+ }
+ }
+ }
+
+ private bool update_status ()
+ {
+ if (DBType == MDBType.UNKNOWN)
+ return true;
+ if (DBStatus == MDBStatus.INVALID)
+ return false;
+ if (DBStatus == MDBStatus.READY)
+ {
+ if (DirIndex > 0
+ || File.Exists (FileInfo.FullName))
+ return true;
+ DBStatus = MDBStatus.INVALID;
+ return false;
+ }
+ 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;
+ return true;
+ }
+ }
+ return false;
}
- private object load (MSymbol key, MSymbol stop)
+ public static MDatabase Find (Tag tag)
{
- Ltime = DateTime.Now;
+ List<MDatabase> mdbs;
+ MDatabase mdb = null;
-
+ if (tag.HasWildcard)
+ throw new ArgumentException ("Wildcard not allowed: " + tag);
+ if (ndict.TryGetValue (tag, out mdbs))
+ {
+ 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_all () && 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;
return null;
}
- }
+ public static List<MDatabase> List (Tag tag)
+ {
+ List<MDatabase> list = new List<MDatabase> ();
+
+ update_all ();
+ 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;
+ }
+ }
+ else
+ {
+ List<MDatabase> mdbs;
+ if (ndict.TryGetValue (tag, out mdbs))
+ foreach (MDatabase mdb in mdbs)
+ if (mdb.update_status ())
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
+ return list;
+ }
+
+ public object Load ()
+ {
+ if (loader != null)
+ return loader (tag, ExtraInfo);
+ if (Info.Format == Mchar_table)
+ throw new Exception ("Use Load (MCharTable) to load this database");
+ if (Info.Format == Mcharset)
+ throw new Exception ("Use Load (MCharset) to load this database");
+ if (! update_status ())
+ throw new Exception ("Database invalid");
+
+ MPlist plist = null;
+ using (FileStream stream = File.OpenRead (FileInfo.FullName))
+ plist = new MPlist (stream);
+ return plist;
+ }
+
+ public object 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 (! update_status ())
+ throw new Exception ("Database invalid");
+ MPlist plist = null;
+ using (FileStream stream = File.OpenRead (FileInfo.FullName))
+ plist = new MPlist (stream, key, stop);
+ return plist;
+ }
+
+ /// <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 ();
+ }
-}
\ No newline at end of file
+ // For IComparable<MDatabase>
+ public int CompareTo (MDatabase other)
+ {
+ return (ListIndex == other.ListIndex
+ ? DirIndex - other.DirIndex
+ : ListIndex - other.ListIndex);
+ }
+ }
+}