Permalink
Browse files

add enum handling as blind memory copies.

  • Loading branch information...
1 parent f9c09ad commit f16dd0065459f9f81f26acdebe2dd620a81c6117 @boucman boucman committed Mar 11, 2013
Showing with 309 additions and 5 deletions.
  1. +44 −4 README.md
  2. +36 −0 demos/demo_enum.c
  3. +35 −0 include/lautoc.h
  4. +3 −1 src/lautoc.c
  5. +183 −0 src/lautoc_enum.c
  6. +8 −0 src/lautoc_stack.c
View
@@ -336,16 +336,56 @@ luaA_function_void(print_int_list, 2, int_list, int);
As you can probably see, automatic wrapping and type conversion becomes hard when memory management and pointers are involved.
+Using Enums
+------------
+
+Enums are transformed into strings. To handle enums you need to first register them, then register the different values as mapping from string to the appropriate value. For each string you can declare independently if it is case-sensitive or not. You can also register multiple strings for a single enum value. Any matching lua string will be transformed into the union value, but the first correct value will be used when tranforming from C to lua
+```c
+#include <stdio.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lautoc.h"
+
+typedef enum {
+ case_sensitive,
+ case_insensitive,
+ not_contiguous =45,
+} enum_val;
+
+int main(int argc, char **argv) {
+
+ lua_State* L = luaL_newstate();
+ luaA_open();
+
+ luaA_enum(L,enum_val);
+ luaA_enum_value(L,enum_val,case_sensitive,true);
+ luaA_enum_value(L,enum_val,case_insensitive,false);
+ luaA_enum_value(L,enum_val,not_contiguous,false);
+ luaA_enum_value_name(L,enum_val,case_sensitive,"alias_sensitive",true);
+
+ enum_val test_enum = not_contiguous;
+ luaA_push(L,enum_val,&test_enum);
+ printf("not_contiguous pushed as %s\n",lua_tostring(L,-1));
+
+ lua_pushstring(L,"alias_sensitive");
+ luaA_to(L,enum_val,&test_enum);
+ printf("alias_sensitive read back as %d\n",test_enum);
+
+ luaA_close();
+ lua_close(L);
+
+ return 0;
+}
+```
+
FAQ
---
* How do unions work?
They work the same way as structs. All the luaA_struct functions should be fine to use on them. Like in C though, accessing them "incorrectly" in Lua will result in the raw data being interpreted differently. Lua AutoC doesn't do any clever checking for you.
-* How do enums work?
-
- Enums work like any other type and the best way to deal with them is to write an explicit conversion function. There is no real way to know what storage type compilers will pick for an enum, it could be a unsigned char, signed int, long or anything else. If though, you are sure what storage type the compiler is using for a particular enum, it might be easier to just use that as the registered type and get a conversion for free.
* Does this work on Linux/Mac/Windows?
@@ -361,4 +401,4 @@ FAQ
There are certainly some macro tricks going on, but most of them are pretty simple and nothing to gruesome - they are just there to save you typing. I use my similar library PyAutoC to wrap my game engine Corange (~10000 LOC, ~1000 functions) without any issues. If you are worried send me an email and I'll explain the internals so that you can decide for yourself. I've also written a short blog post on the nitty details [here](http://theorangeduck.com/page/autoc-tools).
-
+
View
@@ -0,0 +1,36 @@
+#include <stdio.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lautoc.h"
+
+typedef enum {
+ case_sensitive,
+ case_insensitive,
+ not_contiguous =45,
+} enum_val;
+
+int main(int argc, char **argv) {
+
+ lua_State* L = luaL_newstate();
+ luaA_open();
+
+ luaA_enum(L,enum_val);
+ luaA_enum_value(L,enum_val,case_sensitive,true);
+ luaA_enum_value(L,enum_val,case_insensitive,false);
+ luaA_enum_value(L,enum_val,not_contiguous,false);
+ luaA_enum_value_name(L,enum_val,case_sensitive,"alias_sensitive",true);
+
+ enum_val test_enum = not_contiguous;
+ luaA_push(L,enum_val,&test_enum);
+ printf("not_contiguous pushed as %s\n",lua_tostring(L,-1));
+
+ lua_pushstring(L,"alias_sensitive");
+ luaA_to(L,enum_val,&test_enum,-1);
+ printf("alias_sensitive read back as %d\n",test_enum);
+
+ luaA_close();
+ lua_close(L);
+
+ return 0;
+}
View
@@ -150,6 +150,41 @@ bool luaA_struct_registered_typeid(lua_State* L, luaA_Type type);
int luaA_struct_push_typeid(lua_State* L, luaA_Type type,const void* c_in);
void luaA_struct_to_typeid(lua_State* L, luaA_Type type, void* c_out, int index);
+/*
+ ** enum function
+ */
+void luaA_enum_open(void);
+void luaA_enum_close(void);
+/* push and inspect enum members */
+#define luaA_enum_push(L,type,value) luaA_enum_push_typeid(L,luaA_type_id(type),value)
+int luaA_enum_push_typeid(lua_State *L, luaA_Type type, const void* value);
+
+#define luaA_enum_to(L,type,ptr,index) luaA_enum_to_typeid(L,luaA_type_id(type),ptr,index)
+void luaA_enum_to_typeid(lua_State* L, luaA_Type type, void *c_in,int index);
+
+#define luaA_enum_has_value(L,type,value) LuaA_enum_has_value_typeid(L,luaA_type_id(type),value)
+#define luaA_enum_has_name(L,type,value) LuaA_enum_has_name_typeid(L,luaA_type_id(type),value)
+bool luaA_enum_has_value_typeid(lua_State* L, luaA_Type type, const void* value);
+bool luaA_enum_has_name_typeid(lua_State* L, luaA_Type type, const char* name);
+
+#define luaA_enum(L,type) luaA_enum_typeid(L,luaA_type_id(type),sizeof(type))
+#define luaA_enum_value(L,type,value,case_sensitive) do{\
+ type _var; \
+ _var = value; \
+ luaA_enum_value_typeid_name(L,luaA_type_id(type),&_var,#value,case_sensitive); \
+}while(0)
+#define luaA_enum_value_name(L,type,value,name,case_sensitive) do{ \
+ type _var; \
+ _var = value; \
+ luaA_enum_value_typeid_name(L,luaA_type_id(type),&_var,name,case_sensitive); \
+}while(0)
+
+void luaA_enum_typeid(lua_State *L,luaA_Type type,size_t size);
+void luaA_enum_value_typeid_name(lua_State *L, luaA_Type type, const void* value, const char*value_name,bool case_sensitive);
+
+bool luaA_enum_registered_typeid(lua_State *L, luaA_Type type);
+
+
/*
** function calling and registration
View
@@ -4,12 +4,14 @@ void luaA_open(void) {
luaA_type_open();
luaA_stack_open();
luaA_struct_open();
+ luaA_enum_open();
luaA_call_open();
}
void luaA_close(void) {
luaA_call_close();
+ luaA_enum_close();
luaA_struct_close();
luaA_stack_close();
luaA_type_close();
-}
+}
View
@@ -0,0 +1,183 @@
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lautoc.h"
+
+typedef struct enum_entry{
+ void* value;
+ bool case_sensitive;
+ char* name;
+ struct enum_entry*next;
+} enum_entry;
+
+typedef struct enum_type{
+ luaA_Type type;
+ size_t size;
+ struct enum_entry*first;
+} enum_type;
+
+static luaA_Hashtable* enum_table = NULL;
+
+void luaA_enum_open(void) {
+ enum_table = luaA_hashtable_new(256);
+}
+
+static void enum_entry_delete(enum_entry* ee) {
+ if(!ee) return;
+ enum_entry_delete(ee->next);
+ free(ee->name);
+ free(ee->value);
+ free(ee);
+
+}
+
+static void enum_type_delete(enum_type* et) {
+ if(!et) return;
+ enum_entry_delete(et->first);
+ free(et);
+
+}
+
+void luaA_enum_close(void) {
+
+ luaA_hashtable_map(enum_table, (void(*)(void*))enum_type_delete);
+ luaA_hashtable_delete(enum_table);
+
+}
+
+
+int luaA_enum_push_typeid(lua_State *L, luaA_Type type, const void * cin){
+
+ enum_type* et = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if (et != NULL) {
+ enum_entry * ee = et->first;
+ while(ee) {
+ if(!memcmp(cin,ee->value,et->size)){
+ lua_pushstring(L,ee->name);
+ return 1;
+ }
+ ee = ee->next;
+ }
+
+
+ lua_pushfstring(L, "luaA_enum_push_value: value '%d' not registered for enum '%s'!", *(int*)cin, luaA_type_name(type));
+ lua_error(L);
+ }
+
+ lua_pushfstring(L, "luaA_enum_push_value: Enum '%s' not registered!", luaA_type_name(type));
+ lua_error(L);
+ return 0;
+}
+
+
+void luaA_enum_to_typeid(lua_State* L, luaA_Type type, void *c_in,int index) {
+
+ enum_type* et = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if(!lua_isstring(L,index) || lua_isnumber(L,index)) { // we don't want numbers here at all
+ lua_pushfstring(L,"lua_enum_to_value: incorrect value passed '%s'",luaL_tolstring(L,index,NULL));
+ lua_error(L);
+ }
+ const char* value = lua_tostring(L,index);
+
+ if (et != NULL) {
+ enum_entry * ee = et->first;
+ while(ee) {
+ if(ee->case_sensitive && !strcmp(ee->name, value)){
+ memcpy(c_in,ee->value,et->size);
+ return;
+ } else if(!ee->case_sensitive && !strcasecmp(ee->name, value)){
+ memcpy(c_in,ee->value,et->size);
+ return;
+ }
+ ee = ee->next;
+ }
+
+
+ lua_pushfstring(L, "luaA_enum_to_value: name '%s' not registered for enum '%s'!", value, luaA_type_name(type));
+ lua_error(L);
+ }
+
+ lua_pushfstring(L, "luaA_enum_push_value: Enum '%s' not registered!", luaA_type_name(type));
+ lua_error(L);
+}
+
+bool luaA_enum_has_value_typeid(lua_State* L, luaA_Type type, const void* value) {
+
+ enum_type* et = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if (et != NULL) {
+ enum_entry * ee = et->first;
+ while(ee) {
+ if(memcmp(ee->value,value,et->size)) {
+ return true;
+ }
+ ee = ee->next;
+ }
+ return false;
+ }
+
+ lua_pushfstring(L, "luaA_enum_has_value: Enum '%s' not registered!", luaA_type_name(type));
+ lua_error(L);
+ return false;
+}
+
+
+bool luaA_enum_has_name_typeid(lua_State* L, luaA_Type type, const char* name){
+
+ enum_type* et = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if (et != NULL) {
+ enum_entry * ee = et->first;
+ while(ee) {
+ if(ee->case_sensitive && strcmp(ee->name, name)){
+ return true;
+ } else if(!ee->case_sensitive && strcasecmp(ee->name, name)){
+ return true;
+ }
+ ee = ee->next;
+ }
+ return false;
+ }
+
+ lua_pushfstring(L, "luaA_enum_has_name: Enum '%s' not registered!", luaA_type_name(type));
+ lua_error(L);
+ return false;
+}
+
+void luaA_enum_typeid(lua_State *L,luaA_Type type,size_t size) {
+ enum_type* et = malloc(sizeof(enum_type));
+ et->type = type;
+ et->first = NULL;
+ et->size = size;
+ luaA_hashtable_set(enum_table,luaA_type_name(type),et);
+}
+void luaA_enum_value_typeid_name(lua_State *L, luaA_Type type, const void* value, const char*value_name,bool case_sensitive){
+ enum_type* et = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if (et != NULL) {
+ enum_entry* ee = malloc(sizeof(enum_entry));
+ ee->value = malloc(et->size);
+ memcpy(ee->value,value,et->size);
+ ee->name = strdup(value_name);
+ ee->case_sensitive = case_sensitive;
+ ee->next =NULL;
+
+ enum_entry* prev_se = et->first;
+ if(prev_se == NULL) {
+ et->first = ee;
+ } else {
+ while(prev_se->next) prev_se = prev_se->next;
+ prev_se->next = ee;
+ }
+ }else {
+ lua_pushfstring(L, "luaA_enum_value: Enum '%s' not registered!", luaA_type_name(type));
+ lua_error(L);
+ }
+}
+
+bool luaA_enum_registered_typeid(lua_State *L, luaA_Type type){
+
+ enum_entry* ee = luaA_hashtable_get(enum_table, luaA_type_name(type));
+ if (ee == NULL) { return false; } else { return true; }
+
+}
View
@@ -67,6 +67,10 @@ int luaA_push_typeid(lua_State* L, luaA_Type type_id,const void* c_in) {
return luaA_struct_push_typeid(L, type_id, c_in);
}
+ if (luaA_enum_registered_typeid(L, type_id)) {
+ return luaA_enum_push_typeid(L, type_id, c_in);
+ }
+
lua_pushfstring(L, "luaA_push: conversion to lua object from type '%s' not registered!", luaA_type_name(type_id));
lua_error(L);
return 0;
@@ -83,6 +87,10 @@ void luaA_to_typeid(lua_State* L, luaA_Type type_id, void* c_out, int index) {
return luaA_struct_to_typeid(L, type_id, c_out, index);
}
+ if (luaA_enum_registered_typeid(L, type_id)) {
+ return luaA_enum_to_typeid(L, type_id, c_out, index);
+ }
+
lua_pushfstring(L, "luaA_to: conversion from lua object to type '%s' not registered!", luaA_type_name(type_id));
lua_error(L);
}

0 comments on commit f16dd00

Please sign in to comment.