summaryrefslogtreecommitdiffstats
path: root/displayconfig/infimport.py
diff options
context:
space:
mode:
Diffstat (limited to 'displayconfig/infimport.py')
-rwxr-xr-xdisplayconfig/infimport.py297
1 files changed, 297 insertions, 0 deletions
diff --git a/displayconfig/infimport.py b/displayconfig/infimport.py
new file mode 100755
index 0000000..f51475d
--- /dev/null
+++ b/displayconfig/infimport.py
@@ -0,0 +1,297 @@
+#!/usr/bin/python
+#
+# Based on inf2mondb.py from RedHat
+#
+# originally by Matt Wilson <msw@redhat.com>
+# option parsing and database comparison by Fred New
+# ini parsing completely rewritten by Matt Domsch <Matt_Domsch@dell.com> 2006
+#
+# Copyright 2002 Red Hat, Inc.
+# Copyright 2006 Dell, Inc.
+# Copyright 2007 Sebastian Heinlein
+#
+# This software may be freely redistributed under the terms of the GNU
+# library public license.
+#
+# You should have received a copy of the GNU Library Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+Provides an importer for Microsoft Windows monitor descriptions
+
+The code can be used as a python module for or as a script to add new monitor
+definitions to a monitor database.
+
+In code example: Read the list of monitors from an inf file.
+
+import infimport
+monitors = infimport.get_monitors_from_inf(PATH)
+
+Script example: To check for monitors of an inf file that are not yet in the database.
+
+./infimport.py MONITORS.inf /usr/share/hwdata/MonitorsDB
+"""
+
+import sys
+import string
+import re
+import ConfigParser
+import os
+
+import logging
+
+logging.basicConfig()
+log = logging.getLogger("infimport")
+#log.setLevel(logging.DEBUG)
+log.setLevel(logging.INFO)
+
+# this is a class to deal with various file line endings and leading whitespace
+# converts all \r line endings to \n.
+# It also strips leading whitespace.
+# NOTE: be sure to always return _something_, even if it is just "\n", or we
+# break the file API. (nothing == eof)
+class myFile(object):
+ def __init__(self, *args):
+ self.fd = open(*args)
+
+ def close(self):
+ return self.fd.close()
+
+ def readline(self, *args):
+ line = self.fd.readline(*args)
+ line = line.replace('\r', '\n')
+ line = line.replace('\n\n', '\n')
+ line = line.lstrip(" \t")
+ return line
+
+
+# we will use this to override default option parsing in ConfigParser to handle
+# Microsoft-style "INI" files. (Which do not necessarily have " = value " after
+# the option name
+OPTCRE = re.compile(
+ r'(?P<option>[^:=\s][^:=]*)' # very permissive!
+ r'\s*(?P<vi>[:=]{0,1})\s*' # any number of space/tab,
+ # optionally followed by
+ # separator (either : or =)
+ # optionally followed
+ # by any # space/tab
+ r'(?P<value>.*)$' # everything up to eol
+ )
+
+percentSplit = re.compile(r'%(?P<field>.*)%')
+def _percent_to_string(ini, strings, name):
+ mo = percentSplit.match(name)
+ if (mo):
+ field = mo.group('field')
+ try:
+ val = strings[field.lower()]
+ except KeyError:
+ return ""
+ return val.strip(" '\"")
+ return ""
+
+def get_monitors_from_database(path):
+ """Returns a dictonary of the found monitor models in the given
+ monitor models database"""
+ monitors = {}
+ try:
+ mdb = open(path, 'r')
+ except IOError, (errno, str):
+ log.error("Unable to open %s: %s" % (path, str))
+ return {}
+ for line in mdb.readlines():
+ if len(line.strip()) == 0 or line.startswith('#'):
+ continue
+ line_split = line.split(";")
+ vendor = line_split[0].strip()
+ name = line_split[1].strip()
+ id = line_split[2].strip()
+ if monitors.has_key((vendor, name, id)):
+ log.warn("Duplicated entry: %s" % line)
+ else:
+ monitors[(vendor, name, id)] = line
+ mdb.close()
+ return monitors
+
+def get_monitors_from_inf(path):
+ """Returns a dictonary of the found monitor models in the given .inf file"""
+ monitors = {}
+ ini = ConfigParser.ConfigParser()
+ # FIXME: perhaps could be done in a nicer way, but __builtins__ is a dict
+ # for imported modules
+ #ini.optionxform = __builtins__.str
+ ini.optionxform = type("")
+ ini.OPTCRE = OPTCRE
+ try:
+ f = myFile(path)
+ ini.readfp(f)
+ f.close()
+ except IOError, (errno, str):
+ log.error("Unable to open %s: %s" % (path, str))
+ sys.exit(1)
+
+ # a dictionary of manufacturers we're looking at
+ manufacturers = {}
+ # a big fat dictionary of strings to use later on.
+ strings = {}
+
+ # This RE is for EISA info lines
+ # %D5259A%=D5259A, Monitor\HWP0487
+ monitor1Re = re.compile(r'.*,.*Monitor\\(?P<id>[^\s]*)')
+ # This one is for legacy entries
+ # %3020% =PB3020, MonID_PB3020
+ monitor2Re = re.compile(r'.*,.*MonID_(?P<id>[^\s]*)')
+
+ for section in ini.sections():
+ if section.lower() == "manufacturer":
+ for mfr in ini.options(section):
+ # generate the vendor.arch funny entries
+ manufacturer_values = string.split(ini.get(section, mfr),
+ ',')
+ manufacturers[manufacturer_values[0]] = mfr
+ while len(manufacturer_values) > 1:
+ manufacturers["%s.%s" % (manufacturer_values[0],
+ manufacturer_values[-1])] = mfr
+ manufacturer_values = manufacturer_values[0:-1]
+
+ elif section.lower() == "strings":
+ for key in ini.options(section):
+ strings[key.lower()] = string.strip(ini.get(section, key))
+
+ for mfr in manufacturers.keys():
+ if ini.has_section(mfr):
+ monitor_vendor_name = manufacturers[mfr]
+ for monitor_name in ini.options(mfr):
+ v = ini.get(mfr, monitor_name)
+ v = v.split(',')
+ install_key = v[0].strip()
+
+ line = ini.get(mfr, monitor_name)
+ # Find monitor inf IDs and EISA ids
+
+ edid = "0"
+ mo = monitor1Re.match(line)
+ if mo:
+ edid = mo.group('id')
+ else:
+ mo = monitor2Re.match(line)
+ if mo:
+ edid = mo.group('id').strip()
+
+ #if self.monitors.has_key(edid.lower()):
+ # continue
+
+ if ini.has_section(install_key):
+ line = ini.get(install_key, "AddReg")
+ if line:
+ sline = line.split(',')
+ registry = sline[0]
+ try:
+ resolution = sline[1]
+ except IndexError:
+ resolution = ""
+ try:
+ dpms = sline[2]
+ except IndexError:
+ dpms = ""
+
+ if ini.has_section(registry):
+ for line in ini.options(registry):
+ if string.find(line, 'HKR,"MODES') >= 0:
+ sline = line.split('"')
+ try:
+ syncline = sline[3]
+ except IndexError:
+ syncline = ","
+ syncline = syncline.split(',')
+ hsync = syncline[0].strip()
+ vsync = syncline[1].strip()
+
+ vendor_clear = _percent_to_string(ini,
+ strings, monitor_vendor_name)
+ monitor_clear = _percent_to_string(ini,
+ strings, monitor_name)
+
+ output = "%s; %s; %s; %s; %s" % \
+ (vendor_clear, monitor_clear,
+ edid, hsync, vsync)
+ if dpms.lower().strip() == "dpms":
+ output = output + "; 1"
+
+ if not monitors.has_key((vendor_clear,
+ monitor_clear, edid.lower())):
+ log.debug("added %s" % output)
+ monitors[(vendor_clear,
+ monitor_clear,
+ edid.lower())] = output
+ else:
+ log.warn("duplicated entry %s" % output)
+ return monitors
+
+def write_monitors_to_file(monitors, path):
+ """Writes monitors as a monitor models database"""
+ try:
+ if os.path.exists(path):
+ os.remove(path)
+ mdb = open(path, 'w')
+ mdb.writelines(map(lambda l: "%s\n" % l, monitors.values()))
+ mdb.close()
+ except IOError, (errno, str):
+ log.error("Unable to write %s: %s" % (path, str))
+ return False
+
+def append_monitors_to_file(monitors, path):
+ """Appends monitors to a monitor models database"""
+ try:
+ if os.path.exists(path):
+ os.remove(path)
+ mdb = open(path, 'a')
+ mdb.writelines(map(lambda l: "%s\n" % l, monitors.values()))
+ mdb.close()
+ except IOError, (errno, str):
+ log.error("Unable to write %s: %s" % (path, str))
+ return False
+
+if __name__ == "__main__":
+ from optparse import OptionParser
+ import sys
+
+ parser = OptionParser()
+ parser.add_option("-a", "--append",
+ action="store_true", dest="append",
+ help="Append new models to the database")
+ parser.add_option("-o", "--output",
+ default=None,
+ action="store", type="string", dest="output",
+ help="Write changes to an alternative file")
+ parser.usage = "%prog [options] INF_FILE [MONITOR_DATABASE]"
+ (options, args) = parser.parse_args()
+
+ if len(args) == 2:
+ # continue with normal operation
+ pass
+ elif len(args) == 1:
+ # jsut print the monitors from the given inf file
+ monitors_inf = get_monitors_from_inf(args[0])
+ for mon in monitors_inf.values():
+ print "%s" % mon
+ sys.exit()
+ else:
+ parser.error("You have to specify an .inf file that contains the "
+ "monitor models that you want to add and a "
+ "monitor model database")
+
+ monitors_inf = get_monitors_from_inf(args[0])
+ monitors_db = get_monitors_from_database(args[1])
+
+ monitors_new = {}
+ for mon in monitors_inf.keys():
+ if not monitors_db.has_key(mon):
+ log.info("New monitor: %s" % monitors_inf[mon])
+ monitors_new[mon] = monitors_inf[mon]
+
+ if options.append:
+ if options.output:
+ append_monitors_to_file(monitors_new, options.output)
+ else:
+ append_monitors_to_file(new_monitors, args[1])