Home | History | Annotate | Line # | Download | only in lint1
check-msgs.lua revision 1.12
      1   1.1  rillig #! /usr/bin/lua
      2  1.12  rillig -- $NetBSD: check-msgs.lua,v 1.12 2021/09/04 12:30:46 rillig Exp $
      3   1.1  rillig 
      4   1.1  rillig --[[
      5   1.1  rillig 
      6  1.12  rillig usage: lua ./check-msgs.lua *.c *.y
      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.1  rillig   if comment == msg then
     52   1.1  rillig     return
     53   1.1  rillig   end
     54   1.1  rillig 
     55   1.2  rillig   local prefix = comment:match("^(.-)%s*%.%.%.$")
     56   1.2  rillig   if prefix ~= nil and msg:find(prefix, 1, 1) == 1 then
     57   1.1  rillig     return
     58   1.1  rillig   end
     59   1.1  rillig 
     60  1.11  rillig   print_error("%s:%d:   id=%-3d   msg=%-40s   comment=%s",
     61   1.1  rillig     fname, lineno, id, msg, comment)
     62   1.1  rillig end
     63   1.1  rillig 
     64   1.1  rillig 
     65  1.11  rillig local function check_file(fname, msgs)
     66   1.1  rillig   local f = assert(io.open(fname, "r"))
     67   1.1  rillig   local lineno = 0
     68   1.1  rillig   local prev = ""
     69   1.1  rillig   for line in f:lines() do
     70   1.1  rillig     lineno = lineno + 1
     71   1.1  rillig 
     72   1.3  rillig     local func, id = line:match("^%s+(%w+)%((%d+)[),]")
     73   1.4  rillig     id = tonumber(id)
     74  1.10  rillig     if func == "error" or func == "warning" or
     75  1.10  rillig        func == "c99ism" or func == "c11ism" or
     76   1.3  rillig        func == "gnuism" or func == "message" then
     77   1.2  rillig       local comment = prev:match("^%s+/%* (.+) %*/$")
     78   1.1  rillig       if comment ~= nil then
     79  1.11  rillig         check_message(fname, lineno, id, comment, msgs)
     80   1.4  rillig       else
     81  1.11  rillig         print_error("%s:%d: missing comment for %d: /* %s */",
     82   1.4  rillig           fname, lineno, id, msgs[id])
     83   1.1  rillig       end
     84   1.1  rillig     end
     85   1.1  rillig 
     86   1.1  rillig     prev = line
     87   1.1  rillig   end
     88   1.1  rillig 
     89   1.1  rillig   f:close()
     90   1.1  rillig end
     91   1.1  rillig 
     92   1.1  rillig 
     93   1.8  rillig local function file_contains(filename, text)
     94   1.8  rillig   local f = assert(io.open(filename, "r"))
     95   1.9  rillig   local found = f:read("a"):find(text, 1, true)
     96   1.8  rillig   f:close()
     97   1.9  rillig   return found
     98   1.8  rillig end
     99   1.8  rillig 
    100  1.11  rillig 
    101   1.8  rillig local function check_test_files(msgs)
    102   1.8  rillig 
    103   1.8  rillig   local msgids = {}
    104   1.8  rillig   for msgid, _ in pairs(msgs) do
    105   1.8  rillig     table.insert(msgids, msgid)
    106   1.8  rillig   end
    107   1.8  rillig   table.sort(msgids)
    108   1.8  rillig 
    109   1.8  rillig   local testdir = "../../../tests/usr.bin/xlint/lint1"
    110   1.8  rillig   for _, msgid in ipairs(msgids) do
    111   1.8  rillig     local msg = msgs[msgid]:gsub("\\(.)", "%1")
    112   1.8  rillig     local filename = ("%s/msg_%03d.c"):format(testdir, msgid)
    113   1.8  rillig     if not file_contains(filename, msg) then
    114  1.11  rillig       print_error("%s must contain: %s", filename, msg)
    115   1.8  rillig     end
    116   1.8  rillig   end
    117   1.8  rillig end
    118   1.1  rillig 
    119   1.1  rillig local function main(arg)
    120   1.1  rillig   local msgs = load_messages("err.c")
    121   1.1  rillig   for _, fname in ipairs(arg) do
    122  1.11  rillig     check_file(fname, msgs)
    123   1.1  rillig   end
    124  1.11  rillig   check_test_files(msgs)
    125   1.1  rillig end
    126   1.1  rillig 
    127  1.11  rillig main(arg)
    128  1.11  rillig os.exit(not had_errors)
    129