Home | History | Annotate | Line # | Download | only in lint1
check-msgs.lua revision 1.9
      1  1.1  rillig #! /usr/bin/lua
      2  1.9  rillig -- $NetBSD: check-msgs.lua,v 1.9 2021/02/28 12:45:47 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.1  rillig   local msgs = {}
     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.1  rillig local function check_message(fname, lineno, id, comment, msgs, errors)
     32  1.1  rillig   local msg = msgs[id]
     33  1.1  rillig 
     34  1.1  rillig   if msg == nil then
     35  1.1  rillig     errors:add("%s:%d: id=%d not found", fname, lineno, id)
     36  1.1  rillig     return
     37  1.1  rillig   end
     38  1.1  rillig 
     39  1.7  rillig   msg = msg:gsub("/%*", "**")
     40  1.7  rillig   msg = msg:gsub("%*/", "**")
     41  1.7  rillig   msg = msg:gsub("\\(.)", "%1")
     42  1.7  rillig 
     43  1.7  rillig   comment = comment:gsub("arg%.", "argument")
     44  1.7  rillig   comment = comment:gsub("comb%.", "combination")
     45  1.7  rillig   comment = comment:gsub("conv%.", "conversion")
     46  1.7  rillig   comment = comment:gsub("decl%.", "declaration")
     47  1.7  rillig   comment = comment:gsub("defn%.", "definition")
     48  1.7  rillig   comment = comment:gsub("des%.s", "designators")
     49  1.7  rillig   comment = comment:gsub("expr%.", "expression")
     50  1.7  rillig   comment = comment:gsub("func%.", "function")
     51  1.7  rillig   comment = comment:gsub("incomp%.", "incompatible")
     52  1.7  rillig   comment = comment:gsub("init%.", "initialize")
     53  1.7  rillig   comment = comment:gsub("param%.", "parameter")
     54  1.7  rillig   comment = comment:gsub("req%.", "requires")
     55  1.7  rillig   comment = comment:gsub("poss%.", "possibly")
     56  1.7  rillig   comment = comment:gsub("trad%.", "traditional")
     57  1.2  rillig 
     58  1.1  rillig   if comment == msg then
     59  1.1  rillig     return
     60  1.1  rillig   end
     61  1.1  rillig 
     62  1.2  rillig   local prefix = comment:match("^(.-)%s*%.%.%.$")
     63  1.2  rillig   if prefix ~= nil and msg:find(prefix, 1, 1) == 1 then
     64  1.1  rillig     return
     65  1.1  rillig   end
     66  1.1  rillig 
     67  1.1  rillig   errors:add("%s:%d:   id=%-3d   msg=%-40s   comment=%s",
     68  1.1  rillig     fname, lineno, id, msg, comment)
     69  1.1  rillig end
     70  1.1  rillig 
     71  1.1  rillig 
     72  1.1  rillig local function collect_errors(fname, msgs)
     73  1.1  rillig   local errors = {}
     74  1.1  rillig   errors.add = function(self, fmt, ...)
     75  1.7  rillig     table.insert(self, fmt:format(...))
     76  1.1  rillig   end
     77  1.8  rillig 
     78  1.1  rillig   local f = assert(io.open(fname, "r"))
     79  1.1  rillig   local lineno = 0
     80  1.1  rillig   local prev = ""
     81  1.1  rillig   for line in f:lines() do
     82  1.1  rillig     lineno = lineno + 1
     83  1.1  rillig 
     84  1.3  rillig     local func, id = line:match("^%s+(%w+)%((%d+)[),]")
     85  1.4  rillig     id = tonumber(id)
     86  1.3  rillig     if func == "error" or func == "warning" or func == "c99ism" or
     87  1.3  rillig        func == "gnuism" or func == "message" then
     88  1.2  rillig       local comment = prev:match("^%s+/%* (.+) %*/$")
     89  1.1  rillig       if comment ~= nil then
     90  1.4  rillig         check_message(fname, lineno, id, comment, msgs, errors)
     91  1.4  rillig       else
     92  1.4  rillig         errors:add("%s:%d: missing comment for %d: /* %s */",
     93  1.4  rillig           fname, lineno, id, msgs[id])
     94  1.1  rillig       end
     95  1.1  rillig     end
     96  1.1  rillig 
     97  1.1  rillig     prev = line
     98  1.1  rillig   end
     99  1.1  rillig 
    100  1.1  rillig   f:close()
    101  1.1  rillig 
    102  1.1  rillig   return errors
    103  1.1  rillig end
    104  1.1  rillig 
    105  1.1  rillig 
    106  1.1  rillig local function check_file(fname, msgs)
    107  1.1  rillig   local errors = collect_errors(fname, msgs)
    108  1.1  rillig   for _, err in ipairs(errors) do
    109  1.1  rillig     print(err)
    110  1.1  rillig   end
    111  1.1  rillig   return #errors == 0
    112  1.1  rillig end
    113  1.1  rillig 
    114  1.8  rillig local function file_contains(filename, text)
    115  1.8  rillig   local f = assert(io.open(filename, "r"))
    116  1.9  rillig   local found = f:read("a"):find(text, 1, true)
    117  1.8  rillig   f:close()
    118  1.9  rillig   return found
    119  1.8  rillig end
    120  1.8  rillig 
    121  1.8  rillig local function check_test_files(msgs)
    122  1.8  rillig 
    123  1.8  rillig   local msgids = {}
    124  1.8  rillig   for msgid, _ in pairs(msgs) do
    125  1.8  rillig     table.insert(msgids, msgid)
    126  1.8  rillig   end
    127  1.8  rillig   table.sort(msgids)
    128  1.8  rillig 
    129  1.8  rillig   local testdir = "../../../tests/usr.bin/xlint/lint1"
    130  1.8  rillig   local ok = true
    131  1.8  rillig   for _, msgid in ipairs(msgids) do
    132  1.8  rillig     local msg = msgs[msgid]:gsub("\\(.)", "%1")
    133  1.8  rillig     local filename = ("%s/msg_%03d.c"):format(testdir, msgid)
    134  1.8  rillig     if not file_contains(filename, msg) then
    135  1.8  rillig       ok = false
    136  1.8  rillig       print(("%s must contain: %s"):format(filename, msg))
    137  1.8  rillig     end
    138  1.8  rillig   end
    139  1.8  rillig 
    140  1.8  rillig   return ok
    141  1.8  rillig end
    142  1.1  rillig 
    143  1.1  rillig local function main(arg)
    144  1.1  rillig   local msgs = load_messages("err.c")
    145  1.1  rillig   local ok = true
    146  1.1  rillig   for _, fname in ipairs(arg) do
    147  1.1  rillig     ok = check_file(fname, msgs) and ok
    148  1.1  rillig   end
    149  1.8  rillig   ok = check_test_files(msgs) and ok
    150  1.1  rillig   return ok
    151  1.1  rillig end
    152  1.1  rillig 
    153  1.7  rillig 
    154  1.1  rillig os.exit(main(arg))
    155