# Copyright (C) 1996 Red Hat Software, Inc.
# Use of this software is subject to the terms of the GNU General
# Public License

# This module manages standard configuration file handling
# These classes are available:
# Conf:
#  This is the base class.  This is good for working with just about
#  any line-oriented configuration file.
#  Currently does not deal with newline escaping; may never...
# ConfShellVar(Conf):
#  This is a derived class which implements a dictionary for standard
#  VARIABLE=value
#  shell variable setting.
#  Limitations:
#    o one variable per line
#    o assumes everything on the line after the '=' is the value
# ConfESNetwork(ConfShellVar):
#  This is a derived class specifically intended for /etc/sysconfig/network
#  It is another dictionary, but magically fixes /etc/HOSTNAME when the
#  hostname is changed.
# ConfEHosts(Conf):
#  Yet another dictionary, this one for /etc/hosts
#  Dictionary keys are numeric IP addresses in string form, values are
#  2-item lists, the first item of which is the canonical hostname,
#  and the second of which is a list of nicknames.
# ConfEResolv(Conf):
#  Yet another dictionary, this one for /etc/resolv.conf
#  This ugly file has two different kinds of entries.  All but one
#  take the form "key list of arguments", but one entry (nameserver)
#  instead takes multiple lines of "key argument" pairs.
#  In this dictionary, all keys have the same name as the keys in
#  the file, EXCEPT that the multiple nameserver entries are all
#  stored under 'nameservers'.  Each value (even singleton values)
#  is a list.
# ConfESStaticRoutes(Conf):
#  Yet another dictionary, this one for /etc/sysconfig/static-routes
#  This file has a syntax similar to that of /etc/gateways;
#  the interface name is added and active/passive is deleted:
#  <interface> net <netaddr> netmask <netmask> gw <gateway>
#  The key is the interface, the value is a list of
#  [<netaddr>, <netmask>, <gateway>] lists
# ConfChat(Conf):
#  Not a dictionary!
#  This reads chat files, and writes a subset of chat files that
#  has all items enclosed in '' and has one expect/send pair on
#  each line.
#  Uses a list of two-element tuples.
# ConfDIP:
#  This reads chat files, and writes a dip file based on that chat script.
#  Takes three arguments:
#   o The chatfile
#   o The name of the dipfile
#   o The ConfSHellVar instance from which to take variables in the dipfile
# ConfModules(Conf)
#  This reads /etc/conf.modules into a dictionary keyed on device type,
#  holding dictionaries: cm['eth0']['alias'] --> 'smc-ultra'
#                        cm['eth0']['options'] --> {'io':'0x300', 'irq':'10'}
#                        cm['eth0']['post-install'] --> ['/bin/foo','arg1','arg2']
#  path[*] entries are ignored (but not removed)
#  New entries are added at the end to make sure that they
#  come after any path[*] entries.
#  Comments are delimited by initial '#'
# ConfModInfo(Conf)
#  This READ-ONLY class reads /boot/module-info.
#  The first line of /boot/module-info is "Version = <version>";
#  this class reads version 0 module-info files.

from string import *
from regex import *
import regsub
import os

# Implementation:
# A configuration file is a list of lines.
# a line is a string.

