# -*- python -*-
#                           Package   : omniidl
# python.py                 Created on: 1999/10/29
#			    Author    : Duncan Grisby (dpg1)
#
#    Copyright (C) 1999 AT&T Laboratories Cambridge
#
#  This file is part of omniidl.
#
#  omniidl 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.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#  02111-1307, USA.
#
# Description:
#   
#   Back-end for Python

# $Id: python.py,v 1.27 2000/07/12 14:32:13 dpg1 Exp $
# $Log: python.py,v $
# Revision 1.27  2000/07/12 14:32:13  dpg1
# New no_package option to omniidl backend
#
# Revision 1.26  2000/06/28 12:47:48  dpg1
# Proper error messages for unsupported IDL constructs.
#
# Revision 1.25  2000/06/27 15:01:48  dpg1
# Change from POA_M to M__POA mapping.
# Global module only built if necessary.
#
# Revision 1.24  2000/03/29 10:15:47  dpg1
# Exceptions now more closely follow the interface of
# exceptions.Exception.
#
# Revision 1.23  2000/03/17 12:28:09  dpg1
# Comma missing in nested union descriptor.
#
# Revision 1.22  2000/03/03 17:41:28  dpg1
# Major reorganisation to support omniORB 3.0 as well as 2.8.
#
# Revision 1.21  2000/02/23 10:20:52  dpg1
# Bug in descriptors for single-item enums.
#
# Revision 1.20  2000/01/04 15:29:41  dpg1
# Fixes to modules generated within a package.
#
# Revision 1.19  1999/12/21 16:06:15  dpg1
# DOH!  global= not module= !
#
# Revision 1.18  1999/12/21 16:05:11  dpg1
# New module= option.
#
# Revision 1.17  1999/12/17 11:39:52  dpg1
# New arguments to put modules and stubs in a specified package.
#
# Revision 1.16  1999/12/15 11:32:42  dpg1
# -Wbinline option added.
#
# Revision 1.15  1999/12/09 14:12:55  dpg1
# invokeOp() calls now on a single line. typedef now generates a class
# to be passed to CORBA.id().
#
# Revision 1.14  1999/12/07 15:35:14  dpg1
# Bug in currentScope handling.
#
# Revision 1.13  1999/11/30 10:41:20  dpg1
# Back-ends can now have their own usage string.
#
# Revision 1.12  1999/11/25 11:49:31  dpg1
# Minor version number bumped since server-side _is_a() required an
# incompatible change.
#
# Revision 1.11  1999/11/25 11:21:36  dpg1
# Proper support for server-side _is_a().
#
# Revision 1.10  1999/11/19 11:03:49  dpg1
# Extremely important spelling correction in a comment. :-)
#
# Revision 1.9  1999/11/12 15:53:48  dpg1
# New functions omniORB.importIDL() and omniORB.importIDLString().
#
# Revision 1.8  1999/11/11 15:55:29  dpg1
# Python back-end interface now supports valuetype declarations.
# Back-ends still don't support them, though.
#
# Revision 1.7  1999/11/10 16:08:22  dpg1
# Some types weren't registered properly.
#
# Revision 1.6  1999/11/04 11:46:12  dpg1
# Now uses our own version of the GNU C preprocessor.
#
# Revision 1.5  1999/11/02 12:17:26  dpg1
# Top-level module name now has a prefix of _0_ to avoid clashes with
# names of nested declarations.
#
# Revision 1.4  1999/11/02 10:54:01  dpg1
# Two small bugs in union generation.
#
# Revision 1.3  1999/11/02 10:01:46  dpg1
# Minor fixes.
#
# Revision 1.2  1999/11/01 20:19:55  dpg1
# Support for union switch types declared inside the switch statement.
#
# Revision 1.1  1999/11/01 16:40:11  dpg1
# First revision with new front-end.
#

"""omniORB Python bindings"""

from omniidl import idlast, idltype, idlutil, output, main
import sys, string, types, os.path, keyword

cpp_args = ["-D__OMNIIDL_PYTHON__"]
usage_string = """\
  -Wbstdout       Send generated stubs to stdout rather than a file
  -Wbinline       Output stubs for #included files in line with the main file
  -Wbpackage=p    Put both Python modules and stub files in package p
  -Wbmodules=p    Put Python modules in package p
  -Wbstubs=p      Put stub files in package p
  -Wbglobal=g     Module to use for global IDL scope (default _GlobalIDL)"""

#""" Uncomment this line to get syntax highlighting on the output strings

# Output strings

pymodule_template = """\
# DO NOT EDIT THIS FILE!
#
# Python module @module@ generated by omniidl

# ** 1. Stub files contributing to this module

# ** 2. Sub-modules

# ** 3. End"""

pymodule_dead_prefix = """\
# This module uses the old omniORBpy POA_ mapping.
# Use @skelname@ instead.
import sys
sys.stderr.write("POA_@module@ uses the obsolete POA_ mapping. " \\
                 "Use @skelname@ instead.\\n")
sys.stderr.flush()
raise ImportError("Obsolete skeleton module name -- use @skelname@")
"""


file_start = """\
# Python stubs generated by omniidl from @filename@

import omniORB, _omnipy
from omniORB import CORBA, PortableServer
_0_CORBA = CORBA

_omnipy.checkVersion(0,5, __file__)
"""

file_end = """\
_exported_modules = ( @export_string@, )

# The end."""

module_start = """
#
# Start of module "@sname@"
#
__name__ = "@package@@sname@"
_0_@sname@ = omniORB.openModule("@package@@sname@", "@filename@")
_0_@s_sname@ = omniORB.openModule("@package@@s_sname@", "@filename@")
"""

module_end = """
#
# End of module "@sname@"
#
__name__ = "@package@@modname@"
"""

import_idl_file = """\
# #include "@idlfile@"
import @ifilename@"""

open_imported_module_name = """\
_0_@imodname@     = omniORB.openModule("@package@@imodname@")
_0_@s_imodname@ = omniORB.openModule("@package@@s_imodname@")"""

forward_interface = """\

# interface @ifid@;
_0_@modname@._d_@ifid@ = (omniORB.tcInternal.tv_objref, "@repoId@", "@ifid@")"""


