*** empty log message ***
authorhanda <handa>
Sat, 6 Jun 2009 14:34:35 +0000 (14:34 +0000)
committerhanda <handa>
Sat, 6 Jun 2009 14:34:35 +0000 (14:34 +0000)
MDatabase.cs
MPlist.cs
MSymbol.cs
database.cs

index e19ebc4..83c3db2 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using M17N;
@@ -6,103 +7,142 @@ 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;
+    
+      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 {
+      }
+    }
+  }
+
   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 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)
        {
@@ -128,68 +168,200 @@ namespace M17N.Core
          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.plist;
+       if (plist.IsMText)
+         {
+           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.IsEmpty)
+             {
+               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 ();
+                 }                 
+             }
+           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>> ();
 
-    private static Dictionary<MDatabase.Tag, MDatabase[]> DBDictMulti
-      = new Dictionary<MDatabase.Tag, 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[3];
+    private static MDatabaseDir[] DBDirs = new MDatabaseDir[4];
 
-    private static readonly MSymbol Mversion = MSymbol.Of ("version");
+    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");
@@ -218,28 +390,37 @@ namespace M17N.Core
     /// 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.
+    internal FileInfo FileInfo;
+    // When the database file is checked (or validated).
+    internal DateTime CheckedTime;
 
     static MDatabase ()
     {
@@ -249,63 +430,137 @@ namespace M17N.Core
                        (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 ();
     }
 
     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 (); }
+    }
 
-    private static bool update_database_directories ()
+    private static bool update_all ()
     {
       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;
+             }
          }
+      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 ();
+      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 ("[NDITCT]");
+      foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+       foreach (MDatabase mdb in kv.Value)
+         Console.WriteLine (mdb);
     }
 
-    private void register (int priority)
+    private static void register (MDatabase mdb)
     {
-      Dictionary<MDatabase.Tag, MDatabase[]> dict
-       = DBType == MDBType.WILDCARD ? DBDictMulti : DBDict;
-      MDatabase[] mdbs;
+      Dictionary<MDatabase.Tag, List<MDatabase>> dict
+       = mdb.DBType == MDBType.WILDCARD ? wdict : ndict;
+      List<MDatabase> mdbs;
 
-      if (! dict.TryGetValue (tag, out 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 MDatabase[4];
-         dict.Add (tag, mdbs);
+         mdbs = new List<MDatabase> (1);
+         mdbs.Add (mdb);
+         dict.Add (mdb.tag, mdbs);
        }
-      mdbs[priority] = this;
+    }
+
+    private static void register (int list_idx, int dir_idx,
+                                 Tag tag, MDatabaseInfo info)
+    {
+      List<MDatabase> mdbs;
+      MDatabase mdb;
+
+      if (ndict.TryGetValue (tag, out mdbs))
+       for (int i = 0; i < mdbs.Count; i++)
+         {
+           mdb = mdbs[i];
+           if (mdb.ListIndex == list_idx
+               && (dir_idx > 0 && dir_idx <= mdb.DirIndex))
+             {
+               if (mdb.DBStatus == MDBStatus.INVALID)
+                 M17n.DebugPrint ("registering: {0}\n", mdb);
+               else
+                 M17n.DebugPrint ("updating: {0}\n", mdb);
+               if (mdb.DBStatus != MDBStatus.DISABLED)
+                 mdb.DBStatus = (dir_idx < 0
+                                 ? MDBStatus.NOT_READY : MDBStatus.READY);
+               mdb.DirIndex = dir_idx;
+               mdb.Info = info;
+               return;
+             }
+         }
+      else
+       {
+         mdbs = new List<MDatabase> (1);
+         ndict.Add (tag, mdbs);
+       }
+      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)
@@ -313,134 +568,84 @@ namespace M17N.Core
       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;      
-         else
-           {
-             tag.Tags[i] = plist.Symbol;
-             if (tag.Tags[i] == Mwildcard)
-               DBType = MDBType.WILDCARD;
-           }
+         DirIndex = 0;
+         DBStatus = MDBStatus.READY;
        }
