Add modules and examples. update readme

This commit is contained in:
Akumatic 2020-02-13 18:18:41 +01:00
parent a36e1e4e05
commit 6153859957
132 changed files with 1748 additions and 2 deletions

View File

@ -1,2 +1,13 @@
# ViPLab-Backend-C-CPP-Module # ViPLab Backend: C/C++ Module
C/C++ Module for the Virtual Programming Laboratory Backend A read-only copy of my implementation of the C/C++ Module for the [Virtual Programming Laboratory](https://www.tik.uni-stuttgart.de/dienste-a-z/Virtuelles-Programmierlabor-ViPLab/) Backend of the University of Stuttgart written in Python 3.
This module was made with the goal to replace the old backend written in C++. The documentation for the json data used to implement this module can be found [here](https://campusconnect.tik.uni-stuttgart.de/HeikoBernloehr/FreeLancer/ECS/ecs2/NumLab#ECS_ressources)
## Requirements
- Python 3 (tested with 3.8)
- Python module [pycparser](https://github.com/eliben/pycparser)
- gcc for C files
- g++ for C++ files
## Usage
You can see an example how to run this module in [example_run.py](example_run.py)

692
c.py Normal file
View File

@ -0,0 +1,692 @@
import os, sys, subprocess, dataObjects, json, signal
from pycparser import c_parser, c_ast, parse_file
# Path for temp files.
PATH = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "temp")
# Keeps files created in temp folder if DEBUG = True
DEBUG = True
class C:
""" Class for processing, compiling, running and evaluating C code.
Attributes:
solution (Solution):
Solution object storing data from solution json and the corresponding exercise object
result (Result):
Result object storing evaluation data generated by this class.
"""
def __del__(self):
""" Destructor deletes files in temp folder after execution
"""
if os.path.isdir(PATH) and not DEBUG:
for f in os.scandir(PATH):
if not os.path.isdir(f):
os.remove(f.path)
else:
import shutil
shutil.rmtree(f.path)
def __init__(self, solution : dataObjects.Solution, config : dict = None, id : int = None):
""" Constructor
Args:
solution (Solution):
The solution object storing data from solution json and exercise object
"""
self.result = dataObjects.Result(dataObjects.readJson(solution.createJson()))
self.solution = solution
self.cfg = {} if config is None else config
self._lang = self.solution.exercise.lang
self._fileext = ".c" if self._lang == "C" else ".cpp"
if id is not None:
self.result.setId(id)
def processData(self):
""" Processes code, generates files and runs them to get a result.
"""
# Creates temp dir if it does not exist
if not os.path.exists(PATH):
os.makedirs(PATH)
# Prepare code by replacing placeholder code with solutions code
self.replaceCodeWithSolution()
maxState = self.getMaxState()
self.getMappedItems()
# Step 1: Merge source code
exitcode, self.fileInfo = self.merge()
# Step 2: Compile files containing source code
if exitcode == 0 and 1 <= maxState:
try:
exitcode = self.compile()
except Exception as e:
self.result.computation["userInfo"]["summary"] = "UNEXPECTED ERROR IN COMPILING"
self.result.computation["userInfo"]["elements"].append(f"{type(e).__name__}: {e}")
exitcode = 1
# Step 3 (Only C): Check if student's solution contains illegal calls
if exitcode == 0 and 2 <= maxState and self._lang == "C":
try:
exitcode = self.check()
except Exception as e:
self.result.computation["userInfo"]["summary"] = "UNEXPECTED ERROR IN CHECKING"
self.result.computation["userInfo"]["elements"].append(f"{type(e).__name__}: {e}")
exitcode = 1
# Step 4: Link compiled files and libraries
if exitcode == 0 and 3 <= maxState:
try:
exitcode = self.link()
except Exception as e:
self.result.computation["userInfo"]["summary"] = "UNEXPECTED ERROR IN LINKING"
self.result.computation["userInfo"]["elements"].append(f"{type(e).__name__}: {e}")
exitcode = 1
# Step 5: Run exectutable files
if exitcode == 0 and 4 <= maxState:
try:
self.run()
except Exception as e:
self.result.computation["userInfo"]["summary"] = "UNEXPECTED ERROR IN RUNNING"
self.result.computation["userInfo"]["elements"].append(f"{type(e).__name__}: {e}")
exitcode = 1
# Calculating computation time in result object
self.result.computation["technicalInfo"]["exitCode"] = exitcode
self.result.calculateComputationTime()
def getMaxState(self) -> int:
""" Retrieves max state of data processing
Returns:
An integer representing the max state
"""
s = self.solution.exercise.config.get("stopAfterPhase")
return 4 if s is None or s == "running" else \
3 if s == "linking" else \
2 if s == "checking" else \
1 if s == "compiling" else 0
def replaceCodeWithSolution(self):
""" Modifying exercise code by replacing placeholder code with student solution
"""
for sEl in self.solution.exerciseModifications["elements"]:
for eEl in self.solution.exercise.elements:
if eEl["identifier"] == sEl["identifier"] and eEl.get("modifiable") == True:
eEl["value"] = sEl["value"]
break
def mergeError(self, message):
""" Adds merge error to userInfo and returns returncode 1
Returns:
1 (Integer):
Returncode 1
An empty dict:
Empty file informations
"""
self.result.computation["userInfo"]["summary"] = "[ERROR]"
self.result.computation["userInfo"]["elements"].append({
"severity": "error",
"type": "chain",
"message": f"Merging failed! {message}"
})
return 1, {}
def merge(self):
""" Merges all code snippets given by exercise json in config.merging
Returns:
A dict containing one dict per merged source file.
- key: filename (without extension)
- value: dict
The structure of each of these dicts describing source files:
- key: identifier of code snippet
- value: dict containing following (keys: values):
- "visible": Bool indicating if section is visible for student
- "start": Integer indicating Start of Section (line number)
- "stop": Integer indicating End of Section (line number)
"""
merge = self.solution.exercise.config["merging"]
l = len(merge)
if l == 0:
return self.mergeError("Empty merging array")
if isinstance(merge, list) and isinstance(merge[0], dict) and l != 1:
return self.mergeMultipleFiles()
else:
return self.mergeSingleFile()
def mergeSingleFile(self) -> dict:
""" Merges a single file.
Returns:
A dict as specified as in "merge".
The filename is always "temp"
"""
fname = f"temp{self._fileext}"
r = {fname : {"path": os.path.join(PATH, fname)}}
code = ""
loc = 0
if isinstance(self.solution.exercise.config["merging"], list):
sourceElements = self.solution.exercise.config["merging"]
else:
sourceElements = self.solution.exercise.config["merging"]["sources"]
if len(sourceElements) == 0:
return self.mergeError("Empty merging array")
for s in sourceElements:
for e in self.solution.exercise.elements:
if s == e["identifier"]:
r[fname][s] = {}
if e.get("visible") is not None:
r[fname][s]["visible"] = e["visible"]
r[fname][s]["start"] = (loc + 1)
code += e["value"] or "\n"
if not code.endswith("\n"):
code += "\n"
cnt = (e["value"] or "\n").count("\n")
loc += cnt
r[fname][s]["stop"] = loc if cnt != 0 else (loc + 1)
break
fpath = os.path.join(PATH, f"{fname}")
with open(fpath, "w+") as f:
f.write(code)
os.chmod(fpath, 0o666)
return 0, r
def getMappedItems(self):
""" Checks elementMap for files not created yet and creates them.
"""
if self.solution.exercise.elementMap:
for m in self.solution.exercise.elementMap:
mergeInfo = self.solution.exercise.elementMap[m].split(os.sep)
fpath = mergeInfo[3:-1]
fname = mergeInfo[-1]
if fpath:
path = os.path.join(PATH, *path, fname)
if os.path.exists(path):
continue
else:
for element in self.solution.exercise.elements:
if element["identifier"] == m:
with open(path, "w") as f:
f.write(element["value"])
else:
path = os.path.join(PATH, fname)
if os.path.exists(path):
continue
else:
for element in self.solution.exercise.elements:
if element["identifier"] == m:
with open(path, "w") as f:
f.write(element["value"])
def getFileName(self, mergeDict, cnt):
""" Retrieves the filenname and path of a file used for compiling,
checking and running
Args:
mergeDict (dict):
the dict containing merge informations needed for the current file
cnt (int):
an integer counting up each call.
Returns:
Strings representing the filename and the filepath.
Incremented cnt Integer
"""
mergeID, path = mergeDict.get("mergeID"), None
if mergeID:
if self.solution.exercise.elementMap and \
mergeID in self.solution.exercise.elementMap:
mergeInfo = self.solution.exercise.elementMap[mergeID].split(os.sep)
path = mergeInfo[3:-1]
# ERROR HANDLING
if path and not path[0]:
return self.mergeError("Absolute Paths are not allowed"), 0
fname = mergeInfo[-1]
else:
fname = mergeID
else:
fname = f"temp{cnt}"
if self._fileext not in fname and ".h" not in fname:
return f"{fname}{self._fileext}", path, cnt + 1
else:
return fname, path, cnt + 1
def mergeMultipleFiles(self) -> dict:
""" Merges multiple files.
Returns:
A dict as specified as in "merge".
"""
i = 1 # used if neither mergeID nor mapping is given
r = {}
for m in self.solution.exercise.config["merging"]:
fname, fpath, i = self.getFileName(m, i)
if fname == 1:
return fname, fpath
r[fname] = {}
if fpath:
tmp = os.path.join(PATH, *fpath)
if not os.path.exists(tmp):
os.makedirs(tmp)
r[fname]["path"] = os.path.join(tmp, fname)
else:
r[fname]["path"] = os.path.join(PATH, fname)
loc = 0
code = ""
for s in m["sources"]:
for e in self.solution.exercise.elements:
if s == e["identifier"]:
r[fname][s] = {}
if e.get("visible") is not None:
r[fname][s]["visible"] = e["visible"]
r[fname][s]["start"] = (loc + 1)
code += e["value"]
if not code.endswith("\n"):
code += "\n"
cnt = e["value"].count("\n")
loc += cnt
r[fname][s]["stop"] = loc if cnt != 0 else (loc + 1)
break
loc += 1
with open(r[fname]["path"], "w+") as f:
f.write(code)
os.chmod(r[fname]["path"], 0o666)
return 0, r
def getSnippetIdentifier(self, file, line):
""" Retrieves the code snipped identifier of a given line
Args:
file (str):
the file containing the identifier
line (int):
the line number
Returns:
A string containing the snippet identifier
"""
for i in self.fileInfo[file]:
if i == "path":
continue
if line in range(self.fileInfo[file][i]["start"], self.fileInfo[file][i]["stop"] + 1):
return i
def getLoc(self, file, line, join=False):
""" Retrieves a line of code in a given file
Args:
file (str):
the filepath to be opened
line (int):
the line number of the line we want to return
join (bool):
if True, the filepath will be joined with PATH first
Returns:
A String containing the specified line of code.
"""
with open(file if not join else os.path.join(PATH, file), "r") as f:
i = 0
while i < line - 1:
f.readline()
i += 1
return f.readline()
def compile(self):
""" Compiles all merged source files.
Returns:
An Integer representing the return code of the compiler.
"""
# changes current working directory for easier compiling
cwd = os.getcwd()
os.chdir(PATH)
# compiling command as specified as in exercise
com = self.solution.exercise.getCompilingCommand().split(" ")
# path for all source files
for f in self.fileInfo:
if ".h" in f:
continue
com.append(self.fileInfo[f]["path"])
# flag to just compile files without linking
com.append("-c")
# flag for easier error handling. Requires GCC 9.4
com.append("-fdiagnostics-format=json")
self.result.computation["technicalInfo"]["compileCommand"] = " ".join(com)
proc = subprocess.run(com, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
try:
parsed = json.loads(proc.stderr.decode("utf-8")) if proc.stderr else \
json.loads(proc.stdout.decode("utf-8")) if proc.stdout else ""
except json.decoder.JSONDecodeError:
txt = proc.stderr if proc.stderr else \
proc.stdout if proc.stdout else ""
if txt[0] == b"[":
tmp = txt.replace(b"\n", b"")
sliced = tmp[:tmp.rfind(b"]") + 1]
elif txt[0] == b"{":
tmp = txt.replace(b"\n", b"")
sliced = tmp[:tmp.rfind(b"}") + 1]
else:
sliced = txt.replace(b"\n", b"")
txt = txt.decode("utf-8")
try:
parsed = json.loads(sliced)
except json.decoder.JSONDecodeError:
parsed = txt
if len(parsed) > 0:
if isinstance(parsed, dict):
maxState = "info"
elements = []
for p in parsed:
# updating maxState if neccessary
if p["kind"] == "warning" and maxState == "info":
maxState = "warning"
elif p["kind"] == "error" and maxState != "error":
maxState = "error"
# file and line of error
file = p["locations"][0]["caret"]["file"].split(".")[0]
line = p["locations"][0]["caret"]["line"]
# calculating the line
snippet = self.getSnippetIdentifier(file, line)
# dict specifying the current error/warning/info and source
e = {
"severity" : p["kind"],
"type" : "compiler",
"message" : p["message"],
"source" : {
"elementID" : snippet,
"extract" : self.getLoc(f"{file}{self._fileext}", line, join=True),
"begin" : self.fileInfo[file][snippet]["start"],
"end" : self.fileInfo[file][snippet]["stop"],
"line" : line - self.fileInfo[file][snippet]["start"],
"col" : p["locations"][0]["caret"]["column"]
}
}
elements.append(e)
self.result.computation["userInfo"]["summary"] = f"[{maxState.upper()}]"
self.result.computation["userInfo"]["elements"] += elements
elif isinstance(parsed, str):
maxState = None
if "error" in parsed:
maxState = "ERROR"
elif "warning" in parsed:
maxState = "WARNING"
elif "info" in parsed:
maxState = "INFO"
if maxState:
self.result.computation["userInfo"]["summary"] = f"[{maxState}] - could not parse output"
self.result.computation["userInfo"]["elements"].append({
"severity": maxState,
"type": "compiler",
"message": f"Could not parse output:\n{parsed}"
})
else: # list
self.result.computation["userInfo"]["elements"] += parsed
# adds compiling output to "elements" in result object
data = {
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Compiling",
"value" : parsed
}
self.result.elements.append(data)
os.chdir(cwd)
return proc.returncode
def check(self):
""" Checks all merged source files.
Checking after compiling to reduce effort. It's unnecessary to check if compiling fails.
Returns:
An Integer representing the final state of checking:
0 - Checking passed
1 - Checking failed
"""
checkConfig = self.solution.exercise.config.get("checking")
if checkConfig is None:
return 0
returncode = 0
forbidden = checkConfig["forbiddenCalls"].split(" ")
checker = Checker(self.fileInfo)
for a in checker.asts:
checker.getFunctions(checker.asts[a])
elements = []
for file in checker.visitor.data:
f = file.split(os.sep)[-1]
for func in checker.visitor.data[file]:
for i in checker.visitor.data[file][func]:
cur = checker.visitor.data[file][func][i]
id = self.getSnippetIdentifier(f, cur["Line"])
if id in checkConfig["sources"] and cur["FuncCall"] in forbidden:
line = cur["Line"] - self.fileInfo[f][id]["start"]
e = {
"severity": "error",
"type": "callcheck",
"message": f"[C function filtering] Function call not allowed:\n\'"
f"{cur['FuncCall']}\';original source: f'{id}', line "
f"(corrected): {line}, " \
f"col: {cur['Column']}\nForbidden calls:\nsystem.\n",
"source": {
"elementID": id,
"extract": self.getLoc(file, line),
"begin": self.fileInfo[f][id]["start"],
"end": self.fileInfo[f][id]["stop"],
"line": line,
"col": cur["Column"]
}
}
elements.append(e)
if returncode == 0:
returncode = 1
if len(elements) != 0:
if "elements" not in self.result.computation["userInfo"]:
self.result.computation["userInfo"]["elements"] = elements
else:
self.result.computation["userInfo"]["elements"] += elements
if "summary" not in self.result.computation["userInfo"]:
self.result.computation["userInfo"]["summary"] = "[ERROR]"
elif "ERROR" not in self.result.computation["userInfo"]["summary"]:
self.result.computation["userInfo"]["summary"] = "[ERROR]"
data = {
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Checking",
"value" : elements
}
self.result.elements.append(data)
return returncode
def link(self):
""" Links compiled files and libraries.
Returns:
An Integer representing the return code of the compiler.
"""
com = ["gcc" if self._lang == "C" else "g++", "-o", f"{os.path.join(PATH, 'out')}"]
for f in self.fileInfo:
if ".h" in f:
continue
com.append(f"{os.path.join(PATH, f)[:-len(self._fileext)]}.o")
flags = self.solution.exercise.config["linking"].get("flags")
if flags:
com.append(flags)
self.result.computation["technicalInfo"]["linkCommand"] = " ".join(com)
proc = subprocess.run(com, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
data = {
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Linking",
"value" : proc.stdout.decode("utf-8")
}
self.result.elements.append(data)
return proc.returncode
def run(self):
""" Makes file executable and runs it.
Returns:
An Integer representing the return code of the program.
"""
os.chmod(os.path.join(PATH, "out"), 0o700)
com = [f"{os.path.join(PATH, 'out')}"]
cmdLineArgs = self.solution.exercise.config["running"].get("commandLineArguments")
if cmdLineArgs is not None:
com.extend(cmdLineArgs.split())
# Time Limit of running process
timelimit = self.solution.exercise.config["running"].get("timelimitInSeconds")
cfglimit = self.cfg.get("timelimitInSeconds")
if not timelimit:
timelimit = cfglimit # is now either None or int
elif cfglimit:
timelimit = min(timelimit, cfglimit)
self.result.computation["technicalInfo"]["runCommand"] = "".join(com)
proc = subprocess.Popen(com, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
preexec_fn=os.setsid, shell=False)
try:
stdout, stderr = proc.communicate(timeout=timelimit)
text = ""
except subprocess.TimeoutExpired as e:
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
stdout, stderr, text = "", "", f"Runtime failed! Timeout after {e.timeout} seconds"
self.result.computation["userInfo"]["summary"] = "Runtime failed! Exit code: 1"
data = [{
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Running",
"value" : text
},
{
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Running stdout",
"value" : stdout#.decode("utf-8")
},
{
"MIMEtype":"text/plain",
"identifier":f"{self.result.id} Running stderr",
"value" : stderr#.decode("utf-8")
}]
for d in data:
self.result.elements.append(d)
return proc.returncode
class Checker:
""" Class for generating Abstract Syntax Trees (AST) of source files
and retrieving informations about function calls.
Attributes:
asts (dict):
A dict containing one entry for each merged source file
- key: filename (without extension)
- value: AST of source file
"""
def __init__(self, files: dict):
""" Constructor
Args:
files (dict):
A dict generated by the "merge" function in class "C"
"""
self._files = files
self.asts = self.getAsts()
self.visitor = self.Visitor()
class Visitor(c_ast.NodeVisitor):
""" Internal Class for visiting nodes in an AST.
"""
def __init__(self):
self.data = {}
def visit_FuncDef(self, node):
""" Finds and prints all found function calls in a function
"""
if node.decl.coord.file not in self.data:
self.data[node.decl.coord.file] = {}
self.data[node.decl.coord.file][node.decl.name] = {}
i = 0
for n in node.body.block_items:
if isinstance(n, c_ast.FuncCall):
self.data[node.decl.coord.file][node.decl.name][str(i)] = {
"FuncCall" : n.name.name,
"Line" : n.coord.line,
"Column" : n.coord.column
}
i += 1
def getAst(self, filename) -> c_ast.FileAST:
""" Generates an AST from given source file
Args:
filename (str):
The name of the source file to generate an AST for
"""
fake_libc_include = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
'utils', 'fake_libc_include')
return parse_file(filename, use_cpp=True, cpp_path="gcc",
cpp_args=["-E", f"-I{fake_libc_include}"])
def getAsts(self) -> dict:
""" Generates one AST for each merged source file
Returns:
A dict containing one (key, value) pair for each source file.
- key: filename (without extension)
- value: AST for the corresponding file
"""
asts = {}
for f in self._files:
asts[f] = self.getAst(self._files[f]["path"])
return asts
def getFunctions(self, ast: c_ast.FileAST):
""" Iterates over the given AST and visit nodes as specified as in Visitor class
Args:
ast:
An AST representing a source file.
"""
self.visitor.visit(ast)

218
dataObjects.py Executable file
View File

@ -0,0 +1,218 @@
import json, requests, os, socket
from datetime import datetime as dt
class InvalidJsonData(Exception):
pass
def readJson(input):
""" Trying to read JSON from given input.
Interpreting input as path to json file first,
then interpreting input as json string.
If both failed, raise InvalidJsonData Exception
"""
#try to read input data as path
try:
with open(input, "r") as f:
return json.load(f)
except:
pass
#try to read input data as json string
try:
return json.loads(input)
except:
pass
#if nothing found, return None
raise InvalidJsonData()
class Exercise:
def __init__(self, data):
""" Constructor for exercise object.
Args:
data: exercise data parsed by readJson
"""
# elements retrieved with .get are optional and
# return None if not found
self.postTime = data["Exercise"]["postTime"]
self.ttl = data["Exercise"].get("TTL")
self.identifier = data["Exercise"]["identifier"]
self.department = data["Exercise"].get("department")
self.comment = data["Exercise"].get("comment")
self.name = data["Exercise"].get("name")
self.description = data["Exercise"].get("description")
self.elements = data["Exercise"]["elements"]
self.environment = data["Exercise"].get("environment")
self.routing = data["Exercise"].get("routing")
self.elementMap = data["Exercise"].get("elementMap")
self.elementProperties = data["Exercise"].get("elementProperties")
tmp = data["Exercise"].get("config")
if tmp is not None:
self.lang = list(tmp.keys())[0]
self.config = tmp[self.lang]
# adding language of Exercise
def createJson(self):
""" Creates a JSON out of the exercise object
Returns:
A string containing the JSON data
"""
#struct with all possible data
data = {
"Exercise" : {
"postTime" : self.postTime,
"ttl" : self.ttl,
"identifier" : self.identifier,
"department" : self.department,
"comment" : self.comment,
"name" : self.name,
"description" : self.description,
"elements" : self.elements,
"environment" : self.environment,
"routing" : self.routing,
"elementMap" : self.elementMap,
"elementProperties" : self.elementProperties,
"config" : self.config
}
}
#removes optional entries if no value is given
for d in data["Exercise"]:
if d is None:
data["Exercise"].pop(d, None)
return json.dumps(data, indent=4)
def getCompilingCommand(self):
""" retrieving compiling command """
compiler = self.config["compiling"]["compiler"]
if compiler is None or compiler == "":
compiler = "gcc" if self.lang == "C" else "g++"
if self.config['compiling']['flags']:
return f"{compiler} {self.config['compiling']['flags']}"
else:
return compiler
class Solution:
""" Solution object
Documentation:
https://campusconnect.tik.uni-stuttgart.de/HeikoBernloehr/FreeLancer/ECS/ecs2/NumLab/solutions
"""
def __init__(self, data, exercise : Exercise = None):
""" Constructor for solution object.
Args:
data (str): solution data parsed by readJson
exercise (Exercise): optional exercise object. If not given, it will
try to retrieve it from exercise url
"""
self.postTime = data["Solution"]["postTime"]
self.id = data["Solution"]["ID"]
self.evaluationService = data["Solution"].get("evaluationService")
self.comment = data["Solution"].get("comment")
self.exerciseUrl = data["Solution"]["exercise"]
self.exerciseModifications = data["Solution"].get("exerciseModifications")
self.exercise = self.getExercise() if exercise == None else exercise
def getExercise(self):
""" Retrieves the given exercise json and creates exercise object
"""
r = requests.get(self.exerciseUrl)
return Exercise(r.json())
def createJson(self):
""" Creates a JSON out of the solution object
Returns:
A string containing the JSON data
"""
#struct with all possible data
data = {
"Solution" : {
"postTime" : self.postTime,
"ID" : self.id,
"evaluationService" : self.evaluationService,
"comment" : self.comment,
"exercise" : self.exerciseUrl,
"exerciseModifications" : self.exerciseModifications
}
}
#removes optional entries if no value is given
for d in data["Solution"]:
if d is None:
data["Solution"].pop(d, None)
return json.dumps(data, indent=4)
class Result:
""" Result object
Documentation:
https://campusconnect.tik.uni-stuttgart.de/HeikoBernloehr/FreeLancer/ECS/ecs2/NumLab/results
"""
def __init__(self, solution : str, comment : str = None,
status : str = "final"):
""" Constructor for result object.
Args:
solution (str): JSON string containing the solution data
comment (str): optional comment
status (str): has to be "final" or "intermediate"
"""
self.time = dt.now()
self.solution = solution
self.id = dt.strftime(self.time, "%Y-%m-%d %H:%M:%S")
self.comment = comment
self.status = status
self.index = None
self.computation = {
"startTime" : dt.strftime(self.time, "%Y-%m-%d %H:%M:%S"),
"CC_versionLong" : "",
"CC_version" : "",
"chain_version" : "",
"technicalInfo" : {
"host" : socket.gethostname(),
"PID" : os.getpid(),
"ID" : "#1"
},
"userInfo" : {"elements": []}
}
self.elements = []
def setId(self, id: int):
self.computation["technicalInfo"]["ID"] = f"#{id}"
def calculateComputationTime(self):
""" Adds finish time and time delta to computation dict
"""
time = dt.now()
self.computation["finishTime"] = dt.strftime(time, "%Y-%m-%d %H:%M:%S")
self.computation["duration"] = time - self.time
def createJson(self):
""" Creates a JSON out of the result object
Returns:
A string containing the JSON data
"""
#struct with all possible data
data = {
"Result" : {
"ID" : self.id,
"comment" : self.comment,
"status" : self.status,
"index" : self.index,
"computation" : self.computation,
"Solution" : self.solution,
"elements" : self.elements
}
}
#removes optional entries if no value is given
if data["Result"].get("comment") is None:
data["Result"].pop("comment", None)
if data["Result"].get("index") is None:
data["Result"].pop("index", None)
return json.dumps(data, indent=4, default=str)

22
example_run.py Normal file
View File

@ -0,0 +1,22 @@
import os, sys, c, dataObjects
# load exercise and solution data in json format
cur_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
exercise_data_path = os.path.join(cur_dir, "examples", "exercise.json")
solution_data_path = os.path.join(cur_dir, "examples", "solution.json")
exercise_data = dataObjects.readJson(exercise_data_path)
solution_data = dataObjects.readJson(solution_data_path)
# create exercise and solution objects
exercise = dataObjects.Exercise(exercise_data)
solution = dataObjects.Solution(solution_data, exercise)
# optional configuration, e.g. for timeout during running
cfg = {"timelimitInSeconds": 15}
# create C module object, process data and store result data in json format
module = c.C(solution, cfg)
module.processData()
result = module.result.createJson()
print(result)

72
examples/exercise.json Normal file
View File

@ -0,0 +1,72 @@
{
"Exercise": {
"postTime": "1985-04-12T23:20:50.52Z",
"TTL": 360000,
"identifier": "Numerik II, SS10, Aufgabe 1, v1.0",
"department": "RUS",
"comment": "Um die Studenten mal richtig zu fordern.",
"name": "Aufgabe 1",
"description": "Schreiben Sie eine C-Funktion...",
"elements": [
{
"identifier": "preamble",
"visible": true,
"modifiable": false,
"name": "Info: source before your code.",
"MIMEtype": "text/plain",
"syntaxHighlighting": "C",
"emphasis": "low",
"value": "#include <stdio.h>\n"
},
{
"identifier": "codeFromStudent",
"visible": true,
"modifiable": true,
"name": "Fill in your code!",
"MIMEtype": "text/plain",
"syntaxHighlighting": "C",
"emphasis": "medium",
"value": "void bar() { /* Schreiben Sie hier Code, der \"bar\" ausgibt. */\n\n}\n"
},
{
"identifier": "postscript",
"visible": true,
"modifiable": false,
"name": "Info: source after your code calling bar() in it.",
"MIMEtype": "text/plain",
"syntaxHighlighting": "C",
"emphasis": "low",
"value": "int main() { bar(); return 0; }"
}
],
"environment": "anIdentifier",
"config": {
"C": {
"merging": {
"sources": [
"preamble",
"codeFromStudent",
"postscript"
]
},
"compiling": {
"compiler": "gcc",
"flags": "-O2 -Wall"
},
"checking": {
"sources": [
"codeFromStudent"
],
"forbiddenCalls": "system execve"
},
"linking": {
"flags": "-lm"
},
"running": {
"commandLineArguments": "--stepwidth 0.001"
},
"stopAfterPhase": "running"
}
}
}
}

20
examples/solution.json Normal file
View File

@ -0,0 +1,20 @@
{
"Solution": {
"postTime": "1985-04-13T17:10:00.52Z",
"ID": "#37",
"evaluationService": {
"jobID": "1234abc",
"jobSender": "2"
},
"comment": "Die war aber schwer!",
"exercise": "https://ecs.uni-stuttgart.de/numlab/exercises/4711",
"exerciseModifications": {
"elements": [
{
"identifier": "codeFromStudent",
"value": "void bar() { printf(\"bar!\\n\");\n}\n"
}
]
}
}
}

27
utils/LICENSE Normal file
View File

@ -0,0 +1,27 @@
pycparser -- A C parser in Python
Copyright (c) 2008-2017, Eli Bendersky
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Eli Bendersky nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,4 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"
#include "_X11_fake_defines.h"
#include "_X11_fake_typedefs.h"

View File

@ -0,0 +1,4 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"
#include "_X11_fake_defines.h"
#include "_X11_fake_typedefs.h"

View File

@ -0,0 +1,16 @@
#ifndef _X11_FAKE_DEFINES_H
#define _X11_FAKE_DEFINES_H
#define Atom CARD32
#define Bool int
#define KeySym CARD32
#define Pixmap CARD32
#define Time CARD32
#define _XFUNCPROTOBEGIN
#define _XFUNCPROTOEND
#define _Xconst const
#define _X_RESTRICT_KYWD
#define Cardinal unsigned int
#define Boolean int
#endif

View File

@ -0,0 +1,38 @@
#ifndef _X11_FAKE_TYPEDEFS_H
#define _X11_FAKE_TYPEDEFS_H
typedef char* XPointer;
typedef unsigned char KeyCode;
typedef unsigned int CARD32;
typedef unsigned long VisualID;
typedef unsigned long XIMResetState;
typedef unsigned long XID;
typedef XID Window;
typedef XID Colormap;
typedef XID Cursor;
typedef XID Drawable;
typedef void* XtPointer;
typedef XtPointer XtRequestId;
typedef struct Display Display;
typedef struct Screen Screen;
typedef struct Status Status;
typedef struct Visual Visual;
typedef struct Widget *Widget;
typedef struct XColor XColor;
typedef struct XClassHint XClassHint;
typedef struct XEvent XEvent;
typedef struct XFontStruct XFontStruct;
typedef struct XGCValues XGCValues;
typedef struct XKeyEvent XKeyEvent;
typedef struct XKeyPressedEvent XKeyPressedEvent;
typedef struct XPoint XPoint;
typedef struct XRectangle XRectangle;
typedef struct XSelectionRequestEvent XSelectionRequestEvent;
typedef struct XWindowChanges XWindowChanges;
typedef struct _XGC _XCG;
typedef struct _XGC *GC;
typedef struct _XIC *XIC;
typedef struct _XIM *XIM;
typedef struct _XImage XImage;
#endif

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,212 @@
#ifndef _FAKE_DEFINES_H
#define _FAKE_DEFINES_H
#define NULL 0
#define BUFSIZ 1024
#define FOPEN_MAX 20
#define FILENAME_MAX 1024
#ifndef SEEK_SET
#define SEEK_SET 0 /* set file offset to offset */
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1 /* set file offset to current plus offset */
#endif
#ifndef SEEK_END
#define SEEK_END 2 /* set file offset to EOF plus offset */
#endif
#define __LITTLE_ENDIAN 1234
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#define __BIG_ENDIAN 4321
#define BIG_ENDIAN __BIG_ENDIAN
#define __BYTE_ORDER __LITTLE_ENDIAN
#define BYTE_ORDER __BYTE_ORDER
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
#define UCHAR_MAX 255
#define USHRT_MAX 65535
#define UINT_MAX 4294967295U
#define RAND_MAX 32767
#define INT_MAX 32767
/* C99 inttypes.h defines */
#define PRId8 "d"
#define PRIi8 "i"
#define PRIo8 "o"
#define PRIu8 "u"
#define PRIx8 "x"
#define PRIX8 "X"
#define PRId16 "d"
#define PRIi16 "i"
#define PRIo16 "o"
#define PRIu16 "u"
#define PRIx16 "x"
#define PRIX16 "X"
#define PRId32 "d"
#define PRIi32 "i"
#define PRIo32 "o"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#define PRId64 "d"
#define PRIi64 "i"
#define PRIo64 "o"
#define PRIu64 "u"
#define PRIx64 "x"
#define PRIX64 "X"
#define PRIdLEAST8 "d"
#define PRIiLEAST8 "i"
#define PRIoLEAST8 "o"
#define PRIuLEAST8 "u"
#define PRIxLEAST8 "x"
#define PRIXLEAST8 "X"
#define PRIdLEAST16 "d"
#define PRIiLEAST16 "i"
#define PRIoLEAST16 "o"
#define PRIuLEAST16 "u"
#define PRIxLEAST16 "x"
#define PRIXLEAST16 "X"
#define PRIdLEAST32 "d"
#define PRIiLEAST32 "i"
#define PRIoLEAST32 "o"
#define PRIuLEAST32 "u"
#define PRIxLEAST32 "x"
#define PRIXLEAST32 "X"
#define PRIdLEAST64 "d"
#define PRIiLEAST64 "i"
#define PRIoLEAST64 "o"
#define PRIuLEAST64 "u"
#define PRIxLEAST64 "x"
#define PRIXLEAST64 "X"
#define PRIdFAST8 "d"
#define PRIiFAST8 "i"
#define PRIoFAST8 "o"
#define PRIuFAST8 "u"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIdFAST16 "d"
#define PRIiFAST16 "i"
#define PRIoFAST16 "o"
#define PRIuFAST16 "u"
#define PRIxFAST16 "x"
#define PRIXFAST16 "X"
#define PRIdFAST32 "d"
#define PRIiFAST32 "i"
#define PRIoFAST32 "o"
#define PRIuFAST32 "u"
#define PRIxFAST32 "x"
#define PRIXFAST32 "X"
#define PRIdFAST64 "d"
#define PRIiFAST64 "i"
#define PRIoFAST64 "o"
#define PRIuFAST64 "u"
#define PRIxFAST64 "x"
#define PRIXFAST64 "X"
#define PRIdPTR "d"
#define PRIiPTR "i"
#define PRIoPTR "o"
#define PRIuPTR "u"
#define PRIxPTR "x"
#define PRIXPTR "X"
#define PRIdMAX "d"
#define PRIiMAX "i"
#define PRIoMAX "o"
#define PRIuMAX "u"
#define PRIxMAX "x"
#define PRIXMAX "X"
#define SCNd8 "d"
#define SCNi8 "i"
#define SCNo8 "o"
#define SCNu8 "u"
#define SCNx8 "x"
#define SCNd16 "d"
#define SCNi16 "i"
#define SCNo16 "o"
#define SCNu16 "u"
#define SCNx16 "x"
#define SCNd32 "d"
#define SCNi32 "i"
#define SCNo32 "o"
#define SCNu32 "u"
#define SCNx32 "x"
#define SCNd64 "d"
#define SCNi64 "i"
#define SCNo64 "o"
#define SCNu64 "u"
#define SCNx64 "x"
#define SCNdLEAST8 "d"
#define SCNiLEAST8 "i"
#define SCNoLEAST8 "o"
#define SCNuLEAST8 "u"
#define SCNxLEAST8 "x"
#define SCNdLEAST16 "d"
#define SCNiLEAST16 "i"
#define SCNoLEAST16 "o"
#define SCNuLEAST16 "u"
#define SCNxLEAST16 "x"
#define SCNdLEAST32 "d"
#define SCNiLEAST32 "i"
#define SCNoLEAST32 "o"
#define SCNuLEAST32 "u"
#define SCNxLEAST32 "x"
#define SCNdLEAST64 "d"
#define SCNiLEAST64 "i"
#define SCNoLEAST64 "o"
#define SCNuLEAST64 "u"
#define SCNxLEAST64 "x"
#define SCNdFAST8 "d"
#define SCNiFAST8 "i"
#define SCNoFAST8 "o"
#define SCNuFAST8 "u"
#define SCNxFAST8 "x"
#define SCNdFAST16 "d"
#define SCNiFAST16 "i"
#define SCNoFAST16 "o"
#define SCNuFAST16 "u"
#define SCNxFAST16 "x"
#define SCNdFAST32 "d"
#define SCNiFAST32 "i"
#define SCNoFAST32 "o"
#define SCNuFAST32 "u"
#define SCNxFAST32 "x"
#define SCNdFAST64 "d"
#define SCNiFAST64 "i"
#define SCNoFAST64 "o"
#define SCNuFAST64 "u"
#define SCNxFAST64 "x"
#define SCNdPTR "d"
#define SCNiPTR "i"
#define SCNoPTR "o"
#define SCNuPTR "u"
#define SCNxPTR "x"
#define SCNdMAX "d"
#define SCNiMAX "i"
#define SCNoMAX "o"
#define SCNuMAX "u"
#define SCNxMAX "x"
/* C99 stdbool.h defines */
#define __bool_true_false_are_defined 1
#define false 0
#define true 1
/* va_arg macros and type*/
#define va_start(_ap, _type) __builtin_va_start((_ap))
#define va_arg(_ap, _type) __builtin_va_arg((_ap))
#define va_end(_list)
#endif
/* Vectors */
#define __m128 int
#define __m128i int
#define __m128d int
#define __m256 int
#define __m256i int
#define __m256d int
#define __m512 int
#define __m512i int
#define __m512d int

View File

@ -0,0 +1,172 @@
#ifndef _FAKE_TYPEDEFS_H
#define _FAKE_TYPEDEFS_H
typedef int size_t;
typedef int __builtin_va_list;
typedef int __gnuc_va_list;
typedef int va_list;
typedef int __int8_t;
typedef int __uint8_t;
typedef int __int16_t;
typedef int __uint16_t;
typedef int __int_least16_t;
typedef int __uint_least16_t;
typedef int __int32_t;
typedef int __uint32_t;
typedef int __int64_t;
typedef int __uint64_t;
typedef int __int_least32_t;
typedef int __uint_least32_t;
typedef int __s8;
typedef int __u8;
typedef int __s16;
typedef int __u16;
typedef int __s32;
typedef int __u32;
typedef int __s64;
typedef int __u64;
typedef int _LOCK_T;
typedef int _LOCK_RECURSIVE_T;
typedef int _off_t;
typedef int __dev_t;
typedef int __uid_t;
typedef int __gid_t;
typedef int _off64_t;
typedef int _fpos_t;
typedef int _ssize_t;
typedef int wint_t;
typedef int _mbstate_t;
typedef int _flock_t;
typedef int _iconv_t;
typedef int __ULong;
typedef int __FILE;
typedef int ptrdiff_t;
typedef int wchar_t;
typedef int __off_t;
typedef int __pid_t;
typedef int __loff_t;
typedef int u_char;
typedef int u_short;
typedef int u_int;
typedef int u_long;
typedef int ushort;
typedef int uint;
typedef int clock_t;
typedef int time_t;
typedef int daddr_t;
typedef int caddr_t;
typedef int ino_t;
typedef int off_t;
typedef int dev_t;
typedef int uid_t;
typedef int gid_t;
typedef int pid_t;
typedef int key_t;
typedef int ssize_t;
typedef int mode_t;
typedef int nlink_t;
typedef int fd_mask;
typedef int _types_fd_set;
typedef int clockid_t;
typedef int timer_t;
typedef int useconds_t;
typedef int suseconds_t;
typedef int FILE;
typedef int fpos_t;
typedef int cookie_read_function_t;
typedef int cookie_write_function_t;
typedef int cookie_seek_function_t;
typedef int cookie_close_function_t;
typedef int cookie_io_functions_t;
typedef int div_t;
typedef int ldiv_t;
typedef int lldiv_t;
typedef int sigset_t;
typedef int __sigset_t;
typedef int _sig_func_ptr;
typedef int sig_atomic_t;
typedef int __tzrule_type;
typedef int __tzinfo_type;
typedef int mbstate_t;
typedef int sem_t;
typedef int pthread_t;
typedef int pthread_attr_t;
typedef int pthread_mutex_t;
typedef int pthread_mutexattr_t;
typedef int pthread_cond_t;
typedef int pthread_condattr_t;
typedef int pthread_key_t;
typedef int pthread_once_t;
typedef int pthread_rwlock_t;
typedef int pthread_rwlockattr_t;
typedef int pthread_spinlock_t;
typedef int pthread_barrier_t;
typedef int pthread_barrierattr_t;
typedef int jmp_buf;
typedef int rlim_t;
typedef int sa_family_t;
typedef int sigjmp_buf;
typedef int stack_t;
typedef int siginfo_t;
typedef int z_stream;
/* C99 exact-width integer types */
typedef int int8_t;
typedef int uint8_t;
typedef int int16_t;
typedef int uint16_t;
typedef int int32_t;
typedef int uint32_t;
typedef int int64_t;
typedef int uint64_t;
/* C99 minimum-width integer types */
typedef int int_least8_t;
typedef int uint_least8_t;
typedef int int_least16_t;
typedef int uint_least16_t;
typedef int int_least32_t;
typedef int uint_least32_t;
typedef int int_least64_t;
typedef int uint_least64_t;
/* C99 fastest minimum-width integer types */
typedef int int_fast8_t;
typedef int uint_fast8_t;
typedef int int_fast16_t;
typedef int uint_fast16_t;
typedef int int_fast32_t;
typedef int uint_fast32_t;
typedef int int_fast64_t;
typedef int uint_fast64_t;
/* C99 integer types capable of holding object pointers */
typedef int intptr_t;
typedef int uintptr_t;
/* C99 greatest-width integer types */
typedef int intmax_t;
typedef int uintmax_t;
/* C99 stdbool.h bool type. _Bool is built-in in C99 */
typedef _Bool bool;
/* Mir typedefs */
typedef void* MirEGLNativeWindowType;
typedef void* MirEGLNativeDisplayType;
typedef struct MirConnection MirConnection;
typedef struct MirSurface MirSurface;
typedef struct MirSurfaceSpec MirSurfaceSpec;
typedef struct MirScreencast MirScreencast;
typedef struct MirPromptSession MirPromptSession;
typedef struct MirBufferStream MirBufferStream;
typedef struct MirPersistentId MirPersistentId;
typedef struct MirBlob MirBlob;
typedef struct MirDisplayConfig MirDisplayConfig;
/* xcb typedefs */
typedef struct xcb_connection_t xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
#endif

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

View File

@ -0,0 +1,2 @@
#include "_fake_defines.h"
#include "_fake_typedefs.h"

Some files were not shown because too many files have changed in this diff Show More