Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- #multipreproc.py
- if __name__ != "__main__": exit(0)
- from sys import argv
- from os import remove, getcwd, chdir
- from os.path import exists
- from time import time, sleep
- from clipboard import copy
- import subprocess
- NameOfScript=argv[0]
- NewLineSequence="|"
- SearchPaths=[]
- CopyToClipboard=False
- OutputFile=""
- CPPOutput="_PREPROC_OUTPUT"
- DelCPPOutput=True
- # /* removes comments like this */
- def removeLongComments(s):
- sOut,Depth,LineNum,SecondChar = "",0,1,False
- for i in range(len(s)-1):
- CharPair=s[i:i+2]
- if CharPair[0] == "\n": LineNum+=1
- if SecondChar: SecondChar=False; continue
- elif CharPair == "/*": Depth+=1
- elif CharPair == "*/": Depth-=1; SecondChar=True; continue
- if Depth > 0: continue
- elif Depth < 0: break
- else: sOut+=CharPair[0]
- if Depth > 0: return None,"mismatched \"/*\" (EOF reached)"
- elif Depth < 0: return None,"mismatched \"*/\" (Line {})".format(LineNum)
- if s[-2:] != "*/": sOut+=s[-1]
- return sOut,None
- # separates by "\n", "\\n" (optional), and NewLineSequence (default value is "|")
- def splitLines(s):
- lines=s.split("\n")
- #lines=sum([line.split("\\n") for line in lines],[])
- lines=sum([line.split(NewLineSequence) for line in lines],[])
- #lines=[i for i in lines if i] (this would remove empty lines)
- return lines
- # recognizes both "//" and ";"
- def removeSingleLineComments(l):
- lines=[line.split("//")[0] for line in l]
- lines=[line.split(";")[0] for line in lines]
- lines=[line.rstrip() for line in lines]
- return lines
- def optCheckParamType(param):
- if type(param) == str: return True,None
- elif type(param) == NoneType: return False,"no parameter given"
- else: return False,"param is neither of type str nor NoneType??"
- def opt_h(param):
- print("\
- Usage: py {} <options> <input file path> \n\
- Options (case-insensitive, parsed from left to right): \n\
- \"-h\": Print this text \n\
- \"-l <new sequence>\": Change line break sequence (\"|\" by default) \n\
- \"-o <output file path>\": Specify output file name \n\
- \"-c\": Copy output to clipboard (-o isn't required if -c is enabled) \n\
- \"-s <search path>\": Add path to search paths list (currently broken; don't use) \n\
- \"-p\": Don't delete intermediate temp file (\"{}\")\
- ".format(NameOfScript.split("\\")[-1],CPPOutput))
- exit(0) #return True,None
- def opt_l(param):
- global NewLineSequence
- isValid,err=optCheckParamType(param)
- if isValid: NewLineSequence=param
- return isValid,err
- def opt_o(param):
- global OutputFile
- isValid,err=optCheckParamType(param)
- if isValid: OutputFile=param
- return isValid,err
- def opt_c(param):
- global CopyToClipboard
- CopyToClipboard=True
- return True,None
- def opt_s(param):
- global SearchPaths
- isValid,err=optCheckParamType(param)
- if isValid:
- SearchPaths.append("-I")
- SearchPaths.append("\"{}\"".format(param))
- return isValid,err
- def opt_p(param):
- global DelCPPOutput
- DelCPPOutput=False
- return True,None
- options={ #<function>,<'takes an argument?'>
- "-h":(opt_h,False), #print help text
- "-l":(opt_l,True), #change new line sequence
- "-o":(opt_o,True), #set output file name
- "-c":(opt_c,False), #copy output to clipboard
- "-s":(opt_s,True), #add search path
- "-p":(opt_p,False) #don't delete cpp output
- }
- def printExit(code,msg):
- print("{} error: {}".format(NameOfScript,msg))
- exit(code)
- def ifPrintExit(condition,code,msg):
- if condition: printExit(code,msg)
- #handle arguments
- start=time()
- if len(argv) < 2: options["-h"][0](None) #auto-exits
- if not exists(argv[-1]): #system error code 2=ERROR_FILE_NOT_FOUND
- printExit(2,"file \"{}\" could not be found".format(argv[-1]))
- BeforeFileArg,IsParameter = len(argv)-2,False
- for i in range(1,BeforeFileArg+1):
- if IsParameter: IsParameter=False; continue
- Argument=argv[i].lower()
- if not Argument in options:
- printExit(1,"option \"{}\" doesn't exist".format(Argument))
- option=options[Argument]
- IsParameter=option[1]
- if i == BeforeFileArg and IsParameter:
- printExit(1,"option \"{}\" needs a parameter".format(argv[i]))
- success,err=option[0](argv[i+1]) #won't matter if option doesn't use param
- if not success: printExit(1,err)
- #call the c preprocessor
- proc=subprocess.Popen(
- ["cpp","-x","assembler-with-cpp","-nostdinc","-CC","-undef","-P",
- "-o",CPPOutput,]+SearchPaths+[argv[-1]],
- stdout=subprocess.PIPE,shell=True)
- while proc.poll() == None: sleep(0.02)
- pExitCode=proc.poll()
- pOutput,pError = proc.communicate()
- if len(pOutput) != 0: print(pOutput.decode("utf-8"))
- if pExitCode != 0: exit(pExitCode)
- #read cpp output data
- if not exists(CPPOutput): exit(1)
- infile=open(CPPOutput,"r")
- ifPrintExit(not infile,1,"failed to open cpp intermediate file")
- indata=infile.read()
- ifPrintExit(not indata,1,"failed to read cpp intermediate file data")
- infile.close()
- #do the rest of the parsing
- indata,err=removeLongComments(indata) #returns str
- if not indata:
- print("(check \"{}\\{}\" to see the error's cause)".format(getcwd(),CPPOutput))
- printExit(1,err)
- indata=splitLines(indata) #returns list
- indata=removeSingleLineComments(indata) #returns list
- outdata="\n".join(indata)
- #write output data
- if CopyToClipboard: copy(outdata)
- if OutputFile:
- outfile=open(OutputFile,"w")
- ifPrintExit(not outfile,1,"failed to open output file")
- outfile.write(outdata)
- outfile.close()
- elif not CopyToClipboard:
- printExit(1,"no output file specified")
- if DelCPPOutput and exists("_PREPROC_OUTPUT"): remove("_PREPROC_OUTPUT")
- print("finished successfully in {}ms".format(int((time()-start)*1000)))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement