mirror of
https://github.com/tstack/lnav
synced 2024-11-15 18:13:10 +00:00
411ea1fbee
Defect Number: Reviewed By: Testing Done:
259 lines
7.3 KiB
C++
259 lines
7.3 KiB
C++
/**
|
|
* Copyright (c) 2015, 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.
|
|
*/
|
|
|
|
#ifndef LNAV_RELATIVE_TIME_HH
|
|
#define LNAV_RELATIVE_TIME_HH
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
|
|
#define __STDC_FORMAT_MACROS
|
|
#include <inttypes.h>
|
|
|
|
#include <string>
|
|
|
|
#include "ptimec.hh"
|
|
|
|
class relative_time {
|
|
public:
|
|
enum token_t {
|
|
RTT_INVALID = -1,
|
|
|
|
RTT_WHITE,
|
|
RTT_AM,
|
|
RTT_PM,
|
|
RTT_A,
|
|
RTT_AN,
|
|
RTT_AT,
|
|
RTT_TIME,
|
|
RTT_NUMBER,
|
|
RTT_MICROS,
|
|
RTT_MILLIS,
|
|
RTT_SECONDS,
|
|
RTT_MINUTES,
|
|
RTT_HOURS,
|
|
RTT_DAYS,
|
|
RTT_WEEKS,
|
|
RTT_MONTHS,
|
|
RTT_YEARS,
|
|
RTT_TODAY,
|
|
RTT_YESTERDAY,
|
|
RTT_TOMORROW,
|
|
RTT_NOON,
|
|
RTT_AND,
|
|
RTT_AGO,
|
|
RTT_LATER,
|
|
RTT_BEFORE,
|
|
RTT_NOW,
|
|
RTT_HERE,
|
|
|
|
RTT__MAX
|
|
};
|
|
|
|
relative_time() {
|
|
this->clear();
|
|
};
|
|
|
|
void clear() {
|
|
memset(this->rt_field, 0, sizeof(this->rt_field));
|
|
memset(this->rt_is_absolute, 0, sizeof(this->rt_is_absolute));
|
|
};
|
|
|
|
void negate() {
|
|
for (int lpc = 0; lpc < RTF__MAX; lpc++) {
|
|
if (!this->rt_is_absolute[lpc] && this->rt_field[lpc] != 0) {
|
|
this->rt_field[lpc] = -this->rt_field[lpc];
|
|
}
|
|
}
|
|
};
|
|
|
|
bool is_negative() const {
|
|
for (int lpc = 0; lpc < RTF__MAX; lpc++) {
|
|
if (this->rt_field[lpc] < 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
bool is_absolute() const {
|
|
for (int lpc = 0; lpc < RTF__MAX; lpc++) {
|
|
if (this->rt_is_absolute[lpc]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
bool empty() const {
|
|
for (int lpc = 0; lpc < RTF__MAX; lpc++) {
|
|
if (this->rt_field[lpc]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
struct parse_error {
|
|
int pe_column;
|
|
std::string pe_msg;
|
|
};
|
|
|
|
bool parse(const char *str, size_t len, struct parse_error &pe_out);
|
|
|
|
bool parse(const std::string &str, struct parse_error &pe_out) {
|
|
return this->parse(str.c_str(), str.length(), pe_out);
|
|
}
|
|
|
|
relative_time &add_now() {
|
|
struct exttm tm;
|
|
time_t now;
|
|
|
|
time(&now);
|
|
tm.et_tm = *gmtime(&now);
|
|
this->add(tm);
|
|
|
|
return *this;
|
|
};
|
|
|
|
void add(struct exttm &tm) {
|
|
if (this->rt_is_absolute[RTF_MICROSECONDS]) {
|
|
tm.et_nsec = this->rt_field[RTF_MICROSECONDS] * 1000;
|
|
}
|
|
else {
|
|
tm.et_nsec += this->rt_field[RTF_MICROSECONDS] * 1000;
|
|
}
|
|
if (this->rt_is_absolute[RTF_SECONDS]) {
|
|
tm.et_tm.tm_sec = this->rt_field[RTF_SECONDS];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_sec += this->rt_field[RTF_SECONDS];
|
|
}
|
|
if (this->rt_is_absolute[RTF_MINUTES]) {
|
|
tm.et_tm.tm_min = this->rt_field[RTF_MINUTES];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_min += this->rt_field[RTF_MINUTES];
|
|
}
|
|
if (this->rt_is_absolute[RTF_HOURS]) {
|
|
tm.et_tm.tm_hour = this->rt_field[RTF_HOURS];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_hour += this->rt_field[RTF_HOURS];
|
|
}
|
|
if (this->rt_is_absolute[RTF_DAYS]) {
|
|
tm.et_tm.tm_mday = this->rt_field[RTF_DAYS];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_mday += this->rt_field[RTF_DAYS];
|
|
}
|
|
if (this->rt_is_absolute[RTF_MONTHS]) {
|
|
tm.et_tm.tm_mon = this->rt_field[RTF_MONTHS];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_mon += this->rt_field[RTF_MONTHS];
|
|
}
|
|
if (this->rt_is_absolute[RTF_YEARS]) {
|
|
tm.et_tm.tm_year = this->rt_field[RTF_YEARS];
|
|
}
|
|
else {
|
|
tm.et_tm.tm_year += this->rt_field[RTF_YEARS];
|
|
}
|
|
};
|
|
|
|
int64_t to_microseconds() {
|
|
int64_t retval;
|
|
|
|
retval = this->rt_field[RTF_YEARS] * 12;
|
|
retval = (retval + this->rt_field[RTF_MONTHS]) * 30;
|
|
retval = (retval + this->rt_field[RTF_DAYS]) * 24;
|
|
retval = (retval + this->rt_field[RTF_HOURS]) * 60;
|
|
retval = (retval + this->rt_field[RTF_MINUTES]) * 60;
|
|
retval = (retval + this->rt_field[RTF_SECONDS]) * 1000 * 1000;
|
|
|
|
return retval;
|
|
};
|
|
|
|
void to_timeval(struct timeval &tv_out) {
|
|
int64_t us = this->to_microseconds();
|
|
|
|
tv_out.tv_sec = us / (1000 * 1000);
|
|
tv_out.tv_usec = us % (1000 * 1000);
|
|
};
|
|
|
|
std::string to_string() {
|
|
char dst[128];
|
|
|
|
snprintf(dst, sizeof(dst),
|
|
"%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c",
|
|
this->rt_field[RTF_YEARS],
|
|
this->rt_is_absolute[RTF_YEARS] ? 'Y' : 'y',
|
|
this->rt_field[RTF_MONTHS],
|
|
this->rt_is_absolute[RTF_MONTHS] ? 'M' : 'm',
|
|
this->rt_field[RTF_DAYS],
|
|
this->rt_is_absolute[RTF_DAYS] ? 'D' : 'd',
|
|
this->rt_field[RTF_HOURS],
|
|
this->rt_is_absolute[RTF_HOURS] ? 'H' : 'h',
|
|
this->rt_field[RTF_MINUTES],
|
|
this->rt_is_absolute[RTF_MINUTES] ? 'M' : 'm',
|
|
this->rt_field[RTF_SECONDS],
|
|
this->rt_is_absolute[RTF_SECONDS] ? 'S' : 's',
|
|
this->rt_field[RTF_MICROSECONDS],
|
|
this->rt_is_absolute[RTF_MICROSECONDS] ? 'U' : 'u');
|
|
return dst;
|
|
};
|
|
|
|
void rollover();
|
|
|
|
enum {
|
|
RTF_MICROSECONDS,
|
|
RTF_SECONDS,
|
|
RTF_MINUTES,
|
|
RTF_HOURS,
|
|
RTF_DAYS,
|
|
RTF_MONTHS,
|
|
RTF_YEARS,
|
|
|
|
RTF__MAX
|
|
};
|
|
|
|
int64_t rt_field[RTF__MAX];
|
|
bool rt_is_absolute[RTF__MAX];
|
|
};
|
|
|
|
size_t str2reltime(int64_t millis, std::string &value_out);
|
|
|
|
inline
|
|
size_t str2reltime(const struct timeval &tv, std::string &value_out) {
|
|
return str2reltime(tv.tv_sec * 1000 + tv.tv_usec / 1000, value_out);
|
|
};
|
|
|
|
#endif //LNAV_RELATIVE_TIME_HH
|