1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#!/bin/sh -e
VERSION=2
[ "$#" -eq 2 ] || {
printf "usage: %s file.tal.debug address\n" "$0" >&2
exit 1
}
[ -r "$1" ] || {
printf "%s: file not found\n" "$1" >&2
exit 1
}
case "$1" in
*.tal.debug) ;;
*)
printf "%s: does not end in .tal.debug, can't work out source file\n" "$1" >&2
exit 1
;;
esac
[ -t 1 ] && {
red="\033[1;31m"
yellow="\033[1;33m"
reset="\033[m"
}
debug_file="$1"
source_file="${1%.debug}"
check_versions() {
read -r v < "$1"
# version 2 is compatible with version 1 for this tool
if [ "$v" != "$VERSION" ] && [ "$v" != 1 ]; then
printf "${yellow}ERROR${reset}: incompatible version '%s' (this tool is version %d)\n" "$v" "$VERSION" >&2
exit 1
fi
}
compare_file_timestamps() {
# TODO: recurse through included files to check timestamps
case "$(ls -t "$1" "$1.debug")" in
"$1.debug"*) ;;
*) printf "${yellow}WARNING${reset}: source file is newer than debug info\n" >&2 ;;
esac
}
check_versions "$debug_file"
compare_file_timestamps "$source_file"
address="$(printf "%s" "$2" | tr 'a-f' 'A-F')"
dec_address="$(printf "16iAo%s 100-p\n" "$address" | dc || kill 0)"
# add 3 because the zeroth byte is on the third line
dec_address="$((dec_address + 3))"
[ "$dec_address" -lt 0 ] && {
printf "address %s is in zero page, don't subtract 0x0100\n" "$address"
exit 1
}
is_integer() {
printf %d "$1" >/dev/null 2>&1
}
token="$(sed -n "${dec_address}p" "$debug_file" | cut -d' ' -f1)"
: "${token:?cannot find integer from debug file at given byte}"
is_integer "$token" || {
printf "can't find an integer token number in %s for byte %X\n" "$debug_file" "$address" >&2
exit 1
}
print_highlighted() {
index="$1"
shift
j=1
for tok; do
if [ "$j" -eq "$index" ]; then
printf " ${red}%s${reset}" "$tok"
else
printf " %s" "$tok"
fi
j="$((j + 1))"
done
printf "\n"
}
scan() {
i="$1"
lineno=0
f="$2"
while read -r line || return 0; do
lineno="$((lineno + 1))"
# word splitting is desired.
# shellcheck disable=SC2086
set -- $line
i="$((i + $#))"
for op; do case "$op" in "~"*)
cur_line="$lineno" cur_file="$f"
scan "$i" "${op#'~'}"
lineno="$cur_line" f="$cur_file"
;; esac
done
[ "$i" -ge "$token" ] && {
printf "%s line %d: " "$f" "$lineno"
print_highlighted "$(($# - i + token))" "$@"
exit 0
}
done < "$f"
}
scan 0 "$source_file"
|