interface_class = """\

# interface @ifid@
_0_@modname@._d_@ifid@ = (omniORB.tcInternal.tv_objref, "@repoId@", "@ifid@")
class @ifid@ @inherits@:
    _NP_RepositoryId = _0_@modname@._d_@ifid@[1]

    def __init__(self):
        raise RuntimeError("Cannot construct objects of this type.")

    _nil = CORBA.Object._nil
"""

interface_descriptor = """
_0_@modname@.@ifid@ = @ifid@
_0_@modname@._tc_@ifid@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@ifid@)
omniORB.registerType(@ifid@._NP_RepositoryId, _0_@modname@._d_@ifid@, _0_@modname@._tc_@ifid@)"""

callables_header = """
# @ifid@ operations and attributes"""

attribute_get_descriptor = """\
@ifid@._d__get_@attr@ = ((),(@descr@,),None)"""

attribute_set_descriptor = """\
@ifid@._d__set_@attr@ = ((@descr@,),(),None)"""

operation_descriptor = """\
@ifid@._d_@opname@ = (@inds@, @outds@, @excs@)"""

objref_class = """\

# @ifid@ object reference
class _objref_@ifid@ @inherits@:
    _NP_RepositoryId = @ifid@._NP_RepositoryId

    def __del__(self):
        if _omnipy is not None:
            _omnipy.releaseObjref(self)

    def __init__(self):"""

objref_inherit_init = """\
        @inclass@.__init__(self)"""

objref_object_init = """\
        CORBA.Object.__init__(self)"""

objref_attribute_get = """
    def _get_@attr@(self, *args):
        return _omnipy.invoke(self, "_get_@attr@", _0_@modname@.@ifid@._d__get_@attr@, args)"""
objref_attribute_set = """
    def _set_@attr@(self, *args):
        return _omnipy.invoke(self, "_set_@attr@", _0_@modname@.@ifid@._d__set_@attr@, args)"""
objref_operation = """
    def @opname@(self, *args):
        return _omnipy.invoke(self, "@opname@", _0_@modname@.@ifid@._d_@opname@, args)"""
objref_methods = """
    __methods__ = @methods@"""

objref_register = """
omniORB.registerObjref(@ifid@._NP_RepositoryId, _objref_@ifid@)
_0_@modname@._objref_@ifid@ = _objref_@ifid@
del @ifid@, _objref_@ifid@"""

skeleton_class = """
# @ifid@ skeleton
__name__ = "@package@@s_modname@"
class @ifid@ (@inherits@):
    _NP_RepositoryId = _0_@modname@.@ifid@._NP_RepositoryId

    def __del__(self):
        if _omnipy is not None:
            _omnipy.releaseObjref(self)"""

skeleton_methodmap = """
    _omni_op_d = @methodmap@"""

skeleton_inheritmap = """\
    _omni_op_d.update(@inheritclass@._omni_op_d)"""

skeleton_end = """
@ifid@._omni_skeleton = @ifid@
_0_@s_modname@.@ifid@ = @ifid@
del @ifid@
__name__ = "@package@@modname@"\
"""

constant_at_module_scope = """\
_0_@modname@.@cname@ = @value@"""

constant = """\
@cname@ = @value@"""

typedef_at_module_scope = """\

# typedef ... @tdname@
class @tdname@:
    _NP_RepositoryId = "@repoId@"
    def __init__(self):
        raise RuntimeError("Cannot construct objects of this type.")
_0_@modname@.@tdname@ = @tdname@
_0_@modname@._d_@tdname@  = @desc@
_0_@modname@._ad_@tdname@ = (omniORB.tcInternal.tv_alias, @tdname@._NP_RepositoryId, "@tdname@", @tddesc@)
_0_@modname@._tc_@tdname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._ad_@tdname@)
omniORB.registerType(@tdname@._NP_RepositoryId, _0_@modname@._ad_@tdname@, _0_@modname@._tc_@tdname@)
del @tdname@"""

typedef = """\

# typedef ... @tdname@
class @tdname@:
    _NP_RepositoryId = "@repoId@"
    def __init__(self):
        raise RuntimeError("Cannot construct objects of this type.")
_d_@tdname@  = @desc@
_ad_@tdname@ = (omniORB.tcInternal.tv_alias, @tdname@._NP_RepositoryId, "@tdname@", @tddesc@)
_tc_@tdname@ = omniORB.tcInternal.createTypeCode(_ad_@tdname@)
omniORB.registerType(@tdname@._NP_RepositoryId, _ad_@tdname@, _tc_@tdname@)"""

recursive_struct_descr = """
# Recursive struct @sname@
_0_@modname@._d_@sname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])"""

struct_class = """
# struct @sname@
class @sname@:
    _NP_RepositoryId = "@repoId@"
"""

struct_class_init = """\
    def __init__(self@mnames@):"""

struct_init_member = """\
        self.@mname@ = @mname@"""

struct_descriptor_at_module_scope = """\

_0_@modname@.@sname@ = @sname@
_0_@modname@._d_@sname@  = (omniORB.tcInternal.tv_struct, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)"""

struct_indirect_at_module_scope = """\
omniORB.tcInternal.insertIndirections(_0_@modname@._d_@sname@)"""

struct_register_at_module_scope = """\
_0_@modname@._tc_@sname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _0_@modname@._d_@sname@, _0_@modname@._tc_@sname@)
del @sname@"""

struct_descriptor = """\

_d_@sname@  = (omniORB.tcInternal.tv_struct, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)"""

struct_indirect = """\
omniORB.tcInternal.insertIndirections(_d_@sname@)"""

struct_register = """\
_tc_@sname@ = omniORB.tcInternal.createTypeCode(_d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _d_@sname@, _tc_@sname@)"""

struct_module_descriptors = """
_0_@modname@._d_@sname@  = _d_@sname@
_0_@modname@._tc_@sname@ = _tc_@sname@
del @sname@, _d_@sname@, _tc_@sname@"""

exception_class = """\

# exception @sname@
class @sname@ (CORBA.UserException):
    _NP_RepositoryId = "@repoId@"
"""

exception_class_init = """\
    def __init__(self@mnames@):
        CORBA.UserException.__init__(self@mnames@)"""

exception_init_member = """\
        self.@mname@ = @mname@"""

exception_descriptor_at_module_scope = """\

_0_@modname@.@sname@ = @sname@
_0_@modname@._d_@sname@  = (omniORB.tcInternal.tv_except, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)
_0_@modname@._tc_@sname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _0_@modname@._d_@sname@, _0_@modname@._tc_@sname@)
del @sname@"""

