Blame ext/posix/curses/chstr.c

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