You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.4 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2011-2013, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <string.h>
  10. #include <time.h>
  11. #include <sys/time.h>
  12. #include "libcork/core/timestamp.h"
  13. #include "libcork/core/types.h"
  14. #include "libcork/helpers/errors.h"
  15. void
  16. cork_timestamp_init_now(cork_timestamp *ts)
  17. {
  18. struct timeval tp;
  19. gettimeofday(&tp, NULL);
  20. cork_timestamp_init_usec(ts, tp.tv_sec, tp.tv_usec);
  21. }
  22. #define is_digit(ch) ((ch) >= '0' && (ch) <= '9')
  23. static uint64_t
  24. power_of_10(unsigned int width)
  25. {
  26. uint64_t accumulator = 10;
  27. uint64_t result = 1;
  28. while (width != 0) {
  29. if ((width % 2) == 1) {
  30. result *= accumulator;
  31. width--;
  32. }
  33. accumulator *= accumulator;
  34. width /= 2;
  35. }
  36. return result;
  37. }
  38. static int
  39. append_fractional(const cork_timestamp ts, unsigned int width,
  40. struct cork_buffer *dest)
  41. {
  42. if (CORK_UNLIKELY(width == 0 || width > 9)) {
  43. cork_error_set_printf
  44. (EINVAL,
  45. "Invalid width %u for fractional cork_timestamp", width);
  46. return -1;
  47. } else {
  48. uint64_t denom = power_of_10(width);
  49. uint64_t frac = cork_timestamp_gsec_to_units(ts, denom);
  50. cork_buffer_append_printf(dest, "%0*" PRIu64, width, frac);
  51. return 0;
  52. }
  53. }
  54. static int
  55. cork_timestamp_format_parts(const cork_timestamp ts, struct tm *tm,
  56. const char *format, struct cork_buffer *dest)
  57. {
  58. const char *next_percent;
  59. while ((next_percent = strchr(format, '%')) != NULL) {
  60. const char *spec = next_percent + 1;
  61. unsigned int width = 0;
  62. /* First append any text in between the previous format specifier and
  63. * this one. */
  64. cork_buffer_append(dest, format, next_percent - format);
  65. /* Then parse the format specifier */
  66. while (is_digit(*spec)) {
  67. width *= 10;
  68. width += (*spec++ - '0');
  69. }
  70. switch (*spec) {
  71. case '\0':
  72. cork_error_set_string
  73. (EINVAL,
  74. "Trailing %% at end of cork_timestamp format string");
  75. return -1;
  76. case '%':
  77. cork_buffer_append(dest, "%", 1);
  78. break;
  79. case 'Y':
  80. cork_buffer_append_printf(dest, "%04d", tm->tm_year + 1900);
  81. break;
  82. case 'm':
  83. cork_buffer_append_printf(dest, "%02d", tm->tm_mon + 1);
  84. break;
  85. case 'd':
  86. cork_buffer_append_printf(dest, "%02d", tm->tm_mday);
  87. break;
  88. case 'H':
  89. cork_buffer_append_printf(dest, "%02d", tm->tm_hour);
  90. break;
  91. case 'M':
  92. cork_buffer_append_printf(dest, "%02d", tm->tm_min);
  93. break;
  94. case 'S':
  95. cork_buffer_append_printf(dest, "%02d", tm->tm_sec);
  96. break;
  97. case 's':
  98. cork_buffer_append_printf
  99. (dest, "%" PRIu32, cork_timestamp_sec(ts));
  100. break;
  101. case 'f':
  102. rii_check(append_fractional(ts, width, dest));
  103. break;
  104. default:
  105. cork_error_set_printf
  106. (EINVAL,
  107. "Unknown cork_timestamp format specifier %%%c", *spec);
  108. return -1;
  109. }
  110. format = spec + 1;
  111. }
  112. /* When we fall through, there is some additional content after the final
  113. * format specifier. */
  114. cork_buffer_append_string(dest, format);
  115. return 0;
  116. }
  117. int
  118. cork_timestamp_format_utc(const cork_timestamp ts, const char *format,
  119. struct cork_buffer *dest)
  120. {
  121. time_t clock;
  122. struct tm tm;
  123. clock = cork_timestamp_sec(ts);
  124. gmtime_r(&clock, &tm);
  125. return cork_timestamp_format_parts(ts, &tm, format, dest);
  126. }
  127. int
  128. cork_timestamp_format_local(const cork_timestamp ts, const char *format,
  129. struct cork_buffer *dest)
  130. {
  131. time_t clock;
  132. struct tm tm;
  133. clock = cork_timestamp_sec(ts);
  134. localtime_r(&clock, &tm);
  135. return cork_timestamp_format_parts(ts, &tm, format, dest);
  136. }