class Conf:
    def __init__(self, filename, commenttype='#',
                 separators='\t ', separator='\t'):
        self.commenttype = commenttype
        self.separators = separators
        self.separator = separator
        self.line = 0
        # self.line is a "point" -- 0 is before the first line;
        # 1 is between the first and second lines, etc.
        # The "current" line is the line after the point.
        self.filename = filename
        self.read()
    def rewind(self):
        self.line = 0
    def fsf(self):
        self.line = len(self.lines)
    def tell(self):
        return self.line
    def seek(self, line):
        self.line = line
    def nextline(self):
        self.line = min([self.line + 1, len(self.lines)])
    def findnextline(self, regexp='.*'):
        # returns false if no more lines matching pattern
        while self.line < len(self.lines):
            if search(regexp, self.lines[self.line]) > -1:
                return 1
            self.line = self.line + 1
        # if while loop terminated, pattern not found.
        return 0
    def findnextcodeline(self):
        # optional whitespace followed by non-comment character
        # defines a codeline.  blank lines, lines with only whitespace,
        # and comment lines do not count.
        return self.findnextline('^[' + self.separators + ']*' +
                             '[^' + self.commenttype + self.separators + ']+')
    def getline(self):
        if self.line >= len(self.lines):
            return ''
        return self.lines[self.line]
    def getfields(self):
        # returns list of fields split by self.separators
        if self.line >= len(self.lines):
            return []
        return regsub.split(self.lines[self.line], '[' + self.separators + ']+')
    def insertline(self, line=''):
        self.lines.insert(self.line, line)
    def insertlinelist(self, linelist):
        self.insertline(joinfields(linelist, self.separator))
    def sedline(self, pat, repl):
        if self.line < len(self.lines):
            self.lines[self.line] = regsub.gsub(pat, repl, \
                                                self.lines[self.line])
    def changefield(self, fieldno, fieldtext):
        fields = self.getfields()
        fields[fieldno:fieldno+1] = fieldtext
        self.insertlinelist(fields)
    def setline(self, line=[]):
        self.deleteline()
        self.insertline(line)
    def deleteline(self):
        self.lines[self.line:self.line+1] = []
    def read(self):
        if os.path.isfile(self.filename):
            self.file = open(self.filename, 'r', -1)
            self.lines = self.file.readlines()
            # strip newlines
            for index in range(len(self.lines)):
                self.lines[index] = \
                    self.lines[index][0:len(self.lines[index])-1]
            self.file.close()
	else:
	    self.lines = []
    def write(self):
	if not os.path.exists(self.filename):
	    chmod = 1
	else:
	    chmod = 0
        self.file = open(self.filename, 'w', -1)
	if chmod:
	    os.chmod(self.filename, 0600)
        # add newlines
        for index in range(len(self.lines)):
            self.file.write(self.lines[index] + '\n')
        self.file.close()

class ConfShellVar(Conf):
    def __init__(self, filename):
        Conf.__init__(self, filename, commenttype='#',
                      separators='=', separator='=')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
        self.rewind()
        while self.findnextline('^[\t ]*[A-Za-z_][A-Za-z0-9_]*='):
            # initialize dictionary of variable/name pairs
            var = self.getfields()
            self.vars[var[0]] = var[1]
            self.nextline()
        self.rewind()
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return ''
    def __setitem__(self, varname, value):
        # set *every* instance of varname to value to avoid surprises
        place=self.tell()
        self.rewind()
        missing=1
        while self.findnextline('[\t ]*' + varname + '='):
            self.sedline('=.*', '=' + value)
            missing=0
            self.nextline()
        if missing:
            self.seek(place)
            self.insertline(varname + '=' + value)
        self.vars[varname] = value
    def __delitem__(self, varname):
        # delete *every* instance...
        self.rewind()
        while self.findnextline('[\t ]*' + varname + '='):
            self.deleteline()
        del self.vars[varname]


class ConfESNetwork(ConfShellVar):
    # explicitly for /etc/sysconfig/network: HOSTNAME is magical value
    # that writes /etc/HOSTNAME as well
    def __init__ (self):
	ConfShellVar.__init__(self, '/etc/sysconfig/network')
	self.writehostname = 0
    def __setitem__(self, varname, value):
	ConfShellVar.__setitem__(self, varname, value)
	if varname == 'HOSTNAME':
	    self.writehostname = 1
    def write(self):
	ConfShellVar.write(self)
	if self.writehostname:
	    file = open('/etc/HOSTNAME', 'w', -1)
	    file.write(self.vars['HOSTNAME'] + '\n')
	    file.close()
	    os.chmod('/etc/HOSTNAME', 0644)
    def keys(self):
	# There doesn't appear to be a need to return keys in order
	# here because we normally always have the same entries in this
	# file, and order isn't particularly important.
	return self.vars.keys()


