#!/usr/bin/env python
# -*- Mode: Python -*-
# 
# ***** BEGIN LICENSE BLOCK *****
# Source last modified: $Id: pylink,v 1.4 2005/06/30 18:21:28 hubbe Exp $
# 
# Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
# 
# The contents of this file, and the files included with this file,
# are subject to the current version of the RealNetworks Public
# Source License (the "RPSL") available at
# http://www.helixcommunity.org/content/rpsl unless you have licensed
# the file under the current version of the RealNetworks Community
# Source License (the "RCSL") available at
# http://www.helixcommunity.org/content/rcsl, in which case the RCSL
# will apply. You may also obtain the license terms directly from
# RealNetworks.  You may not use this file except in compliance with
# the RPSL or, if you have a valid RCSL with RealNetworks applicable
# to this file, the RCSL.  Please see the applicable RPSL or RCSL for
# the rights, obligations and limitations governing use of the
# contents of the file.
# 
# Alternatively, the contents of this file may be used under the
# terms of the GNU General Public License Version 2 or later (the
# "GPL") in which case the provisions of the GPL are applicable
# instead of those above. If you wish to allow use of your version of
# this file only under the terms of the GPL, and not to allow others
# to use your version of this file under the terms of either the RPSL
# or RCSL, indicate your decision by deleting the provisions above
# and replace them with the notice and other provisions required by
# the GPL. If you do not delete the provisions above, a recipient may
# use your version of this file under the terms of any one of the
# RPSL, the RCSL or the GPL.
# 
# This file is part of the Helix DNA Technology. RealNetworks is the
# developer of the Original Code and owns the copyrights in the
# portions it created.
# 
# This file, and the files included with this file, is distributed
# and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
# KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
# ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
# ENJOYMENT OR NON-INFRINGEMENT.
# 
# Technology Compatibility Kit Test Suite(s) Location:
#    http://www.helixcommunity.org/content/tck
# 
# Contributor(s):
# 
# ***** END LICENSE BLOCK *****
# 

import os
import sys
import string
import getopt
import re

def mkdirhier(dir):
    if not dir or os.path.isdir(dir):
        return
    mkdirhier(os.path.dirname(dir))
    if not os.path.isdir(dir):
        os.mkdir(dir)

def lock(port):
    import socket
    import time

    global sock

    t=time.time()
    while 1:
        if time.time()-t > 60.0:
            print "PYLINK: Failed to lock basefile!"
            return 
        try:
            sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            #sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.bind( ('', port) )
            sock.listen(1)
            return
        except socket.error:
            time.sleep(0.2)


def main(args):
    of = None

    newargs = [ ]

    lock(5918)
    
    for a in args[1:]:
        al=string.lower(a)

        if al[:10] == "-basefile:":
            basefile = al[10:]
            continue

        if al[:9] == "-basedir:":
            basedir = al[9:]
            continue

        if al[:6] == "/base:":
            newbase = eval(al[6:])
            continue

        if al[:5] == "/out:":
            of = a[5:]

        if al[:9] == "/libpath:":
            libPath = a[9:]

            if (libPath[0] != '\"' and libPath[-1] != '\"'):
                a = "%s\"%s\"" % (a[:9], libPath)

        newargs.append(a)

    if not of:
        print "Failed to find output name!"
        sys.exit(1)

    if not newbase:
        print "Failed to find default base!"
        sys.exit(1)

    dllname = os.path.join(basedir, of)

    prev_base = 0
    prev_size = -1

    try:
        for l in open(basefile,"r").readlines():
            l = string.split(l,";")[0]
            l = string.replace(l,"\t"," ")
            fields = string.split(l)
            if len(fields):
                l_name = fields[0]
                l_base = eval(fields[1])
                l_size = eval(fields[2])
                
                if prev_base < l_base:
                    if prev_base + prev_size > l_base:
                        prev_base = 0
                        prev_size = 0
                else:
                    if l_base + l_size > prev_base:
                        prev_base = 0
                        prev_size = 0
                        
                if l_name == dllname:
                    prev_base = l_base
                    prev_size = l_size

                l_newbase = l_base + l_size
                if l_newbase > newbase:
                    newbase = l_newbase
    except IOError:
        pass

    if prev_base:
        base = prev_base
    else:
        base = newbase
        
    ## FIXME: Quoting!!!
    newargs[1:1]=["/BASE:0x%x" % newbase]

    newargs=string.join(newargs)
    print "Pylink, executing link %s" % newargs
    tmpname="pylinktmp-%s" % os.path.splitext(os.path.basename(of))[0]
    open(tmpname,"w").write(newargs)
    ret=os.system("link @%s" % tmpname)
    if ret:
        sys.exit(ret)
    
    size = 0
    p=os.popen("dumpbin %s" % of)
    for l in p.readlines():
        ## print "TESTING %s" % repr(l)
        m=re.match(" *([0-9a-fA-F]*) \\.", l)
        if m:
            ## print "MATCH!"
            size = size + string.atoi(m.group(1),16)
    p.close()

    # Round up
    size = (size + 0xffff) & ~0xffff;

    ## Check if we need to save
    if prev_base == base and size <= prev_size:
        return 0

    mkdirhier(os.path.dirname(basefile))
    open(basefile,"a").write("%s\t0x%x\t0x%x ; \n" % (
        dllname,
        base,
        size))

    
if __name__ == "__main__":
    #import profile
    #profile.run('main()', 'makedepprof')
    main(sys.argv)