exception_descriptor = """\

_d_@sname@  = (omniORB.tcInternal.tv_except, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)
_tc_@sname@ = omniORB.tcInternal.createTypeCode(_d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _d_@sname@, _tc_@sname@)"""


recursive_union_descr_at_module_scope = """
# Recursive union @uname@
_0_@modname@._d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])"""

recursive_union_descr = """
# Recursive union @uname@
_d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])"""

union_class = """
# union @uname@
class @uname@ (omniORB.Union):
    _NP_RepositoryId = "@repoId@"\
"""

union_descriptor_at_module_scope = """
_0_@modname@.@uname@ = @uname@

@uname@._m_to_d = {@m_to_d@}
@uname@._d_to_m = {@d_to_m@}
@uname@._def_m  = @def_m@
@uname@._def_d  = @def_d@

_0_@modname@._m_@uname@  = (@m_un@,)
_0_@modname@._d_@uname@  = (omniORB.tcInternal.tv_union, @uname@, @uname@._NP_RepositoryId, "@uname@", @stype@, @defpos@, _0_@modname@._m_@uname@, @m_def@, {@d_map@})"""

union_indirect_at_module_scope = """\
omniORB.tcInternal.insertIndirections(_0_@modname@._d_@uname@)"""

union_register_at_module_scope = """\
_0_@modname@._tc_@uname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@uname@)
omniORB.registerType(@uname@._NP_RepositoryId, _0_@modname@._d_@uname@, _0_@modname@._tc_@uname@)
del @uname@"""

union_descriptor = """
@uname@._m_to_d = {@m_to_d@}
@uname@._d_to_m = {@d_to_m@}
@uname@._def_m  = @def_m@
@uname@._def_d  = @def_d@

_m_@uname@  = (@m_un@,)
_d_@uname@  = (omniORB.tcInternal.tv_union, @uname@, @uname@._NP_RepositoryId, "@uname@", @stype@, @defpos@, _m_@uname@, @m_def@, {@d_map@})"""

union_indirect = """\
omniORB.tcInternal.insertIndirections(_d_@uname@)"""

union_register = """\
_tc_@uname@ = omniORB.tcInternal.createTypeCode(_d_@uname@)
omniORB.registerType(@uname@._NP_RepositoryId, _d_@uname@, _tc_@uname@)"""


enum_start = """
# enum @ename@\
"""

enum_item_at_module_scope = """\
_0_@modname@.@item@ = omniORB.EnumItem("@item@", @eval@)"""

enum_object_and_descriptor_at_module_scope = """\
_0_@modname@.@ename@ = omniORB.Enum("@repoId@", (@eitems@,))

_0_@modname@._d_@ename@  = (omniORB.tcInternal.tv_enum, _0_@modname@.@ename@._NP_RepositoryId, "@ename@", _0_@modname@.@ename@._items)
_0_@modname@._tc_@ename@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@ename@)
omniORB.registerType(_0_@modname@.@ename@._NP_RepositoryId, _0_@modname@._d_@ename@, _0_@modname@._tc_@ename@)"""

enum_item = """\
@item@ = omniORB.EnumItem("@item@", @eval@)"""

enum_object_and_descriptor = """\
@ename@ = omniORB.Enum("@repoId@", (@eitems@,))

_d_@ename@  = (omniORB.tcInternal.tv_enum, @ename@._NP_RepositoryId, "@ename@", @ename@._items)
_tc_@ename@ = omniORB.tcInternal.createTypeCode(_d_@ename@)
omniORB.registerType(@ename@._NP_RepositoryId, _d_@ename@, _tc_@ename@)"""


# Global state
imported_files   = {}
exported_modules = {}

# Command line options
output_inline    = 0
global_module    = "_GlobalIDL"
module_package   = ""
stub_package     = ""
stub_directory   = ""

def run(tree, args):
    global main_idl_file, imported_files, exported_modules, output_inline
    global global_module, module_package, stub_package, stub_directory

    imported_files.clear()
    exported_modules.clear()

    # Look at the args:
    use_stdout     = 0
    create_package = 1
    for arg in args:

        if arg == "stdout":
            use_stdout     = 1
            create_package = 0

        elif arg == "no_package":
            create_package = 0

        elif arg == "inline":
            output_inline = 1

        elif arg[:8] == "modules=":
            module_package = arg[8:]
            if module_package != "":
                module_package = module_package + "."

        elif arg[:6] == "stubs=":
            stub_package   = arg[6:]
            stub_directory = apply(os.path.join,
                                   string.split(stub_package, "."))
            if stub_package != "":
                stub_package = stub_package + "."

        elif arg[:8] == "package=":
            module_package = stub_package = arg[8:]
            stub_directory = apply(os.path.join,
                                   string.split(stub_package, "."))
            if module_package != "":
                module_package = stub_package = module_package + "."

        elif arg[:7] == "global=":
            global_module = arg[7:]
            if global_module == "":
                sys.stderr.write(main.cmdname + \
                                 ": You may not have an unnamed global " \
                                 "module.\n")
                sys.exit(1)
                
        else:
            sys.stderr.write(main.cmdname + ": Warning: Python " \
                             "back-end does not understand argument: " + \
                             arg + "\n")
    
    main_idl_file = tree.file()

    outpybasename = outputFileName(main_idl_file)
    outpymodule   = stub_package + outpybasename
    outpyname     = os.path.join(stub_directory, outpybasename + ".py")

    imported_files[outpybasename] = 1

    if use_stdout:
        st = output.Stream(sys.stdout, 4)
    else:
        st = output.Stream(open(outpyname, "w"), 4)

    if create_package:
        checkStubPackage(stub_package)

    st.out(file_start, filename=main_idl_file)

    pv = PythonVisitor(st, outpymodule)
    tree.accept(pv)

    exports = exported_modules.keys()
    exports.sort()
    export_list   = map(lambda s: '"' + module_package + s + '"', exports)
    export_string = string.join(export_list, ", ")

    st.out(file_end, export_string=export_string)

    if create_package:
        updateModules(exports, outpymodule)


