import os, os.path, sys, shutil, signal
from optparse import OptionParser, OptionGroup
takeconst = False
takeapis = False
takedtypes = False
def signal_handler(signal, frame):
print("Ctrl-C received")
sys.exit(0)
def harvest_constants(options, src, constants, definitions):
global takeconst, takeapis, takedtypes
path = os.path.join(options.src, src)
try:
inputfile = open(path, "r", encoding="utf-8")
except:
path = os.path.join(options.includedir, src)
try:
inputfile = open(path, "r", encoding="utf-8")
except:
print("File", path, "could not be opened")
return -1
lines = inputfile.readlines()
strconsts = []
strconstlen = 0
errconsts = []
nconsts = []
nconstlen = 0
typedefs = []
apis = []
for n in range(len(lines)):
line = lines[n]
myline = line.strip()
if "/*" in myline or "*/" in myline or myline.startswith("*"):
if "DUPLICATES" in myline:
break
n += 1
continue
if takeconst and myline.startswith("#define"):
value = myline[8:]
if value.startswith("PMIx"):
continue
if value.startswith("PMIX_HAVE_VISIB"):
continue
tokens = value.split()
if len(tokens) >= 2:
if tokens[1][0] == '"':
strconsts.append(tokens[0])
if len(tokens[0]) > strconstlen:
strconstlen = len(tokens[0])
elif "PMIX_ERR_" in value or tokens[1].startswith("-"):
errconsts.append(tokens[0])
if len(tokens[0]) > strconstlen:
strconstlen = len(tokens[0])
elif tokens[1].isdigit() or tokens[1].startswith("UINT") or tokens[1].startswith("0x"):
if tokens[1] == "UINT32_MAX":
tokens[1] = "0xffffffff"
elif "UINT32_MAX-1" in tokens[1]:
tokens[1] = "0xfffffffe"
elif "UINT32_MAX-2" in tokens[1]:
tokens[1] = "0xfffffffd"
elif "UINT32_MAX-3" in tokens[1]:
tokens[1] = "0xfffffffc"
elif "UINT8_MAX" in tokens[1]:
tokens[1] = "0xff"
nconsts.append([tokens[0], tokens[1]])
if len(tokens[0]) > nconstlen:
nconstlen = len(tokens[0])
elif takeapis and myline.startswith("PMIX_EXPORT"):
value = myline[12:].strip()
if ";" in value:
value = value[:-1]
value = value.replace("bool ", "bint ")
start = value.find("(") + 1
end = value.find(")")
snip = value[start:end]
if snip == "void":
value = value[0:start] + value[end:]
newapi = [value]
apis.append(newapi)
else:
value = value.replace("bool ", "bint ")
newapi = [value]
apirunning = True
while apirunning:
n += 1
value = lines[n].strip()
value = value.replace("bool ", "bint ")
if ";" in value:
apirunning = False
value = value[:-1]
newapi.append(value)
apis.append(newapi)
elif takedtypes and myline.startswith("typedef"):
if "enum" in myline:
counter = 0
n += 1
value = lines[n].strip()
if ',' in value:
value = value[:-1]
while '}' not in value and n < len(lines):
tokens[0] = value
tokens[1] = str(counter)
counter += 1
nconsts.append([tokens[0], tokens[1]])
if len(tokens[0]) > nconstlen:
nconstlen = len(tokens[0])
n += 1
value = lines[n].strip()
if ',' in value:
value = value[:-1]
value = "typedef int " + value[2:]
typedefs.append([value])
elif ";" in myline and not "fn_t" in myline and not "cbfunc_t" in myline:
value = myline[:-1]
if "bool" in value:
value.replace("bool ", "bint ")
ck = value.split()
if len(ck) == 4 and ck[1] == "struct" and ck[2] == ck[3]:
n += 1
continue
else:
if "PMIX_MAX_NSLEN+1" in value:
value = value.replace("PMIX_MAX_NSLEN+1", str(256))
elif "PMIX_MAX_NSLEN" in value:
value = value.replace("PMIX_MAX_NSLEN", str(255))
elif "PMIX_MAX_KEYLEN+1" in value:
value = value.replace("PMIX_MAX_KEYLEN+1", str(512))
elif "PMIX_MAX_KEYLEN" in value:
value = value.replace("PMIX_MAX_KEYLEN", str(511))
typedefs.append([value])
elif "fn_t" in myline or "cbfunc_t" in myline:
if ";" in myline:
value = myline[:-1]
if "bool" in value:
value.replace("bool ", "bint ")
typedefs.append([value])
else:
if "bool" in myline:
myline.replace("bool ", "bint ")
newdef = [myline]
defrunning = True
while defrunning:
n += 1
value = lines[n].strip()
if "bool" in value:
value.replace("bool ", "bint ")
if ";" in value:
defrunning = False
value = value[:-1]
newdef.append(value)
typedefs.append(newdef)
else:
value = myline
ck = value.split()
if len(ck) == 4 and ck[1] == "struct" and ck[2] == ck[3]:
n += 1
continue
else:
newdef = []
n += 1
value = lines[n].strip()
nbrk = 1
while nbrk > 0:
if "/*" in value or "*/" in value or value.startswith("*"):
n += 1
value = lines[n].strip()
continue
if "}" in value:
nbrk -= 1
if nbrk > 0:
n += 1
value = lines[n].strip()
continue
if "union" in value:
uniondef = []
n += 1
value = lines[n].strip()
while "}" not in value:
idx = value.rfind(';')
value = " " + value[:idx]
if "bool" in value:
value = value.replace("bool ", "bint ")
elif "struct timeval " in value:
value = value.replace("struct timeval", "timeval")
uniondef.append(value)
n += 1
value = lines[n].strip()
idx = value.rfind(';')
value = value[:idx]
idx = value.rfind(' ')
value = value[idx+1:]
lowname = value
value = value.title()
myvalue = "def union " + value + ":"
uniondef.insert(0, myvalue)
typedefs.append(uniondef)
value = " " + value + " " + lowname
newdef.append(value)
nbrk -= 1
n += 1
value = lines[n].strip()
continue
idx = value.rfind(';')
value = " " + value[:idx]
if "bool" in value:
value = value.replace("bool ", "bint ")
elif "struct timeval " in value:
value = value.replace("struct timeval", "timeval")
idx = value.find('[')
if idx >= 0:
dim = value.rfind(']')
dimstr = value[idx+1:dim]
if "MAX_KEYLEN" in dimstr:
value = value[:idx] + "[512]" + value[dim+1:]
elif "MAX_NSLEN" in dimstr:
value = value[:idx] + "[256]" + value[dim+1:]
else:
print("BAD DIMENSION " + dimstr)
exit(1)
newdef.append(value)
n += 1
value = lines[n].strip()
value = "typedef struct " + value[2:]
value = value[:-1] + ":"
newdef.insert(0, value)
typedefs.append(newdef)
defsrc = False
constsrc = False
if takeconst and len(strconsts) > 0:
if not defsrc:
definitions.write("cdef extern from \"" + src + "\":\n")
defsrc = True
if not constsrc:
constants.write("# " + src + "\n")
constsrc = True
definitions.write("\n # STRING CONSTANTS\n")
for const in strconsts:
defname = "_" + const
definitions.write(" cdef const char* " + defname)
for i in range (4 + strconstlen - len(const)):
definitions.write(" ")
definitions.write("\"" + const + "\"\n")
constants.write(const)
for i in range (4 + strconstlen - len(const)):
constants.write(" ")
constants.write("= " + defname + "\n")
definitions.write("\n")
constants.write("\n")
if takeconst and len(errconsts) > 0:
if not defsrc:
definitions.write("cdef extern from \"" + src + "\":\n")
defsrc = True
if not constsrc:
constants.write("# " + src + "\n")
constsrc = True
definitions.write("\n # ERROR CONSTANTS\n")
for const in errconsts:
defname = "_" + const
definitions.write(" cdef int " + defname)
for i in range (4 + strconstlen - len(const)):
definitions.write(" ")
definitions.write("\"" + const + "\"\n")
constants.write(const)
for i in range (4 + strconstlen - len(const)):
constants.write(" ")
constants.write("= " + defname + "\n")
definitions.write("\n")
constants.write("\n")
if takeconst and len(nconsts) > 0:
if not constsrc:
constants.write("# " + src + "\n")
constsrc = True
for num in nconsts:
constants.write(num[0])
for i in range (4 + strconstlen - len(num[0])):
constants.write(" ")
constants.write("= " + num[1] + "\n")
constants.write("\n")
if takedtypes and len(typedefs) > 0:
if not defsrc:
definitions.write("cdef extern from \"" + src + "\":\n")
defsrc = True
definitions.write("\n # TYPEDEFS\n")
for t in typedefs:
definitions.write(" c" + t[0] + "\n")
if len(t) > 1:
idx = t[0].find("(") + 1
idx = t[0].find("(", idx) + 2
for n in range(1, len(t)):
definitions.write(" ")
for m in range(idx):
definitions.write(" ")
definitions.write(t[n] + "\n")
definitions.write("\n")
definitions.write("\n")
if takeapis and len(apis) > 0:
if not defsrc:
definitions.write("cdef extern from \"" + src + "\":\n")
defsrc = True
definitions.write("\n # APIS\n")
for api in apis:
fill = 5 + api[0].find("(")
fstring = " {}" + ("\n" + " " * fill + "{}") * (len(api)-1) + " nogil\n\n"
definitions.write(fstring.format(*api))
return 0
def main():
global takeconst, takeapis, takedtypes
signal.signal(signal.SIGINT, signal_handler)
parser = OptionParser("usage: %prog [options]")
debugGroup = OptionGroup(parser, "Debug Options")
debugGroup.add_option("--debug",
action="store_true", dest="debug", default=False,
help="Output lots of debug messages while processing")
debugGroup.add_option("--dryrun",
action="store_true", dest="dryrun", default=False,
help="Show commands, but do not execute them")
parser.add_option_group(debugGroup)
execGroup = OptionGroup(parser, "Execution Options")
execGroup.add_option("--src", dest="src",
help="The directory where the PMIx header files will be found")
execGroup.add_option("--include-dir", dest="includedir",
help="The directory where the generated PMIx header files will be found")
execGroup.add_option("--constants",
action="store_true", dest="constants", default=False,
help="Translate constants")
execGroup.add_option("--apis",
action="store_true", dest="apis", default=False,
help="Translate APIs")
execGroup.add_option("--datatypes",
action="store_true", dest="datatypes", default=False,
help="Translate datatypes")
parser.add_option_group(execGroup)
(options, args) = parser.parse_args()
if not options.constants and not options.apis and not options.datatypes:
takeconst = True
takeapis = True
takedtypes = True
if options.constants:
takeconst = True
if options.apis:
takeapis = True
if options.datatypes:
takedtypes = True
if options.dryrun or options.debug:
debug = True
else:
debug = False
if options.src:
if not os.path.exists(options.src):
print("SOURCE directory",options.src,"does not exist")
sys.exit(1)
if options.includedir:
if not os.path.exists(options.includedir):
print("Include directory",options.includedir,"does not exist")
sys.exit(1)
if options.dryrun:
constants = sys.stdout
definitions = sys.stdout
else:
if os.path.exists("pmix_constants.pxd"):
if debug:
print("Remove pmix_constants.pxd")
if not options.dryrun:
os.remove("pmix_constants.pxd")
elif debug:
print("File pmix_constants.pxd not found")
definitions = open("pmix_constants.pxd", "w+")
definitions.write("from posix.types cimport *\n")
definitions.write("from posix.time cimport *\n")
definitions.write("from libc.stdint cimport *\n\n")
if os.path.exists("pmix_constants.pxi"):
if debug:
print("Remove pmix_constants.pxi")
if not options.dryrun:
os.remove("pmix_constants.pxi")
elif debug:
print("File pmix_constants.pxi not found")
constants = open("pmix_constants.pxi", "w+")
constants.write("from pmix_constants cimport *\n\n")
if harvest_constants(options, "pmix_common.h", constants, definitions) != 0:
sys.exit(1)
definitions.write("\n\n")
constants.write("\n\n")
harvest_constants(options, "pmix.h", constants, definitions)
definitions.write("\n\n")
constants.write("\n\n")
harvest_constants(options, "pmix_server.h", constants, definitions)
definitions.write("\n\n")
constants.write("\n\n")
harvest_constants(options, "pmix_tool.h", constants, definitions)
definitions.write("\n\n")
constants.write("\n\n")
harvest_constants(options, "pmix_deprecated.h", constants, definitions)
constants.close()
definitions.close()
if __name__ == '__main__':
main()