Home | History | Annotate | Line # | Download | only in lint1
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