class PythonVisitor:
    def __init__(self, st, outpymodule):
        self.st          = st
        self.outpymodule = outpymodule

    def handleImported(self, node):
        global imported_files

        if node.mainFile() or output_inline:
            return 0
        else:
            ifilename = outputFileName(node.file())
            if not imported_files.has_key(ifilename):
                imported_files[ifilename] = 1
                self.st.out(import_idl_file,
                            idlfile=node.file(),
                            ifilename=stub_package + ifilename)
            return 1
        
    #
    # The global module
    #
    def visitAST(self, node):
        self.at_module_scope = 1
        self.at_global_scope = 1
        self.currentScope    = ["_0_" + global_module]

        decls_in_global_module = 0

        for n in node.declarations():
            if not isinstance(n, idlast.Module):
                decls_in_global_module = 1
                break

        if decls_in_global_module:
            self.modname = global_module
            self.st.out(module_start,
                        sname=global_module,
                        s_sname=skeletonModuleName(global_module),
                        filename=node.file(), package=module_package)
        else:
            self.modname = self.outpymodule

        for n in node.declarations():
            n.accept(self)

        if decls_in_global_module:
            exported_modules[global_module] = 1
            self.st.out(module_end, modname=self.outpymodule,
                        sname=global_module,
                        package="")

    #
    # Module
    #
    def visitModule(self, node):
        if self.handleImported(node):
            imodname = dotName(node.scopedName())
            self.st.out(open_imported_module_name,
                        imodname=imodname,
                        s_imodname=skeletonModuleName(imodname),
                        package=module_package)

        assert self.at_module_scope

        sname = dotName(node.scopedName())

        if node.mainFile() or output_inline:
            self.st.out(module_start,
                        sname = sname,
                        s_sname = skeletonModuleName(sname),
                        filename = node.file(), package=module_package)

        parentmodname = self.modname
        self.modname  = dotName(node.scopedName())

        ags = self.at_global_scope
        if ags:
            self.currentScope = ["_0_" + node.identifier()]
        else:
            self.currentScope.append(node.identifier())

        self.at_global_scope = 0

        for n in node.definitions():
            n.accept(self)

        if ags:
            self.currentScope = ["_0_" + global_module]
        else:
            self.currentScope.pop()
        self.at_global_scope = ags
        self.modname         = parentmodname

        if node.mainFile() or output_inline:
            exported_modules[sname] = 1
            self.st.out(module_end, modname=parentmodname, sname=sname,
                        package=module_package)

    #
    # Forward interface
    #
    def visitForward(self, node):
        if self.handleImported(node): return

        if node.abstract():
            sys.stderr.write(node.file() + ":" + str(node.line()) + \
                             ": omniORBpy does not support abstract " \
                             "interfaces\n")
            sys.exit(1)

        assert self.at_module_scope
        ifid   = mangle(node.identifier())
        repoId = node.repoId()
        self.st.out(forward_interface, ifid=ifid,
                    repoId=repoId, modname=self.modname)

    #
    # Interface
    #
    def visitInterface(self, node):
        if self.handleImported(node): return

        if node.abstract():
            sys.stderr.write(node.file() + ":" + str(node.line()) + \
                             ": omniORBpy does not support abstract " \
                             "interfaces\n")
            sys.exit(1)

        assert self.at_module_scope
        ifid = mangle(node.identifier())

        if len(node.inherits()) > 0:
            inheritl = []
            for i in node.inherits():
                inheritl.append(dotName(fixupScopedName(i.scopedName())))
            
            inherits = "(" + string.join(inheritl, ", ") + ")"
        else:
            inherits = ""

        # Class header
        self.st.out(interface_class, ifid=ifid, inherits=inherits,
                    repoId=node.repoId(), modname=self.modname)

        # Declarations within the interface
        if len(node.declarations()) > 0:
            self.st.inc_indent()
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())

            for d in node.declarations():
                d.accept(self)

            self.currentScope.pop()
            self.at_module_scope = 1
            self.st.dec_indent()
            self.st.out("")

        # Descriptor and TypeCode for the interface
        self.st.out(interface_descriptor,
                    modname = self.modname, ifid = ifid)

        # Attributes and operations
        # *** Was there a good reason for putting these in the class def?
        if len(node.callables()) > 0:
            self.st.out(callables_header, ifid=ifid)

        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                descr = typeToDescriptor(c.attrType())

                for attr in c.identifiers():

                    self.st.out(attribute_get_descriptor,
                                attr=attr, descr=descr, ifid=ifid)

                    if not c.readonly():

                        self.st.out(attribute_set_descriptor,
                                    attr=attr, descr=descr, ifid=ifid)
            else: # Operation

                inds, outds, excs = operationToDescriptors(c)

                # Output the declaration
                self.st.out(operation_descriptor,
                            opname = mangle(c.identifier()),
                            inds   = inds,
                            outds  = outds,
                            excs   = excs,
                            ifid   = ifid)

        # Objref class
        if len(node.inherits()) > 0:
            inheritl = []
            for i in node.inherits():
                sn = fixupScopedName(i.scopedName())
                inheritl.append(dotName(sn[:-1] + ["_objref_" + sn[-1]]))
                
            inherits = "(" + string.join(inheritl, ", ") + ")"
        else:
            inherits = "(CORBA.Object)"

        self.st.out(objref_class, ifid=ifid, inherits=inherits)

        if len(node.inherits()) > 0:
            for inclass in inheritl:
                self.st.out(objref_inherit_init, inclass=inclass)
        else:
            self.st.out(objref_object_init)

        # Operations and attributes
        methodl = []

        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                for attr in c.identifiers():

                    self.st.out(objref_attribute_get,
                                attr    = attr,
                                ifid    = ifid,
                                modname = self.modname)
                    
                    methodl.append('"_get_' + attr + '"')

                    if not c.readonly():

                        self.st.out(objref_attribute_set,
                                    attr    = attr,
                                    ifid    = ifid,
                                    modname = self.modname)
                        
                        methodl.append('"_set_' + attr + '"')

            else: # Operation
                opname = mangle(c.identifier())
                
                self.st.out(objref_operation,
                            opname  = opname,
                            ifid    = ifid,
                            modname = self.modname)
                
                methodl.append('"' + opname + '"')

        # __methods__ assignment
        methods = "[" + string.join(methodl, ", ") + "]"

        if len(node.inherits()) > 0:
            inheritl = []
            for i in node.inherits():
                sn = fixupScopedName(i.scopedName())
                methods = methods + " + " + \
                          dotName(sn[:-1] + ["_objref_" + sn[-1]]) + \
                          ".__methods__"
        else:
            methods = methods + " + CORBA.Object.__methods__"

        self.st.out(objref_methods, methods = methods)

        # registerObjRef()
        self.st.out(objref_register, ifid = ifid, modname = self.modname)

        # Skeleton class
        if len(node.inherits()) > 0:
            inheritl = []
            for i in node.inherits():
                fsn = fixupScopedName(i.scopedName())
                dsn = dotName(fsn)
                ssn = skeletonModuleName(dsn)
                inheritl.append(ssn)
                
            inherits = string.join(inheritl, ", ")
        else:
            inherits = "PortableServer.Servant"

        self.st.out(skeleton_class,
                    ifid      = ifid,
                    inherits  = inherits,
                    modname   = self.modname,
                    s_modname = skeletonModuleName(self.modname),
                    package   = module_package)

        # Operations and attributes
        methodl = []

        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                for attr in c.identifiers():

                    methodl.append('"_get_' + attr + '": ' + \
                                   '_0_' + self.modname + '.' + \
                                   ifid + '.' + '_d__get_' + attr)

                    if not c.readonly():

                        methodl.append('"_set_' + attr + '": ' + \
                                       '_0_' + self.modname + '.' + \
                                       ifid + '.' + '_d__set_' + attr)

            else: # Operation
                opname = mangle(c.identifier())
                
                methodl.append('"' + opname + '": ' + '_0_' + self.modname + \
                               '.' + ifid + '.' + '_d_' + opname)

        methodmap = "{" + string.join(methodl, ", ") + "}"

        self.st.out(skeleton_methodmap, methodmap = methodmap)

        if len(node.inherits()) > 0:
            for inheritclass in inheritl:
                self.st.out(skeleton_inheritmap, inheritclass = inheritclass)

        self.st.out(skeleton_end,
                    ifid      = ifid,
                    modname   = self.modname,
                    s_modname = skeletonModuleName(self.modname),
                    package   = module_package)

    #
    # Constant
    #
    def visitConst(self, node):
        if self.handleImported(node): return

        cname = mangle(node.identifier())

        if self.at_module_scope:
            value = valueToString(node.value(), node.constKind(), [])
        else:
            value = valueToString(node.value(), node.constKind(),
                                  self.currentScope)
        if self.at_module_scope:
            self.st.out(constant_at_module_scope,
                        cname   = cname,
                        value   = value,
                        modname = self.modname)
        else:
            self.st.out(constant,
                        cname   = cname,
                        value   = value)

    #
    # Typedef
    #
    def visitTypedef(self, node):
        if self.handleImported(node): return

        if node.constrType():
            node.aliasType().decl().accept(self)

        for decl in node.declarators():
            tdname = mangle(decl.identifier())
            if self.at_module_scope:
                desc   = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl, [])
                tddesc = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl, [], 1)
                self.st.out(typedef_at_module_scope,
                            tdname  = tdname,
                            desc    = desc,
                            tddesc  = tddesc,
                            repoId  = decl.repoId(),
                            modname = self.modname)
            else:
                desc   = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl,
                                                       self.currentScope)
                tddesc = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl,
                                                       self.currentScope, 1)
                self.st.out(typedef,
                            tdname  = tdname,
                            desc    = desc,
                            tddesc  = tddesc,
                            repoId  = decl.repoId())
    #
    # Struct
    #
    def visitStruct(self, node):
        if self.handleImported(node): return

        sname = mangle(node.identifier())

        if node.recursive():
            self.st.out(recursive_struct_descr,
                        sname   = sname,
                        repoId  = node.repoId(),
                        modname = self.modname)

        self.st.out(struct_class, sname = sname, repoId = node.repoId())

        mnamel = []
        mdescl = []
        for mem in node.members():

            # Deal with nested declarations
            if mem.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                mem.memberType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            for decl in mem.declarators():
                mnamel.append(mangle(decl.identifier()))
                mdescl.append('"' + mangle(decl.identifier()) + '"')
                
                if self.at_module_scope:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      []))
                else:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      self.currentScope))
        if len(mnamel) > 0:
            mnames = ", " + string.join(mnamel, ", ")

            self.st.out(struct_class_init, mnames = mnames)

            for mname in mnamel:
                self.st.out(struct_init_member, mname = mname)

        if len(mdescl) > 0:
            mdescs = ", " + string.join(mdescl, ", ")
        else:
            mdescs = ""

        if self.at_module_scope:
            self.st.out(struct_descriptor_at_module_scope,
                        sname   = sname,
                        mdescs  = mdescs,
                        modname = self.modname)
            
            if node.recursive():
                self.st.out(struct_indirect_at_module_scope,
                            sname   = sname,
                            modname = self.modname)
                
            self.st.out(struct_register_at_module_scope,
                        sname   = sname,
                        modname = self.modname)
        else:
            self.st.out(struct_descriptor, sname = sname, mdescs = mdescs)
            if node.recursive():
                self.st.out(struct_indirect, sname = sname)
            self.st.out(struct_register, sname = sname)

    #
    # Exception
    #
    def visitException(self, node):
        if self.handleImported(node): return

        sname = mangle(node.identifier())
        self.st.out(exception_class, sname = sname, repoId = node.repoId())

        mnamel = []
        mdescl = []
        for mem in node.members():

            # Deal with nested declarations
            if mem.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                mem.memberType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            for decl in mem.declarators():
                mnamel.append(mangle(decl.identifier()))
                mdescl.append('"' + mangle(decl.identifier()) + '"')

                if self.at_module_scope:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      []))
                else:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      self.currentScope))

        if len(mnamel) > 0:
            mnames = ", " + string.join(mnamel, ", ")
            self.st.out(exception_class_init, mnames = mnames)

            for mname in mnamel:
                self.st.out(exception_init_member, mname = mname)

        if len(mdescl) > 0:
            mdescs = ", " + string.join(mdescl, ", ")
        else:
            mdescs = ""

        if self.at_module_scope:
            self.st.out(exception_descriptor_at_module_scope,
                        sname = sname, mdescs = mdescs, modname = self.modname)
        else:
            self.st.out(exception_descriptor, sname = sname, mdescs = mdescs)

    #
    # Union
    #
    def visitUnion(self, node):
        if self.handleImported(node): return

        uname = mangle(node.identifier())
        if self.at_module_scope:
            stype = typeToDescriptor(node.switchType(), [])
        else:
            stype = typeToDescriptor(node.switchType(), self.currentScope)

        if node.recursive():
            if self.at_module_scope:
                self.st.out(recursive_union_descr_at_module_scope,
                            uname   = uname,
                            repoId  = node.repoId(),
                            modname = self.modname)
            else:
                self.st.out(recursive_union_descr,
                            uname   = uname,
                            repoId  = node.repoId(),
                            modname = self.modname)

        self.st.out(union_class, uname=uname, repoId=node.repoId())

        if node.constrType():
            self.st.inc_indent()
            ams = self.at_module_scope
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())
            
            node.switchType().decl().accept(self)

            self.currentScope.pop()
            self.at_module_scope = ams
            self.st.dec_indent()

        def_m    = "None"
        def_d    = "None"
        m_def    = "None"
        defpos   = "-1"
        m_to_d_l = []
        d_to_m_l = []
        m_un_l   = []
        d_map_l  = []

        i = 0
        for case in node.cases():

            # Deal with nested declarations
            if case.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                case.caseType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            if self.at_module_scope:
                ctype = typeAndDeclaratorToDescriptor(case.caseType(),
                                                      case.declarator(),
                                                      [])
            else:
                ctype = typeAndDeclaratorToDescriptor(case.caseType(),
                                                      case.declarator(),
                                                      self.currentScope)

            cname = mangle(case.declarator().identifier())

            for label in case.labels():
                if label.default():
                    def_m  = '"' + cname + '"'
                    defpos = str(i)
                    if self.at_module_scope:
                        def_d  = valueToString(label.value(),
                                               label.labelKind(), [])
                        m_def  = "_0_" + self.modname + "._m_" + uname + \
                                 "[" + defpos + "]"
                    else:
                        def_d  = valueToString(label.value(),
                                               label.labelKind(),
                                               self.currentScope)
                        m_def  = "_m_" + uname + "[" + defpos + "]"

                    m_un_l.append('(' + def_d + ', "' + cname + '", ' +\
                                  ctype + ')')
                else:
                    if self.at_module_scope:
                        slabel = valueToString(label.value(),
                                               label.labelKind(), [])
                    else:
                        slabel = valueToString(label.value(),
                                               label.labelKind(),
                                               self.currentScope)

                    m_to_d_l.append('"' + cname + '": ' + slabel)
                    d_to_m_l.append(slabel + ': "' + cname + '"')

                    m_un_l.append('(' + slabel + ', "' + cname + '", ' +\
                                  ctype + ')')

                    if self.at_module_scope:
                        d_map_l.append(slabel + ': ' + '_0_' + self.modname + \
                                       "._m_" + uname + "[" + str(i) + "]")
                    else:
                        d_map_l.append(slabel + ': ' + "_m_" + \
                                       uname + "[" + str(i) + "]")
                i = i + 1

        m_to_d = string.join(m_to_d_l, ", ")
        d_to_m = string.join(d_to_m_l, ", ")
        m_un   = string.join(m_un_l,   ", ")
        d_map  = string.join(d_map_l,  ", ")

        if self.at_module_scope:
            self.st.out(union_descriptor_at_module_scope,
                        uname   = uname,
                        m_to_d  = m_to_d,
                        d_to_m  = d_to_m,
                        def_m   = def_m,
                        def_d   = def_d,
                        m_un    = m_un,
                        stype   = stype,
                        defpos  = defpos,
                        m_def   = m_def,
                        d_map   = d_map,
                        modname = self.modname)
            
            if node.recursive():
                self.st.out(union_indirect_at_module_scope,
                            uname   = uname,
                            modname = self.modname)
                
            self.st.out(union_register_at_module_scope,
                        uname   = uname,
                        modname = self.modname)
        else:
            self.st.out(union_descriptor,
                        uname   = uname,
                        m_to_d  = m_to_d,
                        d_to_m  = d_to_m,
                        def_m   = def_m,
                        def_d   = def_d,
                        m_un    = m_un,
                        stype   = stype,
                        defpos  = defpos,
                        m_def   = m_def,
                        d_map   = d_map)
            
            if node.recursive():
                self.st.out(union_indirect, uname = uname)
                
            self.st.out(union_register, uname = uname)

    #
    # Enum
    #
    def visitEnum(self, node):
        if self.handleImported(node): return

        ename = mangle(node.identifier())
        self.st.out(enum_start, ename = ename)

        i=0
        elist = []
        for item in node.enumerators():
            eval = str(i)

            if self.at_module_scope:
                self.st.out(enum_item_at_module_scope,
                            item    = item.identifier(),
                            eval    = eval,
                            modname = self.modname)
            else:
                self.st.out(enum_item,
                            item    = item.identifier(),
                            eval    = eval)

            if self.at_module_scope:
                elist.append(dotName(fixupScopedName(item.scopedName())))
            else:
                elist.append(item.identifier())

            i = i + 1

        eitems = string.join(elist, ", ")

        if self.at_module_scope:
            self.st.out(enum_object_and_descriptor_at_module_scope,
                        ename   = ename,
                        repoId  = node.repoId(),
                        eitems  = eitems,
                        modname = self.modname)
        else:
            self.st.out(enum_object_and_descriptor,
                        ename   = ename,
                        repoId  = node.repoId(),
                        eitems  = eitems)

    def visitNative(self, node):
        if self.handleImported(node): return

        sys.stderr.write(main.cmdname + \
                         ": Warning: ignoring declaration of native " + \
                         node.identifier() + "\n")

    def visitValueForward(self, node):
        sys.stderr.write(node.file() + ":" + str(node.line()) + \
                         ": omniORBpy does not support valuetype\n")
        sys.exit(1)

    def visitValueBox(self, node):
        sys.stderr.write(node.file() + ":" + str(node.line()) + \
                         ": omniORBpy does not support valuetype\n")
        sys.exit(1)

    def visitValueAbs(self, node):
        sys.stderr.write(node.file() + ":" + str(node.line()) + \
                         ": omniORBpy does not support valuetype\n")
        sys.exit(1)

    def visitValue(self, node):
        sys.stderr.write(node.file() + ":" + str(node.line()) + \
                         ": omniORBpy does not support valuetype\n")
        sys.exit(1)




