diff options
| author | Hans Hagen <pragma@wxs.nl> | 2022-09-16 15:53:42 +0200 | 
|---|---|---|
| committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2022-09-16 15:53:42 +0200 | 
| commit | c161b7d6fe142231346cc1844e6e27c0ab7718c1 (patch) | |
| tree | 3fd877b8986137703e987e4651a2db8e946a0f72 /source/luametatex/source/luaoptional/lmtsqlite.c | |
| parent | e94fa4dc30ec28a6727aa85e17aaac18b76aeadb (diff) | |
| download | context-c161b7d6fe142231346cc1844e6e27c0ab7718c1.tar.gz | |
2022-09-16 14:41:00
Diffstat (limited to 'source/luametatex/source/luaoptional/lmtsqlite.c')
| -rw-r--r-- | source/luametatex/source/luaoptional/lmtsqlite.c | 228 | 
1 files changed, 228 insertions, 0 deletions
diff --git a/source/luametatex/source/luaoptional/lmtsqlite.c b/source/luametatex/source/luaoptional/lmtsqlite.c new file mode 100644 index 000000000..e6e8f1239 --- /dev/null +++ b/source/luametatex/source/luaoptional/lmtsqlite.c @@ -0,0 +1,228 @@ +/* +    See license.txt in the root of this project. +*/ + +# include "luametatex.h" +# include "lmtoptional.h" + +typedef struct sqlite3_instance sqlite3_instance; + +# define SQLITELIB_METATABLE  "luatex.sqlitelib" + +typedef struct sqlitelib_data { +    /*tex There is not much more than a pointer currently. */ +    sqlite3_instance *db; +} sqlitelib_data ; + +typedef struct sqlitelib_state_info { + +    int initialized; +    int padding; + +    int (*sqlite3_initialize) ( +        void +    ); + +    int (*sqlite3_open) ( +        const char        *filename, +        sqlite3_instance **ppDb +    ); + +    int (*sqlite3_close) ( +        sqlite3_instance * +    ); + +    int (*sqlite3_exec) ( +        sqlite3_instance *, +        const char       *sql, +        int             (*callback)(void*, int, char**, char**), +        void             *, +        char            **errmsg +    ); + +    const char * (*sqlite3_errmsg) ( +        sqlite3_instance * +    ); + +} sqlitelib_state_info; + +static sqlitelib_state_info sqlitelib_state = { + +    .initialized    = 0, +    .padding        = 0, + +    .sqlite3_initialize = NULL, +    .sqlite3_open       = NULL, +    .sqlite3_close      = NULL, +    .sqlite3_exec       = NULL, +    .sqlite3_errmsg     = NULL, + +}; + +static int sqlitelib_initialize(lua_State * L) +{ +    if (! sqlitelib_state.initialized) { +        const char *filename = lua_tostring(L, 1); +        if (filename) { + +            lmt_library lib = lmt_library_load(filename); + +            sqlitelib_state.sqlite3_initialize = lmt_library_find(lib, "sqlite3_initialize"); +            sqlitelib_state.sqlite3_open       = lmt_library_find(lib, "sqlite3_open"); +            sqlitelib_state.sqlite3_close      = lmt_library_find(lib, "sqlite3_close"); +            sqlitelib_state.sqlite3_exec       = lmt_library_find(lib, "sqlite3_exec"); +            sqlitelib_state.sqlite3_errmsg     = lmt_library_find(lib, "sqlite3_errmsg"); + +            sqlitelib_state.initialized = lmt_library_okay(lib); +        } +        if (sqlitelib_state.initialized) { +            sqlitelib_state.sqlite3_initialize(); +        } +    } +    lua_pushboolean(L, sqlitelib_state.initialized); +    return 1; +} + +static int sqlitelib_open(lua_State * L) +{ +    if (sqlitelib_state.initialized) { +        const char *filename = lua_tostring(L, 1); +        if (filename != NULL) { +            sqlitelib_data *data = lua_newuserdatauv(L, sizeof(data), 0); +            if (! sqlitelib_state.sqlite3_open(filename, &(data->db))) { +                luaL_getmetatable(L, SQLITELIB_METATABLE); +                lua_setmetatable(L, -2); +                return 1; +            } +        } +    } +    return 0; +} + +static int sqlitelib_close(lua_State * L) +{ +    if (sqlitelib_state.initialized) { +        sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE); +        if (data != NULL) { +            sqlitelib_state.sqlite3_close(data->db); +            data->db = NULL; +        } +    } +    return 0; +} + +/* we could save the fields in the registry */ + +static int rows_done = 0; /* can go on stack */ + +static int sqlitelib_callback(void * L, int nofcolumns, char **values, char **fields) +{ +    lua_pushvalue(L, -1); +    lua_pushinteger(L, nofcolumns); +    if (nofcolumns > 0 && values != NULL) { +        lua_createtable(L, nofcolumns, 0); +        for (int i = 0; i < nofcolumns; i++) { +            lua_pushstring(L, values[i]); +            lua_rawseti(L, -2, (lua_Integer)i + 1); +        } +        if (! rows_done && fields != NULL) { +            lua_createtable(L, nofcolumns, 0); +            for (int i = 0; i < nofcolumns; i++) { +                lua_pushstring(L, fields[i]); +                lua_rawseti(L, -2, (lua_Integer)i + 1); +            } +            lua_call(L, 3, 0); +        } else { +            lua_call(L, 2, 0); +        } +    } else { +        lua_call(L, 1, 0); +    } +    ++rows_done; +    return 0; +} + +/* execute(database,querystring,callback) : callback(nofcolumns,values,fields)  */ + +static int sqlitelib_execute(lua_State * L) +{ +    if (sqlitelib_state.initialized && ! rows_done) { +        sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE); +        if (data != NULL) { +            const char *query = lua_tostring(L, 2); +            if (query != NULL) { +                int result = 0; +                rows_done = 0; +                if (lua_isfunction(L, 3)) { +                    result = sqlitelib_state.sqlite3_exec(data->db, query, &sqlitelib_callback, L, NULL); +                } else { +                    result = sqlitelib_state.sqlite3_exec(data->db, query, NULL, NULL, NULL); +                } +                rows_done = 0; +                lua_pushboolean(L, ! result); +                return 1; +            } +        } +    } +    lua_pushboolean(L, 0); +    return 1; +} + +static int sqlitelib_getmessage(lua_State * L) +{ +    if (sqlitelib_state.initialized) { +        sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE); +        if (data != NULL) { +            lua_pushstring(L, sqlitelib_state.sqlite3_errmsg(data->db)); +            return 1; +        } +    } +    return 0; +} + +/* private */ + +static int sqlitelib_free(lua_State * L) +{ +    return sqlitelib_close(L); +} + +/* <string> = tostring(instance) */ + +static int sqlitelib_tostring(lua_State * L) +{ +    if (sqlitelib_state.initialized) { +        sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE); +        if (data != NULL) { +            (void) lua_pushfstring(L, "<sqlitelib-instance %p>", data); +        } else { +            lua_pushnil(L); +        } +        return 1; +    } else { +        return 0; +    } +} + +static const struct luaL_Reg sqlitelib_metatable[] = { +    { "__tostring", sqlitelib_tostring }, +    { "__gc",       sqlitelib_free     }, +    { NULL,         NULL               }, +}; + +static struct luaL_Reg sqlitelib_function_list[] = { +    { "initialize", sqlitelib_initialize }, +    { "open",       sqlitelib_open       }, +    { "close",      sqlitelib_close      }, +    { "execute",    sqlitelib_execute    }, +    { "getmessage", sqlitelib_getmessage }, +    { NULL,         NULL                 }, +}; + +int luaopen_sqlite(lua_State * L) +{ +    luaL_newmetatable(L, SQLITELIB_METATABLE); +    luaL_setfuncs(L, sqlitelib_metatable, 0); +    lmt_library_register(L, "sqlite", sqlitelib_function_list); +    return 0; +}  | 
