From 145d388c1be2d6f2cd0c68c51448c339ed96371b Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavelo@centrum.sk>
Date: Mon, 25 Jul 2011 15:42:39 +0200
Subject: Add checkudata and checkargno functions to lua::state

These can be used by functions to check the saneness of arguments. They throw an exception on
error. In the future, I might add more informative error messages.
---
 src/FbTk/Luamm.cc | 31 +++++++++++++++++++++++++++++++
 src/FbTk/Luamm.hh | 12 ++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/src/FbTk/Luamm.cc b/src/FbTk/Luamm.cc
index 1ef751f..80d0926 100644
--- a/src/FbTk/Luamm.cc
+++ b/src/FbTk/Luamm.cc
@@ -24,6 +24,8 @@
 
 #include "Luamm.hh"
 
+#include <sstream>
+
 namespace lua {
     namespace {
         // keys for storing values in lua registry
@@ -274,6 +276,35 @@ namespace lua {
             throw lua::exception(this);
     }
 
+    void state::checkargno(int argno) throw(lua::check_error)
+    {
+        if(gettop() != argno) {
+            std::ostringstream str;
+            str << "Wrong number of arguments: expected " << argno << ", got " << gettop();
+            throw lua::check_error(str.str());
+        }
+    }
+
+    void *state::checkudata(int narg, const char *tname) throw(lua::check_error, std::bad_alloc)
+    {
+        checkstack(2);
+        stack_sentry s(*this);
+
+        void *p = touserdata(narg);
+        if(p != NULL) {
+            if(getmetatable(narg)) {
+                rawgetfield(REGISTRYINDEX, tname);
+                if(rawequal(-1, -2))
+                    return p;
+                pop(2);
+            }
+        }
+        std::ostringstream str;
+        str << "Invalid argument #" << narg << ": expected " << type_name(TUSERDATA)
+            << ", got " << type_name(type(narg));
+        throw lua::check_error(str.str());
+    }
+
     void state::checkstack(int extra) throw(std::bad_alloc)
     {
         if(not lua_checkstack(cobj, extra))
diff --git a/src/FbTk/Luamm.hh b/src/FbTk/Luamm.hh
index 110ac97..b75fb12 100644
--- a/src/FbTk/Luamm.hh
+++ b/src/FbTk/Luamm.hh
@@ -131,6 +131,14 @@ namespace lua {
         {}
     };
 
+    // thrown by check* functions when they detect an invalid argument
+    class check_error: public std::runtime_error {
+    public:
+        check_error(const std::string &msg)
+            : std::runtime_error(msg)
+        {}
+    };
+
     // a fancy wrapper around lua_State
     class state {
         lua_State *cobj;
@@ -264,6 +272,10 @@ namespace lua {
         // type c, throw everything but the kitchen sink
         // call() is a protected mode call, we don't allow unprotected calls
         void call(int nargs, int nresults, int errfunc = 0);
+        void checkargno(int argno) throw(lua::check_error);
+        void *checkudata(int narg, const char *tname) throw(lua::check_error, std::bad_alloc);
+        template<typename T>
+        T *checkudata(int narg, const char *tname) throw(lua::check_error, std::bad_alloc) { return static_cast<T *>(checkudata(narg, tname)); }
         void concat(int n);
         bool equal(int index1, int index2);
         int gc(int what, int data);
-- 
cgit v0.11.2