@var{arg}, as a C @code{double} value.
@end deftypefn
+@deftypefn Function struct timespec extract_time (emacs_env *@var{env}, emacs_value @var{time})
+This function, which is available since Emacs 27, interprets
+@var{time} as an Emacs Lisp time value and returns the corresponding
+@code{struct timespec}. @xref{Time of Day}. @code{struct timespec}
+represents a timestamp with nanosecond precision. It has the
+following members:
+
+@table @code
+@item time_t tv_sec
+Whole number of seconds.
+@item long tv_nsec
+Fractional seconds as number of nanoseconds, always less than one
+billion.
+@end table
+
+@noindent
+@xref{Elapsed Time,,,libc}.
+
+If @var{time} has higher precision than nanoseconds, then this
+function truncates it to nanosecond precision. This function signals
+an error if @var{time} (truncated to nanoseconds) cannot be
+represented by @code{struct timespec}. For example, if @code{time_t}
+is a 32-bit integral type, then a @var{time} value of ten billion
+seconds would signal an error, but a @var{time} value of 600
+picoseconds would get truncated to zero.
+
+If you need to deal with time values that are not representable by
+@code{struct timespec}, or if you want higher precision, call the Lisp
+function @code{encode-time} and work with its return value.
+@xref{Time Conversion}.
+@end deftypefn
+
@deftypefn Function bool copy_string_contents (emacs_env *@var{env}, emacs_value @var{arg}, char *@var{buf}, ptrdiff_t *@var{len})
This function stores the UTF-8 encoded text of a Lisp string specified
by @var{arg} in the array of @code{char} pointed by @var{buf}, which
corresponding Emacs floating-point value.
@end deftypefn
+@deftypefn Function emacs_value make_time (emacs_env *@var{env}, struct timespec @var{time})
+This function, which is available since Emacs 27, takes a @code{struct
+timespec} argument @var{time} and returns the corresponding Emacs
+timestamp as a pair @code{(@var{ticks} . @var{hz})}. @xref{Time of
+Day}. The return value represents exactly the same timestamp as
+@var{time}: all input values are representable, and there is never a
+loss of precision. @code{@var{time}.tv_sec} and
+@code{@var{time}.tv_nsec} can be arbitrary values. In particular,
+there's no requirement that @var{time} be normalized. This means that
+@code{@var{time}.tv_nsec} can be negative or larger than 999,999,999.
+@end deftypefn
+
@deftypefn Function emacs_value make_string (emacs_env *@var{env}, const char *@var{str}, ptrdiff_t @var{strlen})
This function creates an Emacs string from C text string pointed by
@var{str} whose length in bytes, not including the terminating null
this operation. Previously, the empty string was returned in this
case.
+** New module environment functions 'make_time' and 'extract_time' to
+convert between timespec structures and Emacs Lisp time values.
+
\f
* Changes in Emacs 27.1 on Non-Free Operating Systems
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <time.h>
#include "lisp.h"
#include "dynlib.h"
return emacs_process_input_continue;
}
+static struct timespec
+module_extract_time (emacs_env *env, emacs_value value)
+{
+ MODULE_FUNCTION_BEGIN ((struct timespec) {0});
+ return lisp_time_argument (value_to_lisp (value));
+}
+
+static emacs_value
+module_make_time (emacs_env *env, struct timespec time)
+{
+ MODULE_FUNCTION_BEGIN (NULL);
+ return lisp_to_value (env, make_lisp_time (time));
+}
+
\f
/* Subroutines. */
env->vec_size = module_vec_size;
env->should_quit = module_should_quit;
env->process_input = module_process_input;
+ env->extract_time = module_extract_time;
+ env->make_time = module_make_time;
Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments);
return env;
}
#include <stdint.h>
#include <stddef.h>
+#include <time.h>
#ifndef __cplusplus
#include <stdbool.h>
function should quit. */
enum emacs_process_input_result (*process_input) (emacs_env *env)
EMACS_ATTRIBUTE_NONNULL (1);
+
+ struct timespec (*extract_time) (emacs_env *env, emacs_value value)
+ EMACS_ATTRIBUTE_NONNULL (1);
+
+ emacs_value (*make_time) (emacs_env *env, struct timespec time)
+ EMACS_ATTRIBUTE_NONNULL (1);
return env->intern (env, "finished");
}
+static emacs_value
+Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
+ void *data)
+{
+ assert (nargs == 1);
+ struct timespec time = env->extract_time (env, args[0]);
+ assert (time.tv_nsec >= 0);
+ assert (time.tv_nsec < 2000000000); /* possible leap second */
+ time.tv_nsec++;
+ return env->make_time (env, time);
+}
+
/* Lisp utilities for easier readability (simple wrappers). */
/* Provide FEATURE to Emacs. */
DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0,
NULL, NULL);
DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL);
+ DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL);
#undef DEFUN
'finished))
(quit)))))
+(ert-deftest mod-test-add-nanosecond/valid ()
+ (dolist (input (list
+ ;; Some realistic examples.
+ (current-time) (time-to-seconds)
+ (encode-time 12 34 5 6 7 2019 t)
+ ;; Various legacy timestamp forms.
+ '(123 456) '(123 456 789) '(123 456 789 6000)
+ ;; Corner case: this will result in a nanosecond
+ ;; value of 1000000000 after addition. The module
+ ;; code should handle this correctly.
+ '(123 65535 999999 999000)
+ ;; Seconds since the epoch.
+ 123 123.45
+ ;; New (TICKS . HZ) format.
+ '(123456789 . 1000000000)))
+ (ert-info ((format "input: %s" input))
+ (should (time-equal-p (mod-test-add-nanosecond input)
+ (time-add input '(0 0 0 1000)))))))
+
+(ert-deftest mod-test-add-nanosecond/nil ()
+ (should (<= (float-time (mod-test-add-nanosecond nil))
+ (+ (float-time) 1e-9))))
+
+(ert-deftest mod-test-add-nanosecond/invalid ()
+ (dolist (input '(1.0e+INF 1.0e-INF 0.0e+NaN (123) (123.45 6 7) "foo" [1 2]))
+ (ert-info ((format "input: %s" input))
+ (should-error (mod-test-add-nanosecond input)))))
+
;;; emacs-module-tests.el ends here