/*
* Curses binding for Lua 5.1, 5.2 & 5.3.
*
* (c) Gary V. Vaughan <gary@vaughan.pe> 2013-2017
* (c) Reuben Thomas <rrt@sc3d.org> 2009-2012
* (c) Tiago Dionizio <tiago.dionizio AT gmail.com> 2004-2007
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/***
Curses attributed string buffers.
An array of characters, plus associated curses attributes and
colors at each position.
Although marginally useful alone, the constants used to set colors
and attributes in `chstr` buffers are not defined until **after**
`curses.initscr ()` has been called.
@classmod curses.chstr
*/
#ifndef LCURSES_CHSTR_C
#define LCURSES_CHSTR_C 1
#include "_helpers.c"
static const char *CHSTRMETA = "curses:chstr";
typedef struct
{
unsigned int len;
chtype str[1];
} chstr;
#define CHSTR_SIZE(len) (sizeof(chstr) + len * sizeof(chtype))
/* create new chstr object and leave it in the lua stack */
static chstr *
chstr_new(lua_State *L, int len)
{
chstr *cs;
if (len < 1)
return luaL_error(L, "invalid chstr length"), NULL;
cs = lua_newuserdata(L, CHSTR_SIZE(len));
luaL_getmetatable(L, CHSTRMETA);
lua_setmetatable(L, -2);
cs->len = len;
return cs;
}
/* get chstr from lua (convert if needed) */
static chstr *
checkchstr(lua_State *L, int narg)
{
chstr *cs = (chstr*)luaL_checkudata(L, narg, CHSTRMETA);
if (cs)
return cs;
luaL_argerror(L, narg, "bad curses chstr");
/*NOTREACHED*/
return NULL;
}
/***
Change the contents of the chstr.
@function set_str
@int o offset to start of change
@string s characters to insert into *cs* at *o*
@int[opt=A_NORMAL] attr attributes for changed elements
@int[opt=1] rep repeat count
@usage
cs = curses.chstr (10)
cs:set_str(0, "0123456789", curses.A_BOLD)
*/
static int
Cset_str(lua_State *L)
{
chstr *cs = checkchstr(L, 1);
int offset = checkint(L, 2);
const char *str = luaL_checkstring(L, 3);
int len = lua_strlen(L, 3);
int attr = optint(L, 4, A_NORMAL);
int rep = optint(L, 5, 1);
int i;
if (offset < 0)
return 0;
while (rep-- > 0 && offset <= (int)cs->len)
{
if (offset + len - 1 > (int)cs->len)
len = cs->len - offset + 1;
for (i = 0; i < len; ++i)
cs->str[offset + i] = str[i] | attr;
offset += len;
}
return 0;
}
/***
Set a character in the buffer.
*ch* can be a one-character string, or an integer from `string.byte`
@function set_ch
@int o offset to start of change
@param int|string ch character to insert
@int[opt=A_NORMAL] attr attributes for changed elements
@int[opt=1] rep repeat count
@usage
-- Write a bold 'A' followed by normal 'a' chars to a new buffer
size = 10
cs = curses.chstr (size)
cs:set_ch(0, 'A', curses.A_BOLD)
cs:set_ch(1, 'a', curses.A_NORMAL, size - 1)
*/
static int
Cset_ch(lua_State *L)
{
chstr* cs = checkchstr(L, 1);
int offset = checkint(L, 2);
chtype ch = checkch(L, 3);
int attr = optint(L, 4, A_NORMAL);
int rep = optint(L, 5, 1);
while (rep-- > 0)
{
if (offset < 0 || offset >= (int) cs->len)
return 0;
cs->str[offset] = ch | attr;
++offset;
}
return 0;
}
/***
Get information from the chstr.
@function get
@int o offset from start of *cs*
@treturn int character at offset *o* in *cs*
@treturn int bitwise-OR of attributes at offset *o* in *cs*
@treturn int colorpair at offset *o* in *cs*
@usage
cs = curses.chstr (10)
cs:set_ch(0, 'A', curses.A_BOLD, 10)
--> 65 2097152 0
print (cs:get (9))
*/
static int
Cget(lua_State *L)
{
chstr* cs = checkchstr(L, 1);
int offset = checkint(L, 2);
chtype ch;
if (offset < 0 || offset >= (int) cs->len)
return 0;
ch = cs->str[offset];
lua_pushinteger(L, ch & A_CHARTEXT);
lua_pushinteger(L, ch & A_ATTRIBUTES);
lua_pushinteger(L, ch & A_COLOR);
return 3;
}
/***
Retrieve chstr length.
@function len
@tparam chstr cs buffer to act on
@treturn int length of *cs*
@usage
cs = curses.chstr (123)
--> 123
print (cs:len ())
*/
static int
Clen(lua_State *L)
{
chstr *cs = checkchstr(L, 1);
return pushintresult(cs->len);
}
/***
Duplicate chstr.
@function dup
@treturn chstr duplicate of *cs*
@usage
dup = cs:dup ()
*/
static int
Cdup(lua_State *L)
{
chstr *cs = checkchstr(L, 1);
chstr *ncs = chstr_new(L, cs->len);
memcpy(ncs->str, cs->str, CHSTR_SIZE(cs->len));
return 1;
}
/***
Initialise a new chstr.
@function __call
@int len buffer length
@treturn chstr a new chstr filled with spaces
@usage
cs = curses.chstr (10)
*/
static int
C__call(lua_State *L)
{
int len = checkint(L, 2);
chstr* ncs = chstr_new(L, len);
memset(ncs->str, ' ', len * sizeof(chtype));
return 1;
}
static const luaL_Reg curses_chstr_fns[] =
{
LCURSES_FUNC( Clen ),
LCURSES_FUNC( Cset_ch ),
LCURSES_FUNC( Cset_str ),
LCURSES_FUNC( Cget ),
LCURSES_FUNC( Cdup ),
{ NULL, NULL }
};
LUALIB_API int
luaopen_curses_chstr(lua_State *L)
{
int t, mt;
luaL_register(L, "curses.chstr", curses_chstr_fns);
t = lua_gettop(L);
lua_createtable(L, 0, 1); /* u = {} */
lua_pushcfunction(L, C__call);
lua_setfield(L, -2, "__call"); /* u.__call = C__call */
lua_setmetatable(L, -2); /* setmetatable (t, u) */
luaL_newmetatable(L, CHSTRMETA);
mt = lua_gettop(L);
lua_pushvalue(L, mt);
lua_setfield(L, -2, "__index"); /* mt.__index = mt */
lua_pushliteral(L, "CursesChstr");
lua_setfield(L, -2, "_type"); /* mt._type = "CursesChstr" */
/* for k,v in pairs(t) do mt[k]=v end */
for (lua_pushnil(L); lua_next(L, t) != 0;)
lua_setfield(L, mt, lua_tostring(L, -2));
lua_pop(L, 1); /* pop mt */
return 1;
}
#endif /*!LCURSES_CHSTR_C*/