lecholib.c 2.71 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
#include <lua.h>
#include <lauxlib.h>

#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
#include "compat-5.2.h"
#endif

#if defined(_WIN32)

#include <windows.h>

static int getecho(int *active)
{
	HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
	if (hstdin != INVALID_HANDLE_VALUE) {
		DWORD mode;
		if (GetConsoleMode(hstdin, &mode)) {
			*active = (mode & ENABLE_ECHO_INPUT);
			return 0;
		}
	}
	return GetLastError();
}

static int setecho(int active)
{
	HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
	if (hstdin != INVALID_HANDLE_VALUE) {
		DWORD mode;
		if (GetConsoleMode(hstdin, &mode)) {
			mode = active ? (mode | ENABLE_ECHO_INPUT) : (mode & ~ENABLE_ECHO_INPUT);
			if (SetConsoleMode(hstdin, mode)) {
				return 0;
			}
		}
	}
	return GetLastError();
}

static int raiseerror(lua_State *L, int error)
{
	char buffer[256];
	DWORD res = FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|
	                           FORMAT_MESSAGE_FROM_SYSTEM,  /* formatting opts. */
	                           NULL,                        /* ignored */
	                           error,                       /* message id. */
	                           0,                           /* language id. */
	                           buffer,                      /* output buffer */
	                           sizeof(buffer)/sizeof(char), /* buffer size */
	                           NULL);                       /* ignored */
	if (res != 0) {
		DWORD msgerr = GetLastError();
		luaL_error(L, "failed to message for error %d (got error %d)", error, msgerr);
	}
	lua_pushlstring(L, buffer, res);
	lua_error(L);
}

#else

#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <string.h>

static int getecho(int *active)
{
	int fildes = fileno(stdin);
	struct termios opts;
	if (tcgetattr(fildes, &opts) == 0) {
		*active = opts.c_lflag & ECHO;
		return 0;
	}
	return errno;
}

static int setecho(int active)
{
	int fildes = fileno(stdin);
	struct termios opts;
	if (tcgetattr(fildes, &opts) == 0) {
		opts.c_lflag = active ? (opts.c_lflag | ECHO) : (opts.c_lflag & ~ECHO);
		if (tcsetattr(fildes, TCSANOW, &opts) == 0) {
			return 0;
		}
	}
	return errno;
}

static void raiseerror(lua_State *L, int code)
{
	lua_pushstring(L, strerror(code));
	lua_error(L);
}

#endif



static int l_getmode (lua_State *L)
{
	int active;
	int error = getecho(&active);
	if (error) raiseerror(L, error);
	lua_pushboolean(L, active);
	return 1;
}

static int l_setmode (lua_State *L)
{
	int error = setecho(lua_toboolean(L, 1));
	if (error) raiseerror(L, error);
	return 0;
}

static const luaL_Reg funcs[] = {
	{"getecho", l_getmode},
	{"setecho", l_setmode},
	{NULL, NULL}
};


LUAMOD_API int luaopen_openbus_util_echo (lua_State *L) {
	luaL_newlib(L, funcs);
	return 1;
}