5 # - clang-format-diff replacement
6 # - uncrustify for patches (not git refs)
7 # - maybe integrate into travis-ci?
12 $0 [ OPTS ] [ file-or-gitref [ ... ] ]
20 $ git format-patch --stdout -1 | $0 -p
23 # Or via regular files
24 $ git format-patch --stdout -2
31 # And print the whole file not only summary
37 -f - treat as regular file
38 -d - treat as regular file and print diff
39 -r - treat as git revision (default)
40 -C - check using clang-format (default)
41 -U - check with uncrustify
42 -c - config for clang-format/uncrustify
43 -h - print this message
48 [ -z "${options[cfg]}" ] || {
49 echo "${options[cfg]}"
53 local dir="$(dirname "${BASH_SOURCE[0]}")"
54 [ "${options[clang]}" -eq 0 ] || {
55 echo "$dir/.clang-format"
58 [ "${options[uncrustify]}" -eq 0 ] || {
59 echo "$dir/.uncrustify"
68 printf "$msg\n" "$@" >&2
71 function default_arg()
73 if [ "${options[ref]}" -eq 1 ]; then
76 [ ! -t 0 ] || abort "<stdin> is a tty"
80 function parse_options()
91 while getopts "pfrdCUc:h?" c; do
119 options[uncrustify]=0
122 options[uncrustify]=1
125 c) options[cfg]="$OPTIND" ;;
137 options[cfg]="$(cfg)"
139 [ -f "${options[cfg]}" ] || \
140 abort "Config '%s' does not exist" "${options[cfg]}"
142 shift $((OPTIND - 1))
145 if [ ${#args[@]} -eq 0 ]; then
146 # exit on error globally, not only in subshell
147 default_arg > /dev/null
148 args=( "$(default_arg)" )
151 if [ "${args[0]}" = "/dev/stdin" ]; then
152 TMP_FILE="/tmp/libevent.checkpatch.$RANDOM"
154 trap "rm '$TMP_FILE'" EXIT
160 function diff() { command diff --color=always "$@"; }
162 function clang_style()
164 local c="${options[cfg]}"
165 echo "{ $(sed -e 's/#.*//' -e '/---/d' -e '/\.\.\./d' "$c" | tr $'\n' ,) }"
167 function clang_format() { clang-format -style="$(clang_style)" "$@"; }
168 function clang_format_diff() { cat "$@" | clang-format-diff -p1 -style="$(clang_style)"; }
169 # for non-bare repo will work
170 function clang_format_git()
171 { git format-patch --stdout "$@" -1 | clang_format_diff; }
173 function uncrustify() { command uncrustify -c "${options[cfg]}" "$@"; }
174 function uncrustify_frag() { uncrustify -l C --frag "$@"; }
175 function uncrustify_indent_off() { echo '/* *INDENT-OFF* */'; }
176 function uncrustify_indent_on() { echo '/* *INDENT-ON* */'; }
181 git cat-file -p $ref:$f
183 function uncrustify_git_indent_hunk()
185 local start=$1 end=$2
188 # Will be beatier with tee(1), but doh bash async substitution
189 { uncrustify_indent_off; git_hunk "$@" | head -n$((start - 1)); }
190 { uncrustify_indent_on; git_hunk "$@" | head -n$((end - 1)) | tail -n+$start; }
191 { uncrustify_indent_off; git_hunk "$@" | tail -n+$((end + 1)); }
195 local start=$1 end=$2
198 # seek indent_{on,off}()
200 head -n$end | tail -n+$start
202 function patch_ranges()
204 egrep -o '^@@ -[0-9]+(,[0-9]+|) \+[0-9]+(,[0-9]+|) @@' | \
207 function git_ranges()
212 git diff -W $ref^..$ref -- $f | patch_ranges
214 function diff_substitute()
220 -e "s#^--- /dev/fd.*\$#--- a/$f#" \
221 -e "s#^+++ /dev/fd.*\$#+++ b/$f#"
223 function uncrustify_git()
225 local ref=$1 r f start end length
228 local files=( $(git diff --name-only $ref^..$ref | egrep "\.(c|h)$") )
229 for f in "${files[@]}"; do
230 local ranges=( $(git_ranges $ref "$f") )
231 for r in "${ranges[@]}"; do
232 [[ ! "$r" =~ ^\+([0-9]+)(,([0-9]+)|)$ ]] && continue
233 start=${BASH_REMATCH[1]}
234 [ -n "${BASH_REMATCH[3]}" ] && \
235 length=${BASH_REMATCH[3]} || \
237 end=$((start + length))
238 echo "Range: $start:$end ($length)" >&2
241 <(uncrustify_git_indent_hunk $start $end $ref "$f" | strip $start $end) \
242 <(uncrustify_git_indent_hunk $start $end $ref "$f" | uncrustify_frag | strip $start $end) \
243 | diff_substitute "$f"
247 function uncrustify_diff() { abort "Not implemented"; }
248 function uncrustify_file() { uncrustify -f "$@"; }
255 [ "${options[clang]}" -eq 0 ] || {
259 [ "${options[uncrustify]}" -eq 0 ] || {
264 function check_patch() { checker clang_format_diff uncrustify_diff "$@"; }
265 function check_file() { checker clang_format uncrustify_file "$@"; }
266 function check_ref() { checker clang_format_git uncrustify_git "$@"; }
270 [ "${options[patch]}" -eq 0 ] || {
274 [ "${options[file]}" -eq 0 ] || {
278 [ "${options[file_diff]}" -eq 0 ] || {
279 diff -u "$@" <(check_file "$@") | diff_substitute "$@"
282 [ "${options[ref]}" -eq 0 ] || {
291 for a in "${args}"; do
299 main "$@" | less -FRSX