]> PatchyGit - patchyircd.git/commitdiff
admin: generate bindings for rpl_ and err_
authorEgor <egor@patchysicp.xyz>
Thu, 12 Feb 2026 14:35:40 +0000 (16:35 +0200)
committerEgor <egor@patchysicp.xyz>
Thu, 12 Feb 2026 14:35:40 +0000 (16:35 +0200)
Makefile.am
configure.ac
lua/init.lua
rplbindings.lua [new file with mode: 0755]
src/admin.cpp
src/common.hpp
src/irc.cpp
src/ircfmt.cpp
src/ircfmt.hpp

index f62c282..43acfad 100644 (file)
@@ -5,6 +5,7 @@ ACLOCAL_AMFLAGS=-I m4 --install
 bin_PROGRAMS = ircd dbtool
 ircd_SOURCES = \
        src/admin.cpp          src/admin.hpp          \
+                              src/admin_rpl.hpp      \
                               src/common.hpp         \
        src/crypt_blowfish.cpp src/crypt_blowfish.hpp \
        src/db.cpp             src/db.hpp             \
@@ -25,11 +26,19 @@ dbtool_SOURCES = \
        src/db.cpp             src/db.hpp             \
        src/dbtool.cpp
 AM_CXXFLAGS = $(WARNINGCXXFLAGS) $(LIBUV_CFLAGS) $(LIBTLS_CFLAGS) $(LUA_CFLAGS)
+AM_CPPFLAGS = -Isrc -I$(srcdir)/src
 LDADD = $(LIBUV_LIBS) $(LIBTLS_LIBS) $(LUA_LIBS) $(SQLITE3_LIBS)
 
+src/admin.$(OBJEXT): src/admin_rpl.hpp
+src/admin_rpl.hpp: src/ircfmt.hpp rplbindings.lua
+       @if test "x$(LUA)" = xno; then echo "No lua interpreter! Please set LUA="; exit 1; fi
+       $(AM_V_GEN)$(LUA) $(srcdir)/rplbindings.lua <$< >$@
+MAINTAINERCLEANFILES = src/admin_rpl.hpp
+
 dist_ircddata_DATA = \
        data/help.example.txt
 dist_ircdlua_DATA = \
+       lua/autojoin.lua \
        lua/channeldump.lua \
        lua/ctcp.lua \
        lua/init.lua \
@@ -47,7 +56,8 @@ EXTRA_DIST = \
        LICENSES/GPL-2.0-or-later.txt \
        LICENSES/MIT.txt \
        LICENSES/Unlicense.txt \
-       libtls.supp
+       libtls.supp \
+       rplbindings.lua
 
 .PHONY: valgrind
 valgrind: ircd
@@ -56,7 +66,7 @@ valgrind: ircd
 .PHONY: pch
 if ENABLE_PCH
 MOSTLYCLEANFILES = common.hpp.$(PCHEXT)
-AM_CPPFLAGS = -Winvalid-pch `test -f common.hpp.$(PCHEXT) && printf $(PCHOPT) "common.hpp"`
+AM_CPPFLAGS += -Winvalid-pch `test -f common.hpp.$(PCHEXT) && printf $(PCHOPT) "common.hpp"`
 common.hpp.$(PCHEXT): src/common.hpp
        $(AM_V_GEN)$(RM) $@; $(CXXCOMPILE) -x c++-header -o $@ $<
 pch: common.hpp.$(PCHEXT)
index d833463..d3c2a68 100644 (file)
@@ -59,4 +59,7 @@ PKG_HAVE_DEFINE_WITH_MODULES(LIBTLS, [libtls])
 PKG_CHECK_MODULES(LUA, [lua5.4])
 PKG_CHECK_MODULES(SQLITE3, [sqlite3])
 
+AC_ARG_VAR([LUA], [the Lua 5.4 interpreter])
+AS_IF([test "x$LUA" = x], [AC_PATH_PROGS([LUA], [lua5.4 lua54], [no])])
+
 AC_OUTPUT
index 252be05..4ecb5f0 100644 (file)
@@ -5,11 +5,11 @@ if not commands then
 end
 function dispatch_command(client, source, command, ...)
        if client.regstate ~= 2 then -- REG_REGISTERED
