Blame ext/posix/time.c

Packit 437b5e
/*
Packit 437b5e
 * POSIX library for Lua 5.1, 5.2 & 5.3.
Packit 437b5e
 * (c) Gary V. Vaughan <gary@vaughan.pe>, 2013-2015
Packit 437b5e
 * (c) Reuben Thomas <rrt@sc3d.org> 2010-2013
Packit 437b5e
 * (c) Natanael Copa <natanael.copa@gmail.com> 2008-2010
Packit 437b5e
 * Clean up and bug fixes by Leo Razoumov <slonik.az@gmail.com> 2006-10-11
Packit 437b5e
 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> 07 Apr 2006 23:17:49
Packit 437b5e
 * Based on original by Claudio Terra for Lua 3.x.
Packit 437b5e
 * With contributions by Roberto Ierusalimschy.
Packit 437b5e
 * With documentation from Steve Donovan 2012
Packit 437b5e
 */
Packit 437b5e
/***
Packit 437b5e
 Time and Clock Functions.
Packit 437b5e
Packit 437b5e
@module posix.time
Packit 437b5e
*/
Packit 437b5e
Packit 437b5e
#include <config.h>
Packit 437b5e
Packit 437b5e
#include <sys/time.h>
Packit 437b5e
#include <time.h>
Packit 437b5e
Packit 437b5e
#include "_helpers.c"
Packit 437b5e
Packit 437b5e
Packit 437b5e
static const char *Stimespec_fields[] = { "tv_sec", "tv_nsec" };
Packit 437b5e
Packit 437b5e
static void
Packit 437b5e
totimespec(lua_State *L, int index, struct timespec *ts)
Packit 437b5e
{
Packit 437b5e
	luaL_checktype(L, index, LUA_TTABLE);
Packit 437b5e
	ts->tv_sec  = optintfield(L, index, "tv_sec", 0);
Packit 437b5e
	ts->tv_nsec = optintfield(L, index, "tv_nsec", 0);
Packit 437b5e
Packit 437b5e
	checkfieldnames(L, index, Stimespec_fields);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Timespec record.
Packit 437b5e
@table PosixTimespec
Packit 437b5e
@int tv_sec seconds
Packit 437b5e
@int tv_nsec nanoseconds
Packit 437b5e
@see posix.sys.time.PosixTimeval
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
pushtimespec(lua_State *L, struct timespec *ts)
Packit 437b5e
{
Packit 437b5e
	if (!ts)
Packit 437b5e
		return lua_pushnil(L), 1;
Packit 437b5e
Packit 437b5e
	lua_createtable(L, 0, 2);
Packit 437b5e
	setintegerfield(ts, tv_sec);
Packit 437b5e
	setintegerfield(ts, tv_nsec);
Packit 437b5e
Packit 437b5e
	settypemetatable("PosixTimespec");
Packit 437b5e
	return 1;
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
static const char *Stm_fields[] = {
Packit 437b5e
  "tm_sec", "tm_min", "tm_hour", "tm_mday", "tm_mon", "tm_year", "tm_wday",
Packit 437b5e
  "tm_yday", "tm_isdst",
Packit 437b5e
};
Packit 437b5e
Packit 437b5e
static void
Packit 437b5e
totm(lua_State *L, int index, struct tm *t)
Packit 437b5e
{
Packit 437b5e
	luaL_checktype(L, index, LUA_TTABLE);
Packit 437b5e
	t->tm_sec   = optintfield(L, index, "tm_sec", 0);
Packit 437b5e
	t->tm_min   = optintfield(L, index, "tm_min", 0);
Packit 437b5e
	t->tm_hour  = optintfield(L, index, "tm_hour", 0);
Packit 437b5e
	t->tm_mday  = optintfield(L, index, "tm_mday", 0);
Packit 437b5e
	t->tm_mon   = optintfield(L, index, "tm_mon", 0);
Packit 437b5e
	t->tm_year  = optintfield(L, index, "tm_year", 0);
Packit 437b5e
	t->tm_wday  = optintfield(L, index, "tm_wday", 0);
Packit 437b5e
	t->tm_yday  = optintfield(L, index, "tm_yday", 0);
Packit 437b5e
	t->tm_isdst = optintfield(L, index, "tm_isdst", 0);
Packit 437b5e
Packit 437b5e
	checkfieldnames(L, index, Stm_fields);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Datetime record.
Packit 437b5e
@table PosixTm
Packit 437b5e
@int tm_sec second [0,60]
Packit 437b5e
@int tm_min minute [0,59]
Packit 437b5e
@int tm_hour hour [0,23]
Packit 437b5e
@int tm_mday day of month [1, 31]
Packit 437b5e
@int tm_mon month of year [0,11]
Packit 437b5e
@int tm_year years since 1900
Packit 437b5e
@int tm_wday day of week [0=Sunday,6]
Packit 437b5e
@int tm_yday day of year [0,365[
Packit 437b5e
@int tm_isdst 0 if daylight savings time is not in effect
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
pushtm(lua_State *L, struct tm *t)
Packit 437b5e
{
Packit 437b5e
	if (!t)
Packit 437b5e
		return lua_pushnil(L), 1;
Packit 437b5e
Packit 437b5e
	lua_createtable(L, 0, 9);
Packit 437b5e
	setintegerfield(t, tm_sec);
Packit 437b5e
	setintegerfield(t, tm_min);
Packit 437b5e
	setintegerfield(t, tm_hour);
Packit 437b5e
	setintegerfield(t, tm_mday);
Packit 437b5e
	setintegerfield(t, tm_mday);
Packit 437b5e
	setintegerfield(t, tm_mon);
Packit 437b5e
	setintegerfield(t, tm_year);
Packit 437b5e
	setintegerfield(t, tm_wday);
Packit 437b5e
	setintegerfield(t, tm_yday);
Packit 437b5e
	setintegerfield(t, tm_isdst);
Packit 437b5e
Packit 437b5e
	settypemetatable("PosixTm");
Packit 437b5e
	return 1;
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
#if defined _XOPEN_REALTIME && _XOPEN_REALTIME != -1
Packit 437b5e
/***
Packit 437b5e
Find the precision of a clock.
Packit 437b5e
@function clock_getres
Packit 437b5e
@int clk name of clock, one of `CLOCK_REALTIME`, `CLOCK_PROCESS_CPUTIME_ID`,
Packit 437b5e
  `CLOCK_MONOTONIC` or `CLOCK_THREAD_CPUTIME_ID`
Packit 437b5e
@treturn[1] PosixTimespec resolution of *clk*, if successful
Packit 437b5e
@return[2] nil
Packit 437b5e
@treturn[2] string error message
Packit 437b5e
@treturn[2] int errnum
Packit 437b5e
@see clock_getres(3)
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pclock_getres(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct timespec resolution;
Packit 437b5e
	int clk = checkint(L, 1);
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	if (clock_getres(clk, &resolution) == -1)
Packit 437b5e
		return pusherror(L, "clock_getres");
Packit 437b5e
	return pushtimespec(L, &resolution);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Read a clock.
Packit 437b5e
@function clock_gettime
Packit 437b5e
@int clk name of clock, one of `CLOCK_REALTIME`, `CLOCK_PROCESS_CPUTIME_ID`,
Packit 437b5e
  `CLOCK_MONOTONIC` or `CLOCK_THREAD_CPUTIME_ID`
Packit 437b5e
@treturn[1] PosixTimespec current value of *clk*, if successful
Packit 437b5e
@return[2] nil
Packit 437b5e
@treturn[2] string error message
Packit 437b5e
@treturn[2] int errnum
Packit 437b5e
@see clock_gettime(3)
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pclock_gettime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct timespec ts;
Packit 437b5e
	int clk = checkint(L, 1);
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	if (clock_gettime(clk, &ts) == -1)
Packit 437b5e
		return pusherror(L, "clock_gettime");
Packit 437b5e
	return pushtimespec(L, &ts);
Packit 437b5e
}
Packit 437b5e
#endif
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Convert epoch time value to a broken-down UTC time.
Packit 437b5e
@function gmtime
Packit 437b5e
@int t seconds since epoch
Packit 437b5e
@treturn PosixTm broken-down time
Packit 437b5e
@see gmtime(3)
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pgmtime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct tm t;
Packit 437b5e
	time_t epoch = checkint(L, 1);
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	if (gmtime_r(&epoch, &t) == NULL)
Packit 437b5e
		return pusherror(L, "gmtime");
Packit 437b5e
	return pushtm(L, &t);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Convert epoch time value to a broken-down local time.
Packit 437b5e
@function localtime
Packit 437b5e
@int t seconds since epoch
Packit 437b5e
@treturn PosixTm broken-down time
Packit 437b5e
@see localtime(3)
Packit 437b5e
@see mktime
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Plocaltime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct tm t;
Packit 437b5e
	time_t epoch = checkint(L, 1);
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	if (localtime_r(&epoch, &t) == NULL)
Packit 437b5e
		return pusherror(L, "localtime");
Packit 437b5e
	return pushtm(L, &t);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Convert a broken-down localtime table into an epoch time.
Packit 437b5e
@function mktime
Packit 437b5e
@tparam PosixTm broken-down localtime
Packit 437b5e
@treturn int seconds since epoch
Packit 437b5e
@see mktime(3)
Packit 437b5e
@see localtime
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pmktime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct tm t;
Packit 437b5e
	time_t epoch;
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	totm(L, 1, &t);
Packit 437b5e
	if ((epoch = mktime(&t)) < 0)
Packit 437b5e
		return 0;
Packit 437b5e
	return pushintresult(epoch);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Sleep with nanosecond precision.
Packit 437b5e
@function nanosleep
Packit 437b5e
@tparam PosixTimespec requested sleep time
Packit 437b5e
@treturn[1] int `0` if requested time has elapsed
Packit 437b5e
@return[2] nil
Packit 437b5e
@treturn[2] string error message
Packit 437b5e
@treturn[2] int errnum
Packit 437b5e
@treturn[2] PosixTimespec unslept time remaining, if interrupted
Packit 437b5e
@see nanosleep(2)
Packit 437b5e
@see posix.unistd.sleep
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pnanosleep(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct timespec req;
Packit 437b5e
	struct timespec rem;
Packit 437b5e
	int r;
Packit 437b5e
Packit 437b5e
	totimespec(L, 1, &req;;
Packit 437b5e
	checknargs(L, 1);
Packit 437b5e
	r = pushresult (L, nanosleep(&req, &rem), "nanosleep");
Packit 437b5e
	if (r == 3 && errno == EINTR)
Packit 437b5e
		r = r + pushtimespec (L, &rem;;
Packit 437b5e
	return r;
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Write a time out according to a format.
Packit 437b5e
@function strftime
Packit 437b5e
@string format specifier with `%` place-holders
Packit 437b5e
@tparam PosixTm tm broken-down local time
Packit 437b5e
@treturn string *format* with place-holders plugged with *tm* values
Packit 437b5e
@see strftime(3)
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pstrftime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	char tmp[256];
Packit 437b5e
	const char *fmt = luaL_checkstring(L, 1);
Packit 437b5e
	struct tm t;
Packit 437b5e
Packit 437b5e
	totm(L, 2, &t);
Packit 437b5e
	checknargs(L, 2);
Packit 437b5e
Packit 437b5e
	strftime(tmp, sizeof(tmp), fmt, &t);
Packit 437b5e
	return pushstringresult(tmp);
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Parse a date string.
Packit 437b5e
@function strptime
Packit 437b5e
@string s
Packit 437b5e
@string format same as for `strftime`
Packit 437b5e
@usage posix.strptime('20','%d').monthday == 20
Packit 437b5e
@treturn[1] PosixTm broken-down local time
Packit 437b5e
@treturn[1] int next index of first character not parsed as part of the date
Packit 437b5e
@return[2] nil
Packit 437b5e
@see strptime(3)
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Pstrptime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	struct tm t;
Packit 437b5e
	const char *s = luaL_checkstring(L, 1);
Packit 437b5e
	const char *fmt = luaL_checkstring(L, 2);
Packit 437b5e
	char *r;
Packit 437b5e
	checknargs(L, 2);
Packit 437b5e
Packit 437b5e
	memset(&t, 0, sizeof(struct tm));
Packit 437b5e
	r = strptime(s, fmt, &t);
Packit 437b5e
	if (r)
Packit 437b5e
	{
Packit 437b5e
		pushtm(L, &t);
Packit 437b5e
		lua_pushinteger(L, r - s + 1);
Packit 437b5e
		return 2;
Packit 437b5e
	} else
Packit 437b5e
		return 0;
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
/***
Packit 437b5e
Get current time.
Packit 437b5e
@function time
Packit 437b5e
@see time(2)
Packit 437b5e
@return time in seconds since epoch
Packit 437b5e
*/
Packit 437b5e
static int
Packit 437b5e
Ptime(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	time_t t = time(NULL);
Packit 437b5e
	checknargs(L, 0);
Packit 437b5e
	if ((time_t) -1 == t)
Packit 437b5e
		return pusherror(L, "time");
Packit 437b5e
	lua_pushinteger(L, t);
Packit 437b5e
	return 1;
Packit 437b5e
}
Packit 437b5e
Packit 437b5e
Packit 437b5e
static const luaL_Reg posix_time_fns[] =
Packit 437b5e
{
Packit 437b5e
#if defined _XOPEN_REALTIME && _XOPEN_REALTIME != -1
Packit 437b5e
	LPOSIX_FUNC( Pclock_getres	),
Packit 437b5e
	LPOSIX_FUNC( Pclock_gettime	),
Packit 437b5e
#endif
Packit 437b5e
	LPOSIX_FUNC( Pgmtime		),
Packit 437b5e
	LPOSIX_FUNC( Plocaltime		),
Packit 437b5e
	LPOSIX_FUNC( Pmktime		),
Packit 437b5e
	LPOSIX_FUNC( Pnanosleep		),
Packit 437b5e
	LPOSIX_FUNC( Pstrftime		),
Packit 437b5e
	LPOSIX_FUNC( Pstrptime		),
Packit 437b5e
	LPOSIX_FUNC( Ptime		),
Packit 437b5e
	{NULL, NULL}
Packit 437b5e
};
Packit 437b5e
Packit 437b5e
Packit 437b5e
LUALIB_API int
Packit 437b5e
luaopen_posix_time(lua_State *L)
Packit 437b5e
{
Packit 437b5e
	luaL_register(L, "posix.time", posix_time_fns);
Packit 437b5e
	lua_pushliteral(L, "posix.time for " LUA_VERSION " / " PACKAGE_STRING);
Packit 437b5e
	lua_setfield(L, -2, "version");
Packit 437b5e
Packit 437b5e
#if defined _XOPEN_REALTIME && _XOPEN_REALTIME != -1
Packit 437b5e
	LPOSIX_CONST( CLOCK_MONOTONIC		);
Packit 437b5e
	LPOSIX_CONST( CLOCK_PROCESS_CPUTIME_ID	);
Packit 437b5e
	LPOSIX_CONST( CLOCK_REALTIME		);
Packit 437b5e
	LPOSIX_CONST( CLOCK_THREAD_CPUTIME_ID	);
Packit 437b5e
#endif
Packit 437b5e
Packit 437b5e
	return 1;
Packit 437b5e
}