def operationToDescriptors(op):
    """Return the descriptors for an operation.

    Returns a tuple containing (in descriptor, out descriptor,
    exception map)
    """

    indl  = []
    outdl = []

    if op.returnType() is not None and \
       op.returnType().kind() != idltype.tk_void:
        outdl.append(typeToDescriptor(op.returnType()))

    # Make the lists of in and out parameters
    for p in op.parameters():
        if p.is_in():
            indl.append(typeToDescriptor(p.paramType()))
        if p.is_out():
            outdl.append(typeToDescriptor(p.paramType()))

    # Fudge single-item lists so that single item tuples work
    if len(indl)  == 1: indl.append("")
    if len(outdl) == 1: outdl.append("")

    inds = "(" + string.join(indl, ", ") + ")"
    if op.oneway():
        outds = "None"
    else:
        outds = "(" + string.join(outdl, ", ") + ")"

    # Exceptions
    excl = []

    for e in op.raises():
        sn = fixupScopedName(e.scopedName())
        ename = dotName(sn)
        edesc = dotName(sn[:-1] + [ "_d_" + sn[-1]])
        excl.append(ename + "._NP_RepositoryId: " + edesc)

    if len(excl) > 0:
        excs = "{" + string.join(excl, ", ") + "}"
    else:
        excs = "None"

    return inds, outds, excs