-
-      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 (this.tag[0] == Mchar_table || this.tag[0] == Mcharset)
+       Info.Format = this.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;
     }
 
     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;
-
-      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);
-    }
+      // 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;
+           }
 
-    private static void delete_databases (int list_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;
-    }
+      FileInfo dblist = DBDirs[list_idx].ListInfo;
+      if (dblist == null)
+       return;
 
-    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))
        {
          MStreamReader reader = new MStreamReader (stream);
@@ -449,56 +654,149 @@ namespace M17N.Core
       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);
+             }
+         }
+    }
+
+    // Update (or disable) databases in DBDirs[dir_idx].
+    private static void update_dir (int 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)
        {
-         if (! pl.IsPlist)
-           continue;
-         try
+         MPlist plist = null;
+         using (FileStream stream = fileinfo.OpenRead ())
            {
-             new MDatabase (pl.Plist, list_idx + 1);
+             MStreamReader reader = new MStreamReader (stream);
+             plist = new MPlist (reader, 1);
            }
-         catch (Exception e)
+         if (plist != null && plist.IsPlist)
            {
-             Console.WriteLine (e.Message);
+             plist = plist.Plist;
+             Tag tag = new Tag (ref plist);
+
+             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);
+               }
            }
        }
     }
 
-    private void expand_wildcard (int priority)
+    private void expand_wildcard ()
     {
-      if (Info.DirIndex == -2)
-       {
-         
-       }
+      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;
+    }
 
+    private static void maybe_expand_wildcard (Tag tag)
+    {
+      foreach (KeyValuePair<Tag, List<MDatabase>> kv in wdict)
+       if (kv.Key.Match (tag))
+         foreach (MDatabase mdb in kv.Value)
+           if (mdb.DBStatus == MDBStatus.NOT_READY)
+             mdb.expand_wildcard ();
+    }
+
+    private bool check_file ()
+    {
+      if (DBDirs[DirIndex].DirInfo == null)
+       return false;
+      FileInfo[] files = DBDirs[DirIndex].DirInfo.GetFiles (Info.Filename);
+      if (files.Length == 0)
+       return false;
+      FileInfo = files[0];
+      return true;
     }
 
-    private void update_status ()
+    private bool find_file ()
     {
-      if (Info.DirIndex == -2)
+      if (DirIndex == 0)
        {
+         
        }
+      return true;
     }
 
     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 () && 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++)
+       if ((mdb = mdbs[i]).check_file ())
+         return mdb;
       return null;
     }
 
@@ -506,48 +804,30 @@ namespace M17N.Core
     {
       List<MDatabase> list = new List<MDatabase> ();
 
-      update_database_directories ();
-      foreach (KeyValuePair<Tag, MDatabase[]> item in DBDictMulti)
-       if (item.Key.Match (tag))
-         for (int 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 ();
+      maybe_expand_wildcard (tag);
 
-      int i;
-      for (i = 0; i < 4 && tag.Tags[i] == Mwildcard; i++);
-      if (i == 4)
+      if (tag.HasWildcard)
        {
-         // No wildcard.
-         MDatabase[] mdbs;
-         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;
-                   }
-               }
+         foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
+           if (kv.Key.Match (tag))
+             foreach (MDatabase mdb in kv.Value)
+               if (mdb.check_file ())
+                 {
+                   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)
-                 {
-                   MDatabase mdb = item.Value[j];
-                   mdb.update_status ();
-                   if (mdb.DBStatus != MDBStatus.DISABLED)
-                     {
-                       list.Add (mdb);
-                       break;
-                     }
-                 }
+         List<MDatabase> mdbs;
+         if (ndict.TryGetValue (tag, out mdbs))
+           foreach (MDatabase mdb in mdbs)
+             if (mdb.check_file ())
+               {
+                 list.Add (mdb);
+                 break;
+               }
        }
       return list;
     }
@@ -567,9 +847,15 @@ namespace M17N.Core
 
     private object load (MSymbol key, MSymbol stop)
     {
-      LoadedTime = DateTime.UtcNow;
-
       return null;
     }
