check-msgs.lua revision 1.11 1 1.1 rillig #! /usr/bin/lua
2 1.11 rillig -- $NetBSD: check-msgs.lua,v 1.11 2021/06/15 08:37:56 rillig Exp $
3 1.1 rillig
4 1.1 rillig --[[
5 1.1 rillig
6 1.5 rillig usage: lua ./check-msgs.lua *.c
7 1.1 rillig
8 1.5 rillig Check that the message text in the comments of the C source code matches the
9 1.5 rillig actual user-visible message text in err.c.
10 1.1 rillig
11 1.1 rillig ]]
12 1.1 rillig
13 1.1 rillig
14 1.1 rillig local function load_messages(fname)
15 1.11 rillig local msgs = {} ---@type table<number>string
16 1.1 rillig
17 1.1 rillig local f = assert(io.open(fname, "r"))
18 1.1 rillig for line in f:lines() do
19 1.1 rillig local msg, id = line:match("%s*\"(.+)\",%s*/%*%s*(%d+)%s*%*/$")
20 1.1 rillig if msg ~= nil then
21 1.1 rillig msgs[tonumber(id)] = msg
22 1.1 rillig end
23 1.1 rillig end
24 1.1 rillig
25 1.1 rillig f:close()
26 1.1 rillig
27 1.1 rillig return msgs
28 1.1 rillig end
29 1.1 rillig
30 1.1 rillig
31 1.11 rillig local had_errors = false
32 1.11 rillig ---@param fmt string
33 1.11 rillig function print_error(fmt, ...)
34 1.11 rillig print(fmt:format(...))
35 1.11 rillig had_errors = true
36 1.11 rillig end
37 1.11 rillig
38 1.11 rillig
39 1.11 rillig local function check_message(fname, lineno, id, comment, msgs)
40 1.1 rillig local msg = msgs[id]
41 1.1 rillig
42 1.1 rillig if msg == nil then
43 1.11 rillig print_error("%s:%d: id=%d not found", fname, lineno, id)
44 1.1 rillig return
45 1.1 rillig end
46 1.1 rillig
47 1.7 rillig msg = msg:gsub("/%*", "**")
48 1.7 rillig msg = msg:gsub("%*/", "**")
49 1.7 rillig msg = msg:gsub("\\(.)", "%1")
50 1.7 rillig
51 1.11 rillig -- allow a few abbreviations to be used in the code
52 1.7 rillig comment = comment:gsub("arg%.", "argument")
53 1.7 rillig comment = comment:gsub("comb%.", "combination")
54 1.7 rillig comment = comment:gsub("conv%.", "conversion")
55 1.7 rillig comment = comment:gsub("decl%.", "declaration")
56 1.7 rillig comment = comment:gsub("defn%.", "definition")
57 1.7 rillig comment = comment:gsub("des%.s", "designators")
58 1.7 rillig comment = comment:gsub("expr%.", "expression")
59 1.7 rillig comment = comment:gsub("func%.", "function")
60 1.7 rillig comment = comment:gsub("incomp%.", "incompatible")
61 1.7 rillig comment = comment:gsub("init%.", "initialize")
62 1.7 rillig comment = comment:gsub("param%.", "parameter")
63 1.7 rillig comment = comment:gsub("req%.", "requires")
64 1.7 rillig comment = comment:gsub("poss%.", "possibly")
65 1.7 rillig comment = comment:gsub("trad%.", "traditional")
66 1.2 rillig
67 1.1 rillig if comment == msg then
68 1.1 rillig return
69 1.1 rillig end
70 1.1 rillig
71 1.2 rillig local prefix = comment:match("^(.-)%s*%.%.%.$")
72 1.2 rillig if prefix ~= nil and msg:find(prefix, 1, 1) == 1 then
73 1.1 rillig return
74 1.1 rillig end
75 1.1 rillig
76 1.11 rillig print_error("%s:%d: id=%-3d msg=%-40s comment=%s",
77 1.1 rillig fname, lineno, id, msg, comment)
78 1.1 rillig end
79 1.1 rillig
80 1.1 rillig
81 1.11 rillig local function check_file(fname, msgs)
82 1.1 rillig local f = assert(io.open(fname, "r"))
83 1.1 rillig local lineno = 0
84 1.1 rillig local prev = ""
85 1.1 rillig for line in f:lines() do
86 1.1 rillig lineno = lineno + 1
87 1.1 rillig
88 1.3 rillig local func, id = line:match("^%s+(%w+)%((%d+)[),]")
89 1.4 rillig id = tonumber(id)
90 1.10 rillig if func == "error" or func == "warning" or
91 1.10 rillig func == "c99ism" or func == "c11ism" or
92 1.3 rillig func == "gnuism" or func == "message" then
93 1.2 rillig local comment = prev:match("^%s+/%* (.+) %*/$")
94 1.1 rillig if comment ~= nil then
95 1.11 rillig check_message(fname, lineno, id, comment, msgs)
96 1.4 rillig else
97 1.11 rillig print_error("%s:%d: missing comment for %d: /* %s */",
98 1.4 rillig fname, lineno, id, msgs[id])
99 1.1 rillig end
100 1.1 rillig end
101 1.1 rillig
102 1.1 rillig prev = line
103 1.1 rillig end
104 1.1 rillig
105 1.1 rillig f:close()
106 1.1 rillig end
107 1.1 rillig
108 1.1 rillig
109 1.8 rillig local function file_contains(filename, text)
110 1.8 rillig local f = assert(io.open(filename, "r"))
111 1.9 rillig local found = f:read("a"):find(text, 1, true)
112 1.8 rillig f:close()
113 1.9 rillig return found
114 1.8 rillig end
115 1.8 rillig
116 1.11 rillig
117 1.8 rillig local function check_test_files(msgs)
118 1.8 rillig
119 1.8 rillig local msgids = {}
120 1.8 rillig for msgid, _ in pairs(msgs) do
121 1.8 rillig table.insert(msgids, msgid)
122 1.8 rillig end
123 1.8 rillig table.sort(msgids)
124 1.8 rillig
125 1.8 rillig local testdir = "../../../tests/usr.bin/xlint/lint1"
126 1.8 rillig for _, msgid in ipairs(msgids) do
127 1.8 rillig local msg = msgs[msgid]:gsub("\\(.)", "%1")
128 1.8 rillig local filename = ("%s/msg_%03d.c"):format(testdir, msgid)
129 1.8 rillig if not file_contains(filename, msg) then
130 1.11 rillig print_error("%s must contain: %s", filename, msg)
131 1.8 rillig end
132 1.8 rillig end
133 1.8 rillig end
134 1.1 rillig
135 1.1 rillig local function main(arg)
136 1.1 rillig local msgs = load_messages("err.c")
137 1.1 rillig for _, fname in ipairs(arg) do
138 1.11 rillig check_file(fname, msgs)
139 1.1 rillig end
140 1.11 rillig check_test_files(msgs)
141 1.1 rillig end
142 1.1 rillig
143 1.11 rillig main(arg)
144 1.11 rillig os.exit(not had_errors)
145