ttdMap = {
    idltype.tk_short:      "omniORB.tcInternal.tv_short",
    idltype.tk_long:       "omniORB.tcInternal.tv_long",
    idltype.tk_ushort:     "omniORB.tcInternal.tv_ushort",
    idltype.tk_ulong:      "omniORB.tcInternal.tv_ulong",
    idltype.tk_float:      "omniORB.tcInternal.tv_float",
    idltype.tk_double:     "omniORB.tcInternal.tv_double",
    idltype.tk_boolean:    "omniORB.tcInternal.tv_boolean",
    idltype.tk_char:       "omniORB.tcInternal.tv_char",
    idltype.tk_octet:      "omniORB.tcInternal.tv_octet",
    idltype.tk_any:        "omniORB.tcInternal.tv_any",
    idltype.tk_TypeCode:   "omniORB.tcInternal.tv_TypeCode",
    idltype.tk_Principal:  "omniORB.tcInternal.tv_Principal"
}

unsupportedMap = {
    idltype.tk_longlong:   "long long",
    idltype.tk_ulonglong:  "unsigned long long",
    idltype.tk_longdouble: "long double",
    idltype.tk_wchar:      "wchar",
    idltype.tk_wstring:    "wstring",
    idltype.tk_fixed:      "fixed",
    idltype.tk_value:      "valuetype",
    idltype.tk_value_box:  "value box",
    idltype.tk_abstract_interface: "abstract interface"
}

