home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / inifile.py < prev    next >
Encoding:
Text File  |  2004-04-20  |  11.0 KB  |  359 lines

  1. """
  2.  
  3.    inifile.py
  4.  
  5.    Author:    Matthias Gudmundsson
  6.    Created:   2002.09.25
  7.    Project:   Framework
  8.  
  9.    Description:
  10.  
  11.        Does .ini file handling. By default, two handlers are created and
  12.        added to builtins as the global variables 'boot' and 'prefs':
  13.  
  14.        'boot' is bound to boot.ini file in the root directory.
  15.        'prefs' is bound to prefs.ini file in the cache directory.
  16.  
  17.  
  18.    Note! This file is executed by Blue very early on which means that the
  19.    'boot' and 'prefs' variables are available before any other script is
  20.    executed.
  21.  
  22.    'boot' contains the startup settings. By default it uses "boot.ini"
  23.    file but that can be overridden by setting a command line argument
  24.    like this: /config=alternative.ini
  25.  
  26.    The boot values are always read-only, but can be updated with
  27.    new entries but the changes will not be written back to disk.
  28.  
  29.    'prefs' contains all other settings the app might want to store.
  30.    The file used is always "prefs.ini" in the cache folder.
  31.  
  32.    (c) CCP 2000, 2001, 2002
  33.  
  34.  
  35.    Revisions:
  36.  
  37.    2002.09.25   Created.
  38.  
  39. """
  40.  
  41. import blue
  42. import types
  43. from base64 import decodestring, encodestring
  44. from cPickle import loads, dumps
  45.  
  46.  
  47. """
  48. Works like a normal .ini file except there are no groups. All non-blank
  49. lines should include a key value pair, where the key and value is a string,
  50. separated with a =. If the line starts with # it's ignored and considered
  51. a comment. If a line starts with a [ or ; it's also ignored, and is there
  52. for compatibility with external tools which expect an .ini file with groups.
  53.  
  54. The file is kept opened for the whole time and writes are committed on
  55. every modification. Order of key-value pairs, comments and linebreaks are
  56. kept intact.
  57. """
  58. class IniFile:
  59.  
  60.  
  61.     __guid__ = "util.IniFile"
  62.  
  63.     nopickles = [
  64.         types.IntType,
  65.         types.FloatType,
  66.         types.LongType,
  67.         types.StringType,
  68.     ]
  69.  
  70.     nodef = [0]
  71.  
  72.  
  73.     # -----------------------------------------------------------------------------------
  74.     # IniFile - Constructor
  75.     # -----------------------------------------------------------------------------------
  76.     # 'shortname' is the name of the config file, without path and dot.extention.
  77.     # 'root' is the location of the config file, if ommitted, blue.os.rootpath is used.
  78.     # -----------------------------------------------------------------------------------
  79.     def __init__(self, shortname, root = None, readOnly = 0):
  80.  
  81.         # Raw file data
  82.         self.data = ""
  83.  
  84.         # Data is divided into blocks where each block is a single line in a text file
  85.         # format. The block descriptor has byte start offset and block size and is
  86.         # ordered by linenumbers.
  87.         self.blocks = []
  88.  
  89.         # Key is the key name
  90.         # Value is list: [lineno, filepos, value string]
  91.         self.keyval = {}
  92.  
  93.         # Fix root path
  94.         if root is None:
  95.             root = blue.os.rootpath
  96.         elif root[-1] not in ['\\', '/']:
  97.             root += "/"
  98.  
  99.         # Construct a full pathname for file
  100.         if shortname[-4:] != '.ini':
  101.  
  102.             filename = root + shortname + ".ini"
  103.         else:
  104.             filename = root + shortname
  105.         self.filename = filename
  106.  
  107.         # Open the file if it exists, create it if not
  108.         inifile = blue.os.CreateInstance("blue.ResFile")
  109.  
  110.         # File may exists as read-only, so let's be prepared for that
  111.         if not readOnly:
  112.             try:
  113.                 self.readonly = 0
  114.                 if not inifile.Open(filename, 0):
  115.                     inifile.Create(filename)
  116.                 self.inifile = inifile
  117.             except:
  118.  
  119.                 self.readonly = 1
  120.                 if inifile.Open(filename, 1):
  121.                     self.inifile = inifile
  122.                 else:
  123.                     self.readonly = 1
  124.                     self.inifile = None
  125.                     self.lines = []
  126.                     return
  127.  
  128.         else:
  129.             self.readonly = 1
  130.             inifile.OpenAlways(filename, 1)
  131.  
  132.  
  133.         # Read in data
  134.         data = str(inifile.Read())
  135.  
  136.         # Split data into lines
  137.         if len(data):
  138.             data = data.replace("\r", "")
  139.             self.lines = data.split("\n")
  140.             if self.lines[-1] == "":
  141.                 self.lines.pop()
  142.         else:
  143.             self.lines = []
  144.  
  145.         # Create key index
  146.         for line in self.lines:
  147.             if len(line) > 0 and line[0] not in "[;#":
  148.                 sep = line.find("=")
  149.                 if sep > 0 and len(line) > sep+1:
  150.                     self.keyval[str(line[:sep])] = line
  151.  
  152.  
  153.     # -----------------------------------------------------------------------------------
  154.     # HasKey
  155.     # -----------------------------------------------------------------------------------
  156.     # Check for existence of key-value pair.
  157.     #
  158.     # Returns true if 'key' exists, false otherwise
  159.     # -----------------------------------------------------------------------------------
  160.     def HasKey(self, key):
  161.         return str(key).strip() in self.keyval
  162.  
  163.     # -----------------------------------------------------------------------------------
  164.     # GetKeys
  165.     # -----------------------------------------------------------------------------------
  166.     def GetKeys(self, beginWith=None):
  167.         if beginWith is not None:
  168.             return [key for key in self.keyval.keys() if key[:len(beginWith)] == beginWith]
  169.         return self.keyval.keys()
  170.  
  171.     # -----------------------------------------------------------------------------------
  172.     # GetValue
  173.     # -----------------------------------------------------------------------------------
  174.     # Returns the value associated with the key.
  175.     #
  176.     # If 'key' is not found, then 'default' is registered under the key and returned, but
  177.     # if 'default' is ommitted then a key error is raised.
  178.     # -----------------------------------------------------------------------------------
  179.     def GetValue(self, key, default = nodef):
  180.         key = str(key).strip().replace('|', '||').replace('=', '-|-') # avoid '=' in the key
  181.  
  182.  
  183.  
  184.         if not self.keyval.has_key(key):# not in self.keyval:
  185.             if default is self.nodef:
  186.                 raise KeyError(key)
  187.             return default
  188.  
  189.         value = self.keyval[key]
  190.         sep = value.find("=")
  191.         value = value[sep+1:]
  192.  
  193.         if not len(value):
  194.             return value
  195.  
  196.         if value[-1] == '\r':
  197.             value = value[:-1]
  198.  
  199.         # Do type conversion
  200.  
  201.         # Is it pickle?
  202.         if value[:7] == "pickle:":
  203.             return loads(value[7:].replace("", "\n"))
  204.  
  205.         # Try int cast
  206.         try:
  207.             return int(value)
  208.         except:
  209.             pass
  210.  
  211.         # Try long cast
  212.         try:
  213.             return long(value)
  214.         except:
  215.             pass
  216.  
  217.         # Try float cast
  218.         try:
  219.             return float(value)
  220.         except:
  221.             pass
  222.  
  223.         # Try string cast ;)
  224.         return str(value).strip()
  225.  
  226.  
  227.     # -----------------------------------------------------------------------------------
  228.     # SetValue
  229.     # -----------------------------------------------------------------------------------
  230.     # Registers a value under a key.
  231.     #
  232.     # If 'key' already exists, the value is replaced.
  233.     # 'value' can be any picklable python object.
  234.     # If 'forcePickle' is true, the value is always pickled.
  235.     # -----------------------------------------------------------------------------------
  236.     def SetValue(self, key, value, forcePickle = 0):
  237.         key = str(key).strip().replace('|', '||').replace('=', '-|-') # avoid '=' in the key
  238.  
  239.         # Strings with difficult characters must be pickled
  240.         if type(value) == types.StringType:
  241.             for c in value:
  242.                 if ord(c) < 32 or ord(c) > 255:
  243.                     forcePickle = 1
  244.                     break
  245.  
  246.         if forcePickle or type(value) not in self.nopickles:
  247.             value = "pickle:" + dumps(value).replace("\n", "")
  248.         else:
  249.             value = str(value).strip()
  250.  
  251.         line = "%s=%s" % (key, value)
  252.  
  253.         if key in self.keyval:
  254.             old = self.keyval[key]
  255.             if line == self.keyval[key]:
  256.                 # no change
  257.                 return
  258.  
  259.             lineno = self.lines.index(old)
  260.             self.lines.remove(old)
  261.             self.lines.insert(lineno, line)
  262.         else:
  263.             self.lines.append(line)
  264.  
  265.         self.keyval[key] = line
  266.  
  267.         self.__FlushToDisk()
  268.  
  269.  
  270.  
  271.     # -----------------------------------------------------------------------------------
  272.     # DeleteValue
  273.     # -----------------------------------------------------------------------------------
  274.     # Deletes the key-value line, if exists.
  275.     # -----------------------------------------------------------------------------------
  276.     def DeleteValue(self, key):
  277.         key = str(key).strip()
  278.  
  279.         if key in self.keyval:
  280.             self.lines.remove(self.keyval[key])
  281.             del self.keyval[key]
  282.             self.__FlushToDisk()
  283.  
  284.  
  285.     # -----------------------------------------------------------------------------------
  286.     # FlushToDisk - Commit changes to disk
  287.     # -----------------------------------------------------------------------------------
  288.     def __FlushToDisk(self):
  289.         if self.readonly:
  290.             return
  291.  
  292.         self.inifile.Seek(0)
  293.  
  294.         sortlines = [(line.lower()[:3], line) for line in self.lines]
  295.         sortlines.sort()
  296.         lines = [line[1] for line in sortlines]
  297.         for line in lines:
  298.             self.inifile.Write(line + "\r\n")
  299.  
  300.         newpos = self.inifile.pos
  301.         self.inifile.Seek(0)
  302.         self.inifile.SetSize(newpos)
  303.  
  304.  
  305. """
  306. Magic getattr/setattr wrapper for convenience
  307. """
  308. class Handler:
  309.  
  310.     def __init__(self, inifile):
  311.         self.__dict__["ini"] = inifile
  312.  
  313.     def __getattr__(self, key):
  314.         if hasattr(self.__dict__["ini"], key):
  315.             return getattr(self.__dict__["ini"], key)
  316.         else:
  317.             return self.__dict__["ini"].GetValue(key)
  318.  
  319.     def __setattr__(self, key, value):
  320.         self.__dict__["ini"].SetValue(key, value)
  321.  
  322.     def __str__(self):
  323.         return "IniFile %s with %s entries" % (self.__dict__["ini"].filename, len(self.__dict__["ini"].keyval))
  324.  
  325.     def __eq__(self,arg):
  326.         return NotImplemented
  327.  
  328.  
  329. def Init():
  330.     import __builtin__
  331.     if hasattr(__builtin__, "prefs"):
  332.         return
  333.  
  334.     # Initialize bootinfo
  335.     import blue
  336.     file = "boot"
  337.  
  338.     # Command line may override the default boot.ini filename
  339.     for arg in blue.pyos.GetArg():
  340.         if arg[:8] == "/config=":
  341.             file = arg[8:]
  342.             break
  343.  
  344.     # Create the handler
  345.     handler = Handler(IniFile(file, None, 1))
  346.  
  347.     # Shove it into builtins as bootinfo
  348.     __builtin__.boot = handler
  349.  
  350.     # Create settings handler
  351.  
  352.     handler = Handler(IniFile("prefs", blue.os.cachepath))
  353.     __builtin__.prefs = handler
  354.  
  355.  
  356.  
  357.  
  358. Init()
  359.