Adding patch_seam q3map2 regression test. Probably not fixable, but good to
[xonotic/netradiant.git] / utils.py
1 # -*- mode: python -*-
2 # QuakeZero build scripts
3 # TTimo <ttimo@idsoftware.com>
4 # http://scons.sourceforge.net
5
6 import os, commands, platform, xml.sax, re, string, platform
7
8 class vcproj( xml.sax.handler.ContentHandler ):
9         def __init__( self, filepath ):
10                 self.source_files = []
11                 self.misc_files = []
12                 self._files = []
13                 print 'parse %s' % filepath
14                 xml.sax.parse( filepath, self )
15
16         def getSourceFiles( self ):
17                 return self.source_files
18
19         def filterSource( self, expression, filelist = None ):
20                 if ( filelist is None ):
21                         filelist = self.source_files
22                 match = []
23                 nomatch = []
24                 for s in filelist:
25                         if ( re.match( expression, s ) ):
26                                 match.append( s )
27                         else:
28                                 nomatch.append( s )
29                 return ( match, nomatch )
30
31         def startElement( self, name, attrs ):
32                 if ( name == 'File' ):
33                         self._files.append( attrs.getValue('RelativePath') )
34
35         def endDocument( self ):
36                 # split into source and headers, remap path seperator to the platform
37                 for f in self._files:
38                         if ( platform.system() != 'Windows' ):
39                                 f = f.replace( '\\', '/' )
40                         if ( f[-2:] == '.c' or f[-4:] == '.cpp' ):
41                                 self.source_files.append( f.encode('ascii') )
42                         else:
43                                 self.misc_files.append( f )
44                 print '%d source files' % len( self.source_files )
45
46 # action uses LDD to verify that the source doesn't hold unresolved symbols
47 # setup as an AddPostAction of a regular SharedLibrary call
48 def CheckUnresolved( source, target, env ):
49         # TODO: implement this for OSX
50         if ( platform.system() == 'Darwin' ):
51                 return None
52         print 'CheckUnresolved %s' % target[0].abspath
53         if ( not os.path.isfile( target[0].abspath ) ):
54                 print 'CheckUnresolved: %s does not exist' % target[0]
55                 return 1 # fail
56         ( status, output ) = commands.getstatusoutput( 'ldd -r %s' % target[0] )
57         if ( status != 0 ):
58                 print 'CheckUnresolved: ldd command failed (exit code %d)' % status
59                 os.system( 'rm %s' % target[ 0 ] )
60                 return 1 # fail
61         lines = string.split( output, '\n' )
62         have_undef = 0
63         for i_line in lines:
64                 regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)')
65                 if ( regex.match( i_line ) ):
66                         symbol = regex.sub( '\\1', i_line )
67                         try:
68                                 env['ALLOWED_SYMBOLS'].index( symbol )
69                         except:
70                                 have_undef = 1
71         if ( have_undef ):
72                 print output
73                 print "CheckUnresolved: undefined symbols"
74                 os.system('rm %s' % target[0])
75                 return 1
76
77 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486
78
79 def Enum(*names):
80    ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
81
82    class EnumClass(object):
83       __slots__ = names
84       def __iter__(self):        return iter(constants)
85       def __len__(self):         return len(constants)
86       def __getitem__(self, i):  return constants[i]
87       def __repr__(self):        return 'Enum' + str(names)
88       def __str__(self):         return 'enum ' + str(constants)
89
90    class EnumValue(object):
91       __slots__ = ('__value')
92       def __init__(self, value): self.__value = value
93       Value = property(lambda self: self.__value)
94       EnumType = property(lambda self: EnumType)
95       def __hash__(self):        return hash(self.__value)
96       def __cmp__(self, other):
97          # C fans might want to remove the following assertion
98          # to make all enums comparable by ordinal value {;))
99          assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
100          return cmp(self.__value, other.__value)
101       def __invert__(self):      return constants[maximum - self.__value]
102       def __nonzero__(self):     return bool(self.__value)
103       def __repr__(self):        return str(names[self.__value])
104
105    maximum = len(names) - 1
106    constants = [None] * len(names)
107    for i, each in enumerate(names):
108       val = EnumValue(i)
109       setattr(EnumClass, each, val)
110       constants[i] = val
111    constants = tuple(constants)
112    EnumType = EnumClass()
113    return EnumType
114
115 #if __name__ == '__main__':
116 #   print '\n*** Enum Demo ***'
117 #   print '--- Days of week ---'
118 #   Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
119 #   print Days
120 #   print Days.Mo
121 #   print Days.Fr
122 #   print Days.Mo < Days.Fr
123 #   print list(Days)
124 #   for each in Days:
125 #      print 'Day:', each
126 #   print '--- Yes/No ---'
127 #   Confirmation = Enum('No', 'Yes')
128 #   answer = Confirmation.No
129 #   print 'Your answer is not', ~answer
130