117 lines
3.5 KiB
Python
117 lines
3.5 KiB
Python
import argparse
|
|
import os
|
|
import csv
|
|
|
|
parser = argparse.ArgumentParser(description="Convert CSV to .h defines")
|
|
parser.add_argument("--csv", required=True, help="Path to CSV file")
|
|
parser.add_argument("--output", required=True, help="Path to output .h file")
|
|
parser.add_argument("--variable", required=True, help="Name of generated array variable")
|
|
parser.add_argument('--index-include-path', required=False, default='', help="Include path for index defines")
|
|
parser.add_argument('--index-prefix', required=False, default='', help="Prefix for index defines")
|
|
parser.add_argument('--index-column', required=True, help="Column name for index values")
|
|
parser.add_argument('--data-column', required=True, help="Column name for data values")
|
|
args = parser.parse_args()
|
|
|
|
# Start Header
|
|
outHeader = "#pragma once\n"
|
|
outHeader += "#include \"dusk.h\"\n"
|
|
if args.index_include_path:
|
|
outHeader += f'#include "{args.index_include_path}"\n'
|
|
outHeader += "\n"
|
|
|
|
# Read CSV file
|
|
with open(args.csv, newline='') as csvfile:
|
|
reader = csv.reader(csvfile)
|
|
headers = next(reader)
|
|
|
|
# Ensure both index and data columns exist.
|
|
if args.index_column not in headers:
|
|
raise ValueError(f"Index column '{args.index_column}' not found in CSV headers")
|
|
if args.data_column not in headers:
|
|
raise ValueError(f"Data column '{args.data_column}' not found in CSV headers")
|
|
|
|
# Create key-value pairs from CSV rows.
|
|
index_col_idx = headers.index(args.index_column)
|
|
data_col_idx = headers.index(args.data_column)
|
|
keyValuePairs = {}
|
|
for row in reader:
|
|
key = row[index_col_idx]
|
|
value = row[data_col_idx]
|
|
|
|
# Don't allow duplicate keys.
|
|
if key in keyValuePairs:
|
|
raise ValueError(f"Duplicate key '{key}' found in CSV")
|
|
keyValuePairs[key] = value
|
|
|
|
# Determine type. Can be float, int, bool, or string.
|
|
isFloat = False
|
|
isInt = False
|
|
isBool = False
|
|
isString = False
|
|
|
|
# If there's no entries, assume string type.
|
|
if len(keyValuePairs) == 0:
|
|
isString = True
|
|
else:
|
|
allInts = True
|
|
allFloats = True
|
|
|
|
# Check if ALL values can be parsed as int or float.
|
|
for value in keyValuePairs.values():
|
|
if allInts:
|
|
try:
|
|
int(value)
|
|
except:
|
|
allInts = False
|
|
if allFloats:
|
|
try:
|
|
float(value)
|
|
except:
|
|
allFloats = False
|
|
|
|
if not allInts and not allFloats:
|
|
break
|
|
|
|
if allInts:
|
|
isInt = True
|
|
elif allFloats:
|
|
isFloat = True
|
|
else:
|
|
# Not all floats/ints, probably string or bool, check first entry
|
|
firstValue = next(iter(keyValuePairs.values()))
|
|
if firstValue.lower() in ['true', 'false']:
|
|
isBool = True
|
|
else:
|
|
isString = True
|
|
|
|
typeString = ""
|
|
if isFloat:
|
|
typeString = "float"
|
|
elif isInt:
|
|
typeString = "int"
|
|
elif isBool:
|
|
typeString = "bool"
|
|
elif isString:
|
|
typeString = "char*"
|
|
|
|
# Now begin generating header.
|
|
outHeader += f"static const {typeString} {args.variable}[] = {{\n"
|
|
for key in keyValuePairs:
|
|
outHeader += f" [{args.index_prefix}{key}] = "
|
|
value = keyValuePairs[key]
|
|
if isFloat:
|
|
outHeader += str(float(value))
|
|
elif isInt:
|
|
outHeader += str(int(value))
|
|
elif isBool:
|
|
asBool = 'true' if value.lower() == 'true' else 'false'
|
|
outHeader += asBool
|
|
elif isString:
|
|
escaped = value.replace('\\', '\\\\').replace('"', '\\"')
|
|
outHeader += f'"{escaped}"'
|
|
outHeader += ",\n"
|
|
outHeader += "};\n\n"
|
|
|
|
# Write to output file
|
|
with open(args.output, 'w') as outFile:
|
|
outFile.write(outHeader) |