119 lines
3.2 KiB
Bash
Executable File
119 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# unob is a proof-of-concept script.
|
|
# Prior to tac, scripting the layout of C code was intractable.
|
|
#
|
|
# There are uncountably many possible refinements to this script.
|
|
# Enjoy the madness of getting a perfect layout of C code via
|
|
# an automated process. Or just enjoy a significant help in
|
|
# reading obfuscated C code!
|
|
|
|
: "${PROG:=./prog}" # PROG=tac ./unob.sh prog.c
|
|
: "${KW:=c11}" # KW=ioccc.kw.freq ./unob.sh prog.c
|
|
: "${DEF:=}" # DEF="-DW=\\\"kandr2\\\" -DU=\\\"usage\ string\\\"" ./unob.sh -p prog.c
|
|
|
|
# optionally preprocess up to 3 times to handle #ifdef X #define Y
|
|
# unob prog.c # nonce
|
|
# unob -p prog.c # once
|
|
# unob -p -p prog.c # twice
|
|
# unob -p -p -p prog.c # thrice
|
|
# unob -p -p -p -p prog.c # yer out
|
|
|
|
function pp {
|
|
cpp2="cat"
|
|
cpp3="cat"
|
|
if [[ "$1" == "-p" ]]; then
|
|
shift
|
|
if [[ "$1" == "-p" ]]; then
|
|
cpp2="cpp -E"
|
|
shift
|
|
fi
|
|
if [[ "$1" == "-p" ]]; then
|
|
cpp3="cpp -E"
|
|
shift
|
|
fi
|
|
cat "$@" |
|
|
sed 's/# *include/##include/' |
|
|
eval cpp -E "$DEF" |
|
|
eval "$cpp2" |
|
|
eval "$cpp3" |
|
|
sed 's/^#[^#].*$//' |
|
|
sed 's/##inc/#inc/'
|
|
else
|
|
cat "$@"
|
|
fi
|
|
}
|
|
|
|
# For SC2016, we do want to single quote the leading part of the script,
|
|
# and we want $KW to be double quoted within the awk script.
|
|
# Unfortunately, shellcheck does not understand the "'"-ing.
|
|
#
|
|
# SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.
|
|
# https://www.shellcheck.net/wiki/SC2016
|
|
# shellcheck disable=SC2016
|
|
script='
|
|
BEGIN {
|
|
last=nl="\n";
|
|
f="'"$KW"'"; while(getline <f > 0) ++kw[$0]; close(f);
|
|
if (length(kw) == 0) {
|
|
print "cannot find",f "; check KW environment variable" | "cat 1>&2"
|
|
exit
|
|
}
|
|
}
|
|
|
|
function iskw(a) { return a in kw }
|
|
function indent() { return sprintf("%.*s", n*3, " ") }
|
|
function newline() { if (!infor && last != nl) printf last=nl }
|
|
function show(a) {
|
|
if (len>80 || (len>60 && (last ~ /^;/ || (last ~ /^,/ && paren==0))))
|
|
printf "%c%s", last=nl, indent() # yes, double indent here
|
|
if (len>60 && last ~ /^\)/ && a !~ /^\)/ && paren == 0)
|
|
printf last=nl
|
|
if (last==nl) { len=0; printf "%s", indent() }
|
|
|
|
if (length(a) > 80 && a ~ /\"/) {
|
|
newline()
|
|
len = 80
|
|
max = length(a)
|
|
for (off=0; off <= max; off += len)
|
|
printf "%s%s%c%s",
|
|
substr(a, off, len),
|
|
(off+len > max) ? "" : "\\",
|
|
last=nl, indent()
|
|
len = 0
|
|
return
|
|
}
|
|
|
|
printf "%s%s", space(), a
|
|
len += length(a space())
|
|
last=a
|
|
}
|
|
function space() {
|
|
return iskw(last) ||
|
|
(last != "." &&
|
|
last ~ /[A-Za-z0-9_+-\/%^|&\]\)=:<>;]$/ && $0 !~ /[\.:;()\[\],]/) ? " " : ""
|
|
}
|
|
|
|
/^\(/ { ++paren }
|
|
/^\)/ { --paren }
|
|
|
|
/^(if|while|for|return|switch|case|default|union|struct|typedef|#)/ { newline() }
|
|
|
|
/^for$/ { newline(); infor=1 }
|
|
infor && /^;/ { ++infor; show($0 " "); next }
|
|
infor==1 && /^:/ { ++infor }
|
|
infor>1 && paren==0 { infor=0 }
|
|
|
|
/^\?/ { ++tern; ++n; newline(); show($0 " "); next }
|
|
tern && /^:/ { newline(); show($0); --tern; --n; next }
|
|
|
|
/^#/ { newline(); show($0); newline(); next }
|
|
/^;/ { show($0); newline(); next }
|
|
/^{/ { show($0); ++n; newline(); next }
|
|
/^}/ { --n; newline(); show($0); newline(); next }
|
|
|
|
{ show($0) }
|
|
'
|
|
|
|
pp "$@" | "$PROG" -t | ./tokenfix.sh | awk "$script" # sed 's/""//g'
|