"""Extension management for Windows.

Under Windows it is unlikely the .obj files are of use, as special compiler options
are needed (primarily to toggle the behavior of "public" symbols.

I don't consider it worth parsing the MSVC makefiles for compiler options.  Even if
we get it just right, a specific freeze application may have specific compiler
options anyway (eg, to enable or disable specific functionality)

So my basic strategy is:

* Have some Windows INI files which "describe" one or more extension modules.
  (Freeze comes with a default one for all known modules - but you can specify
  your own).
* This description can include:
  - The MSVC .dsp file for the extension.  The .c source file names
    are extracted from there.
  - Specific compiler/linker options
  - Flag to indicate if Unicode compilation is expected.

At the moment the name and location of this INI file is hardcoded,
but an obvious enhancement would be to provide command line options.
"""

import os, sys
try:
    import win32api
except ImportError:
    win32api = None # User has already been warned

class CExtension:
    """An abstraction of an extension implemented in C/C++
    """
    def __init__(self, name, sourceFiles):
        self.name = name
        # A list of strings defining additional compiler options.
        self.sourceFiles = sourceFiles
        # A list of special compiler options to be applied to
        # all source modules in this extension.
        self.compilerOptions = []
        # A list of .lib files the final .EXE will need.
        self.linkerLibs = []

    def GetSourceFiles(self):
        return self.sourceFiles

    def AddCompilerOption(self, option):
        self.compilerOptions.append(option)
    def GetCompilerOptions(self):
        return self.compilerOptions

    def AddLinkerLib(self, lib):
        self.linkerLibs.append(lib)
    def GetLinkerLibs(self):
        return self.linkerLibs

def checkextensions(unknown, extra_inis, prefix):
    # Create a table of frozen extensions

    defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
    if not os.path.isfile(defaultMapName):
        sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName)
    else:
        # must go on end, so other inis can override.
        extra_inis.append(defaultMapName)

    ret = []
    for mod in unknown:
        for ini in extra_inis:
#                       print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
            defn = get_extension_defn( mod, ini, prefix )
            if defn is not None:
#                               print "Yay - found it!"
                ret.append( defn )
                break
#                       print "Nope!"
        else: # For not broken!
            sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))

    return ret

def get_extension_defn(moduleName, mapFileName, prefix):
    if win32api is None: return None
    os.environ['PYTHONPREFIX'] = prefix
    dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
    if dsp=="":
        return None

    # We allow environment variables in the file name
    dsp = win32api.ExpandEnvironmentStrings(dsp)
    # If the path to the .DSP file is not absolute, assume it is relative
    # to the description file.
    if not os.path.isabs(dsp):
        dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
    # Parse it to extract the source files.
    sourceFiles = parse_dsp(dsp)
    if sourceFiles is None:
        return None

    module = CExtension(moduleName, sourceFiles)
    # Put the path to the DSP into the environment so entries can reference it.
    os.environ['dsp_path'] = os.path.split(dsp)[0]
    os.environ['ini_path'] = os.path.split(mapFileName)[0]

    cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
    if cl_options:
        module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))

    exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
    exclude = exclude.split()

    if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
        module.AddCompilerOption('/D UNICODE /D _UNICODE')

    libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split()
    for lib in libs:
        module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))

    for exc in exclude:
        if exc in module.sourceFiles:
            module.sourceFiles.remove(exc)

    return module

# Given an MSVC DSP file, locate C source files it uses
# returns a list of source files.
def parse_dsp(dsp):
#       print "Processing", dsp
    # For now, only support
    ret = []
    dsp_path, dsp_name = os.path.split(dsp)
    try:
        with open(dsp, "r") as fp:
            lines = fp.readlines()
    except IOError as msg:
        sys.stderr.write("%s: %s\n" % (dsp, msg))
        return None
    for line in lines:
        fields = line.strip().split("=", 2)
        if fields[0]=="SOURCE":
            if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']:
                ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
    return ret

def write_extension_table(fname, modules):
    fp = open(fname, "w")
    try:
        fp.write (ext_src_header)
        # Write fn protos
        for module in modules:
            # bit of a hack for .pyd's as part of packages.
            name = module.name.split('.')[-1]
            fp.write('extern void init%s(void);\n' % (name) )
        # Write the table
        fp.write (ext_tab_header)
        for module in modules:
            name = module.name.split('.')[-1]
            fp.write('\t{"%s", init%s},\n' % (name, name) )

        fp.write (ext_tab_footer)
        fp.write(ext_src_footer)
    finally:
        fp.close()


ext_src_header = """\
#include "Python.h"
"""

ext_tab_header = """\

static struct _inittab extensions[] = {
"""

ext_tab_footer = """\
        /* Sentinel */
        {0, 0}
};
"""

ext_src_footer = """\
extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);

int PyInitFrozenExtensions()
{
        return PyImport_ExtendInittab(extensions);
}

"""
