1 /**
2 * Copyright (c) 2014, Timothy Stack
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * * Neither the name of Timothy Stack nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @file ptimec.hh
30 */
31
32 #ifndef pctimec_hh
33 #define pctimec_hh
34
35 // XXX
36 #define __STDC_FORMAT_MACROS
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41 #include <inttypes.h>
42 #include <sys/types.h>
43
44 #include <cstdlib>
45
46 #include "base/lnav_log.hh"
47 #include "base/time_util.hh"
48
49 #define PTIME_CONSUME(amount, block) \
50 if ((off_inout + (amount)) > len) { \
51 return false; \
52 } \
53 \
54 block \
55 \
56 off_inout += (amount);
57
58 #define PTIME_APPEND(ch) \
59 if ((off_inout + 2) >= len) { \
60 return; \
61 } \
62 dst[off_inout] = ch; \
63 off_inout += 1;
64
65 #define ABR_TO_INT(a, b, c) \
66 (((a) << 24) | ((b) << 16) | ((c) << 8))
67
68 inline
ptime_upto(char ch,const char * str,off_t & off_inout,ssize_t len)69 bool ptime_upto(char ch, const char *str, off_t &off_inout, ssize_t len)
70 {
71 for (; off_inout < len; off_inout++) {
72 if (str[off_inout] == ch) {
73 return true;
74 }
75 }
76
77 return false;
78 }
79
80 inline
ptime_upto_end(const char * str,off_t & off_inout,ssize_t len)81 bool ptime_upto_end(const char *str, off_t &off_inout, ssize_t len)
82 {
83 off_inout = len;
84
85 return true;
86 }
87
88 bool ptime_b_slow(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len);
89
ptime_b(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)90 inline bool ptime_b(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
91 {
92 if (off_inout + 3 < len) {
93 auto month_start = (unsigned char *) &str[off_inout];
94 uint32_t month_int =
95 ABR_TO_INT(month_start[0] & ~0x20UL,
96 month_start[1] & ~0x20UL,
97 month_start[2] & ~0x20UL);
98 int val;
99
100 switch (month_int) {
101 case ABR_TO_INT('J', 'A', 'N'):
102 val = 0;
103 break;
104 case ABR_TO_INT('F', 'E', 'B'):
105 val = 1;
106 break;
107 case ABR_TO_INT('M', 'A', 'R'):
108 val = 2;
109 break;
110 case ABR_TO_INT('A', 'P', 'R'):
111 val = 3;
112 break;
113 case ABR_TO_INT('M', 'A', 'Y'):
114 val = 4;
115 break;
116 case ABR_TO_INT('J', 'U', 'N'):
117 val = 5;
118 break;
119 case ABR_TO_INT('J', 'U', 'L'):
120 val = 6;
121 break;
122 case ABR_TO_INT('A', 'U', 'G'):
123 val = 7;
124 break;
125 case ABR_TO_INT('S', 'E', 'P'):
126 val = 8;
127 break;
128 case ABR_TO_INT('O', 'C', 'T'):
129 val = 9;
130 break;
131 case ABR_TO_INT('N', 'O', 'V'):
132 val = 10;
133 break;
134 case ABR_TO_INT('D', 'E', 'C'):
135 val = 11;
136 break;
137 default:
138 val = -1;
139 break;
140 }
141 if (val >= 0) {
142 off_inout += 3;
143 dst->et_tm.tm_mon = val;
144 dst->et_flags |= ETF_MONTH_SET;
145 return true;
146 }
147 }
148
149 return ptime_b_slow(dst, str, off_inout, len);
150 }
151
ftime_a(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)152 inline void ftime_a(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
153 {
154 switch (tm.et_tm.tm_wday) {
155 case 0:
156 PTIME_APPEND('S');
157 PTIME_APPEND('u');
158 PTIME_APPEND('n');
159 break;
160 case 1:
161 PTIME_APPEND('M');
162 PTIME_APPEND('o');
163 PTIME_APPEND('n');
164 break;
165 case 2:
166 PTIME_APPEND('T');
167 PTIME_APPEND('u');
168 PTIME_APPEND('e');
169 break;
170 case 3:
171 PTIME_APPEND('W');
172 PTIME_APPEND('e');
173 PTIME_APPEND('d');
174 break;
175 case 4:
176 PTIME_APPEND('T');
177 PTIME_APPEND('h');
178 PTIME_APPEND('u');
179 break;
180 case 5:
181 PTIME_APPEND('F');
182 PTIME_APPEND('r');
183 PTIME_APPEND('i');
184 break;
185 case 6:
186 PTIME_APPEND('S');
187 PTIME_APPEND('a');
188 PTIME_APPEND('t');
189 break;
190 default:
191 PTIME_APPEND('X');
192 PTIME_APPEND('X');
193 PTIME_APPEND('X');
194 break;
195 }
196 }
197
ftime_Z(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)198 inline void ftime_Z(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
199 {
200 }
201
ftime_b(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)202 inline void ftime_b(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
203 {
204 switch (tm.et_tm.tm_mon) {
205 case 0:
206 PTIME_APPEND('J');
207 PTIME_APPEND('a');
208 PTIME_APPEND('n');
209 break;
210 case 1:
211 PTIME_APPEND('F');
212 PTIME_APPEND('e');
213 PTIME_APPEND('b');
214 break;
215 case 2:
216 PTIME_APPEND('M');
217 PTIME_APPEND('a');
218 PTIME_APPEND('r');
219 break;
220 case 3:
221 PTIME_APPEND('A');
222 PTIME_APPEND('p');
223 PTIME_APPEND('r');
224 break;
225 case 4:
226 PTIME_APPEND('M');
227 PTIME_APPEND('a');
228 PTIME_APPEND('y');
229 break;
230 case 5:
231 PTIME_APPEND('J');
232 PTIME_APPEND('u');
233 PTIME_APPEND('n');
234 break;
235 case 6:
236 PTIME_APPEND('J');
237 PTIME_APPEND('u');
238 PTIME_APPEND('l');
239 break;
240 case 7:
241 PTIME_APPEND('A');
242 PTIME_APPEND('u');
243 PTIME_APPEND('g');
244 break;
245 case 8:
246 PTIME_APPEND('S');
247 PTIME_APPEND('e');
248 PTIME_APPEND('p');
249 break;
250 case 9:
251 PTIME_APPEND('O');
252 PTIME_APPEND('c');
253 PTIME_APPEND('t');
254 break;
255 case 10:
256 PTIME_APPEND('N');
257 PTIME_APPEND('o');
258 PTIME_APPEND('v');
259 break;
260 case 11:
261 PTIME_APPEND('D');
262 PTIME_APPEND('e');
263 PTIME_APPEND('c');
264 break;
265 default:
266 PTIME_APPEND('X');
267 PTIME_APPEND('X');
268 PTIME_APPEND('X');
269 break;
270 }
271 }
272
ptime_S(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)273 inline bool ptime_S(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
274 {
275 PTIME_CONSUME(2, {
276 if (str[off_inout + 1] > '9') {
277 return false;
278 }
279 dst->et_tm.tm_sec = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
280 });
281
282 return (dst->et_tm.tm_sec >= 0 && dst->et_tm.tm_sec <= 59);
283 }
284
ftime_S(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)285 inline void ftime_S(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
286 {
287 PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 10) % 10));
288 PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 1) % 10));
289 }
290
ptime_s(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)291 inline bool ptime_s(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
292 {
293 off_t off_start = off_inout;
294 lnav::time64_t epoch = 0;
295
296 while (off_inout < len && isdigit(str[off_inout])) {
297 if ((off_inout - off_start) > 11) {
298 return false;
299 }
300
301 epoch *= 10;
302 epoch += str[off_inout] - '0';
303 off_inout += 1;
304 }
305
306 if (epoch >= MAX_TIME_T) {
307 return false;
308 }
309
310 secs2tm(epoch, &dst->et_tm);
311 dst->et_flags = ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
312
313 return (epoch > 0);
314 }
315
ftime_s(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)316 inline void ftime_s(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
317 {
318 time_t t = tm2sec(&tm.et_tm);
319
320 snprintf(&dst[off_inout], len - off_inout, "%ld", t);
321 off_inout = strlen(dst);
322 }
323
ptime_q(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)324 inline bool ptime_q(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
325 {
326 off_t off_start = off_inout;
327 lnav::time64_t epoch = 0;
328
329 while (off_inout < len && isxdigit(str[off_inout])) {
330 if ((off_inout - off_start) > 11) {
331 return false;
332 }
333
334 epoch *= 16;
335 switch (tolower(str[off_inout])) {
336 case '0':
337 case '1':
338 case '2':
339 case '3':
340 case '4':
341 case '5':
342 case '6':
343 case '7':
344 case '8':
345 case '9':
346 epoch += str[off_inout] - '0';
347 break;
348 case 'a':
349 case 'b':
350 case 'c':
351 case 'd':
352 case 'e':
353 case 'f':
354 epoch += str[off_inout] - 'a' + 10;
355 break;
356 }
357 off_inout += 1;
358 }
359
360 if (epoch >= MAX_TIME_T) {
361 return false;
362 }
363
364 secs2tm(epoch, &dst->et_tm);
365 dst->et_flags = ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
366
367 return (epoch > 0);
368 }
369
ftime_q(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)370 inline void ftime_q(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
371 {
372 time_t t = tm2sec(&tm.et_tm);
373
374 snprintf(&dst[off_inout], len - off_inout, "%lx", t);
375 off_inout = strlen(dst);
376 }
377
ptime_L(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)378 inline bool ptime_L(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
379 {
380 int ms = 0;
381
382 PTIME_CONSUME(3, {
383 char c0 = str[off_inout];
384 char c1 = str[off_inout + 1];
385 char c2 = str[off_inout + 2];
386 if (!isdigit(c0) || !isdigit(c1) || !isdigit(c2)) {
387 return false;
388 }
389 ms = (
390 (str[off_inout ] - '0') * 100 +
391 (str[off_inout + 1] - '0') * 10 +
392 (str[off_inout + 2] - '0'));
393 });
394
395 if ((ms >= 0 && ms <= 999)) {
396 dst->et_nsec = ms * 1000000;
397 return true;
398 }
399 return false;
400 }
401
ftime_L(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)402 inline void ftime_L(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
403 {
404 int millis = tm.et_nsec / 1000000;
405
406 PTIME_APPEND('0' + ((millis / 100) % 10));
407 PTIME_APPEND('0' + ((millis / 10) % 10));
408 PTIME_APPEND('0' + ((millis / 1) % 10));
409 }
410
ptime_M(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)411 inline bool ptime_M(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
412 {
413 PTIME_CONSUME(2, {
414 if (str[off_inout + 1] > '9') {
415 return false;
416 }
417 dst->et_tm.tm_min = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
418 });
419
420 return (dst->et_tm.tm_min >= 0 && dst->et_tm.tm_min <= 59);
421 }
422
ftime_M(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)423 inline void ftime_M(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
424 {
425 PTIME_APPEND('0' + ((tm.et_tm.tm_min / 10) % 10));
426 PTIME_APPEND('0' + ((tm.et_tm.tm_min / 1) % 10));
427 }
428
ptime_H(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)429 inline bool ptime_H(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
430 {
431 PTIME_CONSUME(2, {
432 if (str[off_inout + 1] > '9') {
433 return false;
434 }
435 dst->et_tm.tm_hour = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
436 });
437
438 return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
439 }
440
ftime_H(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)441 inline void ftime_H(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
442 {
443 PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
444 PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
445 }
446
ptime_i(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)447 inline bool ptime_i(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
448 {
449 uint64_t epoch_ms = 0;
450 lnav::time64_t epoch;
451
452 while (off_inout < len && isdigit(str[off_inout])) {
453 epoch_ms *= 10;
454 epoch_ms += str[off_inout] - '0';
455 off_inout += 1;
456 }
457
458 dst->et_nsec = (epoch_ms % 1000ULL) * 1000000;
459 epoch = (epoch_ms / 1000ULL);
460
461 if (epoch >= MAX_TIME_T) {
462 return false;
463 }
464
465 secs2tm(epoch, &dst->et_tm);
466 dst->et_flags = ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
467
468 return (epoch_ms > 0);
469 }
470
ftime_i(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)471 inline void ftime_i(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
472 {
473 int64_t t = tm2sec(&tm.et_tm);
474
475 t += tm.et_nsec / 1000000;
476 snprintf(&dst[off_inout], len - off_inout, "%" PRId64, t);
477 off_inout = strlen(dst);
478 }
479
ptime_6(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)480 inline bool ptime_6(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
481 {
482 uint64_t epoch_us = 0;
483 lnav::time64_t epoch;
484
485 while (off_inout < len && isdigit(str[off_inout])) {
486 epoch_us *= 10;
487 epoch_us += str[off_inout] - '0';
488 off_inout += 1;
489 }
490
491 dst->et_nsec = (epoch_us % 1000000ULL) * 1000ULL;
492 epoch = (epoch_us / 1000000ULL);
493
494 if (epoch >= MAX_TIME_T) {
495 return false;
496 }
497
498 secs2tm(epoch, &dst->et_tm);
499 dst->et_flags = ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
500
501 return (epoch_us > 0);
502 }
503
ftime_6(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)504 inline void ftime_6(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
505 {
506 int64_t t = tm2sec(&tm.et_tm);
507
508 t += tm.et_nsec / 1000;
509 snprintf(&dst[off_inout], len - off_inout, "%" PRId64, t);
510 off_inout = strlen(dst);
511 }
512
ptime_I(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)513 inline bool ptime_I(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
514 {
515 PTIME_CONSUME(2, {
516 if (str[off_inout + 1] > '9') {
517 return false;
518 }
519 dst->et_tm.tm_hour = (str[off_inout] - '0') * 10 + (str[off_inout + 1] - '0');
520
521 if (dst->et_tm.tm_hour < 1 || dst->et_tm.tm_hour > 12) {
522 return false;
523 }
524 });
525
526 return true;
527 }
528
ftime_I(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)529 inline void ftime_I(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
530 {
531 int hour = tm.et_tm.tm_hour;
532
533 if (hour >= 12) {
534 hour -= 12;
535 }
536 if (hour == 0) {
537 hour = 12;
538 }
539
540 PTIME_APPEND('0' + ((hour / 10) % 10));
541 PTIME_APPEND('0' + ((hour / 1) % 10));
542 }
543
ptime_d(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)544 inline bool ptime_d(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
545 {
546 PTIME_CONSUME(2, {
547 if (str[off_inout] == ' ') {
548 dst->et_tm.tm_mday = 0;
549 }
550 else {
551 dst->et_tm.tm_mday = (str[off_inout] - '0') * 10;
552 }
553 if (str[off_inout + 1] > '9') {
554 return false;
555 }
556 dst->et_tm.tm_mday += (str[off_inout + 1] - '0');
557 });
558
559 if (dst->et_tm.tm_mday >= 1 && dst->et_tm.tm_mday <= 31) {
560 dst->et_flags |= ETF_DAY_SET;
561 return true;
562 }
563 return false;
564 }
565
ftime_d(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)566 inline void ftime_d(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
567 {
568 PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
569 PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
570 }
571
ptime_e(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)572 inline bool ptime_e(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
573 {
574 dst->et_tm.tm_mday = 0;
575 PTIME_CONSUME(1, {
576 if (str[off_inout] < '1' || str[off_inout] > '9') {
577 return false;
578 }
579 dst->et_tm.tm_mday = str[off_inout] - '0';
580 });
581 if (off_inout + 1 < len) {
582 if (str[off_inout] >= '0' && str[off_inout] <= '9') {
583 dst->et_tm.tm_mday *= 10;
584 dst->et_tm.tm_mday += str[off_inout] - '0';
585 off_inout += 1;
586 }
587 }
588
589 if (dst->et_tm.tm_mday >= 1 && dst->et_tm.tm_mday <= 31) {
590 dst->et_flags |= ETF_DAY_SET;
591 return true;
592 }
593 return false;
594 }
595
ftime_e(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)596 inline void ftime_e(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
597 {
598 if (tm.et_tm.tm_mday < 10) {
599 PTIME_APPEND(' ');
600 }
601 else {
602 PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
603 }
604 PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
605 }
606
ptime_m(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)607 inline bool ptime_m(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
608 {
609 off_t orig_off = off_inout;
610
611 dst->et_tm.tm_mon = 0;
612 PTIME_CONSUME(1, {
613 if (str[off_inout] < '0' || str[off_inout] > '9') {
614 return false;
615 }
616 dst->et_tm.tm_mon = str[off_inout] - '0';
617 });
618 if (off_inout + 1 < len) {
619 if (str[off_inout] >= '0' && str[off_inout] <= '9') {
620 dst->et_tm.tm_mon *= 10;
621 dst->et_tm.tm_mon += str[off_inout] - '0';
622 off_inout += 1;
623 }
624 }
625
626 dst->et_tm.tm_mon -= 1;
627
628 if (dst->et_tm.tm_mon >= 0 && dst->et_tm.tm_mon <= 11) {
629 dst->et_flags |= ETF_MONTH_SET;
630 return true;
631 }
632
633 off_inout = orig_off;
634 return false;
635 }
636
ftime_m(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)637 inline void ftime_m(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
638 {
639 PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 10) % 10));
640 PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 1) % 10));
641 }
642
ptime_k(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)643 inline bool ptime_k(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
644 {
645 dst->et_tm.tm_hour = 0;
646 PTIME_CONSUME(1, {
647 if (str[off_inout] < '0' || str[off_inout] > '9') {
648 return false;
649 }
650 dst->et_tm.tm_hour = str[off_inout] - '0';
651 });
652 if (off_inout + 1 < len) {
653 if (str[off_inout] >= '0' && str[off_inout] <= '9') {
654 dst->et_tm.tm_hour *= 10;
655 dst->et_tm.tm_hour += str[off_inout] - '0';
656 off_inout += 1;
657 }
658 }
659
660 return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
661 }
662
ftime_k(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)663 inline void ftime_k(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
664 {
665 if (tm.et_tm.tm_hour < 10) {
666 PTIME_APPEND(' ');
667 }
668 else {
669 PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
670 }
671 PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
672 }
673
ptime_l(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)674 inline bool ptime_l(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
675 {
676 off_t orig_off = off_inout;
677 bool consumed_space = false;
678
679 dst->et_tm.tm_hour = 0;
680
681 if ((off_inout + 1) > len) {
682 return false;
683 }
684
685 if (str[off_inout] == ' ') {
686 consumed_space = true;
687 off_inout += 1;
688 }
689
690 if ((off_inout + 1) > len) {
691 off_inout = orig_off;
692 return false;
693 }
694
695 if (str[off_inout] < '1' || str[off_inout] > '9') {
696 off_inout = orig_off;
697 return false;
698 }
699
700 dst->et_tm.tm_hour = str[off_inout] - '0';
701 off_inout += 1;
702
703 if (consumed_space || str[off_inout] < '0' || str[off_inout] > '9') {
704 return true;
705 }
706
707 dst->et_tm.tm_hour *= 10;
708 dst->et_tm.tm_hour += str[off_inout] - '0';
709 off_inout += 1;
710
711 if (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23) {
712 return true;
713 }
714
715 off_inout = orig_off;
716 return false;
717 }
718
ftime_l(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)719 inline void ftime_l(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
720 {
721 int hour = tm.et_tm.tm_hour;
722
723 if (hour >= 12) {
724 hour -= 12;
725 }
726 if (hour == 0) {
727 hour = 12;
728 }
729
730 if (hour < 10) {
731 PTIME_APPEND(' ');
732 }
733 else {
734 PTIME_APPEND('0' + ((hour / 10) % 10));
735 }
736 PTIME_APPEND('0' + ((hour / 1) % 10));
737 }
738
ptime_p(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)739 inline bool ptime_p(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
740 {
741 PTIME_CONSUME(2, {
742 char lead = str[off_inout];
743
744 if ((str[off_inout + 1] & 0xdf) != 'M') {
745 return false;
746 }
747 else if ((lead & 0xdf) == 'A') {
748 if (dst->et_tm.tm_hour == 12) {
749 dst->et_tm.tm_hour = 0;
750 }
751 }
752 else if ((lead & 0xdf) == 'P') {
753 if (dst->et_tm.tm_hour < 12) {
754 dst->et_tm.tm_hour += 12;
755 }
756 }
757 else {
758 return false;
759 }
760 });
761
762 return true;
763 }
764
ftime_p(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)765 inline void ftime_p(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
766 {
767 if (tm.et_tm.tm_hour < 12) {
768 PTIME_APPEND('A');
769 }
770 else {
771 PTIME_APPEND('P');
772 }
773 PTIME_APPEND('M');
774 }
775
ptime_Y(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)776 inline bool ptime_Y(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
777 {
778 PTIME_CONSUME(4, {
779 dst->et_tm.tm_year = (
780 (str[off_inout + 0] - '0') * 1000 +
781 (str[off_inout + 1] - '0') * 100 +
782 (str[off_inout + 2] - '0') * 10 +
783 (str[off_inout + 3] - '0') * 1) - 1900;
784
785 if (dst->et_tm.tm_year < 0 || dst->et_tm.tm_year > 1100) {
786 return false;
787 }
788
789 dst->et_flags |= ETF_YEAR_SET;
790 });
791
792 return true;
793 }
794
ftime_Y(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)795 inline void ftime_Y(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
796 {
797 int year = tm.et_tm.tm_year + 1900;
798
799 PTIME_APPEND('0' + ((year / 1000) % 10));
800 PTIME_APPEND('0' + ((year / 100) % 10));
801 PTIME_APPEND('0' + ((year / 10) % 10));
802 PTIME_APPEND('0' + ((year / 1) % 10));
803 }
804
ptime_y(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)805 inline bool ptime_y(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
806 {
807 PTIME_CONSUME(2, {
808 dst->et_tm.tm_year = (
809 (str[off_inout + 0] - '0') * 10 +
810 (str[off_inout + 1] - '0') * 1);
811 });
812
813 if (dst->et_tm.tm_year >= 0 && dst->et_tm.tm_year < 100) {
814 if (dst->et_tm.tm_year < 69) {
815 dst->et_tm.tm_year += 100;
816 }
817
818 dst->et_flags |= ETF_YEAR_SET;
819 return true;
820 }
821 return false;
822 }
823
ftime_y(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)824 inline void ftime_y(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
825 {
826 int year = tm.et_tm.tm_year + 1900;
827
828 PTIME_APPEND('0' + ((year / 10) % 10));
829 PTIME_APPEND('0' + ((year / 1) % 10));
830 }
831
ptime_z(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)832 inline bool ptime_z(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
833 {
834 int consume_amount = 5;
835
836 if ((off_inout + 6) <= len && str[off_inout + 3] == ':') {
837 consume_amount = 6;
838 }
839 PTIME_CONSUME(consume_amount, {
840 long sign;
841 long hours;
842 long mins;
843 int skip_colon = (consume_amount == 6) ? 1 : 0;
844
845 if (str[off_inout] == '+') {
846 sign = 1;
847 }
848 else if (str[off_inout] == '-') {
849 sign = -1;
850 }
851 else {
852 return false;
853 }
854
855 hours = (
856 (str[off_inout + 1] - '0') * 10 +
857 (str[off_inout + 2] - '0') * 1) * 60 * 60;
858 mins = (
859 (str[off_inout + skip_colon + 3] - '0') * 10 +
860 (str[off_inout + skip_colon + 4] - '0') * 1) * 60;
861 dst->et_gmtoff = sign * (hours + mins);
862 #ifdef HAVE_STRUCT_TM_TM_ZONE
863 dst->et_tm.tm_gmtoff = sign * (hours + mins);
864 #endif
865 });
866
867 return true;
868 }
869
ftime_z(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)870 inline void ftime_z(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
871 {
872 long gmtoff = std::abs(tm.et_gmtoff) / 60;
873
874 if (tm.et_gmtoff < 0) {
875 PTIME_APPEND('-');
876 }
877 else {
878 PTIME_APPEND('+');
879 }
880
881 long mins = gmtoff % 60;
882 long hours = gmtoff / 60;
883
884 PTIME_APPEND('0' + ((hours / 10) % 10));
885 PTIME_APPEND('0' + ((hours / 1) % 10));
886 PTIME_APPEND('0' + ((mins / 10) % 10));
887 PTIME_APPEND('0' + ((mins / 1) % 10));
888 }
889
ptime_f(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)890 inline bool ptime_f(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
891 {
892 PTIME_CONSUME(6, {
893 for (int lpc = 0; lpc < 6; lpc++) {
894 if (str[off_inout + lpc] < '0' || str[off_inout + lpc] > '9') {
895 return false;
896 }
897 }
898 dst->et_nsec = (
899 (str[off_inout + 0] - '0') * 100000 +
900 (str[off_inout + 1] - '0') * 10000 +
901 (str[off_inout + 2] - '0') * 1000 +
902 (str[off_inout + 3] - '0') * 100 +
903 (str[off_inout + 4] - '0') * 10 +
904 (str[off_inout + 5] - '0') * 1) * 1000;
905 });
906
907 return true;
908 }
909
ftime_f(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)910 inline void ftime_f(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
911 {
912 uint32_t micros = tm.et_nsec / 1000;
913
914 PTIME_APPEND('0' + ((micros / 100000) % 10));
915 PTIME_APPEND('0' + ((micros / 10000) % 10));
916 PTIME_APPEND('0' + ((micros / 1000) % 10));
917 PTIME_APPEND('0' + ((micros / 100) % 10));
918 PTIME_APPEND('0' + ((micros / 10) % 10));
919 PTIME_APPEND('0' + ((micros / 1) % 10));
920 }
921
ptime_N(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)922 inline bool ptime_N(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
923 {
924 PTIME_CONSUME(9, {
925 for (int lpc = 0; lpc < 9; lpc++) {
926 if (str[off_inout + lpc] < '0' || str[off_inout + lpc] > '9') {
927 return false;
928 }
929 }
930 dst->et_nsec = (
931 (str[off_inout + 0] - '0') * 100000000 +
932 (str[off_inout + 1] - '0') * 10000000 +
933 (str[off_inout + 2] - '0') * 1000000 +
934 (str[off_inout + 3] - '0') * 100000 +
935 (str[off_inout + 4] - '0') * 10000 +
936 (str[off_inout + 5] - '0') * 1000 +
937 (str[off_inout + 6] - '0') * 100 +
938 (str[off_inout + 7] - '0') * 10 +
939 (str[off_inout + 8] - '0') * 1);
940 });
941
942 return true;
943 }
944
ftime_N(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)945 inline void ftime_N(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
946 {
947 uint32_t nano = tm.et_nsec;
948
949 PTIME_APPEND('0' + ((nano / 100000000) % 10));
950 PTIME_APPEND('0' + ((nano / 10000000) % 10));
951 PTIME_APPEND('0' + ((nano / 1000000) % 10));
952 PTIME_APPEND('0' + ((nano / 100000) % 10));
953 PTIME_APPEND('0' + ((nano / 10000) % 10));
954 PTIME_APPEND('0' + ((nano / 1000) % 10));
955 PTIME_APPEND('0' + ((nano / 100) % 10));
956 PTIME_APPEND('0' + ((nano / 10) % 10));
957 PTIME_APPEND('0' + ((nano / 1) % 10));
958 }
959
ptime_char(char val,const char * str,off_t & off_inout,ssize_t len)960 inline bool ptime_char(char val, const char *str, off_t &off_inout, ssize_t len)
961 {
962 PTIME_CONSUME(1, {
963 if (str[off_inout] != val) {
964 return false;
965 }
966 });
967
968 return true;
969 }
970
ftime_char(char * dst,off_t & off_inout,ssize_t len,char ch)971 inline void ftime_char(char *dst, off_t &off_inout, ssize_t len, char ch)
972 {
973 PTIME_APPEND(ch);
974 }
975
976 template<typename T>
ptime_hex_to_quad(T & value_inout,const char quad)977 inline bool ptime_hex_to_quad(T &value_inout, const char quad)
978 {
979 value_inout <<= 4;
980 if ('0' <= quad && quad <= '9') {
981 value_inout |= ((quad - '0') & 0x0f);
982 }
983 else if ('a' <= quad && quad <= 'f') {
984 value_inout |= 10 + ((quad - 'a') & 0x0f);
985 }
986 else if ('A' <= quad && quad <= 'F') {
987 value_inout |= 10 + ((quad - 'A') & 0x0f);
988 }
989 else {
990 return false;
991 }
992
993 return true;
994 }
995
ptime_at(struct exttm * dst,const char * str,off_t & off_inout,ssize_t len)996 inline bool ptime_at(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
997 {
998 PTIME_CONSUME(16, {
999 int64_t secs = 0;
1000
1001 for (int lpc = 0; lpc < 16; lpc++) {
1002 char quad = str[off_inout + lpc];
1003
1004 if (!ptime_hex_to_quad(secs, quad)) {
1005 return false;
1006 }
1007 }
1008 dst->et_nsec = 0;
1009
1010 lnav::time64_t small_secs = secs - 4611686018427387914ULL;
1011
1012 if (small_secs >= MAX_TIME_T) {
1013 return false;
1014 }
1015
1016 secs2tm(small_secs, &dst->et_tm);
1017 });
1018
1019 if ((len - off_inout) == 8) {
1020 PTIME_CONSUME(8, {
1021 for (int lpc = 0; lpc < 8; lpc++) {
1022 char quad = str[off_inout + lpc];
1023
1024 if (!ptime_hex_to_quad(dst->et_nsec, quad)) {
1025 return false;
1026 }
1027 }
1028 });
1029 }
1030
1031 dst->et_flags |= ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
1032
1033 return true;
1034 }
1035
ftime_at(char * dst,off_t & off_inout,ssize_t len,const struct exttm & tm)1036 inline void ftime_at(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
1037 {
1038
1039 }
1040
1041 typedef bool (*ptime_func)(struct exttm *dst, const char *str, off_t &off, ssize_t len);
1042 typedef void (*ftime_func)(char *dst, off_t &off_inout, size_t len, const struct exttm &tm);
1043
1044 bool ptime_fmt(const char *fmt, struct exttm *dst, const char *str, off_t &off, ssize_t len);
1045 size_t ftime_fmt(char *dst, size_t len, const char *fmt, const struct exttm &tm);
1046
1047 struct ptime_fmt {
1048 const char *pf_fmt;
1049 ptime_func pf_func;
1050 ftime_func pf_ffunc;
1051 };
1052
1053 extern struct ptime_fmt PTIMEC_FORMATS[];
1054
1055 extern const char *PTIMEC_FORMAT_STR[];
1056
1057 #endif
1058