mirror of https://github.com/tstack/lnav
[build] some more compiler profiling
Defect Number: Reviewed By: Testing Done:pull/796/head
parent
6fe2f552d5
commit
8e629b166a
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 date_time_scanner.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "date_time_scanner.hh"
|
||||
#include "ptimec.hh"
|
||||
|
||||
size_t date_time_scanner::ftime(char *dst, size_t len, const exttm &tm)
|
||||
{
|
||||
off_t off = 0;
|
||||
|
||||
PTIMEC_FORMATS[this->dts_fmt_lock].pf_ffunc(dst, off, len, tm);
|
||||
|
||||
return (size_t) off;
|
||||
}
|
||||
|
||||
bool next_format(const char * const fmt[], int &index, int &locked_index)
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
if (locked_index == -1) {
|
||||
index += 1;
|
||||
if (fmt[index] == nullptr) {
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else if (index == locked_index) {
|
||||
retval = false;
|
||||
}
|
||||
else {
|
||||
index = locked_index;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
const char *date_time_scanner::scan(const char *time_dest,
|
||||
size_t time_len,
|
||||
const char * const time_fmt[],
|
||||
struct exttm *tm_out,
|
||||
struct timeval &tv_out,
|
||||
bool convert_local)
|
||||
{
|
||||
int curr_time_fmt = -1;
|
||||
bool found = false;
|
||||
const char *retval = nullptr;
|
||||
|
||||
if (!time_fmt) {
|
||||
time_fmt = PTIMEC_FORMAT_STR;
|
||||
}
|
||||
|
||||
while (next_format(time_fmt,
|
||||
curr_time_fmt,
|
||||
this->dts_fmt_lock)) {
|
||||
*tm_out = this->dts_base_tm;
|
||||
tm_out->et_flags = 0;
|
||||
if (time_len > 1 &&
|
||||
time_dest[0] == '+' &&
|
||||
isdigit(time_dest[1])) {
|
||||
char time_cp[time_len + 1];
|
||||
int gmt_int, off;
|
||||
|
||||
retval = nullptr;
|
||||
memcpy(time_cp, time_dest, time_len);
|
||||
time_cp[time_len] = '\0';
|
||||
if (sscanf(time_cp, "+%d%n", &gmt_int, &off) == 1) {
|
||||
time_t gmt = gmt_int;
|
||||
|
||||
if (convert_local && this->dts_local_time) {
|
||||
localtime_r(&gmt, &tm_out->et_tm);
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
tm_out->et_tm.tm_zone = nullptr;
|
||||
#endif
|
||||
tm_out->et_tm.tm_isdst = 0;
|
||||
gmt = tm2sec(&tm_out->et_tm);
|
||||
}
|
||||
tv_out.tv_sec = gmt;
|
||||
tv_out.tv_usec = 0;
|
||||
tm_out->et_flags = ETF_DAY_SET|ETF_MONTH_SET|ETF_YEAR_SET|ETF_MACHINE_ORIENTED|ETF_EPOCH_TIME;
|
||||
|
||||
this->dts_fmt_lock = curr_time_fmt;
|
||||
this->dts_fmt_len = off;
|
||||
retval = time_dest + off;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (time_fmt == PTIMEC_FORMAT_STR) {
|
||||
ptime_func func = PTIMEC_FORMATS[curr_time_fmt].pf_func;
|
||||
off_t off = 0;
|
||||
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
if (!this->dts_keep_base_tz) {
|
||||
tm_out->et_tm.tm_zone = nullptr;
|
||||
}
|
||||
#endif
|
||||
if (func(tm_out, time_dest, off, time_len)) {
|
||||
retval = &time_dest[off];
|
||||
|
||||
if (tm_out->et_tm.tm_year < 70) {
|
||||
tm_out->et_tm.tm_year = 80;
|
||||
}
|
||||
if (convert_local &&
|
||||
(this->dts_local_time || tm_out->et_flags & ETF_EPOCH_TIME)) {
|
||||
time_t gmt = tm2sec(&tm_out->et_tm);
|
||||
|
||||
this->to_localtime(gmt, *tm_out);
|
||||
}
|
||||
tv_out.tv_sec = tm2sec(&tm_out->et_tm);
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
secs2wday(tv_out, &tm_out->et_tm);
|
||||
|
||||
this->dts_fmt_lock = curr_time_fmt;
|
||||
this->dts_fmt_len = retval - time_dest;
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
off_t off = 0;
|
||||
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
if (!this->dts_keep_base_tz) {
|
||||
tm_out->et_tm.tm_zone = nullptr;
|
||||
}
|
||||
#endif
|
||||
if (ptime_fmt(time_fmt[curr_time_fmt], tm_out, time_dest, off, time_len) &&
|
||||
(time_dest[off] == '.' || time_dest[off] == ',' || off == (off_t)time_len)) {
|
||||
retval = &time_dest[off];
|
||||
if (tm_out->et_tm.tm_year < 70) {
|
||||
tm_out->et_tm.tm_year = 80;
|
||||
}
|
||||
if (convert_local &&
|
||||
(this->dts_local_time || tm_out->et_flags & ETF_EPOCH_TIME)) {
|
||||
time_t gmt = tm2sec(&tm_out->et_tm);
|
||||
|
||||
this->to_localtime(gmt, *tm_out);
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
tm_out->et_tm.tm_zone = nullptr;
|
||||
#endif
|
||||
tm_out->et_tm.tm_isdst = 0;
|
||||
}
|
||||
|
||||
tv_out.tv_sec = tm2sec(&tm_out->et_tm);
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
secs2wday(tv_out, &tm_out->et_tm);
|
||||
|
||||
this->dts_fmt_lock = curr_time_fmt;
|
||||
this->dts_fmt_len = retval - time_dest;
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
retval = nullptr;
|
||||
}
|
||||
|
||||
if (retval != nullptr) {
|
||||
/* Try to pull out the milli/micro-second value. */
|
||||
if (retval[0] == '.' || retval[0] == ',') {
|
||||
off_t off = (retval - time_dest) + 1;
|
||||
|
||||
if (ptime_f(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
this->dts_fmt_len += 7;
|
||||
retval += 7;
|
||||
}
|
||||
else if (ptime_L(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
this->dts_fmt_len += 4;
|
||||
retval += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 date_time_scanner.hh
|
||||
*/
|
||||
|
||||
#ifndef lnav_date_time_scanner_hh
|
||||
#define lnav_date_time_scanner_hh
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "time_util.hh"
|
||||
|
||||
extern const char *std_time_fmt[];
|
||||
|
||||
struct date_time_scanner {
|
||||
date_time_scanner() : dts_keep_base_tz(false),
|
||||
dts_local_time(false),
|
||||
dts_local_offset_cache(0),
|
||||
dts_local_offset_valid(0),
|
||||
dts_local_offset_expiry(0) {
|
||||
this->clear();
|
||||
};
|
||||
|
||||
void clear() {
|
||||
this->dts_base_time = 0;
|
||||
memset(&this->dts_base_tm, 0, sizeof(this->dts_base_tm));
|
||||
this->dts_fmt_lock = -1;
|
||||
this->dts_fmt_len = -1;
|
||||
};
|
||||
|
||||
void unlock() {
|
||||
this->dts_fmt_lock = -1;
|
||||
this->dts_fmt_len = -1;
|
||||
}
|
||||
|
||||
void set_base_time(time_t base_time) {
|
||||
this->dts_base_time = base_time;
|
||||
localtime_r(&base_time, &this->dts_base_tm.et_tm);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a timestamp to local time.
|
||||
*
|
||||
* Calling localtime_r is slow since it wants to lookup the timezone on
|
||||
* every call, so we cache the result and only call it again if the
|
||||
* requested time falls outside of a fifteen minute range.
|
||||
*/
|
||||
void to_localtime(time_t t, struct exttm &tm_out) {
|
||||
if (t < (24 * 60 * 60)) {
|
||||
// Don't convert and risk going past the epoch.
|
||||
return;
|
||||
}
|
||||
|
||||
if (t < this->dts_local_offset_valid ||
|
||||
t >= this->dts_local_offset_expiry) {
|
||||
time_t new_gmt;
|
||||
|
||||
localtime_r(&t, &tm_out.et_tm);
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
tm_out.et_tm.tm_zone = NULL;
|
||||
#endif
|
||||
tm_out.et_tm.tm_isdst = 0;
|
||||
|
||||
new_gmt = tm2sec(&tm_out.et_tm);
|
||||
this->dts_local_offset_cache = t - new_gmt;
|
||||
this->dts_local_offset_valid = t;
|
||||
this->dts_local_offset_expiry = t + (EXPIRE_TIME - 1);
|
||||
this->dts_local_offset_expiry -=
|
||||
this->dts_local_offset_expiry % EXPIRE_TIME;
|
||||
}
|
||||
else {
|
||||
time_t adjust_gmt = t - this->dts_local_offset_cache;
|
||||
gmtime_r(&adjust_gmt, &tm_out.et_tm);
|
||||
}
|
||||
};
|
||||
|
||||
bool dts_keep_base_tz;
|
||||
bool dts_local_time;
|
||||
time_t dts_base_time;
|
||||
struct exttm dts_base_tm;
|
||||
int dts_fmt_lock;
|
||||
int dts_fmt_len;
|
||||
time_t dts_local_offset_cache;
|
||||
time_t dts_local_offset_valid;
|
||||
time_t dts_local_offset_expiry;
|
||||
|
||||
static const int EXPIRE_TIME = 15 * 60;
|
||||
|
||||
const char *scan(const char *time_src,
|
||||
size_t time_len,
|
||||
const char * const time_fmt[],
|
||||
struct exttm *tm_out,
|
||||
struct timeval &tv_out,
|
||||
bool convert_local = true);
|
||||
|
||||
size_t ftime(char *dst, size_t len, const struct exttm &tm);;
|
||||
|
||||
bool convert_to_timeval(const char *time_src,
|
||||
ssize_t time_len,
|
||||
const char * const time_fmt[],
|
||||
struct timeval &tv_out) {
|
||||
struct exttm tm;
|
||||
|
||||
if (time_len == -1) {
|
||||
time_len = strlen(time_src);
|
||||
}
|
||||
if (this->scan(time_src, time_len, time_fmt, &tm, tv_out) != NULL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool convert_to_timeval(const std::string &time_src,
|
||||
struct timeval &tv_out) {
|
||||
struct exttm tm;
|
||||
|
||||
if (this->scan(time_src.c_str(), time_src.size(),
|
||||
NULL, &tm, tv_out) != NULL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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_math_util_hh
|
||||
#define lnav_math_util_hh
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#undef rounddown
|
||||
|
||||
/**
|
||||
* Round down a number based on a given granularity.
|
||||
*
|
||||
* @param
|
||||
* @param step The granularity.
|
||||
*/
|
||||
template<typename Size, typename Step>
|
||||
inline int rounddown(Size size, Step step)
|
||||
{
|
||||
return size - (size % step);
|
||||
}
|
||||
|
||||
inline int rounddown_offset(size_t size, int step, int offset)
|
||||
{
|
||||
return size - ((size - offset) % step);
|
||||
}
|
||||
|
||||
inline size_t roundup_size(size_t size, int step)
|
||||
{
|
||||
size_t retval = size + step;
|
||||
|
||||
retval -= (retval % step);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 time_util.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "time_util.hh"
|
||||
|
||||
static time_t BAD_DATE = -1;
|
||||
|
||||
time_t tm2sec(const struct tm *t)
|
||||
{
|
||||
int year;
|
||||
time_t days, secs;
|
||||
const int dayoffset[12] =
|
||||
{ 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 };
|
||||
|
||||
year = t->tm_year;
|
||||
|
||||
if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) {
|
||||
return BAD_DATE;
|
||||
}
|
||||
|
||||
/* shift new year to 1st March in order to make leap year calc easy */
|
||||
|
||||
if (t->tm_mon < 2) {
|
||||
year--;
|
||||
}
|
||||
|
||||
/* Find number of days since 1st March 1900 (in the Gregorian calendar). */
|
||||
|
||||
days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
|
||||
days += dayoffset[t->tm_mon] + t->tm_mday - 1;
|
||||
days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
|
||||
|
||||
secs = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
|
||||
|
||||
if (secs < 0) {
|
||||
return BAD_DATE;
|
||||
} /* must have overflowed */
|
||||
else {
|
||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||
if (t->tm_zone) {
|
||||
secs -= t->tm_gmtoff;
|
||||
}
|
||||
#endif
|
||||
return secs;
|
||||
} /* must be a valid time */
|
||||
}
|
||||
|
||||
static const int SECSPERMIN = 60;
|
||||
static const int SECSPERHOUR = 60 * SECSPERMIN;
|
||||
static const int SECSPERDAY = 24 * SECSPERHOUR;
|
||||
static const int YEAR_BASE = 1900;
|
||||
static const int EPOCH_WDAY = 4;
|
||||
static const int DAYSPERWEEK = 7;
|
||||
static const int EPOCH_YEAR = 1970;
|
||||
|
||||
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
|
||||
|
||||
static const int year_lengths[2] = {
|
||||
365,
|
||||
366
|
||||
};
|
||||
|
||||
const unsigned short int mon_yday[2][13] = {
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
void secs2wday(const struct timeval &tv, struct tm *res)
|
||||
{
|
||||
long days, rem;
|
||||
time_t lcltime;
|
||||
|
||||
/* base decision about std/dst time on current time */
|
||||
lcltime = tv.tv_sec;
|
||||
|
||||
days = ((long) lcltime) / SECSPERDAY;
|
||||
rem = ((long) lcltime) % SECSPERDAY;
|
||||
while (rem < 0) {
|
||||
rem += SECSPERDAY;
|
||||
--days;
|
||||
}
|
||||
|
||||
/* compute day of week */
|
||||
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
|
||||
res->tm_wday += DAYSPERWEEK;
|
||||
}
|
||||
|
||||
struct tm *secs2tm(time_t *tim_p, struct tm *res)
|
||||
{
|
||||
long days, rem;
|
||||
time_t lcltime;
|
||||
int y;
|
||||
int yleap;
|
||||
const unsigned short int *ip;
|
||||
|
||||
/* base decision about std/dst time on current time */
|
||||
lcltime = *tim_p;
|
||||
|
||||
days = ((long)lcltime) / SECSPERDAY;
|
||||
rem = ((long)lcltime) % SECSPERDAY;
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += SECSPERDAY;
|
||||
--days;
|
||||
}
|
||||
|
||||
/* compute hour, min, and sec */
|
||||
res->tm_hour = (int) (rem / SECSPERHOUR);
|
||||
rem %= SECSPERHOUR;
|
||||
res->tm_min = (int) (rem / SECSPERMIN);
|
||||
res->tm_sec = (int) (rem % SECSPERMIN);
|
||||
|
||||
/* compute day of week */
|
||||
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
|
||||
res->tm_wday += DAYSPERWEEK;
|
||||
|
||||
/* compute year & day of year */
|
||||
y = EPOCH_YEAR;
|
||||
if (days >= 0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
yleap = isleap(y);
|
||||
if (days < year_lengths[yleap])
|
||||
break;
|
||||
y++;
|
||||
days -= year_lengths[yleap];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
--y;
|
||||
yleap = isleap(y);
|
||||
days += year_lengths[yleap];
|
||||
} while (days < 0);
|
||||
}
|
||||
|
||||
res->tm_year = y - YEAR_BASE;
|
||||
res->tm_yday = days;
|
||||
ip = mon_yday[isleap(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
res->tm_mon = y;
|
||||
res->tm_mday = days + 1;
|
||||
|
||||
res->tm_isdst = 0;
|
||||
|
||||
return (res);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 file_format.hh
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "base/intern_string.hh"
|
||||
#include "auto_fd.hh"
|
||||
#include "lnav_util.hh"
|
||||
#include "file_format.hh"
|
||||
#include "archive_manager.hh"
|
||||
|
||||
file_format_t detect_file_format(const ghc::filesystem::path &filename)
|
||||
{
|
||||
if (archive_manager::is_archive(filename)) {
|
||||
return file_format_t::FF_ARCHIVE;
|
||||
}
|
||||
|
||||
file_format_t retval = file_format_t::FF_UNKNOWN;
|
||||
auto_fd fd;
|
||||
|
||||
if ((fd = openp(filename, O_RDONLY)) != -1) {
|
||||
char buffer[32];
|
||||
ssize_t rc;
|
||||
|
||||
if ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
static auto SQLITE3_HEADER = "SQLite format 3";
|
||||
auto header_frag = string_fragment(buffer, 0, rc);
|
||||
|
||||
if (header_frag.startswith(SQLITE3_HEADER)) {
|
||||
retval = file_format_t::FF_SQLITE_DB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 file_format.hh
|
||||
*/
|
||||
|
||||
#ifndef lnav_file_format_hh
|
||||
#define lnav_file_format_hh
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "ghc/filesystem.hpp"
|
||||
|
||||
enum class file_format_t {
|
||||
FF_UNKNOWN,
|
||||
FF_SQLITE_DB,
|
||||
FF_ARCHIVE,
|
||||
};
|
||||
|
||||
file_format_t detect_file_format(const ghc::filesystem::path& filename);
|
||||
|
||||
namespace fmt {
|
||||
template<>
|
||||
struct formatter<file_format_t> : formatter<string_view> {
|
||||
template<typename FormatContext>
|
||||
auto format(file_format_t ff, FormatContext &ctx)
|
||||
{
|
||||
string_view name = "unknown";
|
||||
switch (ff) {
|
||||
case file_format_t::FF_SQLITE_DB:
|
||||
name = "SQLite Database";
|
||||
break;
|
||||
case file_format_t::FF_ARCHIVE:
|
||||
name = "Archive";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 "help_text.hh"
|
||||
|
||||
|
||||
help_text &help_text::with_parameters(
|
||||
const std::initializer_list<help_text> ¶ms) noexcept
|
||||
{
|
||||
this->ht_parameters = params;
|
||||
for (auto ¶m : this->ht_parameters) {
|
||||
param.ht_context = help_context_t::HC_PARAMETER;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_parameter(const help_text &ht) noexcept
|
||||
{
|
||||
this->ht_parameters.emplace_back(ht);
|
||||
this->ht_parameters.back().ht_context = help_context_t::HC_PARAMETER;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_result(const help_text &ht) noexcept
|
||||
{
|
||||
this->ht_results.emplace_back(ht);
|
||||
this->ht_results.back().ht_context = help_context_t::HC_RESULT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_examples(
|
||||
const std::initializer_list<help_example> &examples) noexcept
|
||||
{
|
||||
this->ht_example = examples;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_example(const help_example &example) noexcept
|
||||
{
|
||||
this->ht_example.emplace_back(example);
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_enum_values(
|
||||
const std::initializer_list<const char *> &enum_values) noexcept
|
||||
{
|
||||
this->ht_enum_values = enum_values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &
|
||||
help_text::with_tags(const std::initializer_list<const char *> &tags) noexcept
|
||||
{
|
||||
this->ht_tags = tags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &help_text::with_opposites(
|
||||
const std::initializer_list<const char *> &opps) noexcept
|
||||
{
|
||||
this->ht_opposites = opps;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void help_text::index_tags()
|
||||
{
|
||||
for (const auto &tag: this->ht_tags) {
|
||||
TAGGED.insert(std::make_pair(tag, this));
|
||||
}
|
||||
}
|
@ -0,0 +1,440 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 log_format_ext.hh
|
||||
*/
|
||||
|
||||
#ifndef lnav_log_format_ext_hh
|
||||
#define lnav_log_format_ext_hh
|
||||
|
||||
#include "log_format.hh"
|
||||
|
||||
class module_format;
|
||||
|
||||
class external_log_format : public log_format {
|
||||
|
||||
public:
|
||||
struct sample {
|
||||
sample() : s_level(LEVEL_UNKNOWN) {};
|
||||
|
||||
std::string s_line;
|
||||
log_level_t s_level;
|
||||
};
|
||||
|
||||
struct value_def {
|
||||
intern_string_t vd_name;
|
||||
logline_value::kind_t vd_kind{logline_value::VALUE_UNKNOWN};
|
||||
std::string vd_collate;
|
||||
bool vd_identifier{false};
|
||||
bool vd_foreign_key{false};
|
||||
intern_string_t vd_unit_field;
|
||||
std::map<const intern_string_t, scaling_factor> vd_unit_scaling;
|
||||
int vd_column{-1};
|
||||
ssize_t vd_values_index{-1};
|
||||
bool vd_hidden{false};
|
||||
bool vd_user_hidden{false};
|
||||
bool vd_internal{false};
|
||||
std::vector<std::string> vd_action_list;
|
||||
std::string vd_rewriter;
|
||||
std::string vd_description;
|
||||
};
|
||||
|
||||
struct indexed_value_def {
|
||||
indexed_value_def(int index = -1,
|
||||
int unit_index = -1,
|
||||
std::shared_ptr<value_def> vd = nullptr)
|
||||
: ivd_index(index),
|
||||
ivd_unit_field_index(unit_index),
|
||||
ivd_value_def(std::move(vd)) {
|
||||
}
|
||||
|
||||
int ivd_index;
|
||||
int ivd_unit_field_index;
|
||||
std::shared_ptr<value_def> ivd_value_def;
|
||||
|
||||
bool operator<(const indexed_value_def &rhs) const {
|
||||
return this->ivd_index < rhs.ivd_index;
|
||||
}
|
||||
};
|
||||
|
||||
struct pattern {
|
||||
std::string p_config_path;
|
||||
std::string p_string;
|
||||
pcrepp *p_pcre{nullptr};
|
||||
std::vector<indexed_value_def> p_value_by_index;
|
||||
std::vector<int> p_numeric_value_indexes;
|
||||
int p_timestamp_field_index{-1};
|
||||
int p_level_field_index{-1};
|
||||
int p_module_field_index{-1};
|
||||
int p_opid_field_index{-1};
|
||||
int p_body_field_index{-1};
|
||||
int p_timestamp_end{-1};
|
||||
bool p_module_format{false};
|
||||
};
|
||||
|
||||
struct level_pattern {
|
||||
std::string lp_regex;
|
||||
pcrepp *lp_pcre{nullptr};
|
||||
};
|
||||
|
||||
external_log_format(const intern_string_t name)
|
||||
: elf_file_pattern(".*"),
|
||||
elf_filename_pcre(NULL),
|
||||
elf_column_count(0),
|
||||
elf_timestamp_divisor(1.0),
|
||||
elf_level_field(intern_string::lookup("level", -1)),
|
||||
elf_body_field(intern_string::lookup("body", -1)),
|
||||
elf_multiline(true),
|
||||
elf_container(false),
|
||||
elf_has_module_format(false),
|
||||
elf_builtin_format(false),
|
||||
elf_type(ELF_TYPE_TEXT),
|
||||
jlf_hide_extra(false),
|
||||
jlf_cached_offset(-1),
|
||||
jlf_yajl_handle(yajl_free),
|
||||
elf_name(name) {
|
||||
this->jlf_line_offsets.reserve(128);
|
||||
};
|
||||
|
||||
const intern_string_t get_name() const {
|
||||
return this->elf_name;
|
||||
};
|
||||
|
||||
bool match_name(const std::string &filename) {
|
||||
pcre_context_static<10> pc;
|
||||
pcre_input pi(filename);
|
||||
|
||||
return this->elf_filename_pcre->match(pc, pi);
|
||||
};
|
||||
|
||||
scan_result_t scan(logfile &lf,
|
||||
std::vector<logline> &dst,
|
||||
const line_info &offset,
|
||||
shared_buffer_ref &sbr);
|
||||
|
||||
bool scan_for_partial(shared_buffer_ref &sbr, size_t &len_out);
|
||||
|
||||
void annotate(uint64_t line_number, shared_buffer_ref &line, string_attrs_t &sa,
|
||||
std::vector<logline_value> &values, bool annotate_module = true) const;
|
||||
|
||||
void rewrite(exec_context &ec,
|
||||
shared_buffer_ref &line,
|
||||
string_attrs_t &sa,
|
||||
std::string &value_out);
|
||||
|
||||
void build(std::vector<std::string> &errors);
|
||||
|
||||
void register_vtabs(log_vtab_manager *vtab_manager,
|
||||
std::vector<std::string> &errors);
|
||||
|
||||
bool match_samples(const std::vector<sample> &samples) const;
|
||||
|
||||
bool hide_field(const intern_string_t field_name, bool val) {
|
||||
auto vd_iter = this->elf_value_defs.find(field_name);
|
||||
|
||||
if (vd_iter == this->elf_value_defs.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vd_iter->second->vd_user_hidden = val;
|
||||
return true;
|
||||
};
|
||||
|
||||
std::unique_ptr<log_format> specialized(int fmt_lock);
|
||||
|
||||
const logline_value_stats *stats_for_value(const intern_string_t &name) const {
|
||||
const logline_value_stats *retval = nullptr;
|
||||
|
||||
for (size_t lpc = 0; lpc < this->elf_numeric_value_defs.size(); lpc++) {
|
||||
value_def &vd = *this->elf_numeric_value_defs[lpc];
|
||||
|
||||
if (vd.vd_name == name) {
|
||||
retval = &this->lf_value_stats[lpc];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
void get_subline(const logline &ll, shared_buffer_ref &sbr, bool full_message);
|
||||
|
||||
log_vtab_impl *get_vtab_impl() const;
|
||||
|
||||
const std::vector<std::string> *get_actions(const logline_value &lv) const {
|
||||
const std::vector<std::string> *retval = nullptr;
|
||||
|
||||
const auto iter = this->elf_value_defs.find(lv.lv_name);
|
||||
if (iter != this->elf_value_defs.end()) {
|
||||
retval = &iter->second->vd_action_list;
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
std::set<std::string> get_source_path() const {
|
||||
return this->elf_source_path;
|
||||
};
|
||||
|
||||
enum json_log_field {
|
||||
JLF_CONSTANT,
|
||||
JLF_VARIABLE
|
||||
};
|
||||
|
||||
struct json_format_element {
|
||||
enum class align_t {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
};
|
||||
|
||||
enum class overflow_t {
|
||||
ABBREV,
|
||||
TRUNCATE,
|
||||
DOTDOT,
|
||||
};
|
||||
|
||||
enum class transform_t {
|
||||
NONE,
|
||||
UPPERCASE,
|
||||
LOWERCASE,
|
||||
CAPITALIZE,
|
||||
};
|
||||
|
||||
json_format_element()
|
||||
: jfe_type(JLF_CONSTANT), jfe_default_value("-"), jfe_min_width(0),
|
||||
jfe_max_width(LLONG_MAX), jfe_align(align_t::LEFT),
|
||||
jfe_overflow(overflow_t::ABBREV),
|
||||
jfe_text_transform(transform_t::NONE)
|
||||
{ };
|
||||
|
||||
json_log_field jfe_type;
|
||||
intern_string_t jfe_value;
|
||||
std::string jfe_default_value;
|
||||
long long jfe_min_width;
|
||||
long long jfe_max_width;
|
||||
align_t jfe_align;
|
||||
overflow_t jfe_overflow;
|
||||
transform_t jfe_text_transform;
|
||||
std::string jfe_ts_format;
|
||||
};
|
||||
|
||||
struct json_field_cmp {
|
||||
json_field_cmp(json_log_field type,
|
||||
const intern_string_t name)
|
||||
: jfc_type(type), jfc_field_name(name) {
|
||||
};
|
||||
|
||||
bool operator()(const json_format_element &jfe) const {
|
||||
return (this->jfc_type == jfe.jfe_type &&
|
||||
this->jfc_field_name == jfe.jfe_value);
|
||||
};
|
||||
|
||||
json_log_field jfc_type;
|
||||
const intern_string_t jfc_field_name;
|
||||
};
|
||||
|
||||
struct highlighter_def {
|
||||
highlighter_def() : hd_underline(false), hd_blink(false) {
|
||||
}
|
||||
|
||||
std::string hd_pattern;
|
||||
std::string hd_color;
|
||||
std::string hd_background_color;
|
||||
bool hd_underline;
|
||||
bool hd_blink;
|
||||
};
|
||||
|
||||
long value_line_count(const intern_string_t ist,
|
||||
bool top_level,
|
||||
const unsigned char *str = nullptr,
|
||||
ssize_t len = -1) const {
|
||||
const auto iter = this->elf_value_defs.find(ist);
|
||||
long line_count = (str != NULL) ? std::count(&str[0], &str[len], '\n') + 1 : 1;
|
||||
|
||||
if (iter == this->elf_value_defs.end()) {
|
||||
return (this->jlf_hide_extra || !top_level) ? 0 : line_count;
|
||||
}
|
||||
|
||||
if (iter->second->vd_hidden) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (std::find_if(this->jlf_line_format.begin(),
|
||||
this->jlf_line_format.end(),
|
||||
json_field_cmp(JLF_VARIABLE, ist)) !=
|
||||
this->jlf_line_format.end()) {
|
||||
return line_count - 1;
|
||||
}
|
||||
|
||||
return line_count;
|
||||
};
|
||||
|
||||
bool has_value_def(const intern_string_t ist) const {
|
||||
const auto iter = this->elf_value_defs.find(ist);
|
||||
|
||||
return iter != this->elf_value_defs.end();
|
||||
};
|
||||
|
||||
std::string get_pattern_name(uint64_t line_number) const {
|
||||
if (this->elf_type != ELF_TYPE_TEXT) {
|
||||
return "structured";
|
||||
}
|
||||
int pat_index = this->pattern_index_for_line(line_number);
|
||||
return this->elf_pattern_order[pat_index]->p_config_path;
|
||||
}
|
||||
|
||||
std::string get_pattern_regex(uint64_t line_number) const {
|
||||
if (this->elf_type != ELF_TYPE_TEXT) {
|
||||
return "";
|
||||
}
|
||||
int pat_index = this->pattern_index_for_line(line_number);
|
||||
return this->elf_pattern_order[pat_index]->p_string;
|
||||
}
|
||||
|
||||
log_level_t convert_level(const pcre_input &pi, pcre_context::capture_t *level_cap) const {
|
||||
log_level_t retval = LEVEL_INFO;
|
||||
|
||||
if (level_cap != nullptr && level_cap->is_valid()) {
|
||||
pcre_context_static<128> pc_level;
|
||||
pcre_input pi_level(pi.get_substr_start(level_cap),
|
||||
0,
|
||||
level_cap->length());
|
||||
|
||||
if (this->elf_level_patterns.empty()) {
|
||||
retval = string2level(pi_level.get_string(), level_cap->length());
|
||||
} else {
|
||||
for (const auto &elf_level_pattern : this->elf_level_patterns) {
|
||||
if (elf_level_pattern.second.lp_pcre->match(pc_level, pi_level)) {
|
||||
retval = elf_level_pattern.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef std::map<intern_string_t, module_format> mod_map_t;
|
||||
static mod_map_t MODULE_FORMATS;
|
||||
static std::vector<external_log_format *> GRAPH_ORDERED_FORMATS;
|
||||
|
||||
std::set<std::string> elf_source_path;
|
||||
std::list<intern_string_t> elf_collision;
|
||||
std::string elf_file_pattern;
|
||||
pcrepp *elf_filename_pcre;
|
||||
std::map<std::string, std::shared_ptr<pattern>> elf_patterns;
|
||||
std::vector<std::shared_ptr<pattern>> elf_pattern_order;
|
||||
std::vector<sample> elf_samples;
|
||||
std::unordered_map<const intern_string_t, std::shared_ptr<value_def>>
|
||||
elf_value_defs;
|
||||
std::vector<std::shared_ptr<value_def>> elf_value_def_order;
|
||||
std::vector<std::shared_ptr<value_def>> elf_numeric_value_defs;
|
||||
int elf_column_count;
|
||||
double elf_timestamp_divisor;
|
||||
intern_string_t elf_level_field;
|
||||
intern_string_t elf_body_field;
|
||||
intern_string_t elf_module_id_field;
|
||||
intern_string_t elf_opid_field;
|
||||
std::map<log_level_t, level_pattern> elf_level_patterns;
|
||||
std::vector<std::pair<int64_t, log_level_t> > elf_level_pairs;
|
||||
bool elf_multiline;
|
||||
bool elf_container;
|
||||
bool elf_has_module_format;
|
||||
bool elf_builtin_format;
|
||||
std::vector<std::pair<intern_string_t, std::string> > elf_search_tables;
|
||||
std::map<const intern_string_t, highlighter_def> elf_highlighter_patterns;
|
||||
|
||||
enum elf_type_t {
|
||||
ELF_TYPE_TEXT,
|
||||
ELF_TYPE_JSON,
|
||||
ELF_TYPE_CSV,
|
||||
};
|
||||
|
||||
elf_type_t elf_type;
|
||||
|
||||
void json_append_to_cache(const char *value, ssize_t len) {
|
||||
size_t old_size = this->jlf_cached_line.size();
|
||||
if (len == -1) {
|
||||
len = strlen(value);
|
||||
}
|
||||
this->jlf_cached_line.resize(old_size + len);
|
||||
memcpy(&(this->jlf_cached_line[old_size]), value, len);
|
||||
};
|
||||
|
||||
void json_append_to_cache(ssize_t len) {
|
||||
size_t old_size = this->jlf_cached_line.size();
|
||||
this->jlf_cached_line.resize(old_size + len);
|
||||
memset(&this->jlf_cached_line[old_size], ' ', len);
|
||||
};
|
||||
|
||||
void json_append(const json_format_element &jfe, const char *value, ssize_t len) {
|
||||
if (len == -1) {
|
||||
len = strlen(value);
|
||||
}
|
||||
if (jfe.jfe_align == json_format_element::align_t::RIGHT) {
|
||||
if (len < jfe.jfe_min_width) {
|
||||
this->json_append_to_cache(jfe.jfe_min_width - len);
|
||||
}
|
||||
}
|
||||
this->json_append_to_cache(value, len);
|
||||
if (jfe.jfe_align == json_format_element::align_t::LEFT) {
|
||||
if (len < jfe.jfe_min_width) {
|
||||
this->json_append_to_cache(jfe.jfe_min_width - len);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool jlf_hide_extra;
|
||||
std::vector<json_format_element> jlf_line_format;
|
||||
int jlf_line_format_init_count{0};
|
||||
std::vector<logline_value> jlf_line_values;
|
||||
|
||||
off_t jlf_cached_offset;
|
||||
bool jlf_cached_full{false};
|
||||
std::vector<off_t> jlf_line_offsets;
|
||||
shared_buffer jlf_share_manager;
|
||||
std::vector<char> jlf_cached_line;
|
||||
string_attrs_t jlf_line_attrs;
|
||||
std::shared_ptr<yajlpp_parse_context> jlf_parse_context;
|
||||
auto_mem<yajl_handle_t> jlf_yajl_handle;
|
||||
private:
|
||||
const intern_string_t elf_name;
|
||||
|
||||
static uint8_t module_scan(const pcre_input &pi,
|
||||
pcre_context::capture_t *body_cap,
|
||||
const intern_string_t &mod_name);
|
||||
};
|
||||
|
||||
class module_format {
|
||||
|
||||
public:
|
||||
external_log_format *mf_mod_format{nullptr};
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,393 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 spectro_source.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "base/math_util.hh"
|
||||
#include "spectro_source.hh"
|
||||
|
||||
bool spectrogram_source::list_input_handle_key(listview_curses &lv, int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'm': {
|
||||
if (this->ss_cursor_top < 0 ||
|
||||
(size_t) this->ss_cursor_top >= this->text_line_count() ||
|
||||
this->ss_cursor_column == -1 ||
|
||||
this->ss_value_source == nullptr) {
|
||||
alerter::singleton().chime();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
|
||||
lv.get_dimensions(height, width);
|
||||
|
||||
spectrogram_bounds &sb = this->ss_cached_bounds;
|
||||
struct timeval begin_time = this->time_for_row(this->ss_cursor_top);
|
||||
struct timeval end_time = begin_time;
|
||||
|
||||
end_time.tv_sec += this->ss_granularity;
|
||||
double range_min, range_max, column_size;
|
||||
|
||||
column_size = (sb.sb_max_value_out - sb.sb_min_value_out) /
|
||||
(double) (width - 1);
|
||||
range_min = sb.sb_min_value_out + this->ss_cursor_column * column_size;
|
||||
range_max = range_min + column_size + column_size * 0.01;
|
||||
this->ss_value_source->spectro_mark((textview_curses &) lv,
|
||||
begin_time.tv_sec, end_time.tv_sec,
|
||||
range_min, range_max);
|
||||
this->invalidate();
|
||||
lv.reload_data();
|
||||
return true;
|
||||
}
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT: {
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
string_attrs_t sa;
|
||||
|
||||
this->ss_cursor_top = lv.get_top();
|
||||
lv.get_dimensions(height, width);
|
||||
|
||||
this->text_attrs_for_line((textview_curses &) lv, this->ss_cursor_top, sa);
|
||||
|
||||
if (sa.empty()) {
|
||||
this->ss_cursor_column = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
string_attrs_t::iterator current;
|
||||
|
||||
struct line_range lr(this->ss_cursor_column, this->ss_cursor_column + 1);
|
||||
|
||||
current = find_string_attr(sa, lr);
|
||||
|
||||
if (current != sa.end()) {
|
||||
if (ch == KEY_LEFT) {
|
||||
if (current == sa.begin()) {
|
||||
current = sa.end();
|
||||
}
|
||||
else {
|
||||
--current;
|
||||
}
|
||||
}
|
||||
else {
|
||||
++current;
|
||||
}
|
||||
}
|
||||
|
||||
if (current == sa.end()) {
|
||||
if (ch == KEY_LEFT) {
|
||||
current = sa.end();
|
||||
--current;
|
||||
}
|
||||
else {
|
||||
current = sa.begin();
|
||||
}
|
||||
}
|
||||
this->ss_cursor_column = current->sa_range.lr_start;
|
||||
|
||||
lv.reload_data();
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
spectrogram_source::list_value_for_overlay(const listview_curses &lv, int y,
|
||||
int bottom, vis_line_t row,
|
||||
attr_line_t &value_out)
|
||||
{
|
||||
if (y != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string &line = value_out.get_string();
|
||||
char buf[128];
|
||||
vis_line_t height;
|
||||
unsigned long width;
|
||||
|
||||
lv.get_dimensions(height, width);
|
||||
|
||||
this->cache_bounds();
|
||||
|
||||
if (this->ss_cached_line_count == 0) {
|
||||
value_out.with_ansi_string(
|
||||
ANSI_ROLE("error: no log data"),
|
||||
view_colors::VCR_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
spectrogram_bounds &sb = this->ss_cached_bounds;
|
||||
spectrogram_thresholds &st = this->ss_cached_thresholds;
|
||||
|
||||
snprintf(buf, sizeof(buf), "Min: %'.10lg", sb.sb_min_value_out);
|
||||
line = buf;
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
ANSI_ROLE(" ") " 1-%'d "
|
||||
ANSI_ROLE(" ") " %'d-%'d "
|
||||
ANSI_ROLE(" ") " %'d+",
|
||||
view_colors::VCR_LOW_THRESHOLD,
|
||||
st.st_green_threshold - 1,
|
||||
view_colors::VCR_MED_THRESHOLD,
|
||||
st.st_green_threshold,
|
||||
st.st_yellow_threshold - 1,
|
||||
view_colors::VCR_HIGH_THRESHOLD,
|
||||
st.st_yellow_threshold);
|
||||
line.append(width / 2 - strlen(buf) / 3 - line.length(), ' ');
|
||||
line.append(buf);
|
||||
scrub_ansi_string(line, value_out.get_attrs());
|
||||
|
||||
snprintf(buf, sizeof(buf), "Max: %'.10lg", sb.sb_max_value_out);
|
||||
line.append(width - strlen(buf) - line.length() - 2, ' ');
|
||||
line.append(buf);
|
||||
|
||||
value_out.with_attr(string_attr(
|
||||
line_range(0, -1),
|
||||
&view_curses::VC_STYLE,
|
||||
A_UNDERLINE));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t spectrogram_source::text_line_count()
|
||||
{
|
||||
if (this->ss_value_source == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->cache_bounds();
|
||||
|
||||
return this->ss_cached_line_count;
|
||||
}
|
||||
|
||||
size_t spectrogram_source::text_line_width(textview_curses &tc)
|
||||
{
|
||||
if (tc.get_window() == nullptr) {
|
||||
return 80;
|
||||
}
|
||||
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
|
||||
tc.get_dimensions(height, width);
|
||||
return width;
|
||||
}
|
||||
|
||||
struct timeval spectrogram_source::time_for_row(int row)
|
||||
{
|
||||
struct timeval retval { 0, 0 };
|
||||
|
||||
this->cache_bounds();
|
||||
retval.tv_sec =
|
||||
rounddown(this->ss_cached_bounds.sb_begin_time, this->ss_granularity) +
|
||||
row * this->ss_granularity;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int spectrogram_source::row_for_time(struct timeval time_bucket)
|
||||
{
|
||||
if (this->ss_value_source == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t diff;
|
||||
int retval;
|
||||
|
||||
this->cache_bounds();
|
||||
if (time_bucket.tv_sec < this->ss_cached_bounds.sb_begin_time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff = time_bucket.tv_sec - this->ss_cached_bounds.sb_begin_time;
|
||||
retval = diff / this->ss_granularity;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void spectrogram_source::text_value_for_line(textview_curses &tc, int row,
|
||||
std::string &value_out,
|
||||
text_sub_source::line_flags_t flags)
|
||||
{
|
||||
spectrogram_row &s_row = this->load_row(tc, row);
|
||||
|
||||
struct timeval row_time;
|
||||
char tm_buffer[128];
|
||||
struct tm tm;
|
||||
|
||||
row_time = this->time_for_row(row);
|
||||
|
||||
gmtime_r(&row_time.tv_sec, &tm);
|
||||
strftime(tm_buffer, sizeof(tm_buffer), " %a %b %d %H:%M:%S", &tm);
|
||||
|
||||
value_out = tm_buffer;
|
||||
value_out.resize(s_row.sr_width, ' ');
|
||||
|
||||
for (size_t lpc = 0; lpc <= s_row.sr_width; lpc++) {
|
||||
if (s_row.sr_values[lpc].rb_marks) {
|
||||
value_out[lpc] = 'x';
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ss_cursor_top == row && this->ss_cursor_column != -1) {
|
||||
if (value_out[this->ss_cursor_column] == 'x') {
|
||||
value_out[this->ss_cursor_column] = '*';
|
||||
}
|
||||
else {
|
||||
value_out[this->ss_cursor_column] = '+';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spectrogram_source::text_attrs_for_line(textview_curses &tc, int row,
|
||||
string_attrs_t &value_out)
|
||||
{
|
||||
if (this->ss_value_source == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
view_colors &vc = view_colors::singleton();
|
||||
spectrogram_thresholds &st = this->ss_cached_thresholds;
|
||||
spectrogram_row &s_row = this->load_row(tc, row);
|
||||
|
||||
for (int lpc = 0; lpc <= (int) s_row.sr_width; lpc++) {
|
||||
int col_value = s_row.sr_values[lpc].rb_counter;
|
||||
|
||||
if (col_value == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int color;
|
||||
|
||||
if (col_value < st.st_green_threshold) {
|
||||
color = COLOR_GREEN;
|
||||
}
|
||||
else if (col_value < st.st_yellow_threshold) {
|
||||
color = COLOR_YELLOW;
|
||||
}
|
||||
else {
|
||||
color = COLOR_RED;
|
||||
}
|
||||
value_out.emplace_back(
|
||||
line_range(lpc, lpc + 1),
|
||||
&view_curses::VC_STYLE,
|
||||
vc.ansi_color_pair(COLOR_BLACK, color)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void spectrogram_source::cache_bounds()
|
||||
{
|
||||
if (this->ss_value_source == nullptr) {
|
||||
this->ss_cached_bounds.sb_count = 0;
|
||||
this->ss_cached_bounds.sb_begin_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
spectrogram_bounds sb;
|
||||
|
||||
this->ss_value_source->spectro_bounds(sb);
|
||||
|
||||
if (sb.sb_count == this->ss_cached_bounds.sb_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->ss_cached_bounds = sb;
|
||||
|
||||
if (sb.sb_count == 0) {
|
||||
this->ss_cached_line_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
time_t grain_begin_time = rounddown(sb.sb_begin_time, this->ss_granularity);
|
||||
time_t grain_end_time = roundup_size(sb.sb_end_time, this->ss_granularity);
|
||||
|
||||
time_t diff = std::max((time_t) 1, grain_end_time - grain_begin_time);
|
||||
this->ss_cached_line_count =
|
||||
(diff + this->ss_granularity - 1) / this->ss_granularity;
|
||||
|
||||
int64_t samples_per_row = sb.sb_count / this->ss_cached_line_count;
|
||||
spectrogram_thresholds &st = this->ss_cached_thresholds;
|
||||
|
||||
st.st_yellow_threshold = samples_per_row / 2;
|
||||
st.st_green_threshold = st.st_yellow_threshold / 2;
|
||||
|
||||
if (st.st_green_threshold <= 1) {
|
||||
st.st_green_threshold = 2;
|
||||
}
|
||||
if (st.st_yellow_threshold <= st.st_green_threshold) {
|
||||
st.st_yellow_threshold = st.st_green_threshold + 1;
|
||||
}
|
||||
}
|
||||
|
||||
spectrogram_row &spectrogram_source::load_row(textview_curses &tc, int row)
|
||||
{
|
||||
this->cache_bounds();
|
||||
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
|
||||
tc.get_dimensions(height, width);
|
||||
width -= 2;
|
||||
|
||||
spectrogram_bounds &sb = this->ss_cached_bounds;
|
||||
spectrogram_request sr(sb);
|
||||
time_t row_time;
|
||||
|
||||
sr.sr_width = width;
|
||||
row_time = rounddown(sb.sb_begin_time, this->ss_granularity) +
|
||||
row * this->ss_granularity;
|
||||
sr.sr_begin_time = row_time;
|
||||
sr.sr_end_time = row_time + this->ss_granularity;
|
||||
|
||||
sr.sr_column_size = (sb.sb_max_value_out - sb.sb_min_value_out) /
|
||||
(double) (width - 1);
|
||||
|
||||
spectrogram_row &s_row = this->ss_row_cache[row_time];
|
||||
|
||||
if (s_row.sr_values == nullptr ||
|
||||
s_row.sr_width != width ||
|
||||
s_row.sr_column_size != sr.sr_column_size) {
|
||||
s_row.sr_width = width;
|
||||
s_row.sr_column_size = sr.sr_column_size;
|
||||
delete[] s_row.sr_values;
|
||||
s_row.sr_values = new spectrogram_row::row_bucket[width + 1];
|
||||
this->ss_value_source->spectro_row(sr, s_row);
|
||||
}
|
||||
|
||||
return s_row;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 "string_attr_type.hh"
|
||||
|
||||
string_attr_type SA_ORIGINAL_LINE("original_line");
|
||||
string_attr_type SA_BODY("body");
|
||||
string_attr_type SA_HIDDEN("hidden");
|
||||
string_attr_type SA_FORMAT("format");
|
||||
string_attr_type SA_REMOVED("removed");
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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_string_attr_type_hh
|
||||
#define lnav_string_attr_type_hh
|
||||
|
||||
class string_attr_type {
|
||||
public:
|
||||
explicit string_attr_type(const char *name = nullptr) noexcept
|
||||
: sat_name(name) {
|
||||
};
|
||||
|
||||
const char *sat_name;
|
||||
};
|
||||
typedef string_attr_type *string_attr_type_t;
|
||||
|
||||
extern string_attr_type SA_ORIGINAL_LINE;
|
||||
extern string_attr_type SA_BODY;
|
||||
extern string_attr_type SA_HIDDEN;
|
||||
extern string_attr_type SA_FORMAT;
|
||||
extern string_attr_type SA_REMOVED;
|
||||
|
||||
#endif
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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_textview_curses_fwd_hh
|
||||
#define lnav_textview_curses_fwd_hh
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "highlighter.hh"
|
||||
|
||||
enum class highlight_source_t {
|
||||
INTERNAL,
|
||||
THEME,
|
||||
PREVIEW,
|
||||
CONFIGURATION,
|
||||
INTERACTIVE,
|
||||
};
|
||||
|
||||
using highlight_map_t = std::map<std::pair<highlight_source_t, std::string>, highlighter>;
|
||||
|
||||
#endif
|
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (c) 2020, 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 "unique_path.hh"
|
||||
|
||||
void unique_path_generator::add_source(
|
||||
const std::shared_ptr<unique_path_source> &path_source)
|
||||
{
|
||||
ghc::filesystem::path path = path_source->get_path();
|
||||
|
||||
path_source->set_unique_path(path.filename());
|
||||
path_source->set_path_prefix(path.parent_path());
|
||||
this->upg_unique_paths[path.filename()].push_back(path_source);
|
||||
}
|
||||
|
||||
void unique_path_generator::generate()
|
||||
{
|
||||
int loop_count = 0;
|
||||
|
||||
while (!this->upg_unique_paths.empty()) {
|
||||
std::vector<std::shared_ptr<unique_path_source>> collisions;
|
||||
|
||||
for (auto pair : this->upg_unique_paths) {
|
||||
if (pair.second.size() == 1) {
|
||||
if (loop_count > 0) {
|
||||
std::shared_ptr<unique_path_source> src = pair.second[0];
|
||||
|
||||
src->set_unique_path("[" + src->get_unique_path());
|
||||
}
|
||||
|
||||
this->upg_max_len = std::max(
|
||||
this->upg_max_len,
|
||||
pair.second[0]->get_unique_path().size());
|
||||
} else {
|
||||
bool all_common = true;
|
||||
|
||||
do {
|
||||
std::string common;
|
||||
|
||||
for (auto &src : pair.second) {
|
||||
auto &path = src->get_path_prefix();
|
||||
|
||||
if (common.empty()) {
|
||||
common = path.filename();
|
||||
if (common.empty()) {
|
||||
all_common = false;
|
||||
}
|
||||
} else if (common != path.filename()) {
|
||||
all_common = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_common) {
|
||||
for (auto &src : pair.second) {
|
||||
auto &path = src->get_path_prefix();
|
||||
auto par = path.parent_path();
|
||||
|
||||
if (path.empty() || path == par) {
|
||||
all_common = false;
|
||||
} else {
|
||||
src->set_path_prefix(path.parent_path());
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (all_common);
|
||||
|
||||
collisions.insert(collisions.end(),
|
||||
pair.second.begin(),
|
||||
pair.second.end());
|
||||
}
|
||||
}
|
||||
|
||||
this->upg_unique_paths.clear();
|
||||
|
||||
for (auto &src : collisions) {
|
||||
const auto unique_path = src->get_unique_path();
|
||||
auto &prefix = src->get_path_prefix();
|
||||
|
||||
if (loop_count == 0) {
|
||||
src->set_unique_path(prefix.filename().string() + "]/" + unique_path);
|
||||
} else {
|
||||
src->set_unique_path(prefix.filename().string() + "/" + unique_path);
|
||||
}
|
||||
|
||||
ghc::filesystem::path parent = prefix.parent_path();
|
||||
|
||||
src->set_path_prefix(parent);
|
||||
|
||||
if (parent.empty() || parent == prefix) {
|
||||
src->set_unique_path("[" + src->get_unique_path());
|
||||
} else {
|
||||
this->upg_unique_paths[src->get_unique_path()].push_back(
|
||||
src);
|
||||
}
|
||||
}
|
||||
|
||||
loop_count += 1;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue