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
|
#! /usr/bin/lua
-- $NetBSD: check-msgs.lua,v 1.18 2023/07/02 23:40:23 rillig Exp $
--[[
usage: lua ./check-msgs.lua *.c *.y
Check that the message text in the comments of the C source code matches the
actual user-visible message text in err.c.
]]
local function load_messages()
local msgs = {} ---@type table<string>string
local f = assert(io.open("err.c"))
for line in f:lines() do
local msg, id = line:match("%s*\"(.+)\",%s*/%*%s*(Q?%d+)%s*%*/$")
if msg ~= nil then
msgs[id] = msg
end
end
f:close()
return msgs
end
local had_errors = false
---@param fmt string
function print_error(fmt, ...)
print(fmt:format(...))
had_errors = true
end
local function check_message(fname, lineno, id, comment, msgs)
local msg = msgs[id]
if msg == nil then
print_error("%s:%d: id=%s not found", fname, lineno, id)
return
end
msg = msg:gsub("/%*", "**")
msg = msg:gsub("%*/", "**")
msg = msg:gsub("\\(.)", "%1")
if comment == msg then
return
end
local prefix = comment:match("^(.-)%s*%.%.%.$")
if prefix ~= nil and msg:find(prefix, 1, 1) == 1 then
return
end
print_error("%s:%d: id=%-3s msg=%-40s comment=%s",
fname, lineno, id, msg, comment)
end
local message_prefix = {
error = "",
error_at = "",
warning = "",
warning_at = "",
query_message = "Q",
c99ism = "",
c11ism = "",
c23ism = "",
gnuism = "",
}
local function check_file(fname, msgs)
local f = assert(io.open(fname, "r"))
local lineno = 0
local prev = ""
for line in f:lines() do
lineno = lineno + 1
local func, id = line:match("^%s+([%w_]+)%((%d+)[),]")
local prefix = message_prefix[func]
if prefix then
id = prefix .. id
local comment = prev:match("^%s+/%* (.+) %*/$")
if comment ~= nil then
check_message(fname, lineno, id, comment, msgs)
else
print_error("%s:%d: missing comment for %s: /* %s */",
fname, lineno, id, msgs[id])
end
end
prev = line
end
f:close()
end
local function file_contains(filename, text)
local f = assert(io.open(filename, "r"))
local found = f:read("a"):find(text, 1, true)
f:close()
return found
end
-- Ensure that each test file for a particular message mentions the full text
-- of that message and the message ID.
local function check_test_files(msgs)
local testdir = "../../../tests/usr.bin/xlint/lint1"
local cmd = ("cd '%s' && printf '%%s\\n' msg_[0-9][0-9][0-9]*.c"):format(testdir)
local filenames = assert(io.popen(cmd))
for filename in filenames:lines() do
local msgid = filename:match("^msg_(%d%d%d)")
if msgs[msgid] then
local unescaped_msg = msgs[msgid]:gsub("\\(.)", "%1")
local expected_text = ("%s [%s]"):format(unescaped_msg, msgid)
local fullname = ("%s/%s"):format(testdir, filename)
if not file_contains(fullname, expected_text) then
print_error("%s must contain: %s", fullname, expected_text)
end
end
end
filenames:close()
end
local function main(arg)
local msgs = load_messages()
for _, fname in ipairs(arg) do
check_file(fname, msgs)
end
check_test_files(msgs)
end
main(arg)
os.exit(not had_errors)
|