11.1Srillig#! /usr/bin/lua
21.6Srillig-- $NetBSD: lint.lua,v 1.6 2021/06/13 19:50:18 rillig Exp $
31.1Srillig
41.1Srillig--[[
51.1Srillig
61.1Srilligusage: lua ./lint.lua
71.1Srillig
81.4SrilligCheck that the argument handling code does not contain unintended
91.1Srilliginconsistencies.
101.1Srillig
111.1Srillig]]
121.1Srillig
131.3Srillig---@return string[]
141.1Srilliglocal function load_lines(fname)
151.1Srillig  local lines = {}
161.1Srillig
171.1Srillig  local f = assert(io.open(fname, "r"))
181.1Srillig  for line in f:lines() do
191.1Srillig    table.insert(lines, line)
201.1Srillig  end
211.1Srillig
221.1Srillig  f:close()
231.1Srillig
241.1Srillig  return lines
251.1Srilligend
261.1Srillig
271.6Srilliglocal had_errors = false
281.6Srilliglocal function print_error(fmt, ...)
291.6Srillig  print(fmt:format(...))
301.6Srillig  had_errors = true
311.1Srilligend
321.1Srillig
331.1Srillig
341.1Srilliglocal function num(s)
351.1Srillig  if s == nil then return nil end
361.1Srillig  return tonumber(s)
371.1Srilligend
381.1Srillig
391.1Srillig
401.1Srillig-- After each macro ARGC, there must be the corresponding macros for ARG.
411.6Srilliglocal function check_args()
421.1Srillig  local fname = "curses_commands.c"
431.1Srillig  local lines = load_lines(fname)
441.4Srillig  local curr_argc, curr_arg ---@type number|nil, number|nil
451.1Srillig
461.1Srillig  for lineno, line in ipairs(lines) do
471.1Srillig
481.5Srillig    local line_argc = num(line:match("^\tARGC%((%d+)"))
491.4Srillig    if line_argc and line_argc > 0 then
501.4Srillig      curr_argc, curr_arg = line_argc, 0
511.5Srillig      goto next
521.1Srillig    end
531.1Srillig
541.5Srillig    local line_arg = line:match("^\tARG_[%w_]+%(")
551.5Srillig    if line_arg and curr_arg then
561.5Srillig      curr_arg = curr_arg + 1
571.5Srillig      if curr_arg == curr_argc then
581.5Srillig        curr_argc, curr_arg = nil, nil
591.5Srillig      end
601.5Srillig    elseif line_arg then
611.6Srillig      print_error("%s:%d: ARG without preceding ARGC", fname, lineno)
621.5Srillig    elseif curr_arg then
631.6Srillig      print_error("%s:%d: expecting ARG %d, got %s",
641.4Srillig        fname, lineno, curr_arg, line)
651.4Srillig      curr_argc, curr_arg = nil, nil
661.1Srillig    end
671.1Srillig
681.5Srillig    ::next::
691.1Srillig  end
701.1Srilligend
711.1Srillig
721.6Srilligcheck_args()
731.6Srilligos.exit(not had_errors)
74