text: #
  # Genmodule - A python program to help you build (template) modules.
  #
  # Usage:
  #
  # o = genmodule.object()
  # o.name = 'dwarve object'
  # o.abbrev = 'dw'
  # o.funclist = ['new', 'dealloc', 'getattr', 'setattr']
  # o.methodlist = ['dig']
  #
  # m = genmodule.module()
  # m.name = 'beings'
  # m.abbrev = 'be'
  # m.methodlist = ['newdwarve']
  # m.objects = [o]
  #
  # genmodule.write(sys.stdout, m)
  #
  import sys
  import os
  import varsubst
  
  error = 'genmodule.error'
  
  #
  # Names of functions in the object-description struct.
  #
  FUNCLIST = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr',
              'tp_compare', 'tp_repr', 'tp_hash', 'tp_call', 'tp_str']
  TYPELIST = ['tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'structure']
  
  #
  # writer is a base class for the object and module classes
  # it contains code common to both.
  #
  class writer:
      def __init__(self):
          self._subst = None
  
      def makesubst(self):
          if not self._subst:
              if not self.__dict__.has_key('abbrev'):
                  self.abbrev = self.name
              self.Abbrev = self.abbrev[0].upper()+self.abbrev[1:]
              subst = varsubst.Varsubst(self.__dict__)
              subst.useindent(1)
              self._subst = subst.subst
  
      def addcode(self, name, fp):
          ifp = self.opentemplate(name)
          self.makesubst()
          d = ifp.read()
          d = self._subst(d)
          fp.write(d)
  
      def opentemplate(self, name):
          for p in sys.path:
              fn = os.path.join(p, name)
              if os.path.exists(fn):
                  return open(fn, 'r')
              fn = os.path.join(p, 'Templates')
              fn = os.path.join(fn, name)
              if os.path.exists(fn):
                  return open(fn, 'r')
          raise error, 'Template '+name+' not found for '+self._type+' '+ \
                       self.name
          
  class module(writer):
      _type = 'module'
  
      def writecode(self, fp):
          self.addcode('copyright', fp)
          self.addcode('module_head', fp)
          for o in self.objects:
              o.writehead(fp)
          for o in self.objects:
              o.writebody(fp)
          new_ml = ''
          for fn in self.methodlist:
              self.method = fn
              self.addcode('module_method', fp)
              new_ml = new_ml + (
                        '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n'
                        %(fn, self.abbrev, fn, self.abbrev, fn))
          self.methodlist = new_ml
          self.addcode('module_tail', fp)
  
  class object(writer):
      _type = 'object'
      def __init__(self):
          self.typelist = []
          self.methodlist = []
          self.funclist = ['new']
          writer.__init__(self)
  
      def writecode(self, fp):
          self.addcode('copyright', fp)
          self.writehead(fp)
          self.writebody(fp)
  
      def writehead(self, fp):
          self.addcode('object_head', fp)
  
      def writebody(self, fp):
          new_ml = ''
          for fn in self.methodlist:
              self.method = fn
              self.addcode('object_method', fp)
              new_ml = new_ml + (
                        '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n'
                        %(fn, self.abbrev, fn, self.abbrev, fn))
          self.methodlist = new_ml
          self.addcode('object_mlist', fp)
  
          # Add getattr if we have methods
          if self.methodlist and not 'tp_getattr' in self.funclist:
              self.funclist.insert(0, 'tp_getattr')
              
          for fn in FUNCLIST:
              setattr(self, fn, '0')
  
          #
          # Special case for structure-access objects: put getattr in the
          # list of functions but don't generate code for it directly,
          # the code is obtained from the object_structure template.
          # The same goes for setattr.
          #
          if 'structure' in self.typelist:
              if 'tp_getattr' in self.funclist:
                  self.funclist.remove('tp_getattr')
              if 'tp_setattr' in self.funclist:
                  self.funclist.remove('tp_setattr')
              self.tp_getattr = self.abbrev + '_getattr'
              self.tp_setattr = self.abbrev + '_setattr'
          for fn in self.funclist:
              self.addcode('object_'+fn, fp)
              setattr(self, fn, '%s_%s'%(self.abbrev, fn[3:]))
          for tn in TYPELIST:
              setattr(self, tn, '0')
          for tn in self.typelist:
              self.addcode('object_'+tn, fp)
              setattr(self, tn, '&%s_%s'%(self.abbrev, tn[3:]))
          self.addcode('object_tail', fp)
  
  def write(fp, obj):
      obj.writecode(fp)
  
  if __name__ == '__main__':
      o = object()
      o.name = 'dwarve object'
      o.abbrev = 'dw'
      o.funclist = ['new', 'tp_dealloc']
      o.methodlist = ['dig']
      m = module()
      m.name = 'beings'
      m.abbrev = 'be'
      m.methodlist = ['newdwarve']
      m.objects = [o]
      write(sys.stdout, m)
  