]> Kevux Git Server - fll/commitdiff
Feature: Add f_time project, adding functions for safely handling struct timespec.
authorKevin Day <kevin@kevux.org>
Sat, 5 Aug 2023 05:16:18 +0000 (00:16 -0500)
committerKevin Day <kevin@kevux.org>
Sat, 5 Aug 2023 05:21:30 +0000 (00:21 -0500)
This adds f_time_spec_millisecond() and f_time_spec_nanosecond() for safely handling overflow and underflow when using standard FLL f_number_unsigned_t numbers.

Unit tests are added.

A comment in the controller prrogram is added to designate that the controller-specific functions should be updated to call these functions.

26 files changed:
build/disable/about.txt
build/level_0/settings
build/monolithic/settings
build/scripts/bootstrap-example.sh
build/scripts/test.sh
build/stand_alone/fake.config.h
level_0/f_time/c/time.c [new file with mode: 0644]
level_0/f_time/c/time.h [new file with mode: 0644]
level_0/f_time/data/build/defines [new file with mode: 0644]
level_0/f_time/data/build/dependencies [new file with mode: 0644]
level_0/f_time/data/build/dependencies-tests [new file with mode: 0644]
level_0/f_time/data/build/fakefile [new file with mode: 0644]
level_0/f_time/data/build/functions [new file with mode: 0644]
level_0/f_time/data/build/macros [new file with mode: 0644]
level_0/f_time/data/build/settings [new file with mode: 0644]
level_0/f_time/data/build/settings-tests [new file with mode: 0644]
level_0/f_time/data/build/structures [new file with mode: 0644]
level_0/f_time/data/build/testfile [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-spec_millisecond.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-spec_millisecond.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-spec_nanosecond.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-spec_nanosecond.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time.h [new file with mode: 0644]
level_0/f_type/c/type.h
level_3/controller/c/controller/private-controller.c

index 79cd64e86d27fec067bbf33dcee043da0df13cd1..da3828dee2fd279b06f34402603de0f2497695ee 100644 (file)
@@ -33,11 +33,11 @@ Consider the following example using the fake dependencies for the stand alone b
 # echo $(cat level_3/fake/data/build/dependencies)
 
 Which prints:
-  # fss-0000 f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_parse f_path f_pipe f_print f_rip f_signal f_thread fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fll_error fll_execute fll_file fll_fss fll_print fll_program
+  # fss-0000 f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_parse f_path f_pipe f_print f_rip f_signal f_thread f_time fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fll_error fll_execute fll_file fll_fss fll_print fll_program
 
 From this list, build the level_0:
 
-# for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_parse f_path f_pipe f_print f_rip f_signal f_thread ; do if [[ -f build/disable/level_0/$i.h ]] ; then echo >> build/stand_alone/fake.config.h && cat build/disable/level_0/$i.h >> build/stand_alone/fake.config.h ; fi ; done
+# for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_parse f_path f_pipe f_print f_rip f_signal f_thread f_time ; do if [[ -f build/disable/level_0/$i.h ]] ; then echo >> build/stand_alone/fake.config.h && cat build/disable/level_0/$i.h >> build/stand_alone/fake.config.h ; fi ; done
 
 From the list, build the level_1:
 
index 38effe03d224143a0b52c6cca94bdcb2057bfd32..fad50c3794fbd145b346f46606ea33df72a8ee3b 100644 (file)
@@ -75,6 +75,7 @@ build_sources_library string/quantity.c string/quantitys.c string/quantityss.c
 build_sources_library string/range.c string/ranges.c string/rangess.c
 build_sources_library string/static.c string/statics.c string/staticss.c
 build_sources_library string/triple.c string/triples.c string/tripless.c
+build_sources_library time.c
 build_sources_library type_array/cell.c type_array/file.c type_array/fll_id.c type_array/int8.c type_array/int16.c type_array/int32.c type_array/int64.c type_array/int128.c type_array/number_unsigned.c type_array/poll.c type_array/state.c type_array/status.c type_array/uint8.c type_array/uint16.c type_array/uint32.c type_array/uint64.c type_array/uint128.c
 build_sources_library type_array/private-cell.c type_array/private-file.c type_array/private-fll_id.c type_array/private-int8.c type_array/private-int16.c type_array/private-int32.c type_array/private-int64.c type_array/private-int128.c type_array/private-number_unsigned.c type_array/private-poll.c type_array/private-state.c type_array/private-status.c type_array/private-uint8.c type_array/private-uint16.c type_array/private-uint32.c type_array/private-uint64.c type_array/private-uint128.c
 build_sources_library utf.c private-utf.c private-utf_alphabetic.c private-utf_combining.c private-utf_control.c private-utf_digit.c private-utf_emoji.c private-utf_numeric.c private-utf_phonetic.c private-utf_private.c private-utf_punctuation.c private-utf_subscript.c private-utf_superscript.c private-utf_symbol.c private-utf_unassigned.c private-utf_valid.c private-utf_whitespace.c private-utf_wide.c private-utf_word.c private-utf_zero_width.c
@@ -128,6 +129,7 @@ build_sources_headers string/quantity.h string/quantitys.h string/quantityss.h
 build_sources_headers string/range.h string/ranges.h string/rangess.h
 build_sources_headers string/static.h string/statics.h string/staticss.h
 build_sources_headers string/triple.h string/triples.h string/tripless.h
+build_sources_headers time.h
 build_sources_headers type.h type_file.h
 build_sources_headers type_array.h type_array_file.h type_array/common.h type_array/cell.h type_array/file.h type_array/fll_id.h type_array/int8.h type_array/int16.h type_array/int32.h type_array/int64.h type_array/int128.h type_array/number_unsigned.h type_array/poll.h type_array/state.h type_array/status.h type_array/uint8.h type_array/uint16.h type_array/uint32.h type_array/uint64.h type_array/uint128.h
 build_sources_headers utf.h utf/common.h utf/convert.h utf/dynamic.h utf/dynamics.h utf/dynamicss.h utf/is.h utf/is_character.h utf/map.h utf/maps.h utf/mapss.h utf/map_multi.h utf/map_multis.h utf/map_multiss.h utf/static.h utf/statics.h utf/staticss.h utf/string.h utf/triple.h utf/triples.h utf/tripless.h
index 6a50e2875e1ea15719924f4d1a630aa9aed047ab..cdf3334b1708ca45ac1f59de5efbd6f3d0ee2a53 100644 (file)
@@ -75,6 +75,7 @@ build_sources_library level_0/string/quantity.c level_0/string/quantitys.c level
 build_sources_library level_0/string/range.c level_0/string/ranges.c level_0/string/rangess.c
 build_sources_library level_0/string/static.c level_0/string/statics.c level_0/string/staticss.c
 build_sources_library level_0/string/triple.c level_0/string/triples.c level_0/string/tripless.c
+build_sources_library level_0/time.c
 build_sources_library level_0/type_array/cell.c level_0/type_array/file.c level_0/type_array/fll_id.c level_0/type_array/int8.c level_0/type_array/int16.c level_0/type_array/int32.c level_0/type_array/int64.c level_0/type_array/int128.c level_0/type_array/number_unsigned.c level_0/type_array/poll.c level_0/type_array/state.c level_0/type_array/status.c level_0/type_array/uint8.c level_0/type_array/uint16.c level_0/type_array/uint32.c level_0/type_array/uint64.c level_0/type_array/uint128.c
 build_sources_library level_0/type_array/private-cell.c level_0/type_array/private-file.c level_0/type_array/private-fll_id.c level_0/type_array/private-int8.c level_0/type_array/private-int16.c level_0/type_array/private-int32.c level_0/type_array/private-int64.c level_0/type_array/private-int128.c level_0/type_array/private-number_unsigned.c level_0/type_array/private-poll.c level_0/type_array/private-state.c level_0/type_array/private-status.c level_0/type_array/private-uint8.c level_0/type_array/private-uint16.c level_0/type_array/private-uint32.c level_0/type_array/private-uint64.c level_0/type_array/private-uint128.c
 build_sources_library level_0/utf.c level_0/private-utf.c level_0/private-utf_alphabetic.c level_0/private-utf_combining.c level_0/private-utf_control.c level_0/private-utf_digit.c level_0/private-utf_emoji.c level_0/private-utf_numeric.c level_0/private-utf_phonetic.c level_0/private-utf_private.c level_0/private-utf_punctuation.c level_0/private-utf_subscript.c level_0/private-utf_superscript.c level_0/private-utf_symbol.c level_0/private-utf_unassigned.c level_0/private-utf_valid.c level_0/private-utf_whitespace.c level_0/private-utf_wide.c level_0/private-utf_word.c level_0/private-utf_zero_width.c
@@ -149,6 +150,7 @@ build_sources_headers level_0/string/quantity.h level_0/string/quantitys.h level
 build_sources_headers level_0/string/range.h level_0/string/ranges.h level_0/string/rangess.h
 build_sources_headers level_0/string/static.h level_0/string/statics.h level_0/string/staticss.h
 build_sources_headers level_0/string/triple.h level_0/string/triples.h level_0/string/tripless.h
+build_sources_headers level_0/time.h
 build_sources_headers level_0/type.h level_0/type_file.h
 build_sources_headers level_0/type_array.h level_0/type_array_file.h level_0/type_array/common.h level_0/type_array/cell.h level_0/type_array/file.h level_0/type_array/fll_id.h level_0/type_array/int8.h level_0/type_array/int16.h level_0/type_array/int32.h level_0/type_array/int64.h level_0/type_array/int128.h level_0/type_array/number_unsigned.h level_0/type_array/poll.h level_0/type_array/state.h level_0/type_array/status.h level_0/type_array/uint8.h level_0/type_array/uint16.h level_0/type_array/uint32.h level_0/type_array/uint64.h level_0/type_array/uint128.h
 build_sources_headers level_0/utf.h level_0/utf/common.h level_0/utf/convert.h level_0/utf/dynamic.h level_0/utf/dynamics.h level_0/utf/dynamicss.h level_0/utf/is.h level_0/utf/is_character.h level_0/utf/map.h level_0/utf/maps.h level_0/utf/mapss.h level_0/utf/map_multi.h level_0/utf/map_multis.h level_0/utf/map_multiss.h level_0/utf/static.h level_0/utf/statics.h level_0/utf/staticss.h level_0/utf/string.h level_0/utf/triple.h level_0/utf/triples.h level_0/utf/tripless.h
index a09f7e657fdfb58beac5243a47aaee9730bce934..d2b36e09f636a1d0d3a8a804443e5613381b175f 100644 (file)
@@ -130,7 +130,7 @@ if [[ ${1} == "individual" ]] ; then
   ${shell_command} build/scripts/package.sh ${verbose} ${color} rebuild -i
 
   if [[ ${?} -eq 0 ]] ; then
-    for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_status_string f_serialize f_signal f_socket f_thread fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fl_status_string fl_utf_file fll_control_group fll_error fll_execute fll_file fll_fss fll_fss_status_string fll_iki fll_print fll_program ; do
+    for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_status_string f_serialize f_signal f_socket f_thread f_time fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fl_status_string fl_utf_file fll_control_group fll_error fll_execute fll_file fll_fss fll_fss_status_string fll_iki fll_print fll_program ; do
       echo && echo "Processing ${i}." &&
 
       cd package/individual/${i}-${version}/ &&
index 870078d118a87cdd2440aeda7ff19ff3c1fa7a83..98d6925e2b3ee4ca06b99f778ea0831e6d2b43be 100644 (file)
@@ -71,7 +71,7 @@ test_main() {
   local verbose=
   local verbose_common=
 
-  local projects="f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_serialize f_signal f_socket f_status_string f_thread fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fl_status_string fl_utf_file fll_control_group fll_error fll_execute fll_file fll_fss fll_fss_status_string fll_iki fll_print fll_program"
+  local projects="f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_serialize f_signal f_socket f_status_string f_thread f_time fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print fl_status_string fl_utf_file fll_control_group fll_error fll_execute fll_file fll_fss fll_fss_status_string fll_iki fll_print fll_program"
   local projects_no_tests="f_type"
   local programs="fss_read"
 
index cfa89b6bb5d5dcbd6009c1f5f9eab73dc57a9bd2..65d65536e749bb903968ebc74d88d35ebbe3a87b 100644 (file)
@@ -2,11 +2,18 @@
 // To assist in building this file use (may need to omit --defined-only): "nm --defined-only -f p programs/shared/fake | grep -oP '^(f|fl|fll)_[^\s]+'".
 // To get the list of all possible functions, use something like: "grep -horP '\b_di_f_\w*\b' level_0/f_color/".
 //
-// Example: echo > /tmp/all.txt
-//          for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_signal f_socket f_thread ; do grep -horP '\b_di_f_\w*\b' level_0/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_0/$i/c >> /tmp/all.txt ; done
-//          for i in fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print ; do grep -horP '\b_di_fl_\w*\b' level_1/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_1/$i/c >> /tmp/all.txt ; done
-//          for i in fll_error fll_execute fll_file fll_fss fll_print fll_program ; do grep -horP '\b_di_fll_\w*\b' level_2/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_2/$i/c >> /tmp/all.txt ; done
-//          sort /tmp/all.txt | uniq | sed -e 's|^_|#define &|g' > /tmp/sorted.txt
+// Note that some special defines may need to be manually added, such as:
+//   #define _di_private_inline_f_print_to_error_
+//   #define _di_private_inline_private_f_print_to_error_
+//
+// Example:
+//   echo > /tmp/all.txt
+//   for i in f_type f_status f_memory f_type_array f_string f_utf f_account f_capability f_color f_compare f_console f_control_group f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_limit f_network f_parse f_path f_pipe f_print f_rip f_signal f_socket f_thread f_time ; do grep -horP '\b_di_f_\w*\b' level_0/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_0/$i/c >> /tmp/all.txt ; done
+//   for i in fl_control_group fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_path fl_print ; do grep -horP '\b_di_fl_\w*\b' level_1/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_1/$i/c >> /tmp/all.txt ; done
+//   for i in fll_error fll_execute fll_file fll_fss fll_print fll_program ; do grep -horP '\b_di_fll_\w*\b' level_2/$i/c >> /tmp/all.txt ; grep -horP '\b_di_macro_\w*\b' level_2/$i/c >> /tmp/all.txt ; done
+//   sort /tmp/all.txt | uniq | sed -e 's|^_|#define &|g' > /tmp/sorted.txt
+//   echo "#define _di_private_inline_f_print_to_error_" >> /tmp/sorted.txt
+//   echo "#define _di_private_inline_private_f_print_to_error_" >> /tmp/sorted.txt
 
 #define _di_f_account_by_id_
 #define _di_f_account_by_name_
 #define _di_f_thread_spin_t_
 #define _di_f_thread_spin_unlock_
 #define _di_f_thread_unlock_
+#define _di_f_time_spec_millisecond_
+#define _di_f_time_spec_nanosecond_
 #define _di_f_time_spec_t_
 #define _di_f_time_t_
 //#define _di_f_type_d_
diff --git a/level_0/f_time/c/time.c b/level_0/f_time/c/time.c
new file mode 100644 (file)
index 0000000..04bd748
--- /dev/null
@@ -0,0 +1,86 @@
+#include "time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_f_time_spec_millisecond_
+  extern f_status_t f_time_spec_millisecond(const f_number_unsigned_t second, const f_number_unsigned_t millisecond, struct timespec * const time) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!time) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (((time_t) second) < 0) {
+      if ((long) millisecond < 0) {
+        time->tv_sec = 0;
+        time->tv_nsec = 0;
+      }
+      else {
+        time->tv_sec = (long) millisecond > 1000 ? ((long) millisecond) / 1000 : 0;
+        time->tv_nsec = (time->tv_sec ? ((long) millisecond) % 1000 : ((long) millisecond)) * 1000;
+      }
+
+      return F_status_set_error(F_number_underflow);
+    }
+
+    if ((long) millisecond < 0) {
+      time->tv_sec = (time_t) second;
+      time->tv_nsec = 0;
+
+      return F_status_set_error(F_number_underflow);
+    }
+
+    if (millisecond) {
+      time->tv_sec = ((long) millisecond) / 1000;
+      time->tv_nsec = (time->tv_sec ? ((long) millisecond) % 1000 : ((long) millisecond)) * 1000;
+    }
+    else {
+      time->tv_sec = 0;
+      time->tv_nsec = 0;
+    }
+
+    time->tv_sec += (time_t) second;
+
+    return time->tv_sec < (time_t) second ? F_status_set_error(F_number_overflow) : F_none;
+  }
+#endif // _di_f_time_spec_millisecond_
+
+#ifndef _di_f_time_spec_nanosecond_
+  extern f_status_t f_time_spec_nanosecond(const f_number_unsigned_t second, const f_number_unsigned_t nanosecond, struct timespec * const time) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!time) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (((time_t) second) < 0) {
+      time->tv_sec = 0;
+      time->tv_nsec = ((long) nanosecond) < 0 ? 0 : (long) nanosecond;
+
+      return F_status_set_error(F_number_underflow);
+    }
+
+    time->tv_sec = (time_t) second;
+
+    if ((long) nanosecond < 0) {
+      time->tv_nsec = 0;
+
+      return F_status_set_error(F_number_underflow);
+    }
+
+    time->tv_nsec = (long) nanosecond;
+
+    // If tv_nsec is 1 second or greater, then increment second.
+    if (time->tv_nsec >= 1000000000) {
+      ++(time->tv_sec);
+
+      time->tv_nsec -= 1000000000;
+
+      if (time->tv_sec < (time_t) second) return F_status_set_error(F_number_overflow);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_time_spec_nanosecond_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_time/c/time.h b/level_0/f_time/c/time.h
new file mode 100644 (file)
index 0000000..b87f304
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides time related functionality.
+ */
+#ifndef _F_time_h
+#define _F_time_h
+
+// Libc includes.
+#include <time.h>
+
+// FLL-0 includes.
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+
+// FLL-0 time includes.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a timespec representing the given seconds and milliseconds.
+ *
+ * This is intended to work with "struct timespec" and is not intended to work with "f_time_spec_t".
+ * The "struct timespec" may have different lengths and so this function provides overflow and underflow protection.
+ * The "f_time_spec_t" should not need this as "f_time_spec_t" is intended to always be uint64_t.
+ *
+ * @param second
+ *   The number of seconds.
+ * @param millisecond
+ *   The number of milliseconds.
+ * @param time
+ *   The time spec representing the given seconds and milliseconds.
+ *
+ *   This is still updated on F_number_overflow, and the result of the overflow is still assigned to seconds.
+ *   This is still updated on F_number_underflow, but the underflow value is set to 0.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_number_overflow (with error bit) if the summation of seconds and milliseconds results in an overflow when cast to appropriate integer type.
+ *   F_number_underflow (with error bit) if the seconds or milliseconds is less than 0 when cast to appropriate integer type.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_time_spec_millisecond_
+  extern f_status_t f_time_spec_millisecond(const f_number_unsigned_t second, const f_number_unsigned_t millisecond, struct timespec * const time);
+#endif // _di_f_time_spec_millisecond_
+
+/**
+ * Create a timespec representing the given seconds and nanoseconds.
+ *
+ * This is intended to work with "struct timespec" and is not intended to work with "f_time_spec_t".
+ * The "struct timespec" may have different lengths and so this function provides overflow and underflow protection.
+ * The "f_time_spec_t" should not need this as "f_time_spec_t" is intended to always be uint64_t.
+ *
+ * @param second
+ *   The number of seconds.
+ * @param nanosecond
+ *   The number of nanoseconds.
+ * @param time
+ *   The time spec representing the given seconds and nanoseconds.
+ *
+ *   This is still updated on F_number_overflow, and the result of the overflow is still assigned to second.
+ *   This is still updated on F_number_underflow, but the underflow value is set to 0.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_number_overflow (with error bit) if the summation of seconds and nanoseconds results in an overflow when cast to appropriate integer type.
+ *   F_number_underflow (with error bit) if the second or nanoseconds is less than 0 when cast to appropriate integer type.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_time_spec_nanosecond_
+  extern f_status_t f_time_spec_nanosecond(const f_number_unsigned_t second, const f_number_unsigned_t nanosecond, struct timespec * const time);
+#endif // _di_f_time_spec_nanosecond_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_time_h
diff --git a/level_0/f_time/data/build/defines b/level_0/f_time/data/build/defines
new file mode 100644 (file)
index 0000000..4f13080
--- /dev/null
@@ -0,0 +1 @@
+# fss-0000
diff --git a/level_0/f_time/data/build/dependencies b/level_0/f_time/data/build/dependencies
new file mode 100644 (file)
index 0000000..d9c4b77
--- /dev/null
@@ -0,0 +1,4 @@
+# fss-0000
+
+f_type
+f_status
diff --git a/level_0/f_time/data/build/dependencies-tests b/level_0/f_time/data/build/dependencies-tests
new file mode 100644 (file)
index 0000000..dea3179
--- /dev/null
@@ -0,0 +1,3 @@
+# fss-0001
+
+cmocka 1.*
diff --git a/level_0/f_time/data/build/fakefile b/level_0/f_time/data/build/fakefile
new file mode 100644 (file)
index 0000000..90a7134
--- /dev/null
@@ -0,0 +1,12 @@
+# fss-0005 iki-0002
+
+settings:
+  fail exit
+  modes individual individual_thread level monolithic clang test fanalyzer thread threadless
+
+  environment PATH LD_LIBRARY_PATH
+  environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+main:
+
+  build
diff --git a/level_0/f_time/data/build/functions b/level_0/f_time/data/build/functions
new file mode 100644 (file)
index 0000000..67f0d67
--- /dev/null
@@ -0,0 +1,3 @@
+# fss-0005
+
+main:
diff --git a/level_0/f_time/data/build/macros b/level_0/f_time/data/build/macros
new file mode 100644 (file)
index 0000000..67f0d67
--- /dev/null
@@ -0,0 +1,3 @@
+# fss-0005
+
+main:
diff --git a/level_0/f_time/data/build/settings b/level_0/f_time/data/build/settings
new file mode 100644 (file)
index 0000000..6779d2c
--- /dev/null
@@ -0,0 +1,71 @@
+# fss-0001
+#
+# Modes:
+#   - individual:        Compile using per project (individual) libraries, does not handle thread or threadless cases.
+#   - individual_thread: This is required when compiling in individual mode with "thread" mode.
+#   - level:             Compile using per level libraries.
+#   - monolithic:        Compile using per monolithic libraries.
+#   - clang:             Use clang rather than the default, which is generally gcc.
+#   - test:              Compile for a test, such as unit testing.
+#   - fanalyzer:         Compile using GCC's -fanalyzer compile time option.
+#   - thread:            Compile with thread support.
+#   - threadless:        Compile without thread support.
+#
+
+build_name f_time
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file micro
+version_target minor
+
+modes individual individual_thread level monolithic clang test fanalyzer thread threadless
+modes_default individual individual_thread thread
+
+build_compiler gcc
+build_compiler-clang clang
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+
+build_libraries -lc
+build_libraries-individual
+
+build_sources_library time.c
+
+build_sources_headers time.h
+
+build_script yes
+build_shared yes
+build_static no
+
+path_headers fll/level_0
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_object_script script
+path_object_shared shared
+path_object_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+
+has_path_standard yes
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses
+flags-clang -Wno-logical-op-parentheses
+flags-test -O0 -fstack-protector -Wall
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+
+flags_library -fPIC
+flags_object -fPIC
+flags_program -fPIE
diff --git a/level_0/f_time/data/build/settings-tests b/level_0/f_time/data/build/settings-tests
new file mode 100644 (file)
index 0000000..3f1ad4f
--- /dev/null
@@ -0,0 +1,57 @@
+# fss-0001
+#
+# Builds a program that is links to the generated library and is executed to perform tests.
+#
+# Memory leaks in the test program can be checked for by running valgrind with this executable.
+#
+
+build_name test-f_time
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file major
+version_target major
+
+modes individual clang test coverage
+modes_default individual test
+
+build_compiler gcc
+build_compiler-clang clang
+build_indexer ar
+build_indexer_arguments rcs
+build_language c
+
+build_libraries -lc -lcmocka
+build_libraries-individual -lf_time
+
+build_sources_program test-time-spec_millisecond.c test-time-spec_nanosecond.c
+build_sources_program test-time.c
+
+build_script no
+build_shared yes
+build_static no
+
+path_headers tests/unit/c
+path_sources tests/unit/c
+
+has_path_standard no
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+defines -Ibuild/includes
+defines_static -Lbuild/libraries/static
+defines_shared -Lbuild/libraries/shared
+
+flags -O2 -z now -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses
+flags-clang -Wno-logical-op-parentheses
+flags-test -fstack-protector -Wall
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+
+flags_program -fPIE
diff --git a/level_0/f_time/data/build/structures b/level_0/f_time/data/build/structures
new file mode 100644 (file)
index 0000000..67f0d67
--- /dev/null
@@ -0,0 +1,3 @@
+# fss-0005
+
+main:
diff --git a/level_0/f_time/data/build/testfile b/level_0/f_time/data/build/testfile
new file mode 100644 (file)
index 0000000..dd9b6d8
--- /dev/null
@@ -0,0 +1,63 @@
+# fss-0005 iki-0002
+
+settings:
+  load_build yes
+  fail exit
+
+  environment PATH LD_LIBRARY_PATH
+  environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+  environment CMOCKA_XML_FILE CMOCKA_MESSAGE_OUTPUT CMOCKA_TEST_ABORT
+
+  # Cmocka is not fully thread-safe, set this to "1" to have cmocka call abort() on a test failure.
+  #CMOCKA_TEST_ABORT 1
+
+  # One of: STDOUT, SUBUNIT, TAP, or XML.
+  #define CMOCKA_MESSAGE_OUTPUT STDOUT
+
+  # When in "XML" output mode, output to this file rather than stdout.
+  #define CMOCKA_XML_FILE ./out.xml
+
+main:
+  build settings individual test
+  build settings-tests individual test
+
+  operate build_path
+  operate ld_library_path
+
+  if exist parameter:"build_path"programs/shared/test-f_time
+    shell parameter:"build_path"programs/shared/test-f_time
+
+  if exist parameter:"build_path"programs/static/test-f_time
+    shell parameter:"build_path"programs/static/test-f_time
+
+  if not exist parameter:"build_path"programs/shared/test-f_time
+  and not exist parameter:"build_path"programs/static/test-f_time
+    operate not_created
+
+not_created:
+  print
+  print 'context:"error"Failed to test due to being unable to find either a shared or static test binary to perform tests. context:"reset"'
+
+  exit failure
+
+build_path:
+  parameter build_path build/
+
+  if parameter build:value
+    parameter build_path parameter:"build:value"
+
+ld_library_path:
+  if define LD_LIBRARY_PATH
+  and parameter work:value
+    define LD_LIBRARY_PATH 'parameter:"build_path"libraries/shared:parameter:"work:value"libraries/shared:define:"LD_LIBRARY_PATH"'
+
+  else
+  if define LD_LIBRARY_PATH
+    define LD_LIBRARY_PATH 'parameter:"build_path"libraries/shared:define:"LD_LIBRARY_PATH"'
+
+  else
+  if parameter work:value
+    define LD_LIBRARY_PATH 'parameter:"build_path"libraries/shared:parameter:"work:value"libraries/shared'
+
+  else
+    define LD_LIBRARY_PATH 'parameter:"build_path"libraries/shared'
diff --git a/level_0/f_time/tests/unit/c/test-time-spec_millisecond.c b/level_0/f_time/tests/unit/c/test-time-spec_millisecond.c
new file mode 100644 (file)
index 0000000..47b0029
--- /dev/null
@@ -0,0 +1,131 @@
+#include "test-time.h"
+#include "test-time-spec_millisecond.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_spec_millisecond__number_overflow(void **state) {
+
+  f_number_unsigned_t second = 0;
+
+  // If is signed, then...
+  if (((time_t) (-1)) < 0) {
+    second = (((f_number_unsigned_t) ((time_t) -1)) >> 1);
+  }
+  else {
+    second = (f_number_unsigned_t) ((time_t) (-1));
+  }
+
+  struct timespec time = { 0 };
+
+  {
+    const f_status_t status = f_time_spec_millisecond(second, 1000, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_overflow));
+  }
+
+  {
+    const f_status_t status = f_time_spec_millisecond(second, 1000, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_overflow));
+  }
+}
+
+void test__f_time_spec_millisecond__number_underflow(void **state) {
+
+  struct timespec time = { .tv_sec = -1, .tv_nsec = -1 };
+
+  // If this system has uses unsigned, then this test is not needed.
+  if (time.tv_sec >= 0 && time.tv_nsec >= 0) return;
+
+  if (time.tv_sec < 0) {
+    const f_status_t status = f_time_spec_millisecond(-1, 0, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  if (time.tv_sec < 0) {
+    const f_status_t status = f_time_spec_millisecond(-1, 1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  time.tv_nsec = -1;
+
+  if (time.tv_nsec < 0) {
+    const f_status_t status = f_time_spec_millisecond(0, -1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  if (time.tv_nsec < 0) {
+    const f_status_t status = f_time_spec_millisecond(1, -1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+}
+
+void test__f_time_spec_millisecond__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = f_time_spec_millisecond(0, 0, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_time_spec_millisecond__works(void **state) {
+
+  struct timespec time = { 0 };
+
+  {
+    const f_number_unsigned_t seconds[] = {
+      1000,
+      1000,
+      0,
+      0,
+    };
+
+    const f_number_unsigned_t milliseconds[] = {
+      100,
+      0,
+      100,
+      0,
+    };
+
+    for (uint8_t i = 0; i < 4; ++i) {
+
+      const f_status_t status = f_time_spec_millisecond(seconds[i], milliseconds[i], &time);
+
+      assert_int_equal(status, F_none);
+      assert_int_equal(time.tv_sec, seconds[i]);
+      assert_int_equal(time.tv_nsec, milliseconds[i] * 1000);
+    } // for
+  }
+
+  {
+    const f_number_unsigned_t seconds[] = {
+      1,
+      2,
+    };
+
+    const f_number_unsigned_t milliseconds[] = {
+      1000,
+      1001,
+    };
+
+    for (uint8_t i = 0; i < 2; ++i) {
+
+      const f_status_t status = f_time_spec_millisecond(seconds[i], milliseconds[i], &time);
+
+      assert_int_equal(status, F_none);
+      assert_int_equal(time.tv_sec, seconds[i] + 1);
+      assert_int_equal(time.tv_nsec, (milliseconds[i] - 1000) * 1000);
+    } // for
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_time/tests/unit/c/test-time-spec_millisecond.h b/level_0/f_time/tests/unit/c/test-time-spec_millisecond.h
new file mode 100644 (file)
index 0000000..b91483d
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_spec_millisecond_h
+#define _TEST__F_time_spec_millisecond_h
+
+/**
+ * Test that function fails due to an overflow.
+ *
+ * @see f_time_spec_millisecond()
+ */
+extern void test__f_time_spec_millisecond__number_overflow(void **state);
+
+/**
+ * Test that function fails due to an underflow.
+ *
+ * @see f_time_spec_millisecond()
+ */
+extern void test__f_time_spec_millisecond__number_underflow(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_spec_millisecond()
+ */
+extern void test__f_time_spec_millisecond__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_spec_millisecond()
+ */
+extern void test__f_time_spec_millisecond__works(void **state);
+
+#endif // _TEST__F_time_spec_millisecond_h
diff --git a/level_0/f_time/tests/unit/c/test-time-spec_nanosecond.c b/level_0/f_time/tests/unit/c/test-time-spec_nanosecond.c
new file mode 100644 (file)
index 0000000..0de029b
--- /dev/null
@@ -0,0 +1,131 @@
+#include "test-time.h"
+#include "test-time-spec_nanosecond.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_spec_nanosecond__number_overflow(void **state) {
+
+  f_number_unsigned_t second = 0;
+
+  // If is signed, then...
+  if (((time_t) (-1)) < 0) {
+    second = (((f_number_unsigned_t) ((time_t) -1)) >> 1);
+  }
+  else {
+    second = (f_number_unsigned_t) ((time_t) (-1));
+  }
+
+  struct timespec time = { 0 };
+
+  {
+    const f_status_t status = f_time_spec_nanosecond(second, 1000000000, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_overflow));
+  }
+
+  {
+    const f_status_t status = f_time_spec_nanosecond(second, 1000000000, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_overflow));
+  }
+}
+
+void test__f_time_spec_nanosecond__number_underflow(void **state) {
+
+  struct timespec time = { .tv_sec = -1, .tv_nsec = -1 };
+
+  // If this system has uses unsigned, then this test is not needed.
+  if (time.tv_sec >= 0 && time.tv_nsec >= 0) return;
+
+  if (time.tv_sec < 0) {
+    const f_status_t status = f_time_spec_nanosecond(-1, 0, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  if (time.tv_sec < 0) {
+    const f_status_t status = f_time_spec_nanosecond(-1, 1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  time.tv_nsec = -1;
+
+  if (time.tv_nsec < 0) {
+    const f_status_t status = f_time_spec_nanosecond(0, -1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+
+  if (time.tv_nsec < 0) {
+    const f_status_t status = f_time_spec_nanosecond(1, -1, &time);
+
+    assert_int_equal(status, F_status_set_error(F_number_underflow));
+  }
+}
+
+void test__f_time_spec_nanosecond__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = f_time_spec_nanosecond(0, 0, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_time_spec_nanosecond__works(void **state) {
+
+  struct timespec time = { 0 };
+
+  {
+    const f_number_unsigned_t seconds[] = {
+      1000,
+      1000,
+      0,
+      0,
+    };
+
+    const f_number_unsigned_t nanoseconds[] = {
+      100,
+      0,
+      100,
+      0,
+    };
+
+    for (uint8_t i = 0; i < 4; ++i) {
+
+      const f_status_t status = f_time_spec_nanosecond(seconds[i], nanoseconds[i], &time);
+
+      assert_int_equal(status, F_none);
+      assert_int_equal(time.tv_sec, seconds[i]);
+      assert_int_equal(time.tv_nsec, nanoseconds[i]);
+    } // for
+  }
+
+  {
+    const f_number_unsigned_t seconds[] = {
+      1,
+      2,
+    };
+
+    const f_number_unsigned_t nanoseconds[] = {
+      1000000000,
+      1000000001,
+    };
+
+    for (uint8_t i = 0; i < 2; ++i) {
+
+      const f_status_t status = f_time_spec_nanosecond(seconds[i], nanoseconds[i], &time);
+
+      assert_int_equal(status, F_none);
+      assert_int_equal(time.tv_sec, seconds[i] + 1);
+      assert_int_equal(time.tv_nsec, (nanoseconds[i] - 1000000000));
+    } // for
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_time/tests/unit/c/test-time-spec_nanosecond.h b/level_0/f_time/tests/unit/c/test-time-spec_nanosecond.h
new file mode 100644 (file)
index 0000000..e13bd27
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_spec_nanosecond_h
+#define _TEST__F_time_spec_nanosecond_h
+
+/**
+ * Test that function fails due to an overflow.
+ *
+ * @see f_time_spec_nanosecond()
+ */
+extern void test__f_time_spec_nanosecond__number_overflow(void **state);
+
+/**
+ * Test that function fails due to an underflow.
+ *
+ * @see f_time_spec_nanosecond()
+ */
+extern void test__f_time_spec_nanosecond__number_underflow(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_time_spec_nanosecond()
+ */
+extern void test__f_time_spec_nanosecond__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_spec_nanosecond()
+ */
+extern void test__f_time_spec_nanosecond__works(void **state);
+
+#endif // _TEST__F_time_spec_nanosecond_h
diff --git a/level_0/f_time/tests/unit/c/test-time.c b/level_0/f_time/tests/unit/c/test-time.c
new file mode 100644 (file)
index 0000000..7a1439d
--- /dev/null
@@ -0,0 +1,41 @@
+#include "test-time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int setup(void **state) {
+
+  return 0;
+}
+
+int setdown(void **state) {
+
+  errno = 0;
+
+  return 0;
+}
+
+int main(void) {
+
+  const struct CMUnitTest tests[] = {
+    cmocka_unit_test(test__f_time_spec_millisecond__number_overflow),
+    cmocka_unit_test(test__f_time_spec_millisecond__number_underflow),
+    cmocka_unit_test(test__f_time_spec_millisecond__works),
+
+    cmocka_unit_test(test__f_time_spec_nanosecond__number_overflow),
+    cmocka_unit_test(test__f_time_spec_nanosecond__number_underflow),
+    cmocka_unit_test(test__f_time_spec_nanosecond__works),
+
+    #ifndef _di_level_0_parameter_checking_
+      cmocka_unit_test(test__f_time_spec_millisecond__parameter_checking),
+      cmocka_unit_test(test__f_time_spec_nanosecond__parameter_checking),
+    #endif // _di_level_0_parameter_checking_
+  };
+
+  return cmocka_run_group_tests(tests, setup, setdown);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_time/tests/unit/c/test-time.h b/level_0/f_time/tests/unit/c/test-time.h
new file mode 100644 (file)
index 0000000..fede1ca
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_h
+#define _TEST__F_time_h
+
+// Libc includes.
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+
+// cmocka includes.
+#include <cmocka.h>
+
+// FLL-0 includes.
+#include <fll/level_0/time.h>
+
+// Mock includes.
+
+// Test includes.
+#include "test-time-spec_millisecond.h"
+#include "test-time-spec_nanosecond.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Perform any setup operations.
+ *
+ * @param state
+ *   The test state.
+ *
+ * @return
+ *   The status of this function, where 0 means success.
+ */
+extern int setup(void **state);
+
+/**
+ * Peform any setdown operations.
+ *
+ * @param state
+ *   The test state.
+ *
+ * @return
+ *   The status of this function, where 0 means success.
+ */
+extern int setdown(void **state);
+
+/**
+ * Run all tests.
+ *
+ * @return
+ *   The final result of the tests.
+ *
+ * @see cmocka_run_group_tests()
+ * @see cmocka_unit_test()
+ */
+extern int main(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _TEST__F_time_h
index 2a79dc4efa6a6154bf9799f89d38d3fd4540f9da..13e94b4737f1296732051ccc45dfff571f7d14f2 100644 (file)
@@ -491,6 +491,8 @@ extern "C" {
  * 1 (Earth) second = 1000000000 Time or 1 GT (GigaTime).
  *
  * Consequentially, 1 day in units of Time is easily represented as 86.4 TT (TeraTime).
+ *
+ * This is not time_t, which is a different structure that may not be uint64_t and is often signed.
  */
 #ifndef _di_f_time_t_
   typedef uint64_t f_time_t;
@@ -499,7 +501,10 @@ extern "C" {
 #endif // _di_f_time_t_
 
 /**
- * A non-kernel dependent version of "struct timespec".
+ * A non-kernel dependent alternative version of "struct timespec".
+ *
+ * This is may not compatible with struct timespec because seconds is time_t and that may not be a uint64_t.
+ * In many cases of "struct timespec", seconds is signed because time_t is signed.
  *
  * Properties:
  *   - seconds:      The total number of seconds.
index 84efa556f2435208ad36e8d331672d2d350482ee..4e36c4c62c82957949521d3e0c6fd8db253e861e 100644 (file)
@@ -732,6 +732,7 @@ extern "C" {
 
 #ifndef _di_controller_time_milliseconds_
   struct timespec controller_time_milliseconds(const f_number_unsigned_t milliseconds) {
+   // @todo update all of these type of functions to use the newer f_time_spec_milliseconds() and f_time_spec_nanoseconds() as appropriate.
 
     struct timespec time;
     time.tv_sec = milliseconds > 1000 ? milliseconds / 1000 : 0;