-               -- TODO: err_notregistered(), sendbuf(client)
+               err_notregistered(client)
                return
        end
        if client.umode & 2 == 0 then -- UMODE_OPER
-               -- TODO: err_noprivileges(), sendbuf(client)
+               err_noprivileges(client)
                return
        end
        commands[command](client, source, command, table.pack(...))
diff --git a/rplbindings.lua b/rplbindings.lua
new file mode 100755 (executable)
index 0000000..6f3ac54
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env lua5.4
+-- Copyright (c) 2026 Egor
+-- SPDX-License-Identifier: GPL-2.0-or-later
+
+-- print line with automatic indentation
+local indent = 0
+local function printlni(format, ...)
+       local s = format:format(...)
+       if s:sub(1, 1) == "}" then
+               indent = indent - 1
+       end
+       io.write(string.rep("\t", indent), format:format(...), "\n")
+       if s:sub(-1) == "{" then
+               indent = indent + 1
+       end
+end
+local check = {
+       ["Client *"] = "ClientRef::check(L, %d)",
+       ["Channel *"] = "ChannelRef::check(L, %d)",
+       ["const char *"] = "luaL_checkstring(L, %d)",
+       ["std::string_view "] = "checkstringview(L, %d)",
+       ["char "] = "luaL_checkstring(L, %d)[0]",
+       ["int "] = "(int)luaL_checkinteger(L, %d)",
+       ["time_t "] = "(time_t)luaL_checkinteger(L, %d)",
+       ["std::span<Client *> "] = "checkclientlist(L, %d)",
+}
+function set(t)
+       local u = {}
+       for i, v in ipairs(t) do u[v] = true end
+       return u
+end
+local blocklist = set{
+       -- unused
+       "rpl_bounce",
+       "rpl_tryagain",
+       "rpl_none",
+       "err_unknownerror",
+       "err_toomanychannels",
+       "err_wasnosuchnick",
+       "err_noorigin",
+       "err_inputtoolong",
+       "err_yourebannedcreep",
+}
+printlni("static void admin_rpl_init(lua_State *L) {")
+printlni("luaL_Reg funcs[] = {")
+for line in io.lines() do
+       local name, fargs = line:match("^void (rpl_[%w_]+)%((.*)%)")
+       if not name then
+               name, fargs = line:match("^void (err_[%w_]+)%((.*)%)")
+       end
+       if name and not blocklist[name] then
+               printlni("{\"%s\", [](lua_State *L) {", name)
+               local aargs = {}
+               local isvoid
+               if fargs == "void" or fargs == "" then
+                       isvoid = true
+                       fargs = "Client *client"
+               end
+               for typename, argname in fargs:gmatch("([^ ,][^,]* %**)([%w_]+)") do
+                       assert(check[typename], name)
+                       aargs[#aargs+1] = argname
+                       printlni("%s%s = %s;", typename, argname, check[typename]:format(#aargs))
+               end
+               assert(aargs[1] == "client")
+               if isvoid then aargs = {} end
+               printlni("return %s(%s), sendbuf(client), 0;", name, table.concat(aargs, ", "))
+               printlni("}},");
+       end
+end
+printlni("{nullptr, nullptr},")
+printlni("};")
+printlni("lua_pushglobaltable(L);")
+printlni("luaL_setfuncs(L, funcs, 0);")
+printlni("lua_pop(L, 1);")
+printlni("}")
index bf47c3d..05419ea 100644 (file)
@@ -151,6 +151,10 @@ struct ClientRef {
        static Client *check(lua_State *L, int idx) {
                return static_cast<ClientRef *>(luaL_checkudata(L, idx, mtname))->cl;
        }
+       static Client *test(lua_State *L, int idx) {
+               auto ref = static_cast<ClientRef *>(luaL_testudata(L, idx, mtname));
+               return ref ? ref->cl : 0;
+       }
        int index(lua_State *L) {
                auto key = checkstringview(L, 2);
                if (!cl)
@@ -376,13 +380,6 @@ static int fn_client_chghost(lua_State *L)
        client_chghost(cl, newusername, newhostname);
        return 0;
 }
-static int fn_rpl_whoisspecial(lua_State *L) {
-       Client *cl1 = ClientRef::check(L, 1);
-       Client *cl2 = ClientRef::check(L, 2);
-       const char *text = luaL_checkstring(L, 3);
-       rpl_whoisspecial(cl1, cl2, "", text), sendbuf(cl1);
-       return 0;
-}
 static int fn_getdatafile(lua_State *L) {
        const char *fn = luaL_checkstring(L, 1);
        const char *res = getdatafile(fn);
@@ -442,7 +439,19 @@ static int fn_querydisk(lua_State *L) {
 static int fn_querymemory(lua_State *L) {
        return query(L, db::memory);
 }
-
+static std::span<Client *> checkclientlist(lua_State *L, int idx) {
+       lua_Integer len = luaL_len(L, idx);
+       Client **p = static_cast<Client **>(lua_newuserdatauv(L, len*sizeof(Client *), 0));
+       for (lua_Integer i = 0; i < len; i++) {
+               lua_geti(L, idx, i+1);
+               p[i] = ClientRef::test(L, -1);
+               if (!p[i])
+                       luaL_error(L, "expected a Set<Client> at index #%d", i+1);
+               lua_pop(L, 1);
+       }
+       return std::span(p, p + len);
+}
+#include "admin_rpl.hpp"
 void admin_init(void)
 {
        lua_State *L = luaL_newstate();
@@ -476,7 +485,6 @@ void admin_init(void)
                        {"channel_mode", fn_channel_mode},
                        {"channel_topic", fn_channel_topic},
                        {"client_chghost", fn_client_chghost},
-                       {"rpl_whoisspecial", fn_rpl_whoisspecial},
                        {"getdatafile", fn_getdatafile},
                        {"getluafile", fn_getluafile},
                        {"querydisk", fn_querydisk},
@@ -486,6 +494,7 @@ void admin_init(void)
                lua_pushglobaltable(L);
                luaL_setfuncs(L, funcs, 0);
                lua_pop(L, 1);
+               admin_rpl_init(L);
        }
 }
 void admin_fini(void)
index 077a445..4686052 100644 (file)
@@ -36,6 +36,7 @@
 #include <iostream>
 #include <iterator>
 #include <memory>
+#include <span>
 #include <string>
 #include <string_view>
 #include <utility>
index a381faf..d2bec40 100644 (file)
@@ -1028,7 +1028,7 @@ privmsg_notice_common:
                        if (cl)
                                *p++ = cl;
                }
-               rpl_userhost(client, cls, (int)(p - cls));
+               rpl_userhost(client, std::span(cls, p));
                sendbuf(client);
        // User-Based Queries
        } MATCH_COMMAND("WHO") {
index 296b2b2..37c0d98 100644 (file)
@@ -177,15 +177,17 @@ void rpl_none(Client *client, const char *line) { // 300
 void rpl_away(Client *client, Client *cl) { // 301
        num_reply(301, " %s :%s\r\n", cl->nick, cl->away);
 }
-void rpl_userhost(Client *client, Client **cls, int count) { // 302
+void rpl_userhost(Client *client, std::span<Client *> cls) { // 302
        num_reply(302, "");
-       for (int i = 0; i < count; i++) {
+       bool first = true;
+       for (Client *cl : cls) {
                append_strf(&databuf, " %s%s%s=%s%s",
-                               i ? "" : ":",
-                               cls[i]->nick,
-                               cls[i]->umode&UMODE_OPER ? "*" : "",
-                               cls[i]->away ? "-" : "+",
-                               cls[i]->hostname);
+                               first ? ":" : "",
+                               cl->nick,
+                               cl->umode&UMODE_OPER ? "*" : "",
+                               cl->away ? "-" : "+",
+                               cl->hostname);
+               first = false;
        }
        append_str(&databuf, "\r\n");
 }
index 2819699..e25c4a3 100644 (file)
@@ -46,7 +46,7 @@ void rpl_globalusers(Client *client, int current, int max); // 266
 void rpl_whoiscertfp(Client *client, Client *cl, const char *certfp); // 276
 void rpl_none(Client *client, const char *line); // 300
 void rpl_away(Client *client, Client *cl); // 301
-void rpl_userhost(Client *client, Client **cls, int count); // 302
+void rpl_userhost(Client *client, std::span<Client *> cls); // 302
 void rpl_unaway(Client *client); // 305
 void rpl_nowaway(Client *client); // 306
 void rpl_whoreply(Client *client, Client *cl, Channel *chan); // 352