Skip to content

Commit 5fda794

Browse files
committed
Merge branch 'cheetah'
2 parents e728dbf + 72eff55 commit 5fda794

1 file changed

Lines changed: 153 additions & 0 deletions

File tree

nam-compiler-cheetah.sh

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/bin/bash
2+
#
3+
# Compile a NAM controller _F_A_S_T_ (experimental).
4+
#
5+
# Requires bash perl sed tail dd iconv xargs.
6+
set -e
7+
print_usage() {
8+
cat << EOM
9+
Compile a NAM controller _F_A_S_T_ (experimental). Usage:
10+
11+
./nam-compiler-cheetah.sh [--lhd] [--low-ram] [ <input> [<output>] ]
12+
13+
where <input> Controller directory (defaults to ./Controller/)
14+
<output> directory or .dat file (defaults to ./NetworkAddonMod_Controller.dat)
15+
--lhd compile a LHD controller (defaults to RHD)
16+
--low-ram compile a smaller controller excluding RHW
17+
-h, --help display this help
18+
19+
Not for productive use as the resulting controller file can differ from the output of the ordinary compiler.
20+
EOM
21+
}
22+
########################################
23+
24+
# handling of input arguments
25+
for arg in "$@"; do
26+
shift
27+
case "$arg" in
28+
'-h') print_usage; exit 0 ;;
29+
'--help') print_usage; exit 0 ;;
30+
'--low-ram') lowram="1" ;;
31+
'--lhd') lhd="1" ;;
32+
'--rhd') ;;
33+
*) set -- "$@" "$arg" ;;
34+
esac
35+
done
36+
INDIR="${1:-./Controller}"
37+
INDIR="${INDIR%/}" # removes trailing slash
38+
OUT="${2:-.}"
39+
if [[ "$OUT" != *.dat ]]; then
40+
# assumes that OUT was a directory
41+
OUT="${OUT%/}/NetworkAddonMod_Controller.dat"
42+
fi
43+
44+
if [ -z ${lhd+x} ]; then driveside='RHD'; else driveside='LHD'; fi
45+
if [ -z ${lhd+x} ]; then drivesideignore='*LHD.*'; else drivesideignore='*RHD.*'; fi
46+
47+
directories=("RUL0" "RUL1" "RUL2" "INI" "LText")
48+
tgis=("0x0A5BCF4B" "0xAA5BCF57" "0x10000000"
49+
"0x0A5BCF4B" "0xAA5BCF57" "0x10000001"
50+
"0x0A5BCF4B" "0xAA5BCF57" "0x10000002"
51+
"0x00000000" "0x8A5971C5" "0x8A5993B9"
52+
"0x2026960B" "0x123006AA" "0x6A47FFFF")
53+
54+
for d in "${directories[@]}"
55+
do
56+
# error out before doing anything harmful
57+
if [[ ! -d "$INDIR/$d" && "$d" != "${directories[-1]}" ]]; then
58+
echo "Error: Directory ‘$INDIR/$d’ does not exist."; exit 1;
59+
fi
60+
done
61+
62+
sorted_input_files() {
63+
# If lowram, this skips all paths containing 'RHW'
64+
find -L "$INDIR/$1" -type f \( -name '*.txt' -o -name '*.rul' -o -name '*.ini' \) \
65+
\! -ipath "$drivesideignore" ${lowram:+ \! -ipath '*RHW*'} -print0 | sort -z
66+
}
67+
68+
concat_before_separator() {
69+
# `tail -v` adds a header line starting with `==>` which demarcates the
70+
# start of each file, so this command includes everything between pairs of
71+
# ==> and separator (and finally deletes lines starting with ==>).
72+
xargs -0 tail -v -n +1 - | sed -ne '/^==>/,/^\s*;###separator###/p' - | sed -e '/^==>/d' -
73+
}
74+
75+
concat_after_separator() {
76+
# Deletes everything from ==> to separator, repeatedly.
77+
xargs -0 tail -v -n +1 - | sed -e '/^==>/,/^\s*;###separator###/d' -
78+
}
79+
80+
strip_drive_side() {
81+
# Uncomments the RHD code (and leaves LHD code commented out, or vice versa).
82+
# If an argument is passed, this uses xargs to read file names from stdin,
83+
# else stdin is read as input directly.
84+
${1:+ xargs -0} sed -e "s/;###${driveside}###//g"
85+
}
86+
# Note that we used sed and tail for concatenation which handle missing
87+
# newlines at the end of input files gracefully (unlike cat).
88+
89+
strip_comments() {
90+
# Not matching whitespace for speed
91+
sed -e '/^;/d' -
92+
}
93+
94+
uint32_to_bytes() {
95+
# little endian
96+
perl -e "print pack('V', $1)"
97+
}
98+
99+
ltext() {
100+
uint32_to_bytes $(("${#1}" | "0x10000000"))
101+
printf "$1" | iconv -f utf-8 -t utf-16le
102+
}
103+
104+
# Header
105+
rm -f "$OUT"
106+
printf 'DBPF' >> "$OUT"
107+
printf '\x01\x00\x00\x00\x00\x00\x00\x00' >> "$OUT" # major.minor = 1.0
108+
for i in {1..21}; do printf '\x00\x00\x00\x00' >> "$OUT"; done # placeholder
109+
110+
declare -a lengths=()
111+
declare -a offsets=($(wc --bytes < "$OUT"))
112+
113+
for d in "${directories[@]}"
114+
do
115+
printf "$d..."
116+
if [ "$d" = "${directories[-1]}" ]; then
117+
# LText file
118+
ltext "Cheetah variant $driveside (not for production) compiled in $SECONDS seconds on $(date)" >> "$OUT"
119+
elif [ "$d" = "${directories[0]}" ]; then
120+
# RUL0 directory
121+
sorted_input_files "$d" | concat_before_separator | strip_drive_side >> "$OUT"
122+
sorted_input_files "$d" | concat_after_separator | strip_drive_side >> "$OUT"
123+
else
124+
# other directories
125+
sorted_input_files "$d" | strip_drive_side -0 | strip_comments >> "$OUT"
126+
fi
127+
offsets+=($(wc --bytes < "$OUT"))
128+
lengths+=($(("${offsets[-1]}" - "${offsets[-2]}")))
129+
done
130+
131+
# TGI Index
132+
for((i=0, k=0, grp=3; i < "${#tgis[@]}"; i+=grp, k+=1))
133+
do
134+
tgi=("${tgis[@]:i:grp}")
135+
for id in "${tgi[@]}"
136+
do
137+
uint32_to_bytes "$id" >> "$OUT"
138+
done
139+
uint32_to_bytes "${offsets[$k]}" >> "$OUT"
140+
uint32_to_bytes "${lengths[$k]}" >> "$OUT"
141+
done
142+
143+
# update Header
144+
header=("$(date +%s)" # creation date
145+
"$(date +%s)" # modification date
146+
"7" # index version
147+
"$k" # number of entries
148+
"${offsets[-1]}" # index location
149+
"$(($k * 20))") # index length
150+
(for h in "${header[@]}"; do uint32_to_bytes "$h"; done) \
151+
| dd conv=notrunc status=none bs=4 seek=6 count="${#header[@]}" of="$OUT"
152+
153+
echo "Done."

0 commit comments

Comments
 (0)