-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdehash.sh
executable file
·162 lines (123 loc) · 5.23 KB
/
dehash.sh
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env bash
if [[ "$(sed --version 2>/dev/null)" =~ "GNU" ]]; then
SED=sed
else
if [[ "$(which gsed)" =~ "gsed" ]]; then
SED=gsed
else
echo "$(basename $0): GNU sed not found. Please install it"
exit -1
fi
fi
declare -r usage="`basename $0`: strip hash-style comments
Usage: `basename $0` [-c] [-b] [-n] [-h] [-o <outfile>] <file>\n
-c|--cpp\tkeep CPP directives.
-b|--blank\tkeep blank lines.
-n|--noext)\tturn off cpp extensions
-o|--out)\toutput to <outfile> (or - for stdout)
-h|--help\thelp.
<file> is the file to dehash to stdout (or - for stdin).
dehash extends cpp with the following cpp directives that expand
to regular CPP directives as follows:
#default X no --> #ifndef X / #define X 0 / #endif
#default X yes --> #ifndef X / #define X 1 / #endif
#default X Y --> #ifndef X / #define X Y / #endif
#default X --> #ifndef X / #define X / #endif
#redefine X Y --> #undef X / #define X Y
#require X --> #ifndef X / #error X is not defined / #endif
These cpp extensions can be disabled using -n.
This script is from git repo github.com/maartenSXM/cpphash.
Note: this script does not vet arguments securely. Do not setuid or host it.
"
while [[ $# > 0 ]]
do
case $1 in
-c|--cpp) GCCFLAGS="$GCCFLAGS -DCPP"; shift;;
-n|--noext) GCCFLAGS="$GCCFLAGS -DNOEXT"; shift;;
-b|--blank) GCCFLAGS="$GCCFLAGS -DBLANK"; shift;;
-o|--out) outfile="$2"; shift 2;;
-h|--help) printf "$usage"; exit 0;;
*) break
esac
done
GCC="gcc -x c -C -undef -nostdinc -E -P -Wno-endif-labels -Wundef -Werror -"
file="$1"
if [[ "$file" == "" ]]; then
file=/dev/stdin
fi
if [[ "$outfile" == "" ]]; then
outfile=/dev/stdout
else
if [[ "$outfile" == "-" ]]; then
outfile=/dev/stdout
fi
fi
# The following sed script is based on the code in the comment from anonymous
# user user218374 found here:
# https://unix.stackexchange.com/questions/383960/sed-stripping-comments-inline/766997
# Thank you! :-)
# q=quote, Q=doubleQuote, d=dollarSign
q=\\x27 Q=\\x22 d=\\x24
# b=backslash, B=doubleBackslash, e=exclamationMark
b=\\x5c B=\\x5c\\x5c e=\\x21
# construct regexes using symbolic names
single_quotes_open="$q[^$b$q]*($B.[^$b$q]*)*$d"
single_quoted_word="$q[^$b$q]*($B.[^$b$q]*)*$q"
double_quotes_open="$Q[^$b$Q]*($B.[^$b$Q]*)*$d"
double_quoted_word="$Q[^$b$Q]*($B.[^$b$Q]*)*$Q"
quoted_word="$double_quoted_word|$single_quoted_word"
# This adds or removes code from the sed script by piping it through
# the C preprocessor based on the flags specified.
echo '
#ifndef CPP
# // If not planning to run output through cpp, line 1 shebang can stay.
1 {/^#!/p}
#else // CPP
# // Else, change it to __SHEBANG__ and caller must change it back
# // later with, for example this sed: 1 {s,^__SHEBANG__,#!}.
1 {s,^#!,__SHEBANG__,}
# // Concatenate lines ending in backslash for further processing below.
# // This will handle multi-line comments and multi-line cpp directives.
:x; /\\\s*$/ { N; s/\\\n//; tx }
#ifndef NOEXT
# // Map "#default X no" to "#ifndef X \n#define X 0\n#endif\n"
{s@^\s*#\s*default\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*)(\s\s*no)($|\s.*$)@//#default \1\2\3\n# ifndef \1\n# define \1 0\n# endif@}
# // Map "#default X yes" to "#ifndef X \n#define X 1\n#endif\n"
{s@^\s*#\s*default\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*)(\s\s*yes)($|\s.*$)@//#default \1\2\3\n# ifndef \1\n# define \1 1\n# endif@}
# // Map "#default X Y" to "#ifndef X \n#define X Y\n#endif\n"
{s@^\s*#\s*default\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*)(\s\s*)(.*)$@//#default \1\2\3\n# ifndef \1\n# define \1\t\3\n# endif@}
# // Map "#default X" to "#ifndef X \n#define X\n#endif\n"
# // Not recommended in general since #ifdef X is legit code without
# // a #default. Use "#default X yes" with "#if X" instead to catch
# // missing #defaults and typos in #if or #default statements.
{s@^\s*#\s*default\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*)(.*)$@//#default \1\2\n# ifndef \1\n# define \1\n# endif@}
# // Map "#redefine X Y" to "#undef X \n#define X Y\n"
{s@^\s*#\s*redefine\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*)(\s\s*)(.*)$@//#redefine \1\2\3\n# undef \1\n# define \1 \3@}
# // Map "#require X" to "#ifndef X \n#error X is not defined \n#endif\n"
{s@^\s*#\s*require\s\s*([a-zA-Z0-9_][a-zA-Z0-9_]*).*$@//#require \1\n# ifndef \1\n# error \1 is not defined\n# endif@}
# // Done expanding #default, #redefine and #require. Go to next line
/^\/\/#(default|redefine|require) /b
#endif // !NOEXT
# // Keep cpp directive lines, go to next line
/^\s*#\s*(assert\s|define\s|elif\s|else|endif|error|ident\s|if\s|ifdef\s|ifndef\s|import\s|include\s|include_next\s|line\s|pragma\s|sccs\s|unassert\s|undef\s|warning)/b
# // Keep C comment lines starting with // that have a hash
/^\s*\/\/.*#/b
#endif // CPP
# // Delete lines starting with #
/^[\t\ ]*#/d
#ifndef BLANK
# // Delete blank lines
/\S/!d
#endif // !BLANK
'"
/(^|\s)$double_quotes_open/{:a;N;ba;}
/(^|\s)$single_quotes_open/{:b;N;bb;}
/$B$d/{:c;N;bc;}
s,\s*#.*|($quoted_word|.|$b$d#|$B#),\1,g
"'
#ifndef BLANK
# // Delete blank lines
/\S/!d
#endif // !BLANK
' | $GCC $GCCFLAGS | $SED -E -r -f - "$file" > "$outfile"
exit $?