main
lint
1#!/bin/sh
2# a small clang wrapper that prints in the same style as the old sun linter. it needs some work,
3# it should probably (definitely) use compile_commands.json, but it's still quite useful.
4# usage:
5#
6# lint [files/directory]
7# lint (recursively searches for .c files)
8#
9# dependencies:
10# shell
11# clang
12set -eu
13
14clang=${CLANG:-clang}
15tmp=${TMPDIR:-/tmp}/lint.$$.out
16trap 'rm -f "$tmp"' EXIT HUP INT TERM
17
18list() {
19 if [ "$#" -eq 0 ]; then
20 find . -type f -name '*.c'
21 return
22 fi
23 for path do
24 if [ -d "$path" ]; then
25 find "$path" -type f -name '*.c'
26 elif [ -f "$path" ]; then
27 case $path in
28 *.c)
29 printf '%s\n' "$path"
30 ;;
31 esac
32 fi
33 done
34}
35
36if ! list "$@" | grep . > /dev/null; then
37 printf '%s: no .c files found\n' "${0##*/}" >&2
38 exit 1
39fi
40
41set +e
42list "$@" | sort -u |
43xargs "$clang" -fsyntax-only \
44 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion \
45 -Wshadow -Wformat=2 -Wimplicit-fallthrough -Wcast-qual \
46 -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
47 -Wpointer-arith -Wundef -Wunreachable-code -Wnull-dereference \
48 > /dev/null 2> "$tmp"
49status=$?
50set -e
51
52list "$@" | sort -u | awk -v diagfile="$tmp" '
53BEGIN {
54 nfiles = 0
55}
56
57{
58 files[++nfiles] = $0
59}
60
61END {
62 while ((getline line < diagfile) > 0) {
63 sub(/\r$/, "", line)
64 if (match(line, /^([^:]+):([0-9]+):([0-9]+): (warning|error|note): (.*)$/, m)) {
65 file = m[1]
66 lnum = m[2]
67 kind = m[4]
68 msg = m[5]
69 if (kind == "note")
70 continue
71 gsub(/[[:space:]]*\[-W[^]]+\]$/, "", msg)
72 msgs[file] = msgs[file] sprintf("(%s) %s: %s\n", lnum, kind, msg)
73 continue
74 }
75 if (match(line, /^([^:]+): (warning|error|note): (.*)$/, m)) {
76 file = m[1]
77 kind = m[2]
78 msg = m[3]
79 if (kind == "note")
80 continue
81 gsub(/[[:space:]]*\[-W[^]]+\]$/, "", msg)
82 msgs[file] = msgs[file] sprintf("%s: %s\n", kind, msg)
83 }
84 }
85 close(diagfile)
86 for (i = 1; i <= nfiles; ++i) {
87 file = files[i]
88 if (file in msgs) {
89 print file ":"
90 printf "%s", msgs[file]
91 }
92 }
93 for (file in msgs) {
94 found = 0
95 for (i = 1; i <= nfiles; ++i) {
96 if (files[i] == file) {
97 found = 1
98 break
99 }
100 }
101 if (!found) {
102 print file ":"
103 printf "%s", msgs[file]
104 }
105 }
106}
107'
108
109exit "$status"