diff options
Diffstat (limited to 'util-src')
-rw-r--r-- | util-src/GNUmakefile | 4 | ||||
-rw-r--r-- | util-src/encodings.c | 169 | ||||
-rw-r--r-- | util-src/hashes.c | 114 | ||||
-rw-r--r-- | util-src/makefile | 5 | ||||
-rw-r--r-- | util-src/net.c | 19 | ||||
-rw-r--r-- | util-src/poll.c | 217 | ||||
-rw-r--r-- | util-src/pposix.c | 124 | ||||
-rw-r--r-- | util-src/ringbuffer.c | 141 | ||||
-rw-r--r-- | util-src/signal.c | 49 | ||||
-rw-r--r-- | util-src/struct.c | 422 | ||||
-rw-r--r-- | util-src/time.c | 8 | ||||
-rw-r--r-- | util-src/windows.c | 7 |
12 files changed, 1014 insertions, 265 deletions
diff --git a/util-src/GNUmakefile b/util-src/GNUmakefile index a8b3529f..810f39f7 100644 --- a/util-src/GNUmakefile +++ b/util-src/GNUmakefile @@ -7,7 +7,8 @@ INSTALL_DATA=install -m644 TARGET?=../util/ ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \ - ringbuffer.so time.so poll.so compat.so strbitop.so + ringbuffer.so time.so poll.so compat.so strbitop.so \ + struct.so ifdef RANDOM ALL+=crand.so @@ -24,6 +25,7 @@ install: $(ALL) clean: rm -f $(ALL) $(patsubst %.so,%.o,$(ALL)) +encodings.o: CFLAGS+=$(IDNA_FLAGS) encodings.so: LDLIBS+=$(IDNA_LIBS) hashes.so: LDLIBS+=$(OPENSSL_LIBS) diff --git a/util-src/encodings.c b/util-src/encodings.c index e55a3f44..72264da8 100644 --- a/util-src/encodings.c +++ b/util-src/encodings.c @@ -24,6 +24,9 @@ #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif /***************** BASE64 *****************/ @@ -216,7 +219,7 @@ static const char *utf8_decode(const char *o, int *val) { * Check that a string is valid UTF-8 * Returns NULL if not */ -const char *check_utf8(lua_State *L, int idx, size_t *l) { +static const char *check_utf8(lua_State *L, int idx, size_t *l) { size_t pos, len; const char *s = luaL_checklstring(L, idx, &len); pos = 0; @@ -247,7 +250,7 @@ static int Lutf8_length(lua_State *L) { size_t len; if(!check_utf8(L, 1, &len)) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushliteral(L, "invalid utf8"); return 2; } @@ -268,41 +271,47 @@ static const luaL_Reg Reg_utf8[] = { #include <unicode/usprep.h> #include <unicode/ustring.h> #include <unicode/utrace.h> +#include <unicode/uspoof.h> +#include <unicode/uidna.h> static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) { size_t input_len; int32_t unprepped_len, prepped_len, output_len; const char *input; char output[1024]; + int flags = USPREP_ALLOW_UNASSIGNED; UChar unprepped[1024]; /* Temporary unicode buffer (1024 characters) */ UChar prepped[1024]; UErrorCode err = U_ZERO_ERROR; - if(!lua_isstring(L, 1)) { - lua_pushnil(L); - return 1; - } - - input = lua_tolstring(L, 1, &input_len); + input = luaL_checklstring(L, 1, &input_len); if(input_len >= 1024) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } + /* strict */ + if(!lua_isnoneornil(L, 2)) { + luaL_checktype(L, 2, LUA_TBOOLEAN); + if(lua_toboolean(L, 2)) { + flags = 0; + } + } + u_strFromUTF8(unprepped, 1024, &unprepped_len, input, input_len, &err); if(U_FAILURE(err)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } - prepped_len = usprep_prepare(profile, unprepped, unprepped_len, prepped, 1024, USPREP_ALLOW_UNASSIGNED, NULL, &err); + prepped_len = usprep_prepare(profile, unprepped, unprepped_len, prepped, 1024, flags, NULL, &err); if(U_FAILURE(err)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } else { u_strToUTF8(output, 1024, &output_len, prepped, prepped_len, &err); @@ -310,29 +319,62 @@ static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) if(U_SUCCESS(err) && output_len < 1024) { lua_pushlstring(L, output, output_len); } else { - lua_pushnil(L); + luaL_pushfail(L); } return 1; } } -UStringPrepProfile *icu_nameprep; -UStringPrepProfile *icu_nodeprep; -UStringPrepProfile *icu_resourceprep; -UStringPrepProfile *icu_saslprep; +static UStringPrepProfile *icu_nameprep; +static UStringPrepProfile *icu_nodeprep; +static UStringPrepProfile *icu_resourceprep; +static UStringPrepProfile *icu_saslprep; +static USpoofChecker *icu_spoofcheck; +static UIDNA *icu_idna2008; + +#if (U_ICU_VERSION_MAJOR_NUM < 58) +/* COMPAT */ +#define USPOOF_CONFUSABLE (USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_WHOLE_SCRIPT_CONFUSABLE) +#endif /* initialize global ICU stringprep profiles */ -void init_icu() { +static void init_icu(void) { UErrorCode err = U_ZERO_ERROR; utrace_setLevel(UTRACE_VERBOSE); icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err); icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err); icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err); icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err); + icu_spoofcheck = uspoof_open(&err); + uspoof_setChecks(icu_spoofcheck, USPOOF_CONFUSABLE, &err); + int options = UIDNA_DEFAULT; +#if 0 + /* COMPAT with future Unicode versions */ + options |= UIDNA_ALLOW_UNASSIGNED; +#endif +#if 1 + /* Forbid eg labels starting with _ */ + options |= UIDNA_USE_STD3_RULES; +#endif +#if 0 + /* TODO determine if we need this */ + options |= UIDNA_CHECK_BIDI; +#endif +#if 0 + /* UTS46 makes it sound like these are the responsibility of registrars */ + options |= UIDNA_CHECK_CONTEXTJ; + options |= UIDNA_CHECK_CONTEXTO; +#endif +#if 0 + /* This disables COMPAT with IDNA 2003 */ + options |= UIDNA_NONTRANSITIONAL_TO_ASCII; + options |= UIDNA_NONTRANSITIONAL_TO_UNICODE; +#endif + icu_idna2008 = uidna_openUTS46(options, &err); if(U_FAILURE(err)) { - fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err)); + fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName(err)); } } @@ -362,27 +404,31 @@ static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) { const char *s; char string[1024]; int ret; - - if(!lua_isstring(L, 1)) { - lua_pushnil(L); - return 1; - } + Stringprep_profile_flags flags = 0; s = check_utf8(L, 1, &len); + /* strict */ + if(!lua_isnoneornil(L, 2)) { + luaL_checktype(L, 2, LUA_TBOOLEAN); + if(lua_toboolean(L, 2)) { + flags = STRINGPREP_NO_UNASSIGNED; + } + } + if(s == NULL || len >= 1024 || len != strlen(s)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; /* TODO return error message */ } strcpy(string, s); - ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile); + ret = stringprep(string, 1024, flags, profile); if(ret == STRINGPREP_OK) { lua_pushstring(L, string); return 1; } else { - lua_pushnil(L); + luaL_pushfail(L); return 1; /* TODO return error message */ } } @@ -421,14 +467,15 @@ static int Lidna_to_ascii(lua_State *L) { /** idna.to_ascii(s) */ u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); if(U_FAILURE(err)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } - dest_len = uidna_IDNToASCII(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + dest_len = uidna_nameToASCII(icu_idna2008, ustr, ulen, dest, 256, &info, &err); - if(U_FAILURE(err)) { - lua_pushnil(L); + if(U_FAILURE(err) || info.errors) { + luaL_pushfail(L); return 1; } else { u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); @@ -436,7 +483,7 @@ static int Lidna_to_ascii(lua_State *L) { /** idna.to_ascii(s) */ if(U_SUCCESS(err) && output_len < 1024) { lua_pushlstring(L, output, output_len); } else { - lua_pushnil(L); + luaL_pushfail(L); } return 1; @@ -455,14 +502,15 @@ static int Lidna_to_unicode(lua_State *L) { /** idna.to_unicode(s) */ u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); if(U_FAILURE(err)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } - dest_len = uidna_IDNToUnicode(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + dest_len = uidna_nameToUnicode(icu_idna2008, ustr, ulen, dest, 1024, &info, &err); - if(U_FAILURE(err)) { - lua_pushnil(L); + if(U_FAILURE(err) || info.errors) { + luaL_pushfail(L); return 1; } else { u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); @@ -470,13 +518,47 @@ static int Lidna_to_unicode(lua_State *L) { /** idna.to_unicode(s) */ if(U_SUCCESS(err) && output_len < 1024) { lua_pushlstring(L, output, output_len); } else { - lua_pushnil(L); + luaL_pushfail(L); } return 1; } } +static int Lskeleton(lua_State *L) { + size_t len; + int32_t ulen, dest_len, output_len; + const char *s = luaL_checklstring(L, 1, &len); + UErrorCode err = U_ZERO_ERROR; + UChar ustr[1024]; + UChar dest[1024]; + char output[1024]; + + u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); + + if(U_FAILURE(err)) { + luaL_pushfail(L); + return 1; + } + + dest_len = uspoof_getSkeleton(icu_spoofcheck, 0, ustr, ulen, dest, 1024, &err); + + if(U_FAILURE(err)) { + luaL_pushfail(L); + return 1; + } + + u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); + + if(U_SUCCESS(err)) { + lua_pushlstring(L, output, output_len); + return 1; + } + + luaL_pushfail(L); + return 1; +} + #else /* USE_STRINGPREP_ICU */ /****************** libidn ********************/ @@ -490,7 +572,7 @@ static int Lidna_to_ascii(lua_State *L) { /** idna.to_ascii(s) */ int ret; if(s == NULL || len != strlen(s)) { - lua_pushnil(L); + luaL_pushfail(L); return 1; /* TODO return error message */ } @@ -501,7 +583,7 @@ static int Lidna_to_ascii(lua_State *L) { /** idna.to_ascii(s) */ idn_free(output); return 1; } else { - lua_pushnil(L); + luaL_pushfail(L); idn_free(output); return 1; /* TODO return error message */ } @@ -518,7 +600,7 @@ static int Lidna_to_unicode(lua_State *L) { /** idna.to_unicode(s) */ idn_free(output); return 1; } else { - lua_pushnil(L); + luaL_pushfail(L); idn_free(output); return 1; /* TODO return error message */ } @@ -558,6 +640,13 @@ LUALIB_API int luaopen_util_encodings(lua_State *L) { luaL_setfuncs(L, Reg_utf8, 0); lua_setfield(L, -2, "utf8"); +#ifdef USE_STRINGPREP_ICU + lua_newtable(L); + lua_pushcfunction(L, Lskeleton); + lua_setfield(L, -2, "skeleton"); + lua_setfield(L, -2, "confusable"); +#endif + lua_pushliteral(L, "-3.14"); lua_setfield(L, -2, "version"); return 1; diff --git a/util-src/hashes.c b/util-src/hashes.c index b16eb03f..8eefcd6b 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -27,6 +27,7 @@ typedef unsigned __int32 uint32_t; #include <openssl/sha.h> #include <openssl/md5.h> #include <openssl/hmac.h> +#include <openssl/evp.h> #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) @@ -35,8 +36,8 @@ typedef unsigned __int32 uint32_t; #define HMAC_IPAD 0x36363636 #define HMAC_OPAD 0x5c5c5c5c -const char *hex_tab = "0123456789abcdef"; -void toHex(const unsigned char *in, int length, unsigned char *out) { +static const char *hex_tab = "0123456789abcdef"; +static void toHex(const unsigned char *in, int length, unsigned char *out) { int i; for(i = 0; i < length; i++) { @@ -76,44 +77,6 @@ struct hash_desc { void *ctx, *ctxo; }; -static void hmac(struct hash_desc *desc, const char *key, size_t key_len, - const char *msg, size_t msg_len, unsigned char *result) { - union xory { - unsigned char bytes[64]; - uint32_t quadbytes[16]; - }; - - int i; - unsigned char hashedKey[64]; /* Maximum used digest length */ - union xory k_ipad, k_opad; - - if(key_len > 64) { - desc->Init(desc->ctx); - desc->Update(desc->ctx, key, key_len); - desc->Final(hashedKey, desc->ctx); - key = (const char *)hashedKey; - key_len = desc->digestLength; - } - - memcpy(k_ipad.bytes, key, key_len); - memset(k_ipad.bytes + key_len, 0, 64 - key_len); - memcpy(k_opad.bytes, k_ipad.bytes, 64); - - for(i = 0; i < 16; i++) { - k_ipad.quadbytes[i] ^= HMAC_IPAD; - k_opad.quadbytes[i] ^= HMAC_OPAD; - } - - desc->Init(desc->ctx); - desc->Update(desc->ctx, k_ipad.bytes, 64); - desc->Init(desc->ctxo); - desc->Update(desc->ctxo, k_opad.bytes, 64); - desc->Update(desc->ctx, msg, msg_len); - desc->Final(result, desc->ctx); - desc->Update(desc->ctxo, result, desc->digestLength); - desc->Final(result, desc->ctxo); -} - #define MAKE_HMAC_FUNCTION(myFunc, evp, size, type) \ static int myFunc(lua_State *L) { \ unsigned char hash[size], result[2*size]; \ @@ -137,56 +100,37 @@ MAKE_HMAC_FUNCTION(Lhmac_sha256, EVP_sha256, SHA256_DIGEST_LENGTH, SHA256_CTX) MAKE_HMAC_FUNCTION(Lhmac_sha512, EVP_sha512, SHA512_DIGEST_LENGTH, SHA512_CTX) MAKE_HMAC_FUNCTION(Lhmac_md5, EVP_md5, MD5_DIGEST_LENGTH, MD5_CTX) -static int LscramHi(lua_State *L) { - union xory { - unsigned char bytes[SHA_DIGEST_LENGTH]; - uint32_t quadbytes[SHA_DIGEST_LENGTH / 4]; - }; - int i; - SHA_CTX ctx, ctxo; - unsigned char Ust[SHA_DIGEST_LENGTH]; - union xory Und; - union xory res; - size_t str_len, salt_len; - struct hash_desc desc; - const char *str = luaL_checklstring(L, 1, &str_len); - const char *salt = luaL_checklstring(L, 2, &salt_len); - char *salt2; - const int iter = luaL_checkinteger(L, 3); - - desc.Init = (int (*)(void *))SHA1_Init; - desc.Update = (int (*)(void *, const void *, size_t))SHA1_Update; - desc.Final = (int (*)(unsigned char *, void *))SHA1_Final; - desc.digestLength = SHA_DIGEST_LENGTH; - desc.ctx = &ctx; - desc.ctxo = &ctxo; +static int Lpbkdf2_sha1(lua_State *L) { + unsigned char out[SHA_DIGEST_LENGTH]; - salt2 = malloc(salt_len + 4); + size_t pass_len, salt_len; + const char *pass = luaL_checklstring(L, 1, &pass_len); + const unsigned char *salt = (unsigned char *)luaL_checklstring(L, 2, &salt_len); + const int iter = luaL_checkinteger(L, 3); - if(salt2 == NULL) { - return luaL_error(L, "Out of memory in scramHi"); + if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, EVP_sha1(), SHA_DIGEST_LENGTH, out) == 0) { + return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed"); } - memcpy(salt2, salt, salt_len); - memcpy(salt2 + salt_len, "\0\0\0\1", 4); - hmac(&desc, str, str_len, salt2, salt_len + 4, Ust); - free(salt2); + lua_pushlstring(L, (char *)out, SHA_DIGEST_LENGTH); - memcpy(res.bytes, Ust, sizeof(res)); + return 1; +} - for(i = 1; i < iter; i++) { - int j; - hmac(&desc, str, str_len, (char *)Ust, sizeof(Ust), Und.bytes); - for(j = 0; j < SHA_DIGEST_LENGTH / 4; j++) { - res.quadbytes[j] ^= Und.quadbytes[j]; - } +static int Lpbkdf2_sha256(lua_State *L) { + unsigned char out[SHA256_DIGEST_LENGTH]; - memcpy(Ust, Und.bytes, sizeof(Ust)); - } + size_t pass_len, salt_len; + const char *pass = luaL_checklstring(L, 1, &pass_len); + const unsigned char *salt = (unsigned char *)luaL_checklstring(L, 2, &salt_len); + const int iter = luaL_checkinteger(L, 3); - lua_pushlstring(L, (char *)res.bytes, SHA_DIGEST_LENGTH); + if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, EVP_sha256(), SHA256_DIGEST_LENGTH, out) == 0) { + return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed"); + } + lua_pushlstring(L, (char *)out, SHA256_DIGEST_LENGTH); return 1; } @@ -213,7 +157,9 @@ static const luaL_Reg Reg[] = { { "hmac_sha256", Lhmac_sha256 }, { "hmac_sha512", Lhmac_sha512 }, { "hmac_md5", Lhmac_md5 }, - { "scram_Hi_sha1", LscramHi }, + { "scram_Hi_sha1", Lpbkdf2_sha1 }, /* COMPAT */ + { "pbkdf2_hmac_sha1", Lpbkdf2_sha1 }, + { "pbkdf2_hmac_sha256", Lpbkdf2_sha256 }, { "equals", Lhash_equals }, { NULL, NULL } }; @@ -223,8 +169,12 @@ LUALIB_API int luaopen_util_hashes(lua_State *L) { luaL_checkversion(L); #endif lua_newtable(L); - luaL_setfuncs(L, Reg, 0);; + luaL_setfuncs(L, Reg, 0); lua_pushliteral(L, "-3.14"); lua_setfield(L, -2, "version"); +#ifdef OPENSSL_VERSION + lua_pushstring(L, OpenSSL_version(OPENSSL_VERSION)); + lua_setfield(L, -2, "_LIBCRYPTO_VERSION"); +#endif return 1; } diff --git a/util-src/makefile b/util-src/makefile index 02bad40a..2df837c7 100644 --- a/util-src/makefile +++ b/util-src/makefile @@ -6,7 +6,8 @@ INSTALL_DATA=install -m644 TARGET?=../util/ ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \ - ringbuffer.so time.so poll.so compat.so strbitop.so + ringbuffer.so time.so poll.so compat.so strbitop.so \ + struct.so .ifdef $(RANDOM) ALL+=crand.so @@ -23,6 +24,8 @@ install: $(ALL) clean: rm -f $(ALL) $(patsubst %.so,%.o,$(ALL)) +encodings.o: encodings.c + $(CC) $(CFLAGS) $(IDNA_FLAGS) -c -o $@ $< encodings.so: encodings.o $(LD) $(LDFLAGS) -o $@ $< $(LDLIBS) $(IDNA_LIBS) diff --git a/util-src/net.c b/util-src/net.c index 5f706d81..d786e885 100644 --- a/util-src/net.c +++ b/util-src/net.c @@ -33,10 +33,13 @@ #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif /* Enumerate all locally configured IP addresses */ -const char *const type_strings[] = { +static const char *const type_strings[] = { "both", "ipv4", "ipv6", @@ -46,8 +49,8 @@ const char *const type_strings[] = { static int lc_local_addresses(lua_State *L) { #ifndef _WIN32 /* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */ - const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */ - const long ip4_mask = htonl(0xffff0000); + const uint32_t ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */ + const uint32_t ip4_mask = htonl(0xffff0000); struct ifaddrs *addr = NULL, *a; #endif int n = 1; @@ -59,7 +62,7 @@ static int lc_local_addresses(lua_State *L) { #ifndef _WIN32 if(getifaddrs(&addr) < 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushfstring(L, "getifaddrs failed (%d): %s", errno, strerror(errno)); return 2; @@ -141,14 +144,14 @@ static int lc_pton(lua_State *L) { case -1: errno_ = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno_)); lua_pushinteger(L, errno_); return 3; default: case 0: - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(EINVAL)); lua_pushinteger(L, EINVAL); return 3; @@ -170,7 +173,7 @@ static int lc_ntop(lua_State *L) { family = AF_INET; } else { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(EAFNOSUPPORT)); lua_pushinteger(L, EAFNOSUPPORT); return 3; @@ -179,7 +182,7 @@ static int lc_ntop(lua_State *L) { if(!inet_ntop(family, ipaddr, buf, INET6_ADDRSTRLEN)) { errno_ = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno_)); lua_pushinteger(L, errno_); return 3; diff --git a/util-src/poll.c b/util-src/poll.c index 0ca0cf28..81caa953 100644 --- a/util-src/poll.c +++ b/util-src/poll.c @@ -1,7 +1,7 @@ /* * Lua polling library - * Copyright (C) 2017-2018 Kim Alvefur + * Copyright (C) 2017-2022 Kim Alvefur * * This project is MIT licensed. Please see the * COPYING file in the source package for more information. @@ -12,8 +12,15 @@ #include <string.h> #include <errno.h> -#ifdef __linux__ +#if defined(__linux__) #define USE_EPOLL +#define POLL_BACKEND "epoll" +#elif defined(__unix__) +#define USE_POLL +#define POLL_BACKEND "poll" +#else +#define USE_SELECT +#define POLL_BACKEND "select" #endif #ifdef USE_EPOLL @@ -21,22 +28,28 @@ #ifndef MAX_EVENTS #define MAX_EVENTS 64 #endif -#else +#endif +#ifdef USE_POLL +#include <poll.h> +#ifndef MAX_EVENTS +#define MAX_EVENTS 10000 +#endif +#endif +#ifdef USE_SELECT #include <sys/select.h> #endif #include <lualib.h> #include <lauxlib.h> -#ifdef USE_EPOLL -#define STATE_MT "util.poll<epoll>" -#else -#define STATE_MT "util.poll<select>" -#endif +#define STATE_MT "util.poll<" POLL_BACKEND ">" #if (LUA_VERSION_NUM == 501) #define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2) #endif +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif /* * Structure to keep state for each type of API @@ -46,7 +59,12 @@ typedef struct Lpoll_state { #ifdef USE_EPOLL int epoll_fd; struct epoll_event events[MAX_EVENTS]; -#else +#endif +#ifdef USE_POLL + nfds_t count; + struct pollfd events[MAX_EVENTS]; +#endif +#ifdef USE_SELECT fd_set wantread; fd_set wantwrite; fd_set readable; @@ -59,7 +77,7 @@ typedef struct Lpoll_state { /* * Add an FD to be watched */ -int Ladd(lua_State *L) { +static int Ladd(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); int fd = luaL_checkinteger(L, 2); @@ -67,7 +85,7 @@ int Ladd(lua_State *L) { int wantwrite = lua_toboolean(L, 4); if(fd < 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(EBADF)); lua_pushinteger(L, EBADF); return 3; @@ -84,7 +102,7 @@ int Ladd(lua_State *L) { if(ret < 0) { ret = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ret)); lua_pushinteger(L, ret); return 3; @@ -93,17 +111,44 @@ int Ladd(lua_State *L) { lua_pushboolean(L, 1); return 1; -#else +#endif +#ifdef USE_POLL + + for(nfds_t i = 0; i < state->count; i++) { + if(state->events[i].fd == fd) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EEXIST)); + lua_pushinteger(L, EEXIST); + return 3; + } + } + + if(state->count >= MAX_EVENTS) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EMFILE)); + lua_pushinteger(L, EMFILE); + return 3; + } + + state->events[state->count].fd = fd; + state->events[state->count].events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + state->events[state->count].revents = 0; + state->count++; + + lua_pushboolean(L, 1); + return 1; +#endif +#ifdef USE_SELECT if(fd > FD_SETSIZE) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(EBADF)); lua_pushinteger(L, EBADF); return 3; } if(FD_ISSET(fd, &state->all)) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(EEXIST)); lua_pushinteger(L, EEXIST); return 3; @@ -137,7 +182,7 @@ int Ladd(lua_State *L) { /* * Set events to watch for, readable and/or writable */ -int Lset(lua_State *L) { +static int Lset(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); int fd = luaL_checkinteger(L, 2); @@ -160,18 +205,41 @@ int Lset(lua_State *L) { } else { ret = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ret)); lua_pushinteger(L, ret); return 3; } -#else +#endif +#ifdef USE_POLL + int wantread = lua_toboolean(L, 3); + int wantwrite = lua_toboolean(L, 4); + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + lua_pushboolean(L, 1); + return 1; + } else if(event->fd == -1) { + break; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif +#ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ENOENT)); lua_pushinteger(L, ENOENT); + return 3; } if(!lua_isnoneornil(L, 3)) { @@ -200,7 +268,7 @@ int Lset(lua_State *L) { /* * Remove FDs */ -int Ldel(lua_State *L) { +static int Ldel(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); int fd = luaL_checkinteger(L, 2); @@ -217,18 +285,54 @@ int Ldel(lua_State *L) { } else { ret = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ret)); lua_pushinteger(L, ret); return 3; } -#else +#endif +#ifdef USE_POLL + + if(state->count == 0) { + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; + } + + /* + * Move the last item on top of the removed one + */ + struct pollfd *last = &state->events[state->count - 1]; + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->fd = last->fd; + event->events = last->events; + event->revents = last->revents; + last->fd = -1; + state->count--; + + lua_pushboolean(L, 1); + return 1; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif +#ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ENOENT)); lua_pushinteger(L, ENOENT); + return 3; } FD_CLR(fd, &state->wantread); @@ -247,7 +351,7 @@ int Ldel(lua_State *L) { /* * Check previously manipulated event state for FDs ready for reading or writing */ -int Lpushevent(lua_State *L, struct Lpoll_state *state) { +static int Lpushevent(lua_State *L, struct Lpoll_state *state) { #ifdef USE_EPOLL if(state->processed > 0) { @@ -259,7 +363,24 @@ int Lpushevent(lua_State *L, struct Lpoll_state *state) { return 3; } -#else +#endif +#ifdef USE_POLL + + for(int i = state->processed - 1; i >= 0; i--) { + struct pollfd *event = &state->events[i]; + + if(event->fd != -1 && event->revents != 0) { + lua_pushinteger(L, event->fd); + lua_pushboolean(L, event->revents & (POLLIN | POLLHUP | POLLERR)); + lua_pushboolean(L, event->revents & POLLOUT); + event->revents = 0; + state->processed = i; + return 3; + } + } + +#endif +#ifdef USE_SELECT for(int fd = state->processed + 1; fd < FD_SETSIZE; fd++) { if(FD_ISSET(fd, &state->readable) || FD_ISSET(fd, &state->writable) || FD_ISSET(fd, &state->err)) { @@ -281,7 +402,7 @@ int Lpushevent(lua_State *L, struct Lpoll_state *state) { /* * Wait for event */ -int Lwait(lua_State *L) { +static int Lwait(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); int ret = Lpushevent(L, state); @@ -295,7 +416,11 @@ int Lwait(lua_State *L) { #ifdef USE_EPOLL ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000); -#else +#endif +#ifdef USE_POLL + ret = poll(state->events, state->count, timeout * 1000); +#endif +#ifdef USE_SELECT /* * select(2) mutates the fd_sets passed to it so in order to not * have to recreate it manually every time a copy is made. @@ -312,18 +437,20 @@ int Lwait(lua_State *L) { #endif if(ret == 0) { + /* Is this an error? */ lua_pushnil(L); lua_pushstring(L, "timeout"); return 2; } else if(ret < 0 && errno == EINTR) { + /* Is this an error? */ lua_pushnil(L); lua_pushstring(L, "signal"); return 2; } else if(ret < 0) { ret = errno; - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(ret)); lua_pushinteger(L, ret); return 3; @@ -334,7 +461,11 @@ int Lwait(lua_State *L) { */ #ifdef USE_EPOLL state->processed = ret; -#else +#endif +#ifdef USE_POLL + state->processed = state->count; +#endif +#ifdef USE_SELECT state->processed = -1; #endif return Lpushevent(L, state); @@ -344,7 +475,7 @@ int Lwait(lua_State *L) { /* * Return Epoll FD */ -int Lgetfd(lua_State *L) { +static int Lgetfd(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); lua_pushinteger(L, state->epoll_fd); return 1; @@ -353,7 +484,7 @@ int Lgetfd(lua_State *L) { /* * Close epoll FD */ -int Lgc(lua_State *L) { +static int Lgc(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); if(state->epoll_fd == -1) { @@ -375,7 +506,7 @@ int Lgc(lua_State *L) { /* * String representation */ -int Ltos(lua_State *L) { +static int Ltos(lua_State *L) { struct Lpoll_state *state = luaL_checkudata(L, 1, STATE_MT); lua_pushfstring(L, "%s: %p", STATE_MT, state); return 1; @@ -384,7 +515,7 @@ int Ltos(lua_State *L) { /* * Create a new context */ -int Lnew(lua_State *L) { +static int Lnew(lua_State *L) { /* Allocate state */ Lpoll_state *state = lua_newuserdata(L, sizeof(Lpoll_state)); luaL_setmetatable(L, STATE_MT); @@ -397,14 +528,26 @@ int Lnew(lua_State *L) { int epoll_fd = epoll_create1(EPOLL_CLOEXEC); if(epoll_fd <= 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return 3; } state->epoll_fd = epoll_fd; -#else +#endif +#ifdef USE_POLL + state->processed = -1; + state->count = 0; + + for(nfds_t i = 0; i < MAX_EVENTS; i++) { + state->events[i].fd = -1; + state->events[i].events = 0; + state->events[i].revents = 0; + } + +#endif +#ifdef USE_SELECT FD_ZERO(&state->wantread); FD_ZERO(&state->wantwrite); FD_ZERO(&state->readable); @@ -466,8 +609,12 @@ int luaopen_util_poll(lua_State *L) { lua_setfield(L, -2, #named_error); push_errno(EEXIST); + push_errno(EMFILE); push_errno(ENOENT); + lua_pushliteral(L, POLL_BACKEND); + lua_setfield(L, -2, "api"); + } return 1; } diff --git a/util-src/pposix.c b/util-src/pposix.c index 004f61a6..a8e0720f 100644 --- a/util-src/pposix.c +++ b/util-src/pposix.c @@ -25,14 +25,18 @@ #define _DEFAULT_SOURCE #endif #endif + #if defined(__APPLE__) #ifndef _DARWIN_C_SOURCE #define _DARWIN_C_SOURCE #endif #endif + +#if ! defined(__FreeBSD__) #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif +#endif #include <stdlib.h> #include <math.h> @@ -57,6 +61,12 @@ #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +#if (LUA_VERSION_NUM < 503) +#define lua_isinteger(L, n) lua_isnumber(L, n) +#endif +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif #include <fcntl.h> #if defined(__linux__) @@ -102,7 +112,7 @@ static int lc_daemonize(lua_State *L) { } else if(pid != 0) { /* We are the parent process */ lua_pushboolean(L, 1); - lua_pushnumber(L, pid); + lua_pushinteger(L, pid); return 2; } @@ -133,7 +143,7 @@ static int lc_daemonize(lua_State *L) { /* Syslog support */ -const char *const facility_strings[] = { +static const char *const facility_strings[] = { "auth", #if !(defined(sun) || defined(__sun)) "authpriv", @@ -159,7 +169,7 @@ const char *const facility_strings[] = { "uucp", NULL }; -int facility_constants[] = { +static int facility_constants[] = { LOG_AUTH, #if !(defined(sun) || defined(__sun)) LOG_AUTHPRIV, @@ -195,9 +205,9 @@ int facility_constants[] = { constant. " -- syslog manpage */ -char *syslog_ident = NULL; +static char *syslog_ident = NULL; -int lc_syslog_open(lua_State *L) { +static int lc_syslog_open(lua_State *L) { int facility = luaL_checkoption(L, 2, "daemon", facility_strings); facility = facility_constants[facility]; @@ -213,7 +223,7 @@ int lc_syslog_open(lua_State *L) { return 0; } -const char *const level_strings[] = { +static const char *const level_strings[] = { "debug", "info", "notice", @@ -221,7 +231,7 @@ const char *const level_strings[] = { "error", NULL }; -int level_constants[] = { +static int level_constants[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, @@ -229,7 +239,7 @@ int level_constants[] = { LOG_CRIT, -1 }; -int lc_syslog_log(lua_State *L) { +static int lc_syslog_log(lua_State *L) { int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)]; if(lua_gettop(L) == 3) { @@ -241,7 +251,7 @@ int lc_syslog_log(lua_State *L) { return 0; } -int lc_syslog_close(lua_State *L) { +static int lc_syslog_close(lua_State *L) { (void)L; closelog(); @@ -253,7 +263,7 @@ int lc_syslog_close(lua_State *L) { return 0; } -int lc_syslog_setmask(lua_State *L) { +static int lc_syslog_setmask(lua_State *L) { int level_idx = luaL_checkoption(L, 1, "notice", level_strings); int mask = 0; @@ -267,31 +277,31 @@ int lc_syslog_setmask(lua_State *L) { /* getpid */ -int lc_getpid(lua_State *L) { +static int lc_getpid(lua_State *L) { lua_pushinteger(L, getpid()); return 1; } /* UID/GID functions */ -int lc_getuid(lua_State *L) { +static int lc_getuid(lua_State *L) { lua_pushinteger(L, getuid()); return 1; } -int lc_getgid(lua_State *L) { +static int lc_getgid(lua_State *L) { lua_pushinteger(L, getgid()); return 1; } -int lc_setuid(lua_State *L) { +static int lc_setuid(lua_State *L) { int uid = -1; if(lua_gettop(L) < 1) { return 0; } - if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { + if(!lua_isinteger(L, 1) && lua_tostring(L, 1)) { /* Passed UID is actually a string, so look up the UID */ struct passwd *p; p = getpwnam(lua_tostring(L, 1)); @@ -304,7 +314,7 @@ int lc_setuid(lua_State *L) { uid = p->pw_uid; } else { - uid = lua_tonumber(L, 1); + uid = lua_tointeger(L, 1); } if(uid > -1) { @@ -342,14 +352,14 @@ int lc_setuid(lua_State *L) { return 2; } -int lc_setgid(lua_State *L) { +static int lc_setgid(lua_State *L) { int gid = -1; if(lua_gettop(L) < 1) { return 0; } - if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { + if(!lua_isinteger(L, 1) && lua_tostring(L, 1)) { /* Passed GID is actually a string, so look up the GID */ struct group *g; g = getgrnam(lua_tostring(L, 1)); @@ -362,7 +372,7 @@ int lc_setgid(lua_State *L) { gid = g->gr_gid; } else { - gid = lua_tonumber(L, 1); + gid = lua_tointeger(L, 1); } if(gid > -1) { @@ -400,13 +410,13 @@ int lc_setgid(lua_State *L) { return 2; } -int lc_initgroups(lua_State *L) { +static int lc_initgroups(lua_State *L) { int ret; gid_t gid; struct passwd *p; if(!lua_isstring(L, 1)) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "invalid-username"); return 2; } @@ -414,7 +424,7 @@ int lc_initgroups(lua_State *L) { p = getpwnam(lua_tostring(L, 1)); if(!p) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "no-such-user"); return 2; } @@ -433,7 +443,7 @@ int lc_initgroups(lua_State *L) { break; default: - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "invalid-gid"); return 2; } @@ -443,17 +453,17 @@ int lc_initgroups(lua_State *L) { if(ret) { switch(errno) { case ENOMEM: - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "no-memory"); break; case EPERM: - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "permission-denied"); break; default: - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, "unknown-error"); } } else { @@ -464,7 +474,7 @@ int lc_initgroups(lua_State *L) { return 2; } -int lc_umask(lua_State *L) { +static int lc_umask(lua_State *L) { char old_mode_string[7]; mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8)); @@ -475,7 +485,7 @@ int lc_umask(lua_State *L) { return 1; } -int lc_mkdir(lua_State *L) { +static int lc_mkdir(lua_State *L) { int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); /* mode 775 */ @@ -500,7 +510,7 @@ int lc_mkdir(lua_State *L) { * Example usage: * pposix.setrlimit("NOFILE", 1000, 2000) */ -int string2resource(const char *s) { +static int string2resource(const char *s) { if(!strcmp(s, "CORE")) { return RLIMIT_CORE; } @@ -550,7 +560,7 @@ int string2resource(const char *s) { return -1; } -rlim_t arg_to_rlimit(lua_State *L, int idx, rlim_t current) { +static rlim_t arg_to_rlimit(lua_State *L, int idx, rlim_t current) { switch(lua_type(L, idx)) { case LUA_TSTRING: @@ -571,7 +581,7 @@ rlim_t arg_to_rlimit(lua_State *L, int idx, rlim_t current) { } } -int lc_setrlimit(lua_State *L) { +static int lc_setrlimit(lua_State *L) { struct rlimit lim; int arguments = lua_gettop(L); int rid = -1; @@ -610,7 +620,7 @@ int lc_setrlimit(lua_State *L) { return 1; } -int lc_getrlimit(lua_State *L) { +static int lc_getrlimit(lua_State *L) { int arguments = lua_gettop(L); const char *resource = NULL; int rid = -1; @@ -643,29 +653,29 @@ int lc_getrlimit(lua_State *L) { if(lim.rlim_cur == RLIM_INFINITY) { lua_pushstring(L, "unlimited"); } else { - lua_pushnumber(L, lim.rlim_cur); + lua_pushinteger(L, lim.rlim_cur); } if(lim.rlim_max == RLIM_INFINITY) { lua_pushstring(L, "unlimited"); } else { - lua_pushnumber(L, lim.rlim_max); + lua_pushinteger(L, lim.rlim_max); } return 3; } -int lc_abort(lua_State *L) { +static int lc_abort(lua_State *L) { (void)L; abort(); return 0; } -int lc_uname(lua_State *L) { +static int lc_uname(lua_State *L) { struct utsname uname_info; if(uname(&uname_info) != 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno)); return 2; } @@ -688,14 +698,14 @@ int lc_uname(lua_State *L) { return 1; } -int lc_setenv(lua_State *L) { +static int lc_setenv(lua_State *L) { const char *var = luaL_checkstring(L, 1); const char *value; /* If the second argument is nil or nothing, unset the var */ if(lua_isnoneornil(L, 2)) { if(unsetenv(var) != 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno)); return 2; } @@ -707,7 +717,7 @@ int lc_setenv(lua_State *L) { value = luaL_checkstring(L, 2); if(setenv(var, value, 1) != 0) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(errno)); return 2; } @@ -717,27 +727,34 @@ int lc_setenv(lua_State *L) { } #ifdef WITH_MALLINFO -int lc_meminfo(lua_State *L) { +static int lc_meminfo(lua_State *L) { +#if __GLIBC_PREREQ(2, 33) + struct mallinfo2 info = mallinfo2(); +#define MALLINFO_T size_t +#else struct mallinfo info = mallinfo(); +#define MALLINFO_T unsigned +#endif lua_createtable(L, 0, 5); /* This is the total size of memory allocated with sbrk by malloc, in bytes. */ - lua_pushinteger(L, (unsigned)info.arena); + lua_pushinteger(L, (MALLINFO_T)info.arena); lua_setfield(L, -2, "allocated"); /* This is the total size of memory allocated with mmap, in bytes. */ - lua_pushinteger(L, (unsigned)info.hblkhd); + lua_pushinteger(L, (MALLINFO_T)info.hblkhd); lua_setfield(L, -2, "allocated_mmap"); /* This is the total size of memory occupied by chunks handed out by malloc. */ - lua_pushinteger(L, (unsigned)info.uordblks); + lua_pushinteger(L, (MALLINFO_T)info.uordblks); lua_setfield(L, -2, "used"); /* This is the total size of memory occupied by free (not in use) chunks. */ - lua_pushinteger(L, (unsigned)info.fordblks); + lua_pushinteger(L, (MALLINFO_T)info.fordblks); lua_setfield(L, -2, "unused"); /* This is the size of the top-most releasable chunk that normally borders the end of the heap (i.e., the high end of the virtual address space's data segment). */ - lua_pushinteger(L, (unsigned)info.keepcost); + lua_pushinteger(L, (MALLINFO_T)info.keepcost); lua_setfield(L, -2, "returnable"); return 1; } +#undef MALLINFO_T #endif /* @@ -745,7 +762,7 @@ int lc_meminfo(lua_State *L) { * Attempt to allocate space first * Truncate to original size on failure */ -int lc_atomic_append(lua_State *L) { +static int lc_atomic_append(lua_State *L) { int err; size_t len; @@ -769,7 +786,7 @@ int lc_atomic_append(lua_State *L) { case ENOSPC: /* No space left */ default: /* Other issues */ - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(err)); lua_pushinteger(L, err); return 3; @@ -796,12 +813,19 @@ int lc_atomic_append(lua_State *L) { return luaL_error(L, "atomic_append() failed in ftruncate(): %s", strerror(errno)); } - lua_pushnil(L); + luaL_pushfail(L); lua_pushstring(L, strerror(err)); lua_pushinteger(L, err); return 3; } +static int lc_isatty(lua_State *L) { + FILE *f = *(FILE **) luaL_checkudata(L, 1, LUA_FILEHANDLE); + const int fd = fileno(f); + lua_pushboolean(L, isatty(fd)); + return 1; +} + /* Register functions */ int luaopen_util_pposix(lua_State *L) { @@ -843,6 +867,8 @@ int luaopen_util_pposix(lua_State *L) { { "atomic_append", lc_atomic_append }, + { "isatty", lc_isatty }, + { NULL, NULL } }; diff --git a/util-src/ringbuffer.c b/util-src/ringbuffer.c index 8f9013f7..0f250c12 100644 --- a/util-src/ringbuffer.c +++ b/util-src/ringbuffer.c @@ -2,11 +2,14 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> -#include <stdio.h> #include <lua.h> #include <lauxlib.h> +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif + typedef struct { size_t rpos; /* read position */ size_t wpos; /* write position */ @@ -15,23 +18,67 @@ typedef struct { char buffer[]; } ringbuffer; -char readchar(ringbuffer *b) { - b->blen--; - return b->buffer[(b->rpos++) % b->alen]; +/* Translate absolute idx to a wrapped index within the buffer, + based on current read position */ +static int wrap_pos(const ringbuffer *b, const long idx, long *pos) { + if(idx > (long)b->blen) { + return 0; + } + if(idx + (long)b->rpos > (long)b->alen) { + *pos = idx - (b->alen - b->rpos); + } else { + *pos = b->rpos + idx; + } + return 1; +} + +static int calc_splice_positions(const ringbuffer *b, long start, long end, long *out_start, long *out_end) { + if(start < 0) { + start = 1 + start + b->blen; + } + if(start <= 0) { + start = 1; + } + + if(end < 0) { + end = 1 + end + b->blen; + } + + if(end > (long)b->blen) { + end = b->blen; + } + if(start < 1) { + start = 1; + } + + if(start > end) { + return 0; + } + + start = start - 1; + + if(!wrap_pos(b, start, out_start)) { + return 0; + } + if(!wrap_pos(b, end, out_end)) { + return 0; + } + + return 1; } -void writechar(ringbuffer *b, char c) { +static void writechar(ringbuffer *b, char c) { b->blen++; b->buffer[(b->wpos++) % b->alen] = c; } /* make sure position counters stay within the allocation */ -void modpos(ringbuffer *b) { +static void modpos(ringbuffer *b) { b->rpos = b->rpos % b->alen; b->wpos = b->wpos % b->alen; } -int find(ringbuffer *b, const char *s, size_t l) { +static int find(ringbuffer *b, const char *s, size_t l) { size_t i, j; int m; @@ -64,7 +111,7 @@ int find(ringbuffer *b, const char *s, size_t l) { * Find first position of a substring in buffer * (buffer, string) -> number */ -int rb_find(lua_State *L) { +static int rb_find(lua_State *L) { size_t l, m; ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); const char *s = luaL_checklstring(L, 2, &l); @@ -82,7 +129,7 @@ int rb_find(lua_State *L) { * Move read position forward without returning the data * (buffer, number) -> boolean */ -int rb_discard(lua_State *L) { +static int rb_discard(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); size_t r = luaL_checkinteger(L, 2); @@ -103,13 +150,13 @@ int rb_discard(lua_State *L) { * Read bytes from buffer * (buffer, number, boolean?) -> string */ -int rb_read(lua_State *L) { +static int rb_read(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); size_t r = luaL_checkinteger(L, 2); int peek = lua_toboolean(L, 3); if(r > b->blen) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } @@ -135,7 +182,7 @@ int rb_read(lua_State *L) { * Read buffer until first occurrence of a substring * (buffer, string) -> string */ -int rb_readuntil(lua_State *L) { +static int rb_readuntil(lua_State *L) { size_t l, m; ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); const char *s = luaL_checklstring(L, 2, &l); @@ -154,14 +201,14 @@ int rb_readuntil(lua_State *L) { * Write bytes into the buffer * (buffer, string) -> integer */ -int rb_write(lua_State *L) { +static int rb_write(lua_State *L) { size_t l, w = 0; ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); const char *s = luaL_checklstring(L, 2, &l); /* Does `l` bytes fit? */ if((l + b->blen) > b->alen) { - lua_pushnil(L); + luaL_pushfail(L); return 1; } @@ -177,32 +224,82 @@ int rb_write(lua_State *L) { return 1; } -int rb_tostring(lua_State *L) { +static int rb_tostring(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); lua_pushfstring(L, "ringbuffer: %p %d/%d", b, b->blen, b->alen); return 1; } -int rb_length(lua_State *L) { +static int rb_sub(lua_State *L) { + ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); + + long start = luaL_checkinteger(L, 2); + long end = luaL_optinteger(L, 3, -1); + + long wrapped_start, wrapped_end; + if(!calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) { + lua_pushstring(L, ""); + } else if(wrapped_end <= wrapped_start) { + lua_pushlstring(L, &b->buffer[wrapped_start], b->alen - wrapped_start); + lua_pushlstring(L, b->buffer, wrapped_end); + lua_concat(L, 2); + } else { + lua_pushlstring(L, &b->buffer[wrapped_start], (wrapped_end - wrapped_start)); + } + + return 1; +} + +static int rb_byte(lua_State *L) { + ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); + + long start = luaL_optinteger(L, 2, 1); + long end = luaL_optinteger(L, 3, start); + + long i; + + long wrapped_start, wrapped_end; + if(calc_splice_positions(b, start, end, &wrapped_start, &wrapped_end)) { + if(wrapped_end <= wrapped_start) { + for(i = wrapped_start; i < (long)b->alen; i++) { + lua_pushinteger(L, (unsigned char)b->buffer[i]); + } + for(i = 0; i < wrapped_end; i++) { + lua_pushinteger(L, (unsigned char)b->buffer[i]); + } + return wrapped_end + (b->alen - wrapped_start); + } else { + for(i = wrapped_start; i < wrapped_end; i++) { + lua_pushinteger(L, (unsigned char)b->buffer[i]); + } + return wrapped_end - wrapped_start; + } + } + + return 0; +} + +static int rb_length(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); lua_pushinteger(L, b->blen); return 1; } -int rb_size(lua_State *L) { +static int rb_size(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); lua_pushinteger(L, b->alen); return 1; } -int rb_free(lua_State *L) { +static int rb_free(lua_State *L) { ringbuffer *b = luaL_checkudata(L, 1, "ringbuffer_mt"); lua_pushinteger(L, b->alen - b->blen); return 1; } -int rb_new(lua_State *L) { - size_t size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE)); +static int rb_new(lua_State *L) { + lua_Integer size = luaL_optinteger(L, 1, sysconf(_SC_PAGESIZE)); + luaL_argcheck(L, size > 0, 1, "positive integer expected"); ringbuffer *b = lua_newuserdata(L, sizeof(ringbuffer) + size); b->rpos = 0; @@ -243,6 +340,10 @@ int luaopen_util_ringbuffer(lua_State *L) { lua_setfield(L, -2, "size"); lua_pushcfunction(L, rb_length); lua_setfield(L, -2, "length"); + lua_pushcfunction(L, rb_sub); + lua_setfield(L, -2, "sub"); + lua_pushcfunction(L, rb_byte); + lua_setfield(L, -2, "byte"); lua_pushcfunction(L, rb_free); lua_setfield(L, -2, "free"); } diff --git a/util-src/signal.c b/util-src/signal.c index c696a3a2..1a398fa0 100644 --- a/util-src/signal.c +++ b/util-src/signal.c @@ -39,6 +39,9 @@ #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +#if (LUA_VERSION_NUM < 503) +#define lua_isinteger(L, n) lua_isnumber(L, n) +#endif #ifndef lsig @@ -164,8 +167,8 @@ static lua_Hook Hsig = NULL; static int Hmask = 0; static int Hcount = 0; -int signals[MAX_PENDING_SIGNALS]; -int nsig = 0; +static int signals[MAX_PENDING_SIGNALS]; +static int nsig = 0; static void sighook(lua_State *L, lua_Debug *ar) { (void)ar; @@ -176,7 +179,7 @@ static void sighook(lua_State *L, lua_Debug *ar) { lua_gettable(L, LUA_REGISTRYINDEX); for(int i = 0; i < nsig; i++) { - lua_pushnumber(L, signals[i]); + lua_pushinteger(L, signals[i]); lua_gettable(L, -2); lua_call(L, 0, 0); }; @@ -223,18 +226,18 @@ static int l_signal(lua_State *L) { t = lua_type(L, 1); if(t == LUA_TNUMBER) { - sig = (int) lua_tonumber(L, 1); + sig = (int) lua_tointeger(L, 1); } else if(t == LUA_TSTRING) { lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); lua_pushvalue(L, 1); lua_gettable(L, -2); - if(!lua_isnumber(L, -1)) { + if(!lua_isinteger(L, -1)) { return luaL_error(L, "invalid signal string"); } - sig = (int) lua_tonumber(L, -1); + sig = (int) lua_tointeger(L, -1); lua_pop(L, 1); /* get rid of number we pushed */ } else { luaL_checknumber(L, 1); /* will always error, with good error msg */ @@ -245,9 +248,9 @@ static int l_signal(lua_State *L) { if(args == 1 || lua_isnil(L, 2)) { /* clear handler */ lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushnumber(L, sig); + lua_pushinteger(L, sig); lua_gettable(L, -2); /* return old handler */ - lua_pushnumber(L, sig); + lua_pushinteger(L, sig); lua_pushnil(L); lua_settable(L, -4); lua_remove(L, -2); /* remove LUA_SIGNAL table */ @@ -258,7 +261,7 @@ static int l_signal(lua_State *L) { lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushnumber(L, sig); + lua_pushinteger(L, sig); lua_pushvalue(L, 2); lua_settable(L, -3); @@ -292,15 +295,15 @@ static int l_signal(lua_State *L) { static int l_raise(lua_State *L) { /* int args = lua_gettop(L); */ int t = 0; /* type */ - lua_Number ret; + lua_Integer ret; luaL_checkany(L, 1); t = lua_type(L, 1); if(t == LUA_TNUMBER) { - ret = (lua_Number) raise((int) lua_tonumber(L, 1)); - lua_pushnumber(L, ret); + ret = (lua_Integer) raise((int) lua_tointeger(L, 1)); + lua_pushinteger(L, ret); } else if(t == LUA_TSTRING) { lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); @@ -311,9 +314,9 @@ static int l_raise(lua_State *L) { return luaL_error(L, "invalid signal string"); } - ret = (lua_Number) raise((int) lua_tonumber(L, -1)); + ret = (lua_Integer) raise((int) lua_tointeger(L, -1)); lua_pop(L, 1); /* get rid of number we pushed */ - lua_pushnumber(L, ret); + lua_pushinteger(L, ret); } else { luaL_checknumber(L, 1); /* will always error, with good error msg */ } @@ -334,7 +337,7 @@ static int l_raise(lua_State *L) { static int l_kill(lua_State *L) { int t; /* type */ - lua_Number ret; /* return value */ + lua_Integer ret; /* return value */ luaL_checknumber(L, 1); /* must be int for pid */ luaL_checkany(L, 2); /* check for a second arg */ @@ -342,9 +345,9 @@ static int l_kill(lua_State *L) { t = lua_type(L, 2); if(t == LUA_TNUMBER) { - ret = (lua_Number) kill((int) lua_tonumber(L, 1), - (int) lua_tonumber(L, 2)); - lua_pushnumber(L, ret); + ret = (lua_Integer) kill((int) lua_tointeger(L, 1), + (int) lua_tointeger(L, 2)); + lua_pushinteger(L, ret); } else if(t == LUA_TSTRING) { lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); @@ -355,10 +358,10 @@ static int l_kill(lua_State *L) { return luaL_error(L, "invalid signal string"); } - ret = (lua_Number) kill((int) lua_tonumber(L, 1), - (int) lua_tonumber(L, -1)); + ret = (lua_Integer) kill((int) lua_tointeger(L, 1), + (int) lua_tointeger(L, -1)); lua_pop(L, 1); /* get rid of number we pushed */ - lua_pushnumber(L, ret); + lua_pushinteger(L, ret); } else { luaL_checknumber(L, 2); /* will always error, with good error msg */ } @@ -396,11 +399,11 @@ int luaopen_util_signal(lua_State *L) { while(lua_signals[i].name != NULL) { /* registry table */ lua_pushstring(L, lua_signals[i].name); - lua_pushnumber(L, lua_signals[i].sig); + lua_pushinteger(L, lua_signals[i].sig); lua_settable(L, -3); /* signal table */ lua_pushstring(L, lua_signals[i].name); - lua_pushnumber(L, lua_signals[i].sig); + lua_pushinteger(L, lua_signals[i].sig); lua_settable(L, -5); i++; } diff --git a/util-src/struct.c b/util-src/struct.c new file mode 100644 index 00000000..e80df4e6 --- /dev/null +++ b/util-src/struct.c @@ -0,0 +1,422 @@ +/* +** {====================================================== +** Library for packing/unpacking structures. +** $Id: struct.c,v 1.8 2018/05/16 11:00:23 roberto Exp $ +** See Copyright Notice at the end of this file +** ======================================================= +*/ +/* +** Valid formats: +** > - big endian +** < - little endian +** ![num] - alignment +** x - padding +** b/B - signed/unsigned byte +** h/H - signed/unsigned short +** l/L - signed/unsigned long +** T - size_t +** i/In - signed/unsigned integer with size 'n' (default is size of int) +** cn - sequence of 'n' chars (from/to a string); when packing, n==0 means + the whole string; when unpacking, n==0 means use the previous + read number as the string length +** s - zero-terminated string +** f - float +** d - double +** ' ' - ignored +*/ + + +#include <ctype.h> +#include <limits.h> +#include <stddef.h> +#include <string.h> + + +#include "lua.h" +#include "lauxlib.h" + + +#if (LUA_VERSION_NUM >= 502) + +#define luaL_register(L,n,f) luaL_newlib(L,f) + +#endif + + +/* basic integer type */ +#if !defined(STRUCT_INT) +#define STRUCT_INT long +#endif + +typedef STRUCT_INT Inttype; + +/* corresponding unsigned version */ +typedef unsigned STRUCT_INT Uinttype; + + +/* maximum size (in bytes) for integral types */ +#define MAXINTSIZE 32 + +/* is 'x' a power of 2? */ +#define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0) + +/* dummy structure to get alignment requirements */ +struct cD { + char c; + double d; +}; + + +#define PADDING (sizeof(struct cD) - sizeof(double)) +#define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int)) + + +/* endian options */ +#define BIG 0 +#define LITTLE 1 + + +static union { + int dummy; + char endian; +} const native = {1}; + + +typedef struct Header { + int endian; + int align; +} Header; + + +static int getnum (const char **fmt, int df) { + if (!isdigit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + *((*fmt)++) - '0'; + } while (isdigit(**fmt)); + return a; + } +} + + +#define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1) + + + +static size_t optsize (lua_State *L, char opt, const char **fmt) { + switch (opt) { + case 'B': case 'b': return sizeof(char); + case 'H': case 'h': return sizeof(short); + case 'L': case 'l': return sizeof(long); + case 'T': return sizeof(size_t); + case 'f': return sizeof(float); + case 'd': return sizeof(double); + case 'x': return 1; + case 'c': return getnum(fmt, 1); + case 'i': case 'I': { + int sz = getnum(fmt, sizeof(int)); + if (sz > MAXINTSIZE) + luaL_error(L, "integral size %d is larger than limit of %d", + sz, MAXINTSIZE); + return sz; + } + default: return 0; /* other cases do not need alignment */ + } +} + + +/* +** return number of bytes needed to align an element of size 'size' +** at current position 'len' +*/ +static int gettoalign (size_t len, Header *h, int opt, size_t size) { + if (size == 0 || opt == 'c') return 0; + if (size > (size_t)h->align) + size = h->align; /* respect max. alignment */ + return (size - (len & (size - 1))) & (size - 1); +} + + +/* +** options to control endianess and alignment +*/ +static void controloptions (lua_State *L, int opt, const char **fmt, + Header *h) { + switch (opt) { + case ' ': return; /* ignore white spaces */ + case '>': h->endian = BIG; return; + case '<': h->endian = LITTLE; return; + case '!': { + int a = getnum(fmt, MAXALIGN); + if (!isp2(a)) + luaL_error(L, "alignment %d is not a power of 2", a); + h->align = a; + return; + } + default: { + const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt); + luaL_argerror(L, 1, msg); + } + } +} + + +static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian, + int size) { + lua_Number n = luaL_checknumber(L, arg); + Uinttype value; + char buff[MAXINTSIZE]; + if (n < 0) + value = (Uinttype)(Inttype)n; + else + value = (Uinttype)n; + if (endian == LITTLE) { + int i; + for (i = 0; i < size; i++) { + buff[i] = (value & 0xff); + value >>= 8; + } + } + else { + int i; + for (i = size - 1; i >= 0; i--) { + buff[i] = (value & 0xff); + value >>= 8; + } + } + luaL_addlstring(b, buff, size); +} + + +static void correctbytes (char *b, int size, int endian) { + if (endian != native.endian) { + int i = 0; + while (i < --size) { + char temp = b[i]; + b[i++] = b[size]; + b[size] = temp; + } + } +} + + +static int b_pack (lua_State *L) { + luaL_Buffer b; + const char *fmt = luaL_checkstring(L, 1); + Header h; + int arg = 2; + size_t totalsize = 0; + defaultoptions(&h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + int toalign = gettoalign(totalsize, &h, opt, size); + totalsize += toalign; + while (toalign-- > 0) luaL_addchar(&b, '\0'); + switch (opt) { + case 'b': case 'B': case 'h': case 'H': + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ + putinteger(L, &b, arg++, h.endian, size); + break; + } + case 'x': { + luaL_addchar(&b, '\0'); + break; + } + case 'f': { + float f = (float)luaL_checknumber(L, arg++); + correctbytes((char *)&f, size, h.endian); + luaL_addlstring(&b, (char *)&f, size); + break; + } + case 'd': { + double d = luaL_checknumber(L, arg++); + correctbytes((char *)&d, size, h.endian); + luaL_addlstring(&b, (char *)&d, size); + break; + } + case 'c': case 's': { + size_t l; + const char *s = luaL_checklstring(L, arg++, &l); + if (size == 0) size = l; + luaL_argcheck(L, l >= (size_t)size, arg, "string too short"); + luaL_addlstring(&b, s, size); + if (opt == 's') { + luaL_addchar(&b, '\0'); /* add zero at the end */ + size++; + } + break; + } + default: controloptions(L, opt, &fmt, &h); + } + totalsize += size; + } + luaL_pushresult(&b); + return 1; +} + + +static lua_Number getinteger (const char *buff, int endian, + int issigned, int size) { + Uinttype l = 0; + int i; + if (endian == BIG) { + for (i = 0; i < size; i++) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } + } + else { + for (i = size - 1; i >= 0; i--) { + l <<= 8; + l |= (Uinttype)(unsigned char)buff[i]; + } + } + if (!issigned) + return (lua_Number)l; + else { /* signed format */ + Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1); + if (l & mask) /* negative value? */ + l |= mask; /* signal extension */ + return (lua_Number)(Inttype)l; + } +} + + +static int b_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)luaL_optinteger(L, 3, 1) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + defaultoptions(&h); + while (*fmt) { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + pos += gettoalign(pos, &h, opt, size); + luaL_argcheck(L, size <= ld - pos, 2, "data string too short"); + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + switch (opt) { + case 'b': case 'B': case 'h': case 'H': + case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ + int issigned = islower(opt); + lua_Number res = getinteger(data+pos, h.endian, issigned, size); + lua_pushnumber(L, res); n++; + break; + } + case 'x': { + break; + } + case 'f': { + float f; + memcpy(&f, data+pos, size); + correctbytes((char *)&f, sizeof(f), h.endian); + lua_pushnumber(L, f); n++; + break; + } + case 'd': { + double d; + memcpy(&d, data+pos, size); + correctbytes((char *)&d, sizeof(d), h.endian); + lua_pushnumber(L, d); n++; + break; + } + case 'c': { + if (size == 0) { + if (n == 0 || !lua_isnumber(L, -1)) + luaL_error(L, "format 'c0' needs a previous size"); + size = lua_tonumber(L, -1); + lua_pop(L, 1); n--; + luaL_argcheck(L, size <= ld - pos, 2, "data string too short"); + } + lua_pushlstring(L, data+pos, size); n++; + break; + } + case 's': { + const char *e = (const char *)memchr(data+pos, '\0', ld - pos); + if (e == NULL) + luaL_error(L, "unfinished string in data"); + size = (e - (data+pos)) + 1; + lua_pushlstring(L, data+pos, size - 1); n++; + break; + } + default: controloptions(L, opt, &fmt, &h); + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + + +static int b_size (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t pos = 0; + defaultoptions(&h); + while (*fmt) { + int opt = *fmt++; + size_t size = optsize(L, opt, &fmt); + pos += gettoalign(pos, &h, opt, size); + if (opt == 's') + luaL_argerror(L, 1, "option 's' has no fixed size"); + else if (opt == 'c' && size == 0) + luaL_argerror(L, 1, "option 'c0' has no fixed size"); + if (!isalnum(opt)) + controloptions(L, opt, &fmt, &h); + pos += size; + } + lua_pushinteger(L, pos); + return 1; +} + +/* }====================================================== */ + + + +static const struct luaL_Reg thislib[] = { + {"pack", b_pack}, + {"unpack", b_unpack}, + {"size", b_size}, + {NULL, NULL} +}; + + +LUALIB_API int luaopen_util_struct (lua_State *L); + +LUALIB_API int luaopen_util_struct (lua_State *L) { + luaL_register(L, "struct", thislib); + return 1; +} + + +/****************************************************************************** +* Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved. +* +* 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. +******************************************************************************/ + diff --git a/util-src/time.c b/util-src/time.c index bfad52ee..afef3df5 100644 --- a/util-src/time.c +++ b/util-src/time.c @@ -1,22 +1,22 @@ #ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200809L #endif #include <time.h> #include <lua.h> -lua_Number tv2number(struct timespec *tv) { +static lua_Number tv2number(struct timespec *tv) { return tv->tv_sec + tv->tv_nsec * 1e-9; } -int lc_time_realtime(lua_State *L) { +static int lc_time_realtime(lua_State *L) { struct timespec t; clock_gettime(CLOCK_REALTIME, &t); lua_pushnumber(L, tv2number(&t)); return 1; } -int lc_time_monotonic(lua_State *L) { +static int lc_time_monotonic(lua_State *L) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); lua_pushnumber(L, tv2number(&t)); diff --git a/util-src/windows.c b/util-src/windows.c index 89bec57b..57af79d5 100644 --- a/util-src/windows.c +++ b/util-src/windows.c @@ -22,6 +22,9 @@ #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +#if (LUA_VERSION_NUM < 504) +#define luaL_pushfail lua_pushnil +#endif static int Lget_nameservers(lua_State *L) { char stack_buffer[1024]; // stack allocated buffer @@ -45,14 +48,14 @@ static int Lget_nameservers(lua_State *L) { return 1; } else { - lua_pushnil(L); + luaL_pushfail(L); lua_pushfstring(L, "DnsQueryConfig returned %d", status); return 2; } } static int lerror(lua_State *L, char *string) { - lua_pushnil(L); + luaL_pushfail(L); lua_pushfstring(L, "%s: %d", string, GetLastError()); return 2; } |