mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 14:20:59 +00:00
fb82a96cc7
Not enough testing :P
374 lines
9.8 KiB
Python
Executable file
374 lines
9.8 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import string
|
|
from pprint import *
|
|
|
|
#os.sapn*p* hack
|
|
#swiped from Alexey Borzenkov snaury at gmail.com
|
|
if (not (hasattr(os, 'spawnvpe') or hasattr(os, 'spawnvp'))
|
|
and hasattr(os, 'spawnve') and hasattr(os, 'spawnv')):
|
|
def _os__spawnvpe(mode, file, args, env=None):
|
|
import sys
|
|
from errno import ENOENT, ENOTDIR
|
|
from os import path, spawnve, spawnv, environ, defpath, pathsep, error
|
|
|
|
if env is not None:
|
|
func = spawnve
|
|
argrest = (args, env)
|
|
else:
|
|
func = spawnv
|
|
argrest = (args,)
|
|
env = environ
|
|
|
|
head, tail = path.split(file)
|
|
if head:
|
|
return func(mode, file, *argrest)
|
|
if 'PATH' in env:
|
|
envpath = env['PATH']
|
|
else:
|
|
envpath = defpath
|
|
PATH = envpath.split(pathsep)
|
|
if os.name == 'nt' or os.name == 'os2':
|
|
PATH.insert(0, '')
|
|
saved_exc = None
|
|
saved_tb = None
|
|
for dir in PATH:
|
|
fullname = path.join(dir, file)
|
|
try:
|
|
return func(mode, fullname, *argrest)
|
|
except error, e:
|
|
tb = sys.exc_info()[2]
|
|
if (e.errno != ENOENT and e.errno != ENOTDIR
|
|
and saved_exc is None):
|
|
saved_exc = e
|
|
saved_tb = tb
|
|
if saved_exc:
|
|
raise error, saved_exc, saved_tb
|
|
raise error, e, tb
|
|
|
|
def _os_spawnvp(mode, file, args):
|
|
return os._spawnvpe(mode, file, args)
|
|
|
|
def _os_spawnvpe(mode, file, args, env):
|
|
return os._spawnvpe(mode, file, args, env)
|
|
|
|
def _os_spawnlp(mode, file, *args):
|
|
return os._spawnvpe(mode, file, args)
|
|
|
|
def _os_spawnlpe(mode, file, *args):
|
|
return os._spawnvpe(mode, file, args[:-1], args[-1])
|
|
|
|
os._spawnvpe = _os__spawnvpe
|
|
os.spawnvp = _os_spawnvp
|
|
os.spawnvpe = _os_spawnvpe
|
|
os.spawnlp = _os_spawnlp
|
|
os.spawnlpe = _os_spawnlpe
|
|
os.__all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe"])
|
|
#end os.sapn*p* hack
|
|
|
|
string_re = re.compile (r'"(\\.|[^"\\])*"')
|
|
comment_whole = re.compile (r'((/\*.*\*/)|//.*)')
|
|
comment_start = re.compile (r'(/\*.*)')
|
|
comment_end = re.compile (r'(.*\*/)')
|
|
directive_re = re.compile (
|
|
r'^\s*#\s*(define|undef|include|includelist|endlist|ifdef|ifndef|endif|else|pragma|[0-9]+)\b' +
|
|
r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)?)' +
|
|
r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)*)')
|
|
macro_re = re.compile (r'#([A-Za-z_][0-9A-Za-z_]*)')
|
|
arg_re = re.compile (
|
|
r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)?)' +
|
|
r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)*)')
|
|
|
|
current_file = []
|
|
source_list = []
|
|
qcc_list = []
|
|
defines = {}
|
|
progs_dat = None
|
|
progs_src = "progs.src"
|
|
compile_this_file = 1
|
|
keep_newlines = 1
|
|
check_redefines = 1
|
|
verbose = 0
|
|
|
|
def append_file (filename):
|
|
global current_file
|
|
f = open (filename, "rb")
|
|
lines = f.readlines ()
|
|
f.close ()
|
|
current_file.append ('# 1 "' + filename + '"')
|
|
for i in range (len (lines)):
|
|
lines[i] = string.rstrip (lines[i])
|
|
current_file = current_file + lines
|
|
|
|
def parse_filename (args):
|
|
m = arg_re.match (args)
|
|
fname = string.strip (m.groups()[0])
|
|
if fname:
|
|
if fname[0] == '"':
|
|
fname = fname[1:]
|
|
if fname[-1] == '"':
|
|
fname = fname[:-1]
|
|
return fname
|
|
|
|
def parse_pragma (pragma, args):
|
|
global progs_dat, progs_dat
|
|
global compile_this_file, keep_newlines, check_redefines
|
|
if pragma == 'PROGS_DAT':
|
|
progs_dat = parse_filename (args)
|
|
elif pragma == 'PROGS_SRC':
|
|
progs_src = parse_filename (args)
|
|
elif pragma == 'DONT_COMPILE_THIS_FILE':
|
|
compile_this_file = 0
|
|
elif pragma == 'COMPILE_THIS_FILE':
|
|
compile_this_file = 1
|
|
elif pragma == 'KEEP_NEWLINES':
|
|
keep_newlines = parse_on_off (args)
|
|
elif pragma == 'CHECK_REDEFINES':
|
|
check_redefines = parse_on_off (args)
|
|
elif pragma == 'CHECK_UNUSED_ON':
|
|
pass
|
|
elif pragma == 'CHECK_UNUSED_OFF':
|
|
pass
|
|
else:
|
|
print "ignoring " + pragma
|
|
|
|
def comment_string (string_list, start, end):
|
|
i = 0
|
|
while i < len (string_list):
|
|
if start <= string_list[i][1] and end >= string_list[i][2]:
|
|
del string_list[i]
|
|
continue
|
|
i += 1
|
|
return string_list
|
|
|
|
def parse_strings_and_comments (l, incomment):
|
|
#print source_file + ":" + `i` + ":" + l
|
|
string_list = []
|
|
s = string_re.search (l)
|
|
while s:
|
|
string_list.append ((l[s.start():s.end()], s.start(), s.end()))
|
|
l = l[:s.start()] + ((s.end() - s.start()) * ' ') + l[s.end():]
|
|
s = string_re.search (l)
|
|
if incomment:
|
|
s = comment_end.search (l)
|
|
if s:
|
|
l = (s.end() * ' ') + l[s.end():]
|
|
incomment = 0
|
|
string_list = comment_string (string_list, s.start(), s.end())
|
|
else:
|
|
string_list = comment_string (string_list, 0, len(l))
|
|
l = ""
|
|
s = comment_whole.search (l)
|
|
if s:
|
|
l = l[:s.start()] + ((s.end() - s.start()) * ' ') + l[s.end():]
|
|
string_list = comment_string (string_list, s.start(), s.end())
|
|
s = comment_start.search (l)
|
|
if s:
|
|
l = l[:s.start()] + ((s.end() - s.start()) * ' ')
|
|
string_list = comment_string (string_list, s.start(), s.end())
|
|
incomment = 1
|
|
for str in string_list:
|
|
l = l[:str[1]] + str[0] + l[str[2]:]
|
|
#print l
|
|
return l, incomment
|
|
|
|
def do_preprogs_src ():
|
|
global current_file
|
|
current_file = []
|
|
condition = [1]
|
|
incomment = 0
|
|
append_file ("preprogs.src")
|
|
preprogs = current_file
|
|
for p in preprogs:
|
|
p, incomment = parse_strings_and_comments (p, incomment)
|
|
m = directive_re.match (p)
|
|
if (m):
|
|
g = m.groups()
|
|
directive = g[0]
|
|
arg1 = string.strip (g[1])
|
|
margs = string.strip (g[4])
|
|
#pprint ((directive, arg1, margs))
|
|
if directive == 'pragma':
|
|
if condition[-1]:
|
|
parse_pragma (arg1, margs)
|
|
elif directive[0] in '0123456789':
|
|
pass
|
|
elif directive == 'includelist':
|
|
if condition[-1]:
|
|
fname = parse_filename (arg1)
|
|
if fname:
|
|
source_list.append (fname)
|
|
elif directive == 'endlist':
|
|
pass
|
|
elif directive == 'ifdef':
|
|
condition.append (condition[-1])
|
|
if not defines.has_key (arg1):
|
|
condition[-1]=0
|
|
elif directive == 'ifndef':
|
|
condition.append (condition[-1])
|
|
if defines.has_key (arg1):
|
|
condition[-1]=0
|
|
elif directive == 'else':
|
|
condition[-1] = condition [-2] and not condition[-1]
|
|
elif directive == 'endif':
|
|
del condition[-1]
|
|
else:
|
|
if condition[-1]:
|
|
print "ignoring " + p
|
|
else:
|
|
if condition[-1]:
|
|
fname = parse_filename (p)
|
|
if fname:
|
|
source_list.append (fname)
|
|
|
|
def include_file (fname):
|
|
global current_file
|
|
fname = parse_filename (fname)
|
|
if fname:
|
|
append_file (fname)
|
|
|
|
def process_source (source_file):
|
|
global compile_this_file, current_file
|
|
if verbose:
|
|
print source_file
|
|
compile_this_file = 1
|
|
includelist = 0
|
|
incomment = 0
|
|
current_file = []
|
|
output = []
|
|
condition = [1]
|
|
append_file (source_file)
|
|
i = 0
|
|
while i < len (current_file):
|
|
l = current_file[i]
|
|
l, incomment = parse_strings_and_comments (l, incomment)
|
|
m = directive_re.match (l)
|
|
if (m):
|
|
g = m.groups()
|
|
directive = g[0]
|
|
arg1 = string.strip (g[1])
|
|
margs = string.strip (g[4])
|
|
#pprint ((directive, arg1, margs))
|
|
comment_out = True
|
|
if directive == 'pragma':
|
|
if condition[-1]:
|
|
parse_pragma (arg1, margs)
|
|
elif directive == 'include':
|
|
if condition[-1]:
|
|
include_file (arg1)
|
|
elif directive == 'includelist':
|
|
if condition[-1]:
|
|
include_file (arg1)
|
|
includelist = 1
|
|
elif directive == 'endlist':
|
|
if condition[-1]:
|
|
includelist = 0
|
|
elif directive == 'define':
|
|
if condition[-1]:
|
|
defines[arg1] = margs
|
|
elif directive == 'undef':
|
|
if condition[-1]:
|
|
if defines.has_key (arg1):
|
|
del defines[arg1]
|
|
elif directive == 'ifdef':
|
|
condition.append (condition[-1])
|
|
if not defines.has_key (arg1):
|
|
condition[-1]=0
|
|
elif directive == 'ifndef':
|
|
condition.append (condition[-1])
|
|
if defines.has_key (arg1):
|
|
condition[-1]=0
|
|
elif directive == 'else':
|
|
condition[-1] = condition [-2] and not condition[-1]
|
|
elif directive == 'endif':
|
|
del condition[-1]
|
|
else:
|
|
if condition[-1]:
|
|
comment_out = False
|
|
if comment_out:
|
|
output.append ('//' + l)
|
|
else:
|
|
output.append (l)
|
|
else:
|
|
if (includelist):
|
|
fname = parse_filename (l)
|
|
if fname:
|
|
include_file (fname)
|
|
output.append ('//' + l)
|
|
else:
|
|
if not condition[-1]:
|
|
l = '//##' + l
|
|
else:
|
|
s = macro_re.search (l)
|
|
while s:
|
|
id = s.groups()[0]
|
|
if defines.has_key (id):
|
|
l = (l[:s.start()]
|
|
+ defines[id]
|
|
+ l[s.end():])
|
|
s = macro_re.search (l)
|
|
else:
|
|
s = macro_re.search (l,
|
|
s.start(1))
|
|
output.append (l)
|
|
i = i + 1
|
|
if compile_this_file:
|
|
fname = source_file + '.pqc'
|
|
qcc_list.append (fname)
|
|
f = open (fname, "wb")
|
|
for l in output:
|
|
f.write(l + '\n')
|
|
f.close ()
|
|
|
|
no_delete = 0
|
|
use_cpp = 0
|
|
i = 0
|
|
qfcc_prefix = "" # search the path
|
|
while i < len (sys.argv):
|
|
if sys.argv[i] == '--keep':
|
|
no_delete = 1
|
|
del sys.argv[i]
|
|
continue
|
|
elif sys.argv[i] == '--verbose':
|
|
verbose = 1
|
|
del sys.argv[i]
|
|
continue
|
|
elif sys.argv[i] == '--cpp':
|
|
use_cpp = 1
|
|
del sys.argv[i]
|
|
continue
|
|
elif sys.argv[i] == '--local-qfcc':
|
|
qfcc_prefix = "./" # search the local directory
|
|
del sys.argv[i]
|
|
continue
|
|
i = i + 1
|
|
progs_dat = None
|
|
do_preprogs_src ()
|
|
if progs_dat == None:
|
|
progs_dat = source_list[0]
|
|
source_list = source_list[1:]
|
|
for s in source_list:
|
|
process_source (s)
|
|
f = open (progs_src, "wb")
|
|
f.write (progs_dat + '\n\n')
|
|
for l in qcc_list:
|
|
f.write(l + '\n')
|
|
f.close ()
|
|
args = sys.argv[1:]
|
|
if not verbose:
|
|
args = ["--quiet"] + args
|
|
if not use_cpp:
|
|
args = ["-C", "no-cpp"] + args
|
|
args = [qfcc_prefix + "qfcc"] + args
|
|
err = os.spawnvp (os.P_WAIT, qfcc_prefix + "qfcc", args)
|
|
if not no_delete:
|
|
for l in qcc_list:
|
|
os.unlink (l)
|
|
os.unlink (progs_src)
|
|
if err == 127:
|
|
print "Could not execute qfcc. Ensure qfcc is either in a directory in"
|
|
print "$PATH, or in the current directory and run qfpreqcc with",
|
|
print "\"--local-qfcc\"."
|