summaryrefslogtreecommitdiffstats
path: root/displayconfig/xorgconfig.py
diff options
context:
space:
mode:
Diffstat (limited to 'displayconfig/xorgconfig.py')
-rwxr-xr-xdisplayconfig/xorgconfig.py903
1 files changed, 903 insertions, 0 deletions
diff --git a/displayconfig/xorgconfig.py b/displayconfig/xorgconfig.py
new file mode 100755
index 0000000..7683b87
--- /dev/null
+++ b/displayconfig/xorgconfig.py
@@ -0,0 +1,903 @@
+#!/usr/bin/python
+###########################################################################
+# xorgconfig.py - description #
+# ------------------------------ #
+# begin : Wed Feb 9 2004 #
+# copyright : (C) 2005 by Simon Edwards #
+# email : simon@simonzone.com #
+# #
+###########################################################################
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+###########################################################################
+import csv
+import codecs
+import locale
+"""
+General usage:
+
+ import xorgconfig
+ config = readConfig("/etc/X11/xorg.conf")
+
+ input_devices = config.getSections("InputDevice")
+ print input_devices[0].driver
+ options = input_devices[0].options
+ for option in options:
+ # option is of type OptionLine.
+ print option._row[0],
+ if len(option._row)>=2:
+ print "=>",option._row[1]
+
+ # Add line: Option "XkbModel" "pc105"
+ options.append( options.makeLine("Comment text",["XkbModel" "pc105"]) )
+
+
+Refactor plan
+=============
+New usage:
+
+ import xorgconfig
+ config = readConfig("/etc/X11/xorg.conf")
+
+ input_devices = config.section.InputDevice
+ print input_devices[0].driver
+ options = input_devices[0].options
+ for option in options:
+ # option is of type OptionLine.
+ print option[1],
+ if len(option)>=3:
+ print "=>",option[2]
+
+ module_section = config.section.module[0]
+ module_section.append(["load","i2c"])
+ assert module_section.existsLoad("i2c")
+ module_section.removeLoad("i2c")
+
+ device_section = config.section.device[0]
+ if device_section.busid is not None:
+ print "Found busid:",device_section.busid
+
+* direct references to myline._row should be removed.
+* A ConfigLine should be a subclass of List. With line[i] accessing the
+ parts of the line.
+* the order of the makeLine() parameters should be reversed.
+* it should be possible to directly append a list or tuple that represents
+ a line to a section.
+"""
+############################################################################
+class ConfigLine(object):
+ """Represents one line from the Xorg.conf file.
+
+ Each part of the line is printed without quotes.
+ """
+ def __init__(self,comment,row):
+ self._row = [item for item in row if item!='']
+ self._comment = comment
+
+ def toString(self,depth=0):
+ caprow = self._row
+ if len(caprow) > 0:
+ caprow[0] = caprow[0].capitalize()
+ string = ('\t' * (depth/2)) + ' ' * (depth%1) + '\t'.join([unicode(item) for item in caprow])
+ if self._comment is not None:
+ string += '#' + self._comment
+ return string + '\n'
+
+############################################################################
+class ConfigLineQuote(ConfigLine):
+ """Represents one line from the Xorg.conf file.
+
+ The first item in the line is not quoted, but the remaining items are.
+ """
+ def toString(self,depth=0):
+ string = ('\t' * (depth/2) + ' ' * (depth%1))
+ if len(self._row)!=0:
+ string += self._row[0].capitalize()
+ if len(self._row)>1:
+ if len(self._row[0]) < 8:
+ string += '\t'
+ string += '\t"' + '"\t"'.join([unicode(item) for item in self._row[1:]]) + '"'
+ if self._comment is not None:
+ string += '#' + self._comment
+ return string + '\n'
+
+############################################################################
+class OptionLine(ConfigLineQuote):
+ def __init__(self,comment,row):
+ arg = ['option']
+ arg.extend(row)
+ ConfigLineQuote.__init__(self,comment,arg)
+
+############################################################################
+class ConfigList(list):
+ def toString(self,depth=0):
+ string = ""
+ for item in self:
+ string += item.toString(depth)
+ return string
+
+############################################################################
+class OptionList(ConfigList):
+ name = "option"
+ def __setitem__(self,key,value):
+ list.__setitem__(self,key,value)
+
+ def makeLine(self,comment,row):
+ return OptionLine(comment,row)
+
+ def appendOptionRow(self,row):
+ self.append(self.makeLine(None,row))
+
+ def removeOptionByName(self,name):
+ name = name.lower()
+ i = 0
+ while i < len(self):
+ if self[i]._row[1].lower()==name:
+ del self[i]
+ else:
+ i += 1
+
+ def getOptionByName(self,name):
+ name = name.lower()
+ for item in self:
+ try:
+ if item._row[1].lower()==name:
+ return item
+ except IndexError:
+ pass
+ return None
+
+############################################################################
+class ScreenConfigLine(ConfigLine):
+ def __init__(self,comment,row):
+ arg = ["screen"]
+ arg.extend(row)
+ ConfigLine.__init__(self,comment,arg)
+
+ def toString(self,depth=0):
+ string = (' ' * depth)
+
+ try: # Keep on building up the string until the IndexError is thrown.
+ string += self._row[0]
+ i = 1
+ if self._row[i].isdigit():
+ string += ' ' + self._row[i]
+ i += 1
+ string += ' "' + self._row[i] + '"'
+ i += 1
+ while True:
+ item = self._row[i].lower()
+ if item in ['rightof','leftof','above','below']:
+ string += ' %s "%s"' % (item, self._row[i+1])
+ i += 1
+ elif item=='absolute':
+ string += ' %s %d %d' % (item, self._row[i+1], self._row[i+2])
+ i += 2
+ elif item.isdigit():
+ i += 1
+ string += ' %s %s' % (item,self._row[i])
+ i += 1
+ except IndexError: pass
+
+ if self._comment is not None:
+ string += ' #' + self._comment
+ return string + '\n'
+
+############################################################################
+class ScreenConfigList(ConfigList):
+ name = "screen"
+ def __setitem__(self,key,value):
+ list.__setitem__(self,key,value)
+
+ def makeLine(self,comment,row):
+ return ScreenConfigLine(comment,row)
+
+############################################################################
+class ConfigContainer(object):
+ """Acts as a container for ConfigLines and other ConfigContainers.
+ Is used for representing things like the whole config file, sections
+ and subsections inside the file.
+
+ """
+ def __init__(self):
+ self._contents = []
+
+ def append(self,item):
+ assert (item is not None)
+ self._contents.append(item)
+
+ def remove(self,item):
+ self._contents.remove(item)
+
+ def toString(self,depth=0):
+ string = ''
+ for item in self._contents:
+ string += item.toString(depth+1)
+ return string
+
+ def makeSection(self,comment,row):
+ return Section(comment,row)
+
+ def isSection(self,name):
+ lname = name.lower()
+ return lname=='section'
+
+ def isEndSection(self,name):
+ return False
+
+ def makeLine(self,comment,row):
+ return ConfigLine(comment,row)
+
+ def isListAttr(self,name):
+ lname = name.lower()
+ return lname in self._listattr
+
+ def makeListAttr(self,comment,row):
+ listobj = self.__getattr__(row[0].lower())
+ listobj.append( listobj.makeLine(comment,row[1:]) )
+
+ def getSections(self,name):
+ """Get all sections having the given name.
+
+ Returns a list of ConfigContainer objects.
+ """
+ name = name.lower()
+ sections = []
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigContainer) and item._name.lower()==name:
+ sections.append(item)
+ except IndexError: pass
+ return sections
+
+ def __getattr__(self,name):
+ if not name.startswith("_"):
+ lname = name.lower()
+ if lname in self._listattr:
+ # Lookup list attributes.
+ for item in self._contents:
+ if isinstance(item,ConfigList) and item.name==lname:
+ return item
+ else:
+ listitem = self._listattr[lname]()
+ self._contents.append(listitem)
+ return listitem
+ else:
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigLine) and item._row[0].lower()==lname:
+ return item._row[1]
+ except IndexError: pass
+ if lname in self._attr or lname in self._quoteattr:
+ return None
+ raise AttributeError, name
+
+ def __setattr__(self,name,value):
+ if name.startswith('_'):
+ return super(ConfigContainer,self).__setattr__(name,value)
+
+ lname = name.lower()
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigLine) and item._row[0].lower()==lname:
+ item._row[1] = value
+ break
+ except IndexError: pass
+ else:
+ if lname in self._attr or lname in self._quoteattr:
+ line = self.makeLine(None,[name,value])
+ self.append(line)
+ else:
+ raise AttributeError, name
+
+ def clear(self):
+ self._contents = []
+
+ def getRow(self,name):
+ if not name.startswith("_"):
+ lname = name.lower()
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigLine) and item._row[0].lower()==lname:
+ return item._row[1:]
+ except IndexError: pass
+
+ if name in self._attr or name in self._quoteattr:
+ # is a valid name, just has no real value right now.
+ return None
+
+ raise AttributeError, name
+
+############################################################################
+class Section(ConfigContainer):
+ """Represents a Section in the config file.
+
+ """
+
+ # List of config line types allowed inside this section.
+ # A list of strings naming lines that need to be stored in ConfigLine objects.
+ _attr = []
+
+ # A list of strings naming the lines that need to be stored in ConfigLineQuote objects.
+ # This is often overridden in subclasses.
+ _quoteattr = []
+
+ _listattr = {}
+
+ def __init__(self,comment,row):
+ ConfigContainer.__init__(self)
+ self._name = row[1]
+ self._comment = comment
+
+ def __show__(self):
+ """ For debugging """
+ for a in self._attr:
+ print self._name, "Attribute:", a
+ for a in self._quoteattr:
+ print self._name, "QuoteAttribute:", a
+ for a in self._listattr:
+ print self._name, "ListAttr:", a
+
+ def isSection(self,name):
+ return name.lower()=='subsection'
+
+ def isEndSection(self,name):
+ return name.lower()=='endsection'
+
+ def makeLine(self,comment,row):
+ try:
+ lname = row[0].lower()
+ if lname in self._quoteattr:
+ return ConfigLineQuote(comment,row)
+ if lname in self._attr:
+ return ConfigLine(comment,row)
+ return None
+ except IndexError:
+ pass
+ return ConfigContainer.makeLine(self,comment,row)
+
+ def toString(self,depth=0):
+ if self._comment is None:
+ return '%sSection "%s"\n%s%sEndSection\n' % \
+ (' ' * depth, self._name, ConfigContainer.toString(self,depth+1), ' ' * depth)
+ else:
+ return '%sSection "%s" # %s\n%s%sEndSection\n' % \
+ (' ' * depth, self._name, self._comment, ConfigContainer.toString(self,depth+1), ' ' * depth)
+
+############################################################################
+class SubSection(Section):
+ def isSection(self,name):
+ return False
+
+ def isEndSection(self,name):
+ return name.lower()=='endsubsection'
+
+ def toString(self,depth=0):
+ return '%sSubSection "%s"\n%s%sEndSubSection\n' % \
+ ('\t' * (depth/2) + ' ' * (depth%1), self._name, ConfigContainer.toString(self,depth+1), '\t' * (depth/2) + ' ' * (depth%1))
+
+
+############################################################################
+class DeviceSection(Section):
+ _attr = ["endsection","dacspeed","clocks","videoram","biosbase","membase", \
+ "iobase","chipid","chiprev","textclockfreq","irq","screen"]
+
+ _quoteattr = ["identifier","vendorname","boardname","chipset","ramdac", \
+ "clockchip","card","driver","busid"]
+
+ _listattr = {"option" : OptionList}
+
+############################################################################
+class DriSection(Section):
+ _attr = ["group","buffers","mode"]
+ def makeLine(self,comment,row):
+ try:
+ lname = row[0].lower()
+ if lname=="group" and not row[1].isdigit():
+ return ConfigLineQuote(comment,row)
+ except IndexError:
+ pass
+ return Section.makeLine(self,comment,row)
+
+############################################################################
+class ExtensionsSection(Section):
+ _listattr = {"option" : OptionList}
+
+############################################################################
+class FilesSection(Section):
+ _quoteattr = ["fontpath","rgbpath","modulepath","inputdevices","logfile"]
+ def makeLine(self,comment,row):
+ return ConfigLineQuote(comment,row)
+
+############################################################################
+class ModuleSection(Section):
+ _quoteattr = ["load","loaddriver","disable"]
+
+ def makeSection(self,comment,row):
+ return ModuleSubSection(comment,row)
+
+ def allowModule(self,modname):
+ killlist = []
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigLineQuote) \
+ and item._row[0].lower()=='disable' \
+ and item._row[1]==modname:
+ killlist.append(item)
+ except IndexError: pass
+
+ for item in killlist:
+ self._contents.remove(item)
+
+ def removeModule(self,modname):
+ killlist = []
+ for item in self._contents:
+ try:
+ if isinstance(item,ConfigLineQuote) \
+ and item._row[0].lower()=='load' \
+ and item._row[1]==modname:
+ killlist.append(item)
+ except IndexError: pass
+
+ for item in killlist:
+ self._contents.remove(item)
+
+ def disableModule(self,modname):
+ self.removeModule(modname)
+ self._contents.append(ConfigLineQuote(None,['disable',modname]))
+
+ def addModule(self,modname):
+ self.removeModule(modname)
+ self._contents.append(ConfigLineQuote(None,['load',modname]))
+
+############################################################################
+class ModuleSubSection(SubSection):
+ _listattr = {"option" : OptionList}
+
+############################################################################
+class ModeSection(Section):
+ _attr = ["dotclock","htimings","vtimings","hskew","bcast","vscan"]
+ _quoteattr = ["flags"]
+
+ def __init__(self,comment,row):
+ Section.__init__(self,comment,row)
+ self._name = row[1]
+
+ def isEndSection(self,name):
+ return name.lower()=='endmode'
+
+ def toString(self,depth=0):
+ if self._comment is None:
+ return '%sMode "%s"\n%s%sEndMode\n' % \
+ (' ' * depth, self._name, ConfigContainer.toString(self,depth+1), ' ' * depth)
+ else:
+ return '%sMode "%s" # %s\n%s%sEndMode\n' % \
+ (' ' * depth, self._name, self._comment, ConfigContainer.toString(self,depth+1), ' ' * depth)
+
+############################################################################
+class ModeList(ConfigList):
+ name = "mode"
+ def __setitem__(self,key,value):
+ list.__setitem__(self,key,value)
+
+ def makeLine(self,comment,row):
+ return ModeLine(comment,row)
+
+############################################################################
+class ModeLineList(ConfigList):
+ name = "modeline"
+ def __setitem__(self,key,value):
+ list.__setitem__(self,key,value)
+
+ def makeLine(self,comment,row):
+ return ModeLineConfigLine(comment,row)
+
+############################################################################
+class MonitorSection(Section):
+ _attr = ["displaysize","horizsync","vertrefresh","gamma"]
+ _quoteattr = ["identifier","vendorname","modelname","usemodes"]
+ _listattr = {"option" : OptionList, "mode" : ModeList, "modeline" : ModeLineList}
+
+ def makeLine(self,comment,row):
+ return Section.makeLine(self,comment,row)
+
+ def isSection(self,name):
+ lname = name.lower()
+ return lname=='mode'
+
+ def isEndSection(self,name):
+ return name.lower()=='endsection'
+
+ def makeSection(self,comment,row):
+ if row[0].lower()=='mode':
+ return ModeSection(comment,row)
+ else:
+ return Section.makeSection(self,comment,row)
+
+############################################################################
+class ModeLineConfigLine(ConfigLine):
+ def toString(self,depth=0):
+ string = (' ' * depth)+"modeline "
+ if len(self._row)>0:
+ string += ' "' + self._row[0] + '"'
+ if len(self._row)>1:
+ string += ' ' + ' '.join([unicode(item) for item in self._row[1:]])
+ if self._comment is not None:
+ string += '#' + self._comment
+ return string + '\n'
+
+############################################################################
+class ModesSection(MonitorSection):
+ # Like a MonitorSection, only smaller.
+ _attr = ["modeline"]
+ _quoteattr = ["identifier"]
+
+############################################################################
+class PointerSection(Section):
+ _attr = ["emulate3timeout","baudrate","samplerate","resolution",\
+ "devicename","buttons"]
+ _quoteattr = ["protocol","device","port","emulate3buttons","chordmiddle",\
+ "cleardtr","clearrts","zaxismapping","alwayscore"]
+
+############################################################################
+class ScreenSection(Section):
+ _attr = ["screenno","defaultcolordepth","defaultdepth","defaultbpp","defaultfbbpp"]
+ _quoteattr = ["identifier","driver","device","monitor","videoadaptor","option"]
+ _listattr = {"option" : OptionList}
+ def makeSection(self,comment,row):
+ if row[1].lower()=='display':
+ return DisplaySubSection(comment,row)
+ return SubSection(comment,row)
+
+############################################################################
+class DisplaySubSection(SubSection):
+ _attr = ["viewport","virtual","black","white","depth","fbbpp","weight"]
+ _quoteattr = ["modes","visual","option"]
+ _listattr = {"option" : OptionList}
+############################################################################
+class ServerFlagsSection(Section):
+ _quoteattr = ["notrapsignals","dontzap","dontzoom","disablevidmodeextension",\
+ "allownonlocalxvidtune","disablemodindev","allownonlocalmodindev","allowmouseopenfail", \
+ "blanktime","standbytime","suspendtime","offtime","defaultserverlayout"]
+ _listattr = {"option" : OptionList}
+
+############################################################################
+class ServerLayoutSection(Section):
+ _attr = []
+ _quoteattr = ["identifier","inactive","inputdevice","option"]
+ _listattr = {"option" : OptionList, "screen" : ScreenConfigList}
+
+############################################################################
+class InputDeviceSection(Section):
+ _quoteattr = ["identifier","driver"]
+ _listattr = {"option" : OptionList}
+############################################################################
+class KeyboardSection(Section):
+ _attr = ["autorepeat","xleds"]
+ _quoteattr = ["protocol","panix106","xkbkeymap","xkbcompat","xkbtypes",\
+ "xkbkeycodes","xkbgeometry","xkbsymbols","xkbdisable","xkbrules",\
+ "xkbmodel","xkblayout","xkbvariant","xkboptions","vtinit","vtsysreq",\
+ "servernumlock","leftalt","rightalt","altgr","scrolllock","rightctl"]
+
+############################################################################
+class VendorSection(Section):
+ _attr = []
+ _quoteattr = ["identifier"]
+ _listattr = {"option" : OptionList}
+ def isSection(self,name): return False
+
+############################################################################
+class VideoAdaptorSection(Section):
+ _attr = []
+ _quoteattr = ["identifier","vendorname","boardname","busid","driver"]
+ _listattr = {"option" : OptionList}
+ def makeSection(self,comment,row):
+ return VideoPortSection(comment,row)
+
+############################################################################
+class VideoPortSection(SubSection):
+ _attr = []
+ _quoteattr = ["identifier"]
+ _listattr = {"option" : OptionList}
+############################################################################
+class XorgConfig(ConfigContainer):
+ _sectiontypes = { \
+ 'device': DeviceSection,
+ 'dri': DriSection,
+ 'extensions': ExtensionsSection,
+ 'files': FilesSection,
+ 'inputdevice': InputDeviceSection,
+ 'keyboard': KeyboardSection,
+ 'modes': ModesSection,
+ 'monitor': MonitorSection,
+ 'module': ModuleSection,
+ 'pointer': PointerSection,
+ 'serverflags': ServerFlagsSection,
+ 'serverlayout': ServerLayoutSection,
+ 'screen': ScreenSection,
+ 'videoadaptor': VideoAdaptorSection}
+
+ def makeSection(self,comment,row):
+ lname = row[1].lower()
+ try:
+ return self._sectiontypes[lname](comment,row)
+ except KeyError:
+ return ConfigContainer.makeSection(self,comment,row)
+
+ def toString(self,depth=-1):
+ return ConfigContainer.toString(self,depth)
+
+ def writeConfig(self,filename):
+ try:
+ encoding = locale.getpreferredencoding()
+ except locale.Error:
+ encoding = 'ANSI_X3.4-1968'
+ fhandle = codecs.open(filename,'w',locale.getpreferredencoding())
+ fhandle.write(self.toString())
+ fhandle.close()
+
+ def createUniqueIdentifier(self,stem="id"):
+ """Create a unique identifier for a section
+
+ """
+ # Build a list of used identifiers
+ used_identifiers = []
+ for name in ['monitor','videoadaptor','inputdevice','serverlayout','device','screen']:
+ for section in self.getSections(name):
+ if section.identifier is not None:
+ used_identifiers.append(section.identifier)
+
+ # Generate a identifier that is not in use.
+ i = 1
+ while (stem+str(i)) in used_identifiers:
+ i += 1
+
+ return stem+str(i)
+
+############################################################################
+def addxorg(context, stack):
+ # Add minimal xorg.conf if it's missing
+ rows = [[None, [u'Section', u'Device']], [None, [u'Identifier', u'Configured Video Device']], \
+ [None, [u'EndSection']], [None, [u'Section', u'Monitor']], \
+ [None, [u'Identifier', u'Configured Monitor']], \
+ [None, [u'EndSection']], [None, [u'Section', u'Screen']], \
+ [None, [u'Identifier', u'Default Screen']], \
+ [None, [u'Monitor', u'Configured Monitor']], [None, [u'EndSection']], \
+ [None, [u'Section', u'ServerLayout']], \
+ [None, [u'Identifier', u'Default Layout']], \
+ [None, [u'screen', u'Default Screen']], \
+ [None, [u'EndSection']]]
+
+ for data in rows:
+ rowcomment = data[0]
+ row = data[1]
+ try:
+ first = row[0].lower()
+ if context.isSection(first):
+ section = context.makeSection(rowcomment,row)
+ context.append(section)
+ stack.append(context)
+ context = section
+ context_class = context.__class__
+ elif context.isEndSection(first):
+ context = stack.pop()
+ elif context.isListAttr(first):
+ context.makeListAttr(rowcomment,row)
+ else:
+ newline = context.makeLine(rowcomment,row)
+ if newline is None:
+ raise ParseException,"Unknown line type '%s' on line %i" % (first,line)
+ context.append(newline)
+ except IndexError:
+ context.append(ConfigLine(rowcomment,row))
+
+ return context, section, stack, first
+
+############################################################################
+def addServerLayout(context, section, stack, first):
+ # Add empty server layout section to xorg.conf if it's missing
+ rows = [[None, [u'Section', u'ServerLayout']], \
+ [None, [u'Identifier', u'Default Layout']], \
+ [None, [u'screen', u'0', u'Default Screen', u'0', u'0']], \
+ [None, [u'Inputdevice', u'Generic Keyboard']], \
+ [None, [u'Inputdevice', u'Configured Mouse']], \
+ [None, []], ["Uncomment if you have a wacom tablet", []], \
+ ["InputDevice \"stylus\" \"SendCoreEvents\"", []], \
+ [" InputDevice \"cursor\" \"SendCoreEvents\"", []], \
+ [" InputDevice \"eraser\" \"SendCoreEvents\"", []], \
+ [None, [u'Inputdevice', u'Synaptics Touchpad']], [None, [u'EndSection']]]
+ for data in rows:
+ rowcomment = data[0]
+ row = data[1]
+ try:
+ first = row[0].lower()
+ if context.isSection(first):
+ section = context.makeSection(rowcomment,row)
+ context.append(section)
+ stack.append(context)
+ context = section
+ context_class = context.__class__
+ elif context.isEndSection(first):
+ context = stack.pop()
+ elif context.isListAttr(first):
+ context.makeListAttr(rowcomment,row)
+ else:
+ newline = context.makeLine(rowcomment,row)
+ if newline is None:
+ raise ParseException,"Unknown line type '%s' on line %i" % (first,line)
+ context.append(newline)
+ except IndexError:
+ context.append(ConfigLine(rowcomment,row))
+
+ return context, section, stack, first
+
+############################################################################
+def readConfig(filename, check_exists=False):
+
+ context = XorgConfig()
+ stack = []
+ line = 1
+ hasserverlayout = False
+ hasxorg = True
+ try:
+ import os
+ try:
+ if os.path.isfile('/etc/X11/xorg.conf'):
+ if os.path.getsize(filename) == 0:
+ raise IOError, "xorg.conf is empty - making up config"
+ else:
+ raise IOError, "xorg.conf is empty - making up config"
+ except OSError, errmsg:
+ raise IOError, errmsg
+ for row in XorgconfCVSReader(filename=filename).readlines():
+ try:
+ first = row[0].lower()
+ if context.isSection(first):
+ section = context.makeSection(row.comment,row)
+ if section._name == 'ServerLayout':
+ hasserverlayout = True
+ context.append(section)
+ stack.append(context)
+ context = section
+ context_class = context.__class__
+ elif context.isEndSection(first):
+ context = stack.pop()
+ elif context.isListAttr(first):
+ context.makeListAttr(row.comment,row)
+ else:
+ newline = context.makeLine(row.comment,row)
+ if newline is None:
+ raise ParseException,"Unknown line type '%s' on line %i" % (first,line)
+ context.append(newline)
+ except IndexError:
+ context.append(ConfigLine(row.comment,row))
+ line += 1
+ except IOError, errmsg:
+ ermsg = str(errmsg)
+ print "IOError", ermsg, " - will create xorg.conf if possible."
+ if ermsg[:9] == "[Errno 2]": # No such file or directory:
+ hasxorg = False
+ addxorg(context, stack)
+ try:
+ xorgfile = open(filename, 'a')
+ xorgfile.close()
+ except IOError, errmsg:
+ ermsg = str(errmsg)
+ if ermsg[:9] == "[Errno 13]": #Permission denied:
+ pass
+ # Since we aren't root, changes can't be made anyway.
+ elif ermsg[:9] == "xorg.conf": # xorg.conf exists, but is empty
+ hasxorg = False
+ addxorg(context, stack)
+
+ if len(stack)!=0:
+ raise ParseException,"Unexpected end of file on line %i" % line
+ if not hasserverlayout and hasxorg:
+ addServerLayout(context, section, stack, first)
+ if check_exists:
+ return context, hasxorg
+ else:
+ return context
+
+############################################################################
+class ParseException(Exception):
+ def __init__(self,*args):
+ Exception.__init__(self,*args)
+
+############################################################################
+def toBoolean(value):
+ return unicode(value).lower() in ['on','true','1','yes']
+
+############################################################################
+# Our own class for reading CSV file. This version supports unicode while
+# standard Python (2.4) version doesn't. Hence the need for this class.
+#
+class XorgconfCVSReader(object):
+ def __init__(self,filename=None, text=None):
+ assert filename is not None or text is not None
+
+ STATE_DELIMITER = 0
+ STATE_ITEM = 1
+ STATE_QUOTE = 2
+ QUOTE = '"'
+ LINE_COMMENT = '#'
+
+ class CommentList(list):
+ def __init__(self):
+ list.__init__(self)
+ self.comment = None
+
+ if filename is not None:
+ try:
+ loc = locale.getpreferredencoding()
+ except locale.Error:
+ loc = 'ANSI_X3.4-1968'
+ fhandle = codecs.open(filename,'r',loc,'replace')
+ source_lines = fhandle.readlines()
+ fhandle.close()
+ else:
+ source_lines = text.split('\n')
+
+ self.lines = []
+ for line in source_lines:
+ if len(line)!=0 and line[-1]=='\n':
+ line = line[:-1]
+
+ state = STATE_DELIMITER
+ row = CommentList()
+ item = None
+ for i in range(len(line)):
+ c = line[i]
+
+ if state==STATE_DELIMITER:
+ if not c.isspace():
+ if c==QUOTE:
+ item = []
+ state = STATE_QUOTE
+ elif c==LINE_COMMENT:
+ row.comment = line[i+1:]
+ break
+ else:
+ item = []
+ item.append(c)
+ state = STATE_ITEM
+
+ elif state==STATE_ITEM:
+ if c.isspace():
+ row.append(u''.join(item))
+ state = STATE_DELIMITER
+ item = None
+ else:
+ item.append(c)
+
+ elif state==STATE_QUOTE:
+ if c==QUOTE:
+ row.append(u''.join(item))
+ state = STATE_DELIMITER
+ item = None
+ else:
+ item.append(c)
+
+ if item is not None:
+ row.append(u''.join(item))
+
+ self.lines.append(row)
+
+ def readlines(self):
+ return self.lines
+
+############################################################################
+if __name__=='__main__':
+ import sys
+ if len(sys.argv)==2:
+ filename = sys.argv[1]
+ else:
+ filename = "/etc/X11/xorg.conf"
+ print "Reading",filename
+ c = readConfig(filename)
+ print c.toString()
+