summaryrefslogtreecommitdiffstats
path: root/src/ptimec.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/ptimec.hh')
-rw-r--r--src/ptimec.hh1119
1 files changed, 1119 insertions, 0 deletions
diff --git a/src/ptimec.hh b/src/ptimec.hh
new file mode 100644
index 0000000..9db6b0c
--- /dev/null
+++ b/src/ptimec.hh
@@ -0,0 +1,1119 @@
+/**
+ * Copyright (c) 2014, Timothy Stack
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Timothy Stack nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @file ptimec.hh
+ */
+
+#ifndef pctimec_hh
+#define pctimec_hh
+
+#include "config.h"
+
+// XXX
+#define __STDC_FORMAT_MACROS
+#include <cstdlib>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "base/lnav_log.hh"
+#include "base/time_util.hh"
+
+#define PTIME_CONSUME(amount, block) \
+ if ((off_inout + (amount)) > len) { \
+ return false; \
+ } \
+\
+ block \
+\
+ off_inout \
+ += (amount);
+
+#define PTIME_APPEND(ch) \
+ if ((off_inout + 2) >= len) { \
+ return; \
+ } \
+ dst[off_inout] = ch; \
+ off_inout += 1;
+
+#define ABR_TO_INT(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
+
+inline bool
+ptime_upto(char ch, const char* str, off_t& off_inout, ssize_t len)
+{
+ for (; off_inout < len; off_inout++) {
+ if (str[off_inout] == ch) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+inline bool
+ptime_upto_end(const char* str, off_t& off_inout, ssize_t len)
+{
+ off_inout = len;
+
+ return true;
+}
+
+bool ptime_b_slow(struct exttm* dst,
+ const char* str,
+ off_t& off_inout,
+ ssize_t len);
+
+inline bool
+ptime_b(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ if (off_inout + 3 < len) {
+ auto month_start = (unsigned char*) &str[off_inout];
+ uint32_t month_int = ABR_TO_INT(month_start[0] & ~0x20UL,
+ month_start[1] & ~0x20UL,
+ month_start[2] & ~0x20UL);
+ int val;
+
+ switch (month_int) {
+ case ABR_TO_INT('J', 'A', 'N'):
+ val = 0;
+ break;
+ case ABR_TO_INT('F', 'E', 'B'):
+ val = 1;
+ break;
+ case ABR_TO_INT('M', 'A', 'R'):
+ val = 2;
+ break;
+ case ABR_TO_INT('A', 'P', 'R'):
+ val = 3;
+ break;
+ case ABR_TO_INT('M', 'A', 'Y'):
+ val = 4;
+ break;
+ case ABR_TO_INT('J', 'U', 'N'):
+ val = 5;
+ break;
+ case ABR_TO_INT('J', 'U', 'L'):
+ val = 6;
+ break;
+ case ABR_TO_INT('A', 'U', 'G'):
+ val = 7;
+ break;
+ case ABR_TO_INT('S', 'E', 'P'):
+ val = 8;
+ break;
+ case ABR_TO_INT('O', 'C', 'T'):
+ val = 9;
+ break;
+ case ABR_TO_INT('N', 'O', 'V'):
+ val = 10;
+ break;
+ case ABR_TO_INT('D', 'E', 'C'):
+ val = 11;
+ break;
+ default:
+ val = -1;
+ break;
+ }
+ if (val >= 0) {
+ off_inout += 3;
+ dst->et_tm.tm_mon = val;
+ dst->et_flags |= ETF_MONTH_SET;
+ return true;
+ }
+ }
+
+ return ptime_b_slow(dst, str, off_inout, len);
+}
+
+inline void
+ftime_a(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ switch (tm.et_tm.tm_wday) {
+ case 0:
+ PTIME_APPEND('S');
+ PTIME_APPEND('u');
+ PTIME_APPEND('n');
+ break;
+ case 1:
+ PTIME_APPEND('M');
+ PTIME_APPEND('o');
+ PTIME_APPEND('n');
+ break;
+ case 2:
+ PTIME_APPEND('T');
+ PTIME_APPEND('u');
+ PTIME_APPEND('e');
+ break;
+ case 3:
+ PTIME_APPEND('W');
+ PTIME_APPEND('e');
+ PTIME_APPEND('d');
+ break;
+ case 4:
+ PTIME_APPEND('T');
+ PTIME_APPEND('h');
+ PTIME_APPEND('u');
+ break;
+ case 5:
+ PTIME_APPEND('F');
+ PTIME_APPEND('r');
+ PTIME_APPEND('i');
+ break;
+ case 6:
+ PTIME_APPEND('S');
+ PTIME_APPEND('a');
+ PTIME_APPEND('t');
+ break;
+ default:
+ PTIME_APPEND('X');
+ PTIME_APPEND('X');
+ PTIME_APPEND('X');
+ break;
+ }
+}
+
+inline void
+ftime_Z(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+}
+
+inline void
+ftime_b(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ switch (tm.et_tm.tm_mon) {
+ case 0:
+ PTIME_APPEND('J');
+ PTIME_APPEND('a');
+ PTIME_APPEND('n');
+ break;
+ case 1:
+ PTIME_APPEND('F');
+ PTIME_APPEND('e');
+ PTIME_APPEND('b');
+ break;
+ case 2:
+ PTIME_APPEND('M');
+ PTIME_APPEND('a');
+ PTIME_APPEND('r');
+ break;
+ case 3:
+ PTIME_APPEND('A');
+ PTIME_APPEND('p');
+ PTIME_APPEND('r');
+ break;
+ case 4:
+ PTIME_APPEND('M');
+ PTIME_APPEND('a');
+ PTIME_APPEND('y');
+ break;
+ case 5:
+ PTIME_APPEND('J');
+ PTIME_APPEND('u');
+ PTIME_APPEND('n');
+ break;
+ case 6:
+ PTIME_APPEND('J');
+ PTIME_APPEND('u');
+ PTIME_APPEND('l');
+ break;
+ case 7:
+ PTIME_APPEND('A');
+ PTIME_APPEND('u');
+ PTIME_APPEND('g');
+ break;
+ case 8:
+ PTIME_APPEND('S');
+ PTIME_APPEND('e');
+ PTIME_APPEND('p');
+ break;
+ case 9:
+ PTIME_APPEND('O');
+ PTIME_APPEND('c');
+ PTIME_APPEND('t');
+ break;
+ case 10:
+ PTIME_APPEND('N');
+ PTIME_APPEND('o');
+ PTIME_APPEND('v');
+ break;
+ case 11:
+ PTIME_APPEND('D');
+ PTIME_APPEND('e');
+ PTIME_APPEND('c');
+ break;
+ default:
+ PTIME_APPEND('X');
+ PTIME_APPEND('X');
+ PTIME_APPEND('X');
+ break;
+ }
+}
+
+inline bool
+ptime_S(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ if (str[off_inout + 1] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_sec
+ = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
+ dst->et_flags |= ETF_SECOND_SET;
+ });
+
+ return (dst->et_tm.tm_sec >= 0 && dst->et_tm.tm_sec <= 59);
+}
+
+inline void
+ftime_S(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 10) % 10));
+ PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 1) % 10));
+}
+
+inline bool
+ptime_s(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ off_t off_start = off_inout;
+ lnav::time64_t epoch = 0;
+
+ while (off_inout < len && isdigit(str[off_inout])) {
+ if ((off_inout - off_start) > 11) {
+ return false;
+ }
+
+ epoch *= 10;
+ epoch += str[off_inout] - '0';
+ off_inout += 1;
+ }
+
+ if (epoch >= MAX_TIME_T) {
+ return false;
+ }
+
+ secs2tm(epoch, &dst->et_tm);
+ dst->et_flags = ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
+ | ETF_MINUTE_SET | ETF_SECOND_SET | ETF_MACHINE_ORIENTED
+ | ETF_EPOCH_TIME;
+
+ return (epoch > 0);
+}
+
+inline void
+ftime_s(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ time_t t = tm2sec(&tm.et_tm);
+
+ snprintf(&dst[off_inout], len - off_inout, "%ld", t);
+ off_inout = strlen(dst);
+}
+
+inline bool
+ptime_q(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ off_t off_start = off_inout;
+ lnav::time64_t epoch = 0;
+
+ while (off_inout < len && isxdigit(str[off_inout])) {
+ if ((off_inout - off_start) > 11) {
+ return false;
+ }
+
+ epoch *= 16;
+ switch (tolower(str[off_inout])) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ epoch += str[off_inout] - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ epoch += str[off_inout] - 'a' + 10;
+ break;
+ }
+ off_inout += 1;
+ }
+
+ if (epoch >= MAX_TIME_T) {
+ return false;
+ }
+
+ secs2tm(epoch, &dst->et_tm);
+ dst->et_flags = ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
+ | ETF_MINUTE_SET | ETF_SECOND_SET | ETF_MACHINE_ORIENTED
+ | ETF_EPOCH_TIME;
+
+ return (epoch > 0);
+}
+
+inline void
+ftime_q(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ time_t t = tm2sec(&tm.et_tm);
+
+ snprintf(&dst[off_inout], len - off_inout, "%lx", t);
+ off_inout = strlen(dst);
+}
+
+inline bool
+ptime_L(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ int ms = 0;
+
+ PTIME_CONSUME(3, {
+ char c0 = str[off_inout];
+ char c1 = str[off_inout + 1];
+ char c2 = str[off_inout + 2];
+ if (!isdigit(c0) || !isdigit(c1) || !isdigit(c2)) {
+ return false;
+ }
+ ms = ((str[off_inout] - '0') * 100 + (str[off_inout + 1] - '0') * 10
+ + (str[off_inout + 2] - '0'));
+ });
+
+ if ((ms >= 0 && ms <= 999)) {
+ dst->et_nsec = ms * 1000000;
+ return true;
+ }
+ return false;
+}
+
+inline void
+ftime_L(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int millis = tm.et_nsec / 1000000;
+
+ PTIME_APPEND('0' + ((millis / 100) % 10));
+ PTIME_APPEND('0' + ((millis / 10) % 10));
+ PTIME_APPEND('0' + ((millis / 1) % 10));
+}
+
+inline bool
+ptime_M(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ if (str[off_inout + 1] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_min
+ = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
+ dst->et_flags |= ETF_MINUTE_SET;
+ });
+
+ return (dst->et_tm.tm_min >= 0 && dst->et_tm.tm_min <= 59);
+}
+
+inline void
+ftime_M(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ PTIME_APPEND('0' + ((tm.et_tm.tm_min / 10) % 10));
+ PTIME_APPEND('0' + ((tm.et_tm.tm_min / 1) % 10));
+}
+
+inline bool
+ptime_H(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ if (str[off_inout + 1] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_hour
+ = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
+ dst->et_flags |= ETF_HOUR_SET;
+ });
+
+ return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
+}
+
+inline void
+ftime_H(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
+ PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
+}
+
+inline bool
+ptime_i(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ uint64_t epoch_ms = 0;
+ lnav::time64_t epoch;
+
+ while (off_inout < len && isdigit(str[off_inout])) {
+ epoch_ms *= 10;
+ epoch_ms += str[off_inout] - '0';
+ off_inout += 1;
+ }
+
+ dst->et_nsec = (epoch_ms % 1000ULL) * 1000000;
+ epoch = (epoch_ms / 1000ULL);
+
+ if (epoch >= MAX_TIME_T) {
+ return false;
+ }
+
+ secs2tm(epoch, &dst->et_tm);
+ dst->et_flags = ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
+ | ETF_MINUTE_SET | ETF_SECOND_SET | ETF_MACHINE_ORIENTED
+ | ETF_EPOCH_TIME;
+
+ return (epoch_ms > 0);
+}
+
+inline void
+ftime_i(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int64_t t = tm2sec(&tm.et_tm);
+
+ t += tm.et_nsec / 1000000;
+ snprintf(&dst[off_inout], len - off_inout, "%" PRId64, t);
+ off_inout = strlen(dst);
+}
+
+inline bool
+ptime_6(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ uint64_t epoch_us = 0;
+ lnav::time64_t epoch;
+
+ while (off_inout < len && isdigit(str[off_inout])) {
+ epoch_us *= 10;
+ epoch_us += str[off_inout] - '0';
+ off_inout += 1;
+ }
+
+ dst->et_nsec = (epoch_us % 1000000ULL) * 1000ULL;
+ epoch = (epoch_us / 1000000ULL);
+
+ if (epoch >= MAX_TIME_T) {
+ return false;
+ }
+
+ secs2tm(epoch, &dst->et_tm);
+ dst->et_flags = ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
+ | ETF_MINUTE_SET | ETF_SECOND_SET | ETF_MACHINE_ORIENTED
+ | ETF_EPOCH_TIME;
+
+ return (epoch_us > 0);
+}
+
+inline void
+ftime_6(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int64_t t = tm2sec(&tm.et_tm);
+
+ t += tm.et_nsec / 1000;
+ snprintf(&dst[off_inout], len - off_inout, "%" PRId64, t);
+ off_inout = strlen(dst);
+}
+
+inline bool
+ptime_I(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ if (str[off_inout + 1] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_hour
+ = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
+
+ if (dst->et_tm.tm_hour < 1 || dst->et_tm.tm_hour > 12) {
+ return false;
+ }
+ dst->et_flags |= ETF_HOUR_SET;
+ });
+
+ return true;
+}
+
+inline void
+ftime_I(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int hour = tm.et_tm.tm_hour;
+
+ if (hour >= 12) {
+ hour -= 12;
+ }
+ if (hour == 0) {
+ hour = 12;
+ }
+
+ PTIME_APPEND('0' + ((hour / 10) % 10));
+ PTIME_APPEND('0' + ((hour / 1) % 10));
+}
+
+inline bool
+ptime_d(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ if (str[off_inout] == ' ') {
+ dst->et_tm.tm_mday = 0;
+ } else {
+ dst->et_tm.tm_mday = (str[off_inout] - '0') * 10;
+ }
+ if (str[off_inout + 1] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_mday += (str[off_inout + 1] - '0');
+ });
+
+ if (dst->et_tm.tm_mday >= 1 && dst->et_tm.tm_mday <= 31) {
+ dst->et_flags |= ETF_DAY_SET;
+ return true;
+ }
+ return false;
+}
+
+inline void
+ftime_d(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
+ PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
+}
+
+inline bool
+ptime_e(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ dst->et_tm.tm_mday = 0;
+ PTIME_CONSUME(1, {
+ if (str[off_inout] < '0' || str[off_inout] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_mday = str[off_inout] - '0';
+ });
+ if (off_inout < len) {
+ if (str[off_inout] >= '0' && str[off_inout] <= '9') {
+ dst->et_tm.tm_mday *= 10;
+ dst->et_tm.tm_mday += str[off_inout] - '0';
+ off_inout += 1;
+ }
+ }
+
+ if (dst->et_tm.tm_mday >= 1 && dst->et_tm.tm_mday <= 31) {
+ dst->et_flags |= ETF_DAY_SET;
+ return true;
+ }
+ return false;
+}
+
+inline void
+ftime_e(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ if (tm.et_tm.tm_mday < 10) {
+ PTIME_APPEND(' ');
+ } else {
+ PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
+ }
+ PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
+}
+
+inline bool
+ptime_m(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ off_t orig_off = off_inout;
+
+ dst->et_tm.tm_mon = 0;
+ PTIME_CONSUME(1, {
+ if (str[off_inout] < '0' || str[off_inout] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_mon = str[off_inout] - '0';
+ });
+ if (off_inout < len) {
+ if (str[off_inout] >= '0' && str[off_inout] <= '9') {
+ dst->et_tm.tm_mon *= 10;
+ dst->et_tm.tm_mon += str[off_inout] - '0';
+ off_inout += 1;
+ }
+ }
+
+ dst->et_tm.tm_mon -= 1;
+
+ if (dst->et_tm.tm_mon >= 0 && dst->et_tm.tm_mon <= 11) {
+ dst->et_flags |= ETF_MONTH_SET;
+ return true;
+ }
+
+ off_inout = orig_off;
+ return false;
+}
+
+inline void
+ftime_m(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 10) % 10));
+ PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 1) % 10));
+}
+
+inline bool
+ptime_k(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ dst->et_tm.tm_hour = 0;
+ PTIME_CONSUME(1, {
+ if (str[off_inout] < '0' || str[off_inout] > '9') {
+ return false;
+ }
+ dst->et_tm.tm_hour = str[off_inout] - '0';
+ });
+ if (off_inout < len) {
+ if (str[off_inout] >= '0' && str[off_inout] <= '9') {
+ dst->et_tm.tm_hour *= 10;
+ dst->et_tm.tm_hour += str[off_inout] - '0';
+ dst->et_flags |= ETF_HOUR_SET;
+ off_inout += 1;
+ }
+ }
+
+ return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
+}
+
+inline void
+ftime_k(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ if (tm.et_tm.tm_hour < 10) {
+ PTIME_APPEND(' ');
+ } else {
+ PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
+ }
+ PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
+}
+
+inline bool
+ptime_l(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ off_t orig_off = off_inout;
+ bool consumed_space = false;
+
+ dst->et_tm.tm_hour = 0;
+
+ if ((off_inout + 1) > len) {
+ return false;
+ }
+
+ if (str[off_inout] == ' ') {
+ consumed_space = true;
+ off_inout += 1;
+ }
+
+ if ((off_inout + 1) > len) {
+ off_inout = orig_off;
+ return false;
+ }
+
+ if (str[off_inout] < '1' || str[off_inout] > '9') {
+ off_inout = orig_off;
+ return false;
+ }
+
+ dst->et_tm.tm_hour = str[off_inout] - '0';
+ off_inout += 1;
+
+ if (consumed_space || str[off_inout] < '0' || str[off_inout] > '9') {
+ return true;
+ }
+
+ dst->et_tm.tm_hour *= 10;
+ dst->et_tm.tm_hour += str[off_inout] - '0';
+ off_inout += 1;
+
+ if (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23) {
+ return true;
+ }
+
+ dst->et_flags |= ETF_HOUR_SET;
+
+ off_inout = orig_off;
+ return false;
+}
+
+inline void
+ftime_l(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int hour = tm.et_tm.tm_hour;
+
+ if (hour >= 12) {
+ hour -= 12;
+ }
+ if (hour == 0) {
+ hour = 12;
+ }
+
+ if (hour < 10) {
+ PTIME_APPEND(' ');
+ } else {
+ PTIME_APPEND('0' + ((hour / 10) % 10));
+ }
+ PTIME_APPEND('0' + ((hour / 1) % 10));
+}
+
+inline bool
+ptime_p(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ char lead = str[off_inout];
+
+ if ((str[off_inout + 1] & 0xdf) != 'M') {
+ return false;
+ } else if ((lead & 0xdf) == 'A') {
+ if (dst->et_tm.tm_hour == 12) {
+ dst->et_tm.tm_hour = 0;
+ }
+ } else if ((lead & 0xdf) == 'P') {
+ if (dst->et_tm.tm_hour < 12) {
+ dst->et_tm.tm_hour += 12;
+ }
+ } else {
+ return false;
+ }
+ });
+
+ return true;
+}
+
+inline void
+ftime_p(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ if (tm.et_tm.tm_hour < 12) {
+ PTIME_APPEND('A');
+ } else {
+ PTIME_APPEND('P');
+ }
+ PTIME_APPEND('M');
+}
+
+inline bool
+ptime_Y(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(4, {
+ dst->et_tm.tm_year = ((str[off_inout + 0] - '0') * 1000
+ + (str[off_inout + 1] - '0') * 100
+ + (str[off_inout + 2] - '0') * 10
+ + (str[off_inout + 3] - '0') * 1)
+ - 1900;
+
+ if (dst->et_tm.tm_year < 0 || dst->et_tm.tm_year > 1100) {
+ return false;
+ }
+
+ dst->et_flags |= ETF_YEAR_SET;
+ });
+
+ return true;
+}
+
+inline void
+ftime_Y(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int year = tm.et_tm.tm_year + 1900;
+
+ PTIME_APPEND('0' + ((year / 1000) % 10));
+ PTIME_APPEND('0' + ((year / 100) % 10));
+ PTIME_APPEND('0' + ((year / 10) % 10));
+ PTIME_APPEND('0' + ((year / 1) % 10));
+}
+
+inline bool
+ptime_y(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(2, {
+ dst->et_tm.tm_year = ((str[off_inout + 0] - '0') * 10
+ + (str[off_inout + 1] - '0') * 1);
+ });
+
+ if (dst->et_tm.tm_year >= 0 && dst->et_tm.tm_year < 100) {
+ if (dst->et_tm.tm_year < 69) {
+ dst->et_tm.tm_year += 100;
+ }
+
+ dst->et_flags |= ETF_YEAR_SET;
+ return true;
+ }
+ return false;
+}
+
+inline void
+ftime_y(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ int year = tm.et_tm.tm_year + 1900;
+
+ PTIME_APPEND('0' + ((year / 10) % 10));
+ PTIME_APPEND('0' + ((year / 1) % 10));
+}
+
+inline bool
+ptime_z(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ int consume_amount = 5;
+
+ if ((off_inout + 6) <= len && str[off_inout + 3] == ':') {
+ consume_amount = 6;
+ }
+ PTIME_CONSUME(consume_amount, {
+ long sign;
+ long hours;
+ long mins;
+ int skip_colon = (consume_amount == 6) ? 1 : 0;
+
+ if (str[off_inout] == '+') {
+ sign = 1;
+ } else if (str[off_inout] == '-') {
+ sign = -1;
+ } else {
+ return false;
+ }
+
+ hours
+ = ((str[off_inout + 1] - '0') * 10 + (str[off_inout + 2] - '0') * 1)
+ * 60 * 60;
+ mins = ((str[off_inout + skip_colon + 3] - '0') * 10
+ + (str[off_inout + skip_colon + 4] - '0') * 1)
+ * 60;
+ dst->et_gmtoff = sign * (hours + mins);
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+ dst->et_tm.tm_gmtoff = sign * (hours + mins);
+#endif
+ });
+
+ return true;
+}
+
+inline void
+ftime_z(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ long gmtoff = std::abs(tm.et_gmtoff) / 60;
+
+ if (tm.et_gmtoff < 0) {
+ PTIME_APPEND('-');
+ } else {
+ PTIME_APPEND('+');
+ }
+
+ long mins = gmtoff % 60;
+ long hours = gmtoff / 60;
+
+ PTIME_APPEND('0' + ((hours / 10) % 10));
+ PTIME_APPEND('0' + ((hours / 1) % 10));
+ PTIME_APPEND('0' + ((mins / 10) % 10));
+ PTIME_APPEND('0' + ((mins / 1) % 10));
+}
+
+inline bool
+ptime_f(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(6, {
+ for (int lpc = 0; lpc < 6; lpc++) {
+ if (str[off_inout + lpc] < '0' || str[off_inout + lpc] > '9') {
+ return false;
+ }
+ }
+ dst->et_nsec = ((str[off_inout + 0] - '0') * 100000
+ + (str[off_inout + 1] - '0') * 10000
+ + (str[off_inout + 2] - '0') * 1000
+ + (str[off_inout + 3] - '0') * 100
+ + (str[off_inout + 4] - '0') * 10
+ + (str[off_inout + 5] - '0') * 1)
+ * 1000;
+ });
+
+ return true;
+}
+
+inline void
+ftime_f(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ uint32_t micros = tm.et_nsec / 1000;
+
+ PTIME_APPEND('0' + ((micros / 100000) % 10));
+ PTIME_APPEND('0' + ((micros / 10000) % 10));
+ PTIME_APPEND('0' + ((micros / 1000) % 10));
+ PTIME_APPEND('0' + ((micros / 100) % 10));
+ PTIME_APPEND('0' + ((micros / 10) % 10));
+ PTIME_APPEND('0' + ((micros / 1) % 10));
+}
+
+inline bool
+ptime_N(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(9, {
+ for (int lpc = 0; lpc < 9; lpc++) {
+ if (str[off_inout + lpc] < '0' || str[off_inout + lpc] > '9') {
+ return false;
+ }
+ }
+ dst->et_nsec = ((str[off_inout + 0] - '0') * 100000000
+ + (str[off_inout + 1] - '0') * 10000000
+ + (str[off_inout + 2] - '0') * 1000000
+ + (str[off_inout + 3] - '0') * 100000
+ + (str[off_inout + 4] - '0') * 10000
+ + (str[off_inout + 5] - '0') * 1000
+ + (str[off_inout + 6] - '0') * 100
+ + (str[off_inout + 7] - '0') * 10
+ + (str[off_inout + 8] - '0') * 1);
+ });
+
+ return true;
+}
+
+inline void
+ftime_N(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+ uint32_t nano = tm.et_nsec;
+
+ PTIME_APPEND('0' + ((nano / 100000000) % 10));
+ PTIME_APPEND('0' + ((nano / 10000000) % 10));
+ PTIME_APPEND('0' + ((nano / 1000000) % 10));
+ PTIME_APPEND('0' + ((nano / 100000) % 10));
+ PTIME_APPEND('0' + ((nano / 10000) % 10));
+ PTIME_APPEND('0' + ((nano / 1000) % 10));
+ PTIME_APPEND('0' + ((nano / 100) % 10));
+ PTIME_APPEND('0' + ((nano / 10) % 10));
+ PTIME_APPEND('0' + ((nano / 1) % 10));
+}
+
+inline bool
+ptime_char(char val, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(1, {
+ if (str[off_inout] != val) {
+ return false;
+ }
+ });
+
+ return true;
+}
+
+inline void
+ftime_char(char* dst, off_t& off_inout, ssize_t len, char ch)
+{
+ PTIME_APPEND(ch);
+}
+
+template<typename T>
+inline bool
+ptime_hex_to_quad(T& value_inout, const char quad)
+{
+ value_inout <<= 4;
+ if ('0' <= quad && quad <= '9') {
+ value_inout |= ((quad - '0') & 0x0f);
+ } else if ('a' <= quad && quad <= 'f') {
+ value_inout |= 10 + ((quad - 'a') & 0x0f);
+ } else if ('A' <= quad && quad <= 'F') {
+ value_inout |= 10 + ((quad - 'A') & 0x0f);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+inline bool
+ptime_at(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
+{
+ PTIME_CONSUME(16, {
+ int64_t secs = 0;
+
+ for (int lpc = 0; lpc < 16; lpc++) {
+ char quad = str[off_inout + lpc];
+
+ if (!ptime_hex_to_quad(secs, quad)) {
+ return false;
+ }
+ }
+ dst->et_nsec = 0;
+
+ lnav::time64_t small_secs = secs - 4611686018427387914ULL;
+
+ if (small_secs >= MAX_TIME_T) {
+ return false;
+ }
+
+ secs2tm(small_secs, &dst->et_tm);
+ });
+
+ if ((len - off_inout) == 8) {
+ PTIME_CONSUME(8, {
+ for (int lpc = 0; lpc < 8; lpc++) {
+ char quad = str[off_inout + lpc];
+
+ if (!ptime_hex_to_quad(dst->et_nsec, quad)) {
+ return false;
+ }
+ }
+ });
+ }
+
+ dst->et_flags |= ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
+ | ETF_MINUTE_SET | ETF_SECOND_SET | ETF_MACHINE_ORIENTED
+ | ETF_EPOCH_TIME;
+
+ return true;
+}
+
+inline void
+ftime_at(char* dst, off_t& off_inout, ssize_t len, const struct exttm& tm)
+{
+}
+
+using ptime_func = bool (*)(struct exttm*, const char*, off_t&, ssize_t);
+using ftime_func = void (*)(char*, off_t&, size_t, const struct exttm&);
+
+bool ptime_fmt(const char* fmt,
+ struct exttm* dst,
+ const char* str,
+ off_t& off,
+ ssize_t len);
+size_t ftime_fmt(char* dst,
+ size_t len,
+ const char* fmt,
+ const struct exttm& tm);
+
+struct ptime_fmt {
+ const char* pf_fmt;
+ ptime_func pf_func;
+ ftime_func pf_ffunc;
+};
+
+extern struct ptime_fmt PTIMEC_FORMATS[];
+
+extern const char* PTIMEC_FORMAT_STR[];
+
+#endif