mirror of https://github.com/tstack/lnav
[cmd] add support for times in goto
parent
7cd7bf4dc4
commit
ec473edc85
@ -0,0 +1,274 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "pcrepp.hh"
|
||||
#include "lnav_util.hh"
|
||||
#include "relative_time.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
pcrepp pcre;
|
||||
} MATCHERS[relative_time::RTT__MAX] = {
|
||||
{ "ws", pcrepp("\\A\\s+\\b") },
|
||||
{ "am", pcrepp("\\Aam|a\\.m\\.\\b") },
|
||||
{ "pm", pcrepp("\\Apm|p\\.m\\.\\b") },
|
||||
{ "a", pcrepp("\\Aa\\b") },
|
||||
{ "an", pcrepp("\\Aan\\b") },
|
||||
{ "time", pcrepp("\\A(\\d{1,2}):(\\d{2})(?::(\\d{2}))?") },
|
||||
{ "num", pcrepp("\\A((?:-|\\+)?\\d+)") },
|
||||
{ "us", pcrepp("\\Amicros(?:econds?)?|us(?![a-zA-Z])") },
|
||||
{ "ms", pcrepp("\\Amillis(?:econds?)?|ms(?![a-zA-Z])") },
|
||||
{ "sec", pcrepp("\\As(?:ec(?:onds?)?)?(?![a-zA-Z])") },
|
||||
{ "min", pcrepp("\\Am(?:in(?:utes?)?)?(?![a-zA-Z])") },
|
||||
{ "h", pcrepp("\\Ah(?:ours?)?(?![a-zA-Z])") },
|
||||
{ "day", pcrepp("\\Ad(?:ays?)?(?![a-zA-Z])") },
|
||||
{ "week", pcrepp("\\Aw(?:eeks?)?(?![a-zA-Z])") },
|
||||
{ "mon", pcrepp("\\Amon(?:ths?)?(?![a-zA-Z])") },
|
||||
{ "year", pcrepp("\\Ay(?:ears?)?(?![a-zA-Z])") },
|
||||
{ "today", pcrepp("\\Atoday\\b") },
|
||||
{ "yest", pcrepp("\\Ayesterday\\b") },
|
||||
{ "tomo", pcrepp("\\Atomorrow\\b") },
|
||||
{ "noon", pcrepp("\\Anoon\\b") },
|
||||
{ "and", pcrepp("\\Aand\\b") },
|
||||
{ "ago", pcrepp("\\Aago\\b") },
|
||||
{ "lter", pcrepp("\\Alater\\b") },
|
||||
{ "bfor", pcrepp("\\Abefore\\b") },
|
||||
};
|
||||
|
||||
static int64_t TIME_SCALES[] = {
|
||||
1000 * 1000,
|
||||
60,
|
||||
60,
|
||||
24,
|
||||
};
|
||||
|
||||
bool relative_time::parse(const char *str, size_t len, struct parse_error &pe_out)
|
||||
{
|
||||
pcre_input pi(str, 0, len);
|
||||
pcre_context_static<30> pc;
|
||||
int64_t number = 0;
|
||||
bool number_set = false;
|
||||
|
||||
pe_out.pe_column = -1;
|
||||
pe_out.pe_msg.clear();
|
||||
|
||||
while (true) {
|
||||
if (pi.pi_next_offset >= pi.pi_length) {
|
||||
if (number_set) {
|
||||
pe_out.pe_msg = "Number given without a time unit";
|
||||
return false;
|
||||
}
|
||||
|
||||
this->rollover();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (int lpc = 0; lpc < RTT__MAX && !found; lpc++) {
|
||||
token_t token = (token_t) lpc;
|
||||
if (!MATCHERS[lpc].pcre.match(pc, pi, PCRE_ANCHORED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pe_out.pe_column = pc.all()->c_begin;
|
||||
found = true;
|
||||
if (RTT_MICROS <= token && token <= RTT_YEARS) {
|
||||
if (!number_set) {
|
||||
pe_out.pe_msg = "Expecting a number before time unit";
|
||||
return false;
|
||||
}
|
||||
number_set = false;
|
||||
}
|
||||
switch (token) {
|
||||
case RTT_INVALID:
|
||||
case RTT_WHITE:
|
||||
case RTT_AND:
|
||||
break;
|
||||
case RTT_AM:
|
||||
case RTT_PM:
|
||||
if (number_set) {
|
||||
this->rt_field[RTF_HOURS] = number;
|
||||
this->rt_is_absolute[RTF_HOURS] = true;
|
||||
this->rt_field[RTF_MINUTES] = 0;
|
||||
this->rt_is_absolute[RTF_MINUTES] = true;
|
||||
this->rt_field[RTF_SECONDS] = 0;
|
||||
this->rt_is_absolute[RTF_SECONDS] = true;
|
||||
this->rt_field[RTF_MICROSECONDS] = 0;
|
||||
this->rt_is_absolute[RTF_MICROSECONDS] = true;
|
||||
number_set = false;
|
||||
}
|
||||
if (!this->rt_is_absolute[RTF_HOURS]) {
|
||||
pe_out.pe_msg = "Expecting absolute time with A.M. or P.M.";
|
||||
return false;
|
||||
}
|
||||
if (token == RTT_AM) {
|
||||
if (this->rt_field[RTF_HOURS] == 12) {
|
||||
this->rt_field[RTF_HOURS] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->rt_field[RTF_HOURS] += 12;
|
||||
}
|
||||
break;
|
||||
case RTT_A:
|
||||
case RTT_AN:
|
||||
number = 1;
|
||||
number_set = true;
|
||||
break;
|
||||
case RTT_TIME: {
|
||||
string hstr = pi.get_substr(pc[0]);
|
||||
string mstr = pi.get_substr(pc[1]);
|
||||
this->rt_field[RTF_HOURS] = atoi(hstr.c_str());
|
||||
this->rt_is_absolute[RTF_HOURS] = true;
|
||||
this->rt_field[RTF_MINUTES] = atoi(mstr.c_str());
|
||||
this->rt_is_absolute[RTF_MINUTES] = true;
|
||||
if (pc[2]->is_valid()) {
|
||||
string sstr = pi.get_substr(pc[2]);
|
||||
this->rt_field[RTF_SECONDS] = atoi(sstr.c_str());
|
||||
}
|
||||
else {
|
||||
this->rt_field[RTF_SECONDS] = 0;
|
||||
}
|
||||
this->rt_is_absolute[RTF_SECONDS] = true;
|
||||
this->rt_field[RTF_MICROSECONDS] = 0;
|
||||
this->rt_is_absolute[RTF_MICROSECONDS] = true;
|
||||
break;
|
||||
}
|
||||
case RTT_NUMBER: {
|
||||
if (number_set) {
|
||||
pe_out.pe_msg = "No time unit given for the previous number";
|
||||
return false;
|
||||
}
|
||||
|
||||
string numstr = pi.get_substr(pc[0]);
|
||||
|
||||
if (sscanf(numstr.c_str(), "%qd", &number) != 1) {
|
||||
pe_out.pe_msg = "Invalid number: " + numstr;
|
||||
return false;
|
||||
}
|
||||
number_set = true;
|
||||
break;
|
||||
}
|
||||
case RTT_MICROS:
|
||||
this->rt_field[RTF_MICROSECONDS] = number;
|
||||
break;
|
||||
case RTT_MILLIS:
|
||||
this->rt_field[RTF_MICROSECONDS] = number * 1000;
|
||||
break;
|
||||
case RTT_SECONDS:
|
||||
this->rt_field[RTF_SECONDS] = number;
|
||||
break;
|
||||
case RTT_MINUTES:
|
||||
this->rt_field[RTF_MINUTES] = number;
|
||||
break;
|
||||
case RTT_HOURS:
|
||||
this->rt_field[RTF_HOURS] = number;
|
||||
break;
|
||||
case RTT_DAYS:
|
||||
this->rt_field[RTF_DAYS] = number;
|
||||
break;
|
||||
case RTT_WEEKS:
|
||||
this->rt_field[RTF_DAYS] = number * 7;
|
||||
break;
|
||||
case RTT_MONTHS:
|
||||
this->rt_field[RTF_MONTHS] = number;
|
||||
break;
|
||||
case RTT_YEARS:
|
||||
this->rt_field[RTF_YEARS] = number;
|
||||
break;
|
||||
case RTT_BEFORE:
|
||||
case RTT_AGO:
|
||||
if (this->empty()) {
|
||||
pe_out.pe_msg = "Expecting a time unit";
|
||||
return false;
|
||||
}
|
||||
for (int field = 0; field < RTF__MAX; field++) {
|
||||
if (this->rt_field[field] > 0) {
|
||||
this->rt_field[field] = -this->rt_field[field];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RTT_LATER:
|
||||
if (this->empty()) {
|
||||
pe_out.pe_msg = "Expecting a time unit before 'later'";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case RTT_TODAY:
|
||||
break;
|
||||
case RTT_YESTERDAY:
|
||||
this->rt_field[RTF_DAYS] = -1;
|
||||
break;
|
||||
case RTT_TOMORROW:
|
||||
this->rt_field[RTF_DAYS] = 1;
|
||||
break;
|
||||
case RTT_NOON:
|
||||
this->rt_field[RTF_HOURS] = 12;
|
||||
this->rt_is_absolute[RTF_HOURS] = true;
|
||||
break;
|
||||
|
||||
case RTT__MAX:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pe_out.pe_msg = "Unrecognized input";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relative_time::rollover()
|
||||
{
|
||||
for (int lpc = 0; lpc < RTF_DAYS; lpc++) {
|
||||
int64_t val = this->rt_field[lpc];
|
||||
this->rt_field[lpc] = val % TIME_SCALES[lpc];
|
||||
this->rt_field[lpc + 1] += val / TIME_SCALES[lpc];
|
||||
}
|
||||
if (std::abs(this->rt_field[RTF_DAYS]) > 31) {
|
||||
int64_t val = this->rt_field[RTF_DAYS];
|
||||
this->rt_field[RTF_DAYS] = val % 31;
|
||||
this->rt_field[RTF_MONTHS] += val / 31;
|
||||
}
|
||||
if (std::abs(this->rt_field[RTF_MONTHS]) > 12) {
|
||||
int64_t val = this->rt_field[RTF_MONTHS];
|
||||
this->rt_field[RTF_MONTHS] = val % 12;
|
||||
this->rt_field[RTF_YEARS] += val / 12;
|
||||
}
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* 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>
|
||||
|
||||
#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_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__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);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
||||
std::string to_string() {
|
||||
char dst[128];
|
||||
|
||||
snprintf(dst, sizeof(dst),
|
||||
"%qd%c%qd%c%qd%c%qd%c%qd%c%qd%c%qd%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];
|
||||
};
|
||||
|
||||
#endif //LNAV_RELATIVE_TIME_HH
|
@ -0,0 +1,13 @@
|
||||
Sep 13 00:58:45 Tim-Stacks-iMac kernel[0]: AirParrot device perform power state change 0 -> 1
|
||||
Sep 13 00:59:30 Tim-Stacks-iMac.local airportd[59]: _configureScanOffloadParameters: Unable to configure scan offloading on en1 (Device power is off)
|
||||
Sep 13 01:23:54 Tim-Stacks-iMac kernel[0]: RTC: PowerByCalendarDate setting ignored
|
||||
Sep 13 03:12:04 Tim-Stacks-iMac kernel[0]: vm_compressor_record_warmup (9478314 - 9492476)
|
||||
Sep 13 03:12:04 Tim-Stacks-iMac kernel[0]: AppleBCM5701Ethernet [en0]: 0 0 memWrInd fBJP_Wakeup_Timer
|
||||
Sep 13 01:25:39 Tim-Stacks-iMac kernel[0]: AppleThunderboltNHIType2::waitForOk2Go2Sx - retries = 60000
|
||||
Sep 13 03:12:04 Tim-Stacks-iMac kernel[0]: hibernate_page_list_setall(preflight 0) start 0xffffff8428276000, 0xffffff8428336000
|
||||
Sep 13 03:12:58 Tim-Stacks-iMac kernel[0]: *** kernel exceeded 500 log message per second limit - remaining messages this second discarded ***
|
||||
Sep 13 03:46:03 Tim-Stacks-iMac kernel[0]: IOThunderboltSwitch<0xffffff803f4b3000>(0x0)::listenerCallback - Thunderbolt HPD packet for route = 0x0 port = 11 unplug = 0
|
||||
Sep 13 03:46:03 Tim-Stacks-iMac kernel[0]: vm_compressor_flush - starting
|
||||
Sep 13 03:46:03 Tim-Stacks-iMac kernel[0]: AppleBCM5701Ethernet [en0]: 0 0 memWrInd fBJP_Wakeup_Timer
|
||||
Sep 13 03:13:16 Tim-Stacks-iMac kernel[0]: AppleThunderboltNHIType2::waitForOk2Go2Sx - retries = 60000
|
||||
Sep 13 03:46:03 Tim-Stacks-iMac kernel[0]: hibernate_page_list_setall(preflight 0) start 0xffffff838f1fc000, 0xffffff838f2bc000
|
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "relative_time.hh"
|
||||
|
||||
struct {
|
||||
const char *reltime;
|
||||
const char *expected;
|
||||
} TEST_DATA[] = {
|
||||
{ "a minute ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "1m ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "a min ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "a m ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "+1 minute ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "-1 minute ago", "0y0m0d0h-1m0s0u" },
|
||||
{ "-1 minute", "0y0m0d0h-1m0s0u" },
|
||||
{ "1:40", "0y0m0d1H40M0S0U" },
|
||||
{ "01:40", "0y0m0d1H40M0S0U" },
|
||||
{ "1h40m", "0y0m0d1h40m0s0u" },
|
||||
{ "1pm", "0y0m0d13H0M0S0U" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *reltime;
|
||||
const char *expected_error;
|
||||
} BAD_TEST_DATA[] = {
|
||||
{ "ago", "" },
|
||||
{ "minute", "" },
|
||||
{ "1 2", "" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
time_t base_time = 1317913200;
|
||||
struct exttm base_tm;
|
||||
base_tm.et_tm = *gmtime(&base_time);
|
||||
struct relative_time::parse_error pe;
|
||||
struct exttm tm;
|
||||
time_t new_time;
|
||||
|
||||
relative_time rt;
|
||||
|
||||
for (int lpc = 0; TEST_DATA[lpc].reltime; lpc++) {
|
||||
rt.clear();
|
||||
rt.parse(TEST_DATA[lpc].reltime, pe);
|
||||
printf("%s %s %s\n", TEST_DATA[lpc].reltime, TEST_DATA[lpc].expected, rt.to_string().c_str());
|
||||
assert(std::string(TEST_DATA[lpc].expected) == rt.to_string());
|
||||
}
|
||||
|
||||
for (int lpc = 0; BAD_TEST_DATA[lpc].reltime; lpc++) {
|
||||
bool rc;
|
||||
rt.clear();
|
||||
rc = rt.parse(BAD_TEST_DATA[lpc].reltime, pe);
|
||||
printf("%s -- %s\n", BAD_TEST_DATA[lpc].reltime, pe.pe_msg.c_str());
|
||||
assert(!rc);
|
||||
}
|
||||
|
||||
rt.parse("a minute ago", pe);
|
||||
assert(rt.rt_field[relative_time::RTF_MINUTES] == -1);
|
||||
|
||||
rt.parse("5 milliseconds", pe);
|
||||
|
||||
assert(rt.rt_field[relative_time::RTF_MICROSECONDS] == 5 * 1000);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("5000 ms ago", pe);
|
||||
assert(rt.rt_field[relative_time::RTF_SECONDS] == -5);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("5 hours 20 minutes ago", pe);
|
||||
|
||||
assert(rt.rt_field[relative_time::RTF_HOURS] == -5);
|
||||
assert(rt.rt_field[relative_time::RTF_MINUTES] == -20);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("5 hours and 20 minutes ago", pe);
|
||||
|
||||
assert(rt.rt_field[relative_time::RTF_HOURS] == -5);
|
||||
assert(rt.rt_field[relative_time::RTF_MINUTES] == -20);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("1:23", pe);
|
||||
|
||||
assert(rt.rt_field[relative_time::RTF_HOURS] == 1);
|
||||
assert(rt.rt_is_absolute[relative_time::RTF_HOURS]);
|
||||
assert(rt.rt_field[relative_time::RTF_MINUTES] == 23);
|
||||
assert(rt.rt_is_absolute[relative_time::RTF_MINUTES]);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("1:23:45", pe);
|
||||
|
||||
assert(rt.rt_field[relative_time::RTF_HOURS] == 1);
|
||||
assert(rt.rt_is_absolute[relative_time::RTF_HOURS]);
|
||||
assert(rt.rt_field[relative_time::RTF_MINUTES] == 23);
|
||||
assert(rt.rt_is_absolute[relative_time::RTF_MINUTES]);
|
||||
assert(rt.rt_field[relative_time::RTF_SECONDS] == 45);
|
||||
assert(rt.rt_is_absolute[relative_time::RTF_SECONDS]);
|
||||
|
||||
tm = base_tm;
|
||||
rt.add(tm);
|
||||
|
||||
new_time = timegm(&tm.et_tm);
|
||||
tm.et_tm = *gmtime(&new_time);
|
||||
assert(tm.et_tm.tm_hour == 1);
|
||||
assert(tm.et_tm.tm_min == 23);
|
||||
|
||||
rt.clear();
|
||||
rt.parse("5 minutes ago", pe);
|
||||
|
||||
tm = base_tm;
|
||||
rt.add(tm);
|
||||
|
||||
new_time = timegm(&tm.et_tm);
|
||||
|
||||
assert(new_time == (base_time - (5 * 60)));
|
||||
|
||||
}
|
Loading…
Reference in New Issue