aboutsummaryrefslogtreecommitdiffstats
path: root/util-src
diff options
context:
space:
mode:
Diffstat (limited to 'util-src')
-rw-r--r--util-src/GNUmakefile4
-rw-r--r--util-src/encodings.c169
-rw-r--r--util-src/hashes.c114
-rw-r--r--util-src/makefile5
-rw-r--r--util-src/net.c19
-rw-r--r--util-src/poll.c217
-rw-r--r--util-src/pposix.c124
-rw-r--r--util-src/ringbuffer.c141
-rw-r--r--util-src/signal.c49
-rw-r--r--util-src/struct.c422
-rw-r--r--util-src/time.c8
-rw-r--r--util-src/windows.c7
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;
}