def typeToDescriptor(tspec, from_scope=[], is_typedef=0):
    if hasattr(tspec, "python_desc"):
        return tspec.python_desc

    if ttdMap.has_key(tspec.kind()):
        tspec.python_desc = ttdMap[tspec.kind()]
        return tspec.python_desc

    if unsupportedMap.has_key(tspec.kind()):
        sys.stderr.write(main.cmdname + \
                         ": omniORBpy does not support the " + \
                         unsupportedMap[tspec.kind()] + \
                         " type.\n")
        sys.exit(1)

    if tspec.kind() == idltype.tk_string:
        ret = "(omniORB.tcInternal.tv_string," + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_wstring:
        ret = "(omniORB.tcInternal.tv_wstring," + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_sequence:
        ret = "(omniORB.tcInternal.tv_sequence, " + \
              typeToDescriptor(tspec.seqType(), from_scope) + \
              ", " + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_fixed:
        ret = "(omniORB.tcInternal.tv_fixed, " + \
              str(tspec.digits()) + ", " + str(tspec.scale()) + ")"

    elif tspec.kind() == idltype.tk_alias:
        sn = fixupScopedName(tspec.scopedName())
        if is_typedef:
            ret = dotName(sn[:-1] + ["_ad_" + sn[-1]], from_scope)
        else:
            ret = dotName(sn[:-1] + ["_d_" + sn[-1]], from_scope)
        return ret

    else:
        # ***
#          if type(tspec.decl()) is types.TupleType:
#              # No Decl object for type -- it must be a recursive type
#              markRecursive(tspec)
#              rscope, rname    = tspec.decl()
#              rdesc            = ast.findDecl(rscope, rname)

#              return '(omniORB.tcInternal.tv__indirect, ["' + \
#                     rdesc.repoId() + '"])'
            
        sn  = fixupScopedName(tspec.scopedName())
        ret = dotName(sn[:-1] + ["_d_" + sn[-1]], from_scope)
        return ret

    tspec.python_desc = ret
    return ret


def typeAndDeclaratorToDescriptor(tspec, decl, from_scope, is_typedef=0):
    desc = typeToDescriptor(tspec, from_scope, is_typedef)

    if len(decl.sizes()) > 0:
        sizes = decl.sizes()[:]
        sizes.reverse()
        for size in sizes:
            desc = "(omniORB.tcInternal.tv_array, " + \
                   desc + ", " + str(size) + ")"
    return desc

def skeletonModuleName(mname):
    """Convert a scoped name string into the corresponding skeleton
module name. e.g. M1.M2.I -> M1__POA.M2.I"""
    l = string.split(mname, ".")
    l[0] = l[0] + "__POA"
    return string.join(l, ".")

def dotName(scopedName, our_scope=[]):
    if scopedName[:len(our_scope)] == our_scope:
        l = map(mangle, scopedName[len(our_scope):])
    else:
        l = map(mangle, scopedName)
    return string.join(l, ".")

def mangle(name):
    if keyword.iskeyword(name): return "_" + name
    return name

def fixupScopedName(scopedName, prefix="_0_"):
    """Add a prefix and _GlobalIDL to the front of a ScopedName if necessary"""

    if isinstance(idlast.findDecl([scopedName[0]]), idlast.Module):
        scopedName = [prefix + scopedName[0]] + scopedName[1:]
    else:
        scopedName = [prefix + global_module] + scopedName
    return scopedName

