namespace M17N.Core
{
+ internal class MDatabaseDir
+ {
+ private const string ListFileName = "mdb.dir";
+
+ public string Dirname;
+ public DirectoryInfo DirInfo;
+ public FileInfo ListInfo;
+ public DateTime LastScanned;
+
+ 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;
+ }
+ }
+ }
+
+ public bool CheckStatus ()
+ {
+ 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;
+ }
+ else
+ {
+ try {
+ ListInfo = DirInfo.GetFiles (ListFileName)[0];
+ return true;
+ } catch {
+ ListInfo = null;
+ }
+ }
+ return (LastScanned < DirInfo.LastWriteTime
+ || (ListInfo != null
+ && LastScanned < ListInfo.LastWriteTime));
+ }
+ else
+ {
+ if (Dirname != null && Directory.Exists (Dirname))
+ {
+ DirInfo = new DirectoryInfo (Dirname);
+ try {
+ ListInfo = DirInfo.GetFiles (ListFileName)[0];
+ } 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
{
+ /// Tags to identify a MDatabase.
public struct Tag
{
- public MSymbol Tag0, Tag1, Tag2, Tag3;
+ public MSymbol[] Tags;
public Tag (MSymbol tag0)
{
- Tag0 = tag0; Tag1 = Tag2 = Tag3 = MSymbol.nil;
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = Tags[2] = Tags[3] = MSymbol.nil;
}
public Tag (MSymbol tag0, MSymbol tag1)
{
- Tag0 = tag0; Tag1 = tag1; Tag2 = Tag3 = MSymbol.nil;
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = tag1; Tags[2] = Tags[3] = MSymbol.nil;
}
public Tag (MSymbol tag0, MSymbol tag1, MSymbol tag2)
{
- Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = MSymbol.nil;
+ 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)
{
- Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = tag3;
+ Tags = new MSymbol[4];
+ Tags[0] = tag0; Tags[1] = tag1; Tags[2] = tag2; Tags[3] = tag3;
}
- }
-
- public delegate object Loader (Tag tag, object extra_info);
-
- private class MDatabaseDir
- {
- private const string ListFileName = "mdb.dir";
- public string Dirname;
- public DirectoryInfo DirInfo;
- public DateTime LastScanned;
- public FileInfo ListInfo;
-
- private static void GetInfo (string dirname, out DirectoryInfo dirinfo,
- out FileInfo listinfo)
+ public bool Match (Tag tag)
{
- if (Directory.Exists (dirname))
- try { dirinfo = new DirectoryInfo (dirname);
- try { listinfo = dirinfo.GetFiles (ListFileName)[0];
- } catch { listinfo = null; }
- } catch { dirinfo = null; listinfo = null; }
- else
+ for (int i = 0; i < 4; i++)
{
- dirinfo = null;
- listinfo = null;
- }
- }
-
- public MDatabaseDir (string dirname)
- {
- Dirname = dirname;
- GetInfo (dirname, out DirInfo, out ListInfo);
- }
-
- public bool StatusChanged {
- get {
- bool exists = Directory.Exists (Dirname);
-
- if (DirInfo != null)
- {
- if (! exists)
- {
- DirInfo = null;
- ListInfo = null;
- LastScanned = new DateTime (0);
- }
- if (LastScanned.Year == 0)
- return true;
- DirInfo.Refresh ();
- if (ListInfo != null)
- ListInfo.Refresh ();
- return (LastScanned < DirInfo.LastWriteTime
- || LastScanned < ListInfo.LastWriteTime);
- }
- else
- {
- if (exists)
- {
- DirInfo = new DirectoryInfo (Dirname);
- try {
- ListInfo = DirInfo.GetFiles (ListFileName)[0];
- } catch {
- ListInfo = null;
- }
- return true;
- }
+ if (tag.Tags[i] == Mwildcard || Tags[i] == Mwildcard)
+ return true;
+ if (tag.Tags[i] != Tags[i])
return false;
- }
- }
- }
-
- public void UpdateStatus ()
- {
- if (DirInfo != null)
- LastScanned = DateTime.UtcNow;
+ }
+ return true;
}
- public FileInfo[] Scan (string filename)
+ public override string ToString ()
{
- if (DirInfo == null)
- return null;
- DirInfo.Refresh ();
- return DirInfo.GetFiles (filename);
+ return ("<"
+ + Tags[0] + "," + Tags[1] + "," + Tags[2] + "," + Tags[3]
+ + ">");
}
}
+ public delegate object Loader (Tag tag, object extra_info);
+
internal class MDatabaseInfo {
- internal DirectoryInfo Dir;
+ // -2: absolute, -1: unknown 0: DBDirs[0], 1: DBDirs[1], 2: DBDirs[2]
+ internal int DirIndex;
internal string Description;
- internal MText Filename;
+ internal string Filename;
internal FileInfo FileInfo;
internal FileInfo Validater;
internal int Version;
internal MSymbol Format;
internal MSymbol Schema;
- internal MText SchemaFile;
+ internal string SchemaFile;
internal DateTime ModifiedTime;
internal MPlist Props;
+
+ public MDatabaseInfo ()
+ {
+ Format = Schema = MSymbol.nil;
+ DirIndex = -1;
+ }
+
+ public override string ToString ()
+ {
+ string str = ("#<Info " + Format + " \"" + Filename
+ + "\" (" + DirIndex + ")");
+ if (Schema != MSymbol.nil)
+ str += " " + Schema;
+ return str + ">";
+ }
}
- private static Dictionary<MDatabase.Tag, MDatabase> DBDict
- = new Dictionary<MDatabase.Tag, MDatabase> ();
+ private static Dictionary<MDatabase.Tag, MDatabase[]> DBDict
+ = new Dictionary<MDatabase.Tag, MDatabase[]> ();
+
+ private static Dictionary<MDatabase.Tag, MDatabase[]> DBDictMulti
+ = new Dictionary<MDatabase.Tag, MDatabase[]> ();
private static MDatabaseDir[] DBDirs = new MDatabaseDir[3];
- private const string SystemDirectory = "/usr/share/m17n";
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.
MULTIPLE,
/// The database was defined explicitely by MDatabase.Define
/// 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
INVALID,
};
- public readonly Tag tag;
+ public Tag tag;
private Loader loader;
private object ExtraInfo;
private MDBType DBType;
internal DateTime LoadedTime;
internal MDatabaseInfo Info;
- public static string ApplicationDirectory;
-
static MDatabase ()
{
string share_dir = (Environment.GetFolderPath
} catch (ArgumentException) {
DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n_d"));
}
- DBDirs[1] = null;
+ DBDirs[1] = new MDatabaseDir (null);
DBDirs[2] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
}
- private MDatabase (Tag tag, Loader loader, object extra_info)
+ public static string ApplicationDir
+ { get { return (DBDirs[1].Dirname); }
+ set { DBDirs[1].Dirname = value; DBDirs[1].CheckStatus (); } }
+
+ private static bool update_database_directories ()
+ {
+ bool updated = false;
+ for (int i = 0; i < 3; i++)
+ if (DBDirs[i].CheckStatus ())
+ {
+ delete_databases (i);
+ if (DBDirs[i].ListInfo != null)
+ update_databases (i);
+ updated = true;
+ }
+ return updated;
+ }
+
+ public static void ListDirs ()
+ {
+ update_database_directories ();
+ for (int i = 0; i < 3; i++)
+ if (DBDirs[i].Dirname != null)
+ {
+ Console.Write ("{0}:{1}", i, DBDirs[i].Dirname);
+ if (DBDirs[i].DirInfo != null)
+ {
+ if (DBDirs[i].ListInfo != null)
+ Console.WriteLine (" {0}", DBDirs[i].ListInfo);
+ else
+ Console.WriteLine (".. no mdb.dir");
+ }
+ else
+ Console.WriteLine (".. not exist");
+ }
+ }
+
+ private void register (int priority)
+ {
+ Dictionary<MDatabase.Tag, MDatabase[]> dict
+ = DBType == MDBType.WILDCARD ? DBDictMulti : DBDict;
+ MDatabase[] mdbs;
+
+ if (! dict.TryGetValue (tag, out mdbs))
+ {
+ mdbs = new MDatabase[4];
+ dict.Add (tag, mdbs);
+ }
+ mdbs[priority] = this;
+ }
+
+ public MDatabase (Tag tag, Loader loader, object extra_info)
{
this.tag = tag;
this.loader = loader;
+ DBType = MDBType.UNKNOWN;
+ DBStatus = MDBStatus.UPDATED;
ExtraInfo = extra_info;
+ this.register (0);
}
- private MDatabase (Tag tag, string filename)
+ public MDatabase (Tag tag, string filename)
{
this.tag = tag;
+ DBType = MDBType.EXPLICIT;
+ DBStatus = MDBStatus.OUTDATED;
Info = new MDatabaseInfo ();
- Info.Filename = new MText (filename);
+ Info.Filename = filename;
+ Info.DirIndex = Path.IsPathRooted (filename) ? -2 : -1;
+ this.register (0);
}
- private MDatabase (MPlist plist)
+ private MDatabase (MPlist plist, int priority)
{
- 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 Tag (tags[0], tags[1], tags[2], tags[3]);
+ tag = new Tag (MSymbol.nil);
+ DBType = MDBType.AUTO;
+ DBStatus = MDBStatus.OUTDATED;
+ for (int i = 0; plist.IsSymbol; i++, plist = plist.Next)
+ {
+ if (DBType == MDBType.WILDCARD)
+ tag.Tags[i] = MSymbol.nil;
+ else
+ {
+ tag.Tags[i] = plist.Symbol;
+ if (tag.Tags[i] == Mwildcard)
+ DBType = MDBType.WILDCARD;
+ }
+ }
+
+ 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;
+ Info.Filename = plist.Text.ToString ();
plist = plist.Next;
}
else if (plist.IsPlist)
MPlist p = plist.Plist;
if (p.IsMText)
- Info.Filename = plist.Text;
+ Info.Filename = plist.Text.ToString ();
p = p.Next;
if (! p.IsEmpty)
{
Info.Schema = p.Symbol;
p = p.Next;
if (p.IsMText)
- Info.SchemaFile = p.Text;
+ Info.SchemaFile = p.Text.ToString ();
}
}
plist = plist.Next;
}
- DBStatus = MDBStatus.OUTDATED;;
+ 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)
}
Info.Props.Put (pl.Key, pl.Val);
}
+ this.register (priority);
+ }
+
+ public override String ToString () {
+ string str = "#<MDataBase " + tag + " " + DBType + " " + DBStatus;
+
+ if (DBType != MDBType.EXPLICIT && DBType != MDBType.UNKNOWN)
+ str += " " + Info;
+ return str + ">";
}
private static int parse_version (MPlist plist)
return ((major << 16) | (minor << 8) | release);
}
- public static MDatabase Define (Tag tag, Loader loader, object extra_info)
+ private static void delete_databases (int list_idx)
{
- MDatabase db = MDatabase.Find (tag);
+ 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;
+ }
- if (db != null)
+ private static void update_databases (int list_idx)
+ {
+ MDatabaseDir dbdir = DBDirs[list_idx];
+ FileInfo dblist = dbdir.ListInfo;
+ MPlist plist = null;
+
+ using (FileStream stream = File.OpenRead (dblist.FullName))
{
- db.loader = loader;
- db.ExtraInfo = extra_info;
- db.DBType = MDBType.EXPLICIT;
- db.DBStatus = MDBStatus.OUTDATED;
- db.Info = null;
- return db;
+ MStreamReader reader = new MStreamReader (stream);
+ plist = new MPlist (reader);
+ }
+ if (plist == null)
+ return;
+ foreach (MPlist pl in plist)
+ {
+ if (! pl.IsPlist)
+ continue;
+ try
+ {
+ new MDatabase (pl.Plist, list_idx + 1);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine (e.Message);
+ }
}
- return new MDatabase (tag, loader, extra_info);
}
- public static MDatabase Define (Tag tag, string filename)
+ private void expand_wildcard (int priority)
{
- MDatabase db = MDatabase.Find (tag);
-
- if (db != null)
+ if (Info.DirIndex == -2)
{
- db.loader = null;
- db.DBType = MDBType.EXPLICIT;
- db.DBStatus = MDBStatus.OUTDATED;
- db.Info = new MDatabaseInfo ();
- db.Info.Filename = new MText (filename);
-
- return db;
+
}
- return new MDatabase (tag, filename);
+
}
- private void update ()
+ private void update_status ()
{
- for (int i = 0; i < 3; i++)
+ if (Info.DirIndex == -2)
{
- if (DBDirs[0].StatusChanged)
- break;
}
}
public static MDatabase Find (Tag tag)
{
- MDatabase db;
+ MDatabase[] mdbs;
+ MDatabase mdb = null;
+
+ if (DBDict.TryGetValue (tag, out mdbs))
+ {
+ if (mdbs[0] != null)
+ return mdbs[0];
+ for (int i = 1; i < 4; i++)
+ if ((mdb = mdbs[i]) != null)
+ break;
+ }
+ if (! update_database_directories ())
+ return mdb;
+ if (! DBDict.TryGetValue (tag, out mdbs))
+ return null;
+ for (int i = 1; i < 4; i++)
+ if (mdbs[i] != null)
+ return mdbs[i];
+ return null;
+ }
- return (DBDict.TryGetValue (tag, out db) ? db : null);
+ public static List<MDatabase> List (Tag tag)
+ {
+ 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);
+
+ for (int i = 0; i < 4 && tag.Tags[i] == Mwildcard; i++);
+ if (i == 4)
+ {
+ // No wildcard.
+ if (DBDict.TryGetValue (tag, out mdbs))
+ for (int j = 0; j < 4; j++)
+ if (mdbs[j] != null)
+ {
+ mdbs[j].update_status ();
+ if (mdbs[j].DBStatus != MDBStatus.DISABLED)
+ {
+ list.Add (mdbs[j]);
+ 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)
+ {
+ MDatabase mdb = item.Value[j];
+ mdb.update_status ();
+ if (mdb.DBStatus != MDBStatus.DISABLED)
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
+ }
+ return list;
}
public object Load ()
{
LoadedTime = DateTime.UtcNow;
-
-
return null;
}
}