+
+    // For IComparable<MDatabase>
+    public int CompareTo (MDatabase other)
+    {
+      return (ListIndex == other.ListIndex
+             ? DirIndex - other.DirIndex
+             : ListIndex - other.ListIndex);
+    }
   }
 }
\ No newline at end of file
index f607bc7..8a040ec 100644 (file)
--- a/MPlist.cs
+++ b/MPlist.cs
@@ -30,6 +30,53 @@ namespace M17N.Core
          next = new MPlist (reader);
       }
 
+    public MPlist (MStreamReader reader, int count)
+      {
+       MSymbol key;
+       object val;
+       bool result = reader.ReadElement (out key, out val);
+
+       Key = key;
+       Val = val;
+       if (result && --count > 0)
+         next = new MPlist (reader, count);
+       else
+         next = new MPlist ();
+      }
+
+    public MPlist (MStreamReader reader, MSymbol target, MSymbol stop)
+      {
+       MSymbol key;
+       object val;
+       bool result;
+
+       Key = MSymbol.nil;
+       Val = null;
+       while (true)
+         {
+           result = reader.ReadElement (out key, out val);
+           if (! result)
+             return;
+           if (key == MSymbol.plist)
+             {
+               MPlist plist = (MPlist) val;
+
+               if (plist.IsSymbol)
+                 {
+                   if (plist.Symbol == stop)
+                     return;
+                   if (plist.Symbol == target)
+                     {
+                       Key = target;
+                       Val = val;
+                       next = new MPlist ();
+                       return;
+                     }
+                 }
+             }
+         }
+      }
+
     private MPlist (MSymbol key, object val)
       {
        Key = key;
@@ -112,6 +159,14 @@ namespace M17N.Core
       return find (key).Val;
     }
 
+    internal MPlist Assq (MSymbol key)
+    {
+      foreach (MPlist p in this)
+       if (p.IsPlist && p.Plist.IsSymbol && p.Plist.Symbol == key)
+         return p;
+      return null;
+    }
+
     private delegate MPlist MPlistDelegate (MSymbol key, object val);
 
     private MPlist mplist_op (MPlistDelegate op, object val)
@@ -372,7 +427,7 @@ namespace M17N.Core
     {
       int c = Peek ();
 
-      if (c == -1 || c == '(' || c == ' ' || c == '\n' || c == '"')
+      if (c == -1 || c == '(' || c == ')' || c == ' ' || c == '\n' || c == '"')
        return "";
       Read ();
       if (c == '\\')
index 4aeffb4..c41fda9 100644 (file)
@@ -66,7 +66,8 @@ namespace M17N.Core
 
       foreach (char c in Name)
        {
-         if (c == '\\' || c == ' ' || c == '\'' || c == '\"' || c == ':')
+         if (c == '\\' || c == ' ' || c == '\'' || c == '\"'
+             || c == '(' || c == ')')
            str += "\\";
          str += c;
        }
index cc0f258..ce44154 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using M17N;
 using M17N.Core;
 
@@ -9,12 +10,20 @@ public class Test
   {
     M17n.debug = true;
     MDatabase.ApplicationDir = "/usr/local/share/m17n";
+    MDatabase.Tag tag = new MDatabase.Tag (MSymbol.Of ("input-method"),
+                                          MSymbol.t,
+                                          MSymbol.Of ("unicode"));
+    DirectoryInfo dirinfo = new DirectoryInfo ("/home/handa/.m17n.d");
 
-    MDatabase.ListDirs ();
-    List<MDatabase> mdb_list
-      = MDatabase.List (new MDatabase.Tag (MSymbol.Of ("*")));
-    Console.WriteLine ("Total {0} databases:", mdb_list.Count);
-    foreach (MDatabase db in mdb_list)
-      Console.WriteLine (db);
+    while (true)
+      {
+       Console.Write ("mdb> ");
+       string str = Console.ReadLine ();
+       if (str == null || str == "quit" || str == "exit")
+         break;
+       dirinfo.Refresh ();
+       Console.WriteLine (dirinfo.LastWriteTimeUtc
+                          + ":" + MDatabase.Find (tag));
+      }
   }
 }