def valueToString(val, kind, scope=[]):
    if kind == idltype.tk_enum:
        return dotName(fixupScopedName(val.scopedName()), scope)

    elif kind == idltype.tk_string or kind == idltype.tk_char:
        return '"' + idlutil.escapifyString(val) + '"'

    elif kind == idltype.tk_long and val == -2147483647 - 1:
        return "-2147483647 - 1"
    else:
        return str(val)

def outputFileName(idlname):
    return string.replace(os.path.basename(idlname), ".", "_")

def checkStubPackage(package):
    """Check the given package name for use as a stub directory

    Make sure all fragments of the package name are directories, or
    create them. Make __init__.py files in all directories."""

    if len(package) == 0:
        return

    if package[-1] == ".":
        package = package[:-1]

    path = ""
    for name in string.split(package, "."):
        path = os.path.join(path, name)
        
        if os.path.exists(path):
            if not os.path.isdir(path):
                sys.stderr.write(main.cmdname + ': Output error: "' + path +\
                                 '" exists and is not a directory.\n')
                sys.exit(1)
        else:
            os.mkdir(path)

        initfile = os.path.join(path, "__init__.py")

        if os.path.exists(initfile):
            if not os.path.isfile(initfile):
                sys.stderr.write(main.cmdname + ': Output error: "' + \
                                 initfile + \
                                 '" exists and is not a file.\n')
                sys.exit(1)
        else:
            open(initfile, "w").write("# omniORB stub directory\n")


def updateModules(modules, pymodule):
    """Create or update the Python modules corresponding to the IDL
    module names"""

    checkStubPackage(module_package)

    poamodules = map(skeletonModuleName, modules)

    real_updateModules(modules,    pymodule)
    real_updateModules(poamodules, pymodule)

    killOldPOAModules(modules)


def real_updateModules(modules, pymodule):

    for module in modules:
        modlist = string.split(module_package, ".") + string.split(module, ".")
        modpath = apply(os.path.join, modlist)
        modfile = os.path.join(modpath, "__init__.py")
        tmpfile = os.path.join(modpath, "new__init__.py")

        if not os.path.exists(modpath):
            os.makedirs(modpath)

        # Make the __init__.py file if it does not already exist
        if not os.path.exists(modfile):
            f = open(modfile, "w")
            st = output.Stream(f, 4)

            st.out(pymodule_template, module=module)

            f.close()
            del f, st

        if not os.path.isfile(modfile):
            sys.stderr.write(main.cmdname + ': Output error: "' + modfile +\
                             '" exists but is not a file.\n')
            sys.exit(1)

        # Insert the import line for the current IDL file
        inf  = open(modfile, "r")
        outf = open(tmpfile, "w")

        line = ""
        while line[:7] != "# ** 1.":
            line = inf.readline()
            if line == "":
                sys.stderr.write(main.cmdname + ': Output error: "' + \
                                 modfile + \
                                 '" ended before I found a "# ** 1." tag.\n' \
                                 'Have you left behind some files from a '  \
                                 'different Python ORB?\n')
                sys.exit(1)
                
            outf.write(line)
            
        already    = 0
        outputline = "import " + pymodule + "\n"

        while line != "\n":
            line = inf.readline()
            if line == "":
                sys.stderr.write(main.cmdname + ': Output error: "' + \
                                 modfile +\
                                 '" ended while I was looking at imports.\n')
                sys.exit(1)

            if line != "\n":
                outf.write(line)
                if line == outputline:
                    already = 1

        if not already:
            outf.write(outputline)

        outf.write("\n")

        # Output the rest of the file
        while line != "":
            line = inf.readline()
            outf.write(line)

        inf.close()
        outf.close()

        os.remove(modfile)
        os.rename(tmpfile, modfile)


    # Go round again, importing sub-modules from their parent modules
    for module in modules:
        modlist = string.split(module, ".")

        if len(modlist) == 1:
            continue

        modlist = string.split(module_package, ".") + modlist
        submod  = modlist[-1]
        modpath = apply(os.path.join, modlist[:-1])
        modfile = os.path.join(modpath, "__init__.py")
        tmpfile = os.path.join(modpath, "new__init__.py")

        # Insert the import line for the sub-module
        inf  = open(modfile, "r")
        outf = open(tmpfile, "w")

        line = ""
        while line[:7] != "# ** 2.":
            line = inf.readline()
            if line == "":
                sys.stderr.write(main.cmdname + ': Output error: "' + \
                                 modfile + \
                                 '" ended before I found a "# ** 2." tag.\n')
                sys.exit(1)
                
            outf.write(line)
            
        already    = 0
        outputline = "import " + submod + "\n"

        while line != "\n":
            line = inf.readline()
            if line == "":
                sys.stderr.write(main.cmdname + ': Output error: "' + \
                                 modfile +\
                                 '" ended while I was looking at imports.\n')
                sys.exit(1)

            if line != "\n":
                outf.write(line)
                if line == outputline:
                    already = 1

        if not already:
            outf.write(outputline)

        outf.write("\n")

        # Output the rest of the file
        while line != "":
            line = inf.readline()
            outf.write(line)

        inf.close()
        outf.close()

        os.remove(modfile)
        os.rename(tmpfile, modfile)



def killOldPOAModules(modules):
    """Damage old-style POA_M modules so they fail on import"""

    for module in modules:
        modlist = string.split(module_package, ".") + \
                  string.split("POA_" + module, ".")
        modpath = apply(os.path.join, modlist)
        modfile = os.path.join(modpath, "__init__.py")
        tmpfile = os.path.join(modpath, "new__init__.py")

        if os.path.exists(modfile):

            inf  = open(modfile, "r")
            line = inf.readline()

            if line == "# DO NOT EDIT THIS FILE!\n":

                sys.stderr.write(main.cmdname + \
                                 ': Warning: disabling old-style ' \
                                 'POA_ module in "' + modpath + '"\n')

                outf = open(tmpfile, "w")
                st   = output.Stream(outf, 4)

                st.out(pymodule_dead_prefix, module=module,
                       skelname = skeletonModuleName(module))

                while line != "":
                    outf.write(line)
                    line = inf.readline()

                del st
                inf.close()
                outf.close()

                os.remove(modfile)
                os.rename(tmpfile, modfile)

            else:
                sys.stderr.write(main.cmdname + \
                                 ': Warning: previously disabled old-style ' \
                                 'POA_ module in "' + modpath + '"\n')
