Home | History | Annotate | Line # | Download | only in lint1
check-msgs.lua revision 1.7
      1  1.1  rillig #! /usr/bin/lua
      2  1.7  rillig -- $NetBSD: check-msgs.lua,v 1.7 2021/02/19 23:22:19 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.1  rillig   local f = assert(io.open(fname, "r"))
     78  1.1  rillig   local lineno = 0
     79  1.1  rillig   local prev = ""
     80  1.1  rillig   for line in f:lines() do
     81  1.1  rillig     lineno = lineno + 1
     82  1.1  rillig 
     83  1.3  rillig     local func, id = line:match("^%s+(%w+)%((%d+)[),]")
     84  1.4  rillig     id = tonumber(id)
     85  1.3  rillig     if func == "error" or func == "warning" or func == "c99ism" or
     86  1.3  rillig        func == "gnuism" or func == "message" then
     87  1.2  rillig       local comment = prev:match("^%s+/%* (.+) %*/$")
     88  1.1  rillig       if comment ~= nil then
     89  1.4  rillig         check_message(fname, lineno, id, comment, msgs, errors)
     90  1.4  rillig       else
     91  1.4  rillig         errors:add("%s:%d: missing comment for %d: /* %s */",
     92  1.4  rillig           fname, lineno, id, msgs[id])
     93  1.1  rillig       end
     94  1.1  rillig     end
     95  1.1  rillig 
     96  1.1  rillig     prev = line
     97  1.1  rillig   end
     98  1.1  rillig 
     99  1.1  rillig   f:close()
    100  1.1  rillig 
    101  1.1  rillig   return errors
    102  1.1  rillig end
    103  1.1  rillig 
    104  1.1  rillig 
    105  1.1  rillig local function check_file(fname, msgs)
    106  1.1  rillig   local errors = collect_errors(fname, msgs)
    107  1.1  rillig   for _, err in ipairs(errors) do
    108  1.1  rillig     print(err)
    109  1.1  rillig   end
    110  1.1  rillig   return #errors == 0
    111  1.1  rillig end
    112  1.1  rillig 
    113  1.1  rillig 
    114  1.1  rillig local function main(arg)
    115  1.1  rillig   local msgs = load_messages("err.c")
    116  1.1  rillig   local ok = true
    117  1.1  rillig   for _, fname in ipairs(arg) do
    118  1.1  rillig     ok = check_file(fname, msgs) and ok
    119  1.1  rillig   end
    120  1.1  rillig   return ok
    121  1.1  rillig end
    122  1.1  rillig 
    123  1.7  rillig 
    124  1.1  rillig os.exit(main(arg))
    125