class ConfEHosts(Conf):
    # for /etc/hosts
    # implements a dictionary keyed by IP address, with values
    # consisting of a list: [ hostname, [list, of, nicknames] ]
    def __init__(self):
        Conf.__init__(self, '/etc/hosts')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
        self.rewind()
        while self.findnextcodeline():
            # initialize dictionary of variable/name pairs
            var = self.getfields()
            if len(var) > 2:
		# has nicknames
                self.vars[var[0]] = [ var[1], var[2:] ]
	    else:
                self.vars[var[0]] = [ var[1], [] ]
            self.nextline()
        self.rewind()
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return ''
    def __setitem__(self, varname, value):
        # set first (should be only) instance to values in list value
        place=self.tell()
        self.rewind()
        if self.findnextline('^' + regsub.gsub('\.', '\\\\.', varname) +
                             '[' + self.separators + ']+'):
            self.deleteline()
	    self.insertlinelist([ varname, value[0],
                                  joinfields(value[1], self.separator) ])
            self.seek(place)
        else:
            self.seek(place)
	    self.insertlinelist([ varname, value[0],
                                  joinfields(value[1], self.separator) ])
        self.vars[varname] = value
    def __delitem__(self, varname):
        # delete *every* instance...
        self.rewind()
        while self.findnextline('[' + self.separators + ']*' +
                                regsub.gsub('\.', '\\\\.', varname) +
				'[' + self.separators + ']'):
            self.deleteline()
        del self.vars[varname]
    def keys(self):
	# It is rather important to return the keys in order here,
	# in order to maintain a consistent presentation in apps.
        place=self.tell()
        self.rewind()
        keys = []
        while self.findnextcodeline():
            # initialize dictionary of variable/name pairs
            var = self.getfields()
            keys.append(var[0])
            self.nextline()
	self.seek(place)
	return keys


class ConfEResolv(Conf):
    # /etc/resolv.conf
    def __init__(self):
	Conf.__init__(self, '/etc/resolv.conf', '#', '\t ', ' ')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
        self.rewind()
        while self.findnextcodeline():
            var = self.getfields()
	    if var[0] == 'nameserver':
		if self.vars.has_key('nameservers'):
		    self.vars['nameservers'].append(var[1])
		else:
		    self.vars['nameservers'] = [ var[1] ]
	    else:
		self.vars[var[0]] = var[1:]
            self.nextline()
        self.rewind()
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return []
    def __setitem__(self, varname, value):
        # set first (should be only) instance to values in list value
        place=self.tell()
        self.rewind()
	if varname == 'nameservers':
            if self.findnextline('^nameserver[' + self.separators + ']+'):
		# if there is a nameserver line, save the place,
		# remove all nameserver lines, then put in new ones in order
		placename=self.tell()
		while self.findnextline('^nameserver['+self.separators+']+'):
                    self.deleteline()
		self.seek(placename)
                for nameserver in value:
		    self.insertline('nameserver' + self.separator + nameserver)
		    self.nextline()
                self.seek(place)
            else:
		# no nameservers entries so far
                self.seek(place)
                for nameserver in value:
		    self.insertline('nameserver' + self.separator + nameserver)
	else:
	    # not a nameserver, so all items on one line...
            if self.findnextline('^' + varname + '[' + self.separators + ']+'):
                self.deleteline()
	        self.insertlinelist([ varname, 
                                      joinfields(value, self.separator) ])
                self.seek(place)
            else:
                self.seek(place)
	        self.insertlinelist([ varname,
                                      joinfields(value, self.separator) ])
	# no matter what, update our idea of the variable...
        self.vars[varname] = value
    def __delitem__(self, varname):
        # delete *every* instance...
        self.rewind()
        while self.findnextline('[' + self.separators + ']*' + varname +
				'[' + self.separators + ']'):
            self.deleteline()
        del self.vars[varname]
    def write(self):
	# Need to make sure __setitem__ is called for each item to
	# maintain consistancy, in case some did something like
	# resolv['nameservers'].append('123.123.123.123')
	# or
	# resolv['search'].append('another.domain')
	for key in self.vars.keys():
	    self[key] = self.vars[key]
	Conf.write(self)
    def keys(self):
	# no need to return list in order here, I think.
	return self.vars.keys()


# ConfESStaticRoutes(Conf):
#  Yet another dictionary, this one for /etc/sysconfig/static-routes
#  This file has a syntax similar to that of /etc/gateways;
#  the interface name is added and active/passive is deleted:
#  <interface> net <netaddr> netmask <netmask> gw <gateway>
#  The key is the interface, the value is a list of
#  [<netaddr>, <netmask>, <gateway>] lists
class ConfESStaticRoutes(Conf):
    def __init__(self):
	Conf.__init__(self, '/etc/sysconfig/static-routes', '#', '\t ', ' ')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
        self.rewind()
        while self.findnextcodeline():
            var = self.getfields()
	    if not self.vars.has_key(var[0]):
		self.vars[var[0]] = [[var[2], var[4], var[6]]]
	    else:
		self.vars[var[0]].append([var[2], var[4], var[6]])
            self.nextline()
        self.rewind()
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return [[]]
    def __setitem__(self, varname, value):
	# since we re-write the file completely on close, we don't
	# need to alter it piecemeal here.
        self.vars[varname] = value
    def __delitem__(self, varname):
	# again, since we re-write the file completely on close, we don't
	# need to alter it piecemeal here.
        del self.vars[varname]
    def delroute(self, device, route):
	# deletes a route from a device if the route exists,
	# and if it is the only route for the device, removes
	# the device from the dictionary
	# Note: This could normally be optimized considerably,
	# except that our input may have come from the file,
	# which others may have hand-edited, and this makes it
	# possible for us to deal with hand-inserted multiple
	# identical routes in a reasonably correct way.
	if self.vars.has_key(device):
	    for i in range(len(self.vars[device])):
		if i < len(self.vars[device]) and \
		   not cmp(self.vars[device][i], route):
		    # need first comparison because list shrinks
		    self.vars[device][i:i+1] = []
		    if len(self.vars[device]) == 0:
			del self.vars[device]
    def addroute(self, device, route):
	# adds a route to a device, deleteing it first to avoid dups
	self.delroute(device, route)
	if self.vars.has_key(device):
	    self.vars[device].append(route)
	else:
	    self.vars[device] = [route]
    def write(self):
	# forget current version of file
	self.rewind()
	self.lines = []
	for device in self.vars.keys():
	    for route in self.vars[device]:
		self.insertlinelist((device, 'net', route[0], 'netmask', route[1],
				     'gw', route[2]))
	Conf.write(self)
    def keys(self):
	# no need to return list in order here, I think.
	return self.vars.keys()



# ConfChat(Conf):
#  Not a dictionary!
#  This reads chat files, and writes a subset of chat files that
#  has all items enclosed in '' and has one expect/send pair on
#  each line.
#  Uses a list of two-element tuples.
class ConfChat(Conf):
    def __init__(self, filename):
	Conf.__init__(self, filename, '', '\t ', ' ')
    def read(self):
        Conf.read(self)
        self.initlist()
    def initlist(self):
	self.list = []
	i = 0
	hastick = 0
	s = '' 
	chatlist = []
	for line in self.lines:
	    s = s + line + ' '
	while i < len(s) and s[i] in " \t":
	    i = i + 1
	while i < len(s):
	    str = ''
	    # here i points to a new entry
	    if s[i] in "'":
		hastick = 1
		i = i + 1
		while i < len(s) and s[i] not in "'":
		    if s[i] in '\\':
			if not s[i+1] in " \t":
			    str = str + '\\'
			i = i + 1
		    str = str + s[i]
		    i = i + 1
		# eat up the ending '
		i = i + 1
	    else:
		while i < len(s) and s[i] not in " \t":
		    str = str + s[i]
		    i = i + 1
	    chatlist.append(str)
	    # eat whitespace between strings
	    while i < len(s) and s[i] in ' \t':
		i = i + 1
	# now form self.list from chatlist
	if len(chatlist) % 2:
	    chatlist.append('')
	while chatlist:
	    self.list.append((chatlist[0], chatlist[1]))
	    chatlist[0:2] = []
    def getlist(self):
	return self.list
    def putlist(self, list):
	self.list = list
    def write(self):
	# create self.lines for Conf.write...
	self.lines = []
	for (p,q) in self.list:
	    p = regsub.gsub("'", "\'", p)
	    q = regsub.gsub("'", "\'", q)
	    self.lines.append("'"+p+"' '"+q+"'")
	Conf.write(self)



# ConfDIP:
#  This reads chat files, and writes a dip file based on that chat script.
#  Takes three arguments:
#   o The chatfile
#   o The name of the dipfile
#   o The ConfSHellVar instance from which to take variables in the dipfile
class ConfDIP:
    def __init__(self, chatfile, dipfilename, configfile):
	self.dipfilename = dipfilename
	self.chatfile = chatfile
	self.cf = configfile
    def write(self):
        self.file = open(self.dipfilename, 'w', -1)
	os.chmod(self.dipfilename, 0600)
	self.file.write('# dip script for interface '+self.cf['DEVICE']+'\n' +
	  '# DO NOT HAND-EDIT; ALL CHANGES *WILL* BE LOST BY THE netcfg PROGRAM\n' +
	  '# This file is created automatically from several other files by netcfg\n' +
	  '# Re-run netcfg to modify this file\n\n' +
	  'main:\n' +
	  '  get $local '+self.cf['IPADDR']+'\n' +
	  '  get $remote '+self.cf['REMIP']+'\n' +
	  '  port '+self.cf['MODEMPORT']+'\n' +
	  '  speed '+self.cf['LINESPEED']+'\n')
	if self.cf['MTU']:
	    self.file.write('  get $mtu '+self.cf['MTU']+'\n')
	for pair in self.chatfile.list:
	    if cmp(pair[0], 'ABORT') and cmp(pair[0], 'TIMEOUT'):
		if pair[0]:
		    self.file.write('  wait '+pair[0]+' 30\n' +
			    '  if $errlvl != 0 goto error\n')
		self.file.write('  send '+pair[1]+'\\r\\n\n' +
			'  if $errlvl != 0 goto error\n')
	if not cmp(self.cf['DEFROUTE'], 'yes'):
	    self.file.write('  default\n')
	self.file.write('  mode '+self.cf['MODE']+'\n' +
	  '  exit\n' +
	  'error:\n' +
	  '  print connection to $remote failed.\n')
        self.file.close()


# ConfModules(Conf)
#  This reads /etc/conf.modules into a dictionary keyed on device type,
#  holding dictionaries: cm['eth0']['alias'] --> 'smc-ultra'
#                        cm['eth0']['options'] --> {'io':'0x300', 'irq':'10'}
#                        cm['eth0']['post-install'] --> ['/bin/foo','arg1','arg2']
#  path[*] entries are ignored (but not removed)
#  New entries are added at the end to make sure that they
#  come after any path[*] entries.
#  Comments are delimited by initial '#'
class ConfModules(Conf):
    def __init__(self, filename = '/etc/conf.modules'):
	Conf.__init__(self, filename, '#', '\t ', ' ')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
	keys = ('alias', 'options', 'post-install')
        self.rewind()
        while self.findnextcodeline():
            var = self.getfields()
	    if len(var) > 2 and var[0] in keys:
		if not self.vars.has_key(var[1]):
		    self.vars[var[1]] = {'alias':'', 'options':{}, 'post-install':[]}
		if not cmp(var[0], 'alias'):
		    self.vars[var[1]]['alias'] = var[2]
		elif not cmp(var[0], 'options'):
		    self.vars[var[1]]['options'] = self.splitoptlist(var[2:])
		elif not cmp(var[0], 'post-install'):
		    self.vars[var[1]]['post-install'] = var[2:]
            self.nextline()
        self.rewind()
    def splitoptlist(self, optlist):
	dict = {}
	for opt in optlist:
	    optup = self.splitopt(opt)
	    if optup:
		dict[optup[0]] = optup[1]
	return dict
    def splitopt(self, opt):
	eq = search('=', opt)
	if eq > 0:
	    return (opt[:eq], opt[eq+1:])
	else:
	    return ()
    def joinoptlist(self, dict):
	optstring = ''
	for key in dict.keys():
	    optstring = optstring + key + '=' + dict[key] + ' '
	return optstring
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return {}
    def __setitem__(self, varname, value):
        # set *every* instance (should only be one, but...) to avoid surprises
        place=self.tell()
        self.vars[varname] = value
	for key in value.keys():
            self.rewind()
            missing=1
	    if not cmp(key, 'alias'):
		endofline = value[key]
	    elif not cmp(key, 'options'):
		endofline = self.joinoptlist(value[key])
	    elif not cmp(key, 'post-install'):
		endofline = joinfields(value[key], ' ')
	    else:
		# some idiot apparantly put an unrecognized key in
		# the dictionary; ignore it...
		continue
	    if endofline:
		# there's something to write...
        	while self.findnextline('[\t ]*' + key + '[\t ]+' + varname):
        	    self.setline(key + ' ' + varname + ' ' + endofline)
        	    missing=0
        	    self.nextline()
        	if missing:
		    self.fsf()
        	    self.insertline(key + ' ' + varname + ' ' + endofline)
	    else:
		# delete any instances of this if they exist.
        	while self.findnextline('[\t ]*' + key + '[\t ]+' + varname):
        	    self.deleteline()
	self.seek(place)
    def __delitem__(self, varname):
        # delete *every* instance...
        place=self.tell()
	for key in self.vars[varname].keys():
            self.rewind()
            while self.findnextline('[\t ]*' + key + '[\t ]+' + varname):
        	self.deleteline()
        del self.vars[varname]
	self.seek(place)
    def write(self):
	# need to make sure everything is set, because program above may
	# well have done cm['eth0']['post-install'] = ['/bin/foo', '-f', '/tmp/bar']
	# which is completely reasonable, but won't invoke __setitem__
	for key in self.vars.keys():
	    self[key] = self.vars[key]
	Conf.write(self)
    def keys(self):
	return self.vars.keys()


# ConfModInfo(Conf)
#  This READ-ONLY class reads /boot/module-info.
#  The first line of /boot/module-info is "Version <version>";
#  this class reads version 0 module-info files.
class ConfModInfo(Conf):
    def __init__(self, filename = '/boot/module-info'):
	Conf.__init__(self, filename, '#', '\t ', ' ')
    def read(self):
        Conf.read(self)
        self.initvars()
    def initvars(self):
        self.vars = {}
        self.rewind()
	device = 0
	modtype = 1
	description = 2
	arguments = 3
	lookingfor = device
	version = self.getfields()
        self.nextline()
	if not cmp(version[1], '0'):
            while self.findnextcodeline():
        	line = self.getline()
		if not line[0] in self.separators:
		    curdev = line
		    self.vars[curdev] = {}
		    lookingfor = modtype
		elif lookingfor == modtype:
		    fields = self.getfields()
		    # first "field" is null (before separators)
		    self.vars[curdev]['type'] = fields[1]
		    if len(fields) > 2:
			self.vars[curdev]['typealias'] = fields[2]
		    lookingfor = description
		elif lookingfor == description:
		    self.vars[curdev]['description'] = regsub.gsub(
			'^"', '', regsub.gsub(
			    '^['+self.separators+']', '', regsub.gsub(
				'"['+self.separators+']*$', '', line)))
		    lookingfor = arguments
		elif lookingfor == arguments:
		    if not self.vars[curdev].has_key('arguments'):
			self.vars[curdev]['arguments'] = {}
		    # get argument name (first "field" is null again)
		    thislist = []
		    # point at first character of argument description
		    p = search('"', line)
		    while p != -1 and p < len(line):
			q = search('"', line[p+1:])
			# deal with escaped quotes (\")
			while q != -1 and not cmp(line[p+q-1], '\\'):
			    q = search('"', line[p+q+1:])
			if q == -1:
			    break
			thislist.append(line[p+1:p+q+1])
			# advance to beginning of next string, if any
			r = search('"', line[p+q+2:])
			if r >= 0:
			    p = p+q+2+r
			else:
			    # end of the line
			    p = r
		    self.vars[curdev]['arguments'][self.getfields()[1]] = thislist
        	self.nextline()
	# elif version[1] == 1: (when version 1 is created...)
	else:
	    print 'Only version 0 module-info files are supported'
	    raise 'ModInfoVersionMismatch'
        self.rewind()
    def __getitem__(self, varname):
        if self.vars.has_key(varname):
            return self.vars[varname]
        else:
            return {}
    def keys(self):
	return self.vars.keys()
    def has_key(self, key):
	return self.vars.has_key(key)
    def write(self):
	pass

