[clang-format] init

pull/968/head
Timothy Stack 2 years ago
parent d0ba84d9be
commit 66ef5fdae1

@ -1,12 +1,12 @@
---
Language: Cpp
# BasedOnStyle: Chromium
AccessModifierOffset: -2
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: Consecutive
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: DontAlign
AlignOperands: DontAlign
AlignTrailingComments: false
@ -20,38 +20,38 @@ AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
# AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterClass: false
AfterControlStatement: MultiLine
AfterEnum: true
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterStruct: false
AfterUnion: false
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
# BreakBeforeInheritanceComma: true
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeComma
# BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: true
BreakStringLiterals: true
ColumnLimit: 80
@ -88,7 +88,7 @@ IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentWidth: 2
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Double
@ -99,11 +99,11 @@ MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakAssignment: 4
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
@ -143,13 +143,13 @@ RawStringFormats:
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortIncludes: CaseInsensitive
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
@ -157,7 +157,7 @@ SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false

@ -35,7 +35,7 @@ set(lnav_LIBS
)
add_subdirectory(src)
add_subdirectory(test)
# add_subdirectory(test)
# ---- Install rules ----

@ -35,6 +35,7 @@ class LnavConan(ConanFile):
"pcre:with_jit": True,
"sqlite3:enable_json1": True,
"sqlite3:enable_soundex": True,
"readline:with_library": "curses",
}
def generate(self):

@ -19,6 +19,8 @@ add_subdirectory(pcrepp)
add_subdirectory(remote)
add_subdirectory(tailer)
add_subdirectory(formats/logfmt)
add_subdirectory(yajl)
add_subdirectory(yajlpp)
add_executable(bin2c bin2c.hh tools/bin2c.c)
target_link_libraries(bin2c ZLIB::ZLIB)
@ -26,465 +28,447 @@ target_link_libraries(bin2c ZLIB::ZLIB)
add_executable(ptimec ptimec.hh ptimec.c)
set(TIME_FORMATS
"@%@"
"%Y-%m-%d %H:%M:%S"
"%Y-%m-%d %H:%M:%S%z"
"%Y-%m-%d %H:%M:%S %z"
"%Y-%m-%d %H:%M"
"%Y-%m-%dT%H:%M:%S.%f%z"
"%y-%m-%dT%H:%M:%S.%f%z"
"%Y-%m-%dT%H:%M:%SZ"
"%Y-%m-%dT%H:%M:%S%z"
"%Y-%m-%dT%H:%M:%S"
"%Y-%m-%dT%H:%M:%S%z"
"%Y/%m/%d %H:%M:%S"
"%Y/%m/%d %H:%M:%S %z"
"%Y/%m/%d %H:%M:%S%z"
"%Y/%m/%d %H:%M"
"%Y %b %d %a %H:%M:%S.%L"
"%Y %b %d %H:%M:%S.%L"
"%Y %b %d %H:%M:%S"
"%a %b %d %H:%M:%S %Y"
"%a %b %d %H:%M:%S.%f %Y"
"%a %b %d %H:%M:%S %Z %Y"
"%a %b %d %H:%M:%S "
"%a %b %d %H:%M:%S.%L "
"%d/%b/%Y:%H:%M:%S +0000"
"%d/%b/%Y:%H:%M:%S %z"
"%d-%b-%Y %H:%M:%S %z"
"%d-%b-%Y %H:%M:%S %Z"
"%d %b %Y %H:%M:%S"
"%d %b %Y %H:%M:%S.%L"
"%d %b %Y %H:%M:%S,%L"
"%b %d %H:%M:%S"
"%b %d %k:%M:%S"
"%b %d %l:%M:%S"
"%b %e, %Y %l:%M:%S %p"
"%m/%d/%y %H:%M:%S"
"%m/%d/%Y %I:%M:%S:%L %p %Z"
"%m/%d/%Y %I:%M:%S %p %Z"
"%m/%d/%Y %l:%M:%S %p %Z"
"%m/%e/%Y %I:%M:%S %p"
"%m/%e/%Y %l:%M:%S %p"
"%d/%b/%y %H:%M:%S"
"%m%d %H:%M:%S"
"%H:%M:%S"
"%M:%S"
"%m/%d %H:%M:%S"
"%Y-%m-%d"
"%Y-%m"
"%Y/%m/%d"
"%Y/%m"
"%s.%f")
"@%@"
"%Y-%m-%d %H:%M:%S"
"%Y-%m-%d %H:%M:%S%z"
"%Y-%m-%d %H:%M:%S %z"
"%Y-%m-%d %H:%M"
"%Y-%m-%dT%H:%M:%S.%f%z"
"%y-%m-%dT%H:%M:%S.%f%z"
"%Y-%m-%dT%H:%M:%SZ"
"%Y-%m-%dT%H:%M:%S%z"
"%Y-%m-%dT%H:%M:%S"
"%Y-%m-%dT%H:%M:%S%z"
"%Y/%m/%d %H:%M:%S"
"%Y/%m/%d %H:%M:%S %z"
"%Y/%m/%d %H:%M:%S%z"
"%Y/%m/%d %H:%M"
"%Y %b %d %a %H:%M:%S.%L"
"%Y %b %d %H:%M:%S.%L"
"%Y %b %d %H:%M:%S"
"%a %b %d %H:%M:%S %Y"
"%a %b %d %H:%M:%S.%f %Y"
"%a %b %d %H:%M:%S %Z %Y"
"%a %b %d %H:%M:%S "
"%a %b %d %H:%M:%S.%L "
"%d/%b/%Y:%H:%M:%S +0000"
"%d/%b/%Y:%H:%M:%S %z"
"%d-%b-%Y %H:%M:%S %z"
"%d-%b-%Y %H:%M:%S %Z"
"%d %b %Y %H:%M:%S"
"%d %b %Y %H:%M:%S.%L"
"%d %b %Y %H:%M:%S,%L"
"%b %d %H:%M:%S"
"%b %d %k:%M:%S"
"%b %d %l:%M:%S"
"%b %e, %Y %l:%M:%S %p"
"%m/%d/%y %H:%M:%S"
"%m/%d/%Y %I:%M:%S:%L %p %Z"
"%m/%d/%Y %I:%M:%S %p %Z"
"%m/%d/%Y %l:%M:%S %p %Z"
"%m/%e/%Y %I:%M:%S %p"
"%m/%e/%Y %l:%M:%S %p"
"%d/%b/%y %H:%M:%S"
"%m%d %H:%M:%S"
"%H:%M:%S"
"%M:%S"
"%m/%d %H:%M:%S"
"%Y-%m-%d"
"%Y-%m"
"%Y/%m/%d"
"%Y/%m"
"%s.%f")
set(GEN_SRCS "")
add_custom_command(OUTPUT time_fmts.cc COMMAND ptimec ${TIME_FORMATS} >
time_fmts.cc)
list(APPEND GEN_SRCS time_fmts.cc)
time_fmts.cc)
add_library(lnavdt STATIC config.h.in ptimec.hh ptimec_rt.cc time_fmts.cc)
target_include_directories(lnavdt PUBLIC . ${CMAKE_CURRENT_BINARY_DIR})
function(bin2c)
cmake_parse_arguments(BIN2C_ "" "VARNAME" "" ${ARGN})
cmake_parse_arguments(BIN2C_ "" "VARNAME" "" ${ARGN})
list(TRANSFORM BIN2C_UNPARSED_ARGUMENTS "\\." "-")
add_custom_command(
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
DEPENDS bin2c "${FILE_TO_LINK}")
list(TRANSFORM BIN2C_UNPARSED_ARGUMENTS "\\." "-")
add_custom_command(
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
DEPENDS bin2c "${FILE_TO_LINK}")
endfunction(bin2c)
foreach(FILE_TO_LINK ansi-palette.json xterm-palette.json help.txt init.sql)
string(REPLACE "." "-" DST_FILE "${FILE_TO_LINK}")
add_custom_command(
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
DEPENDS bin2c "${FILE_TO_LINK}")
list(APPEND GEN_SRCS "${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.h"
"${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.cc")
endforeach(FILE_TO_LINK)
foreach (FILE_TO_LINK ansi-palette.json xterm-palette.json help.txt init.sql)
string(REPLACE "." "-" DST_FILE "${FILE_TO_LINK}")
add_custom_command(
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
DEPENDS bin2c "${FILE_TO_LINK}")
list(APPEND GEN_SRCS "${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.h"
"${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.cc")
endforeach (FILE_TO_LINK)
set(FORMAT_FILES
formats/access_log.json
formats/alb_log.json
formats/autodeploy_log.json
formats/block_log.json
formats/candlepin_log.json
formats/choose_repo_log.json
formats/cups_log.json
formats/dpkg_log.json
formats/elb_log.json
formats/engine_log.json
formats/error_log.json
formats/fsck_hfs_log.json
formats/glog_log.json
formats/haproxy_log.json
formats/java_log.json
formats/journald_json_log.json
formats/katello_log.json
formats/openam_log.json
formats/openamdb_log.json
formats/openstack_log.json
formats/page_log.json
formats/papertrail_log.json
formats/snaplogic_log.json
formats/sssd_log.json
formats/strace_log.json
formats/sudo_log.json
formats/syslog_log.json
formats/s3_log.json
formats/tcf_log.json
formats/tcsh_history.json
formats/uwsgi_log.json
formats/vdsm_log.json
formats/vmk_log.json
formats/vmw_log.json
formats/xmlrpc_log.json)
formats/access_log.json
formats/alb_log.json
formats/autodeploy_log.json
formats/block_log.json
formats/candlepin_log.json
formats/choose_repo_log.json
formats/cups_log.json
formats/dpkg_log.json
formats/elb_log.json
formats/engine_log.json
formats/error_log.json
formats/fsck_hfs_log.json
formats/glog_log.json
formats/haproxy_log.json
formats/java_log.json
formats/journald_json_log.json
formats/katello_log.json
formats/openam_log.json
formats/openamdb_log.json
formats/openstack_log.json
formats/page_log.json
formats/papertrail_log.json
formats/snaplogic_log.json
formats/sssd_log.json
formats/strace_log.json
formats/sudo_log.json
formats/syslog_log.json
formats/s3_log.json
formats/tcf_log.json
formats/tcsh_history.json
formats/uwsgi_log.json
formats/vdsm_log.json
formats/vmk_log.json
formats/vmw_log.json
formats/xmlrpc_log.json)
set(FORMAT_FILE_PATHS ${FORMAT_FILES})
list(TRANSFORM FORMAT_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
add_custom_command(
OUTPUT default-formats.h default-formats.cc
COMMAND bin2c -n lnav_format_json default-formats ${FORMAT_FILE_PATHS}
DEPENDS bin2c ${FORMAT_FILES})
OUTPUT default-formats.h default-formats.cc
COMMAND bin2c -n lnav_format_json default-formats ${FORMAT_FILE_PATHS}
DEPENDS bin2c ${FORMAT_FILES})
list(APPEND GEN_SRCS default-formats.h default-formats.cc)
set(CONFIG_FILES
root-config.json
keymaps/de-keymap.json
keymaps/default-keymap.json
keymaps/fr-keymap.json
keymaps/uk-keymap.json
keymaps/us-keymap.json
themes/default-theme.json
themes/grayscale.json
themes/eldar.json
themes/monocai.json
themes/night-owl.json
themes/solarized-dark.json
themes/solarized-light.json)
root-config.json
keymaps/de-keymap.json
keymaps/default-keymap.json
keymaps/fr-keymap.json
keymaps/uk-keymap.json
keymaps/us-keymap.json
themes/default-theme.json
themes/grayscale.json
themes/eldar.json
themes/monocai.json
themes/night-owl.json
themes/solarized-dark.json
themes/solarized-light.json)
set(CONFIG_FILE_PATHS ${CONFIG_FILES})
list(TRANSFORM CONFIG_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
add_custom_command(
OUTPUT default-config.h default-config.cc
COMMAND bin2c -n lnav_config_json default-config ${CONFIG_FILE_PATHS}
DEPENDS bin2c ${CONFIG_FILES})
OUTPUT default-config.h default-config.cc
COMMAND bin2c -n lnav_config_json default-config ${CONFIG_FILE_PATHS}
DEPENDS bin2c ${CONFIG_FILES})
list(APPEND GEN_SRCS default-config.h default-config.cc)
set(BUILTIN_LNAV_SCRIPTS
scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
scripts/partition-by-boot.lnav scripts/rename-stdin.lnav
scripts/search-for.lnav)
scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
scripts/partition-by-boot.lnav scripts/rename-stdin.lnav
scripts/search-for.lnav)
set(BUILTIN_LNAV_SCRIPT_PATHS ${BUILTIN_LNAV_SCRIPTS})
list(TRANSFORM BUILTIN_LNAV_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
add_custom_command(
OUTPUT builtin-scripts.h builtin-scripts.cc
COMMAND bin2c -n lnav_scripts builtin-scripts ${BUILTIN_LNAV_SCRIPT_PATHS}
DEPENDS bin2c ${BUILTIN_LNAV_SCRIPTS})
OUTPUT builtin-scripts.h builtin-scripts.cc
COMMAND bin2c -n lnav_scripts builtin-scripts ${BUILTIN_LNAV_SCRIPT_PATHS}
DEPENDS bin2c ${BUILTIN_LNAV_SCRIPTS})
list(APPEND GEN_SRCS builtin-scripts.h builtin-scripts.cc)
set(BUILTIN_SH_SCRIPTS scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
scripts/partition-by-boot.lnav scripts/search-for.lnav)
scripts/partition-by-boot.lnav scripts/search-for.lnav)
set(BUILTIN_SH_SCRIPT_PATHS ${BUILTIN_SH_SCRIPTS})
list(TRANSFORM BUILTIN_SH_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
add_custom_command(
OUTPUT builtin-sh-scripts.h builtin-sh-scripts.cc
COMMAND bin2c -n lnav_sh_scripts builtin-sh-scripts ${BUILTIN_SH_SCRIPT_PATHS}
DEPENDS bin2c ${BUILTIN_SH_SCRIPTS})
OUTPUT builtin-sh-scripts.h builtin-sh-scripts.cc
COMMAND bin2c -n lnav_sh_scripts builtin-sh-scripts ${BUILTIN_SH_SCRIPT_PATHS}
DEPENDS bin2c ${BUILTIN_SH_SCRIPTS})
list(APPEND GEN_SRCS builtin-sh-scripts.h builtin-sh-scripts.cc)
add_library(
cppfmt STATIC
fmtlib/format.cc
fmtlib/os.cc
fmtlib/fmt/chrono.h
fmtlib/fmt/color.h
fmtlib/fmt/compile.h
fmtlib/fmt/core.h
fmtlib/fmt/format-inl.h
fmtlib/fmt/format.h
fmtlib/fmt/locale.h
fmtlib/fmt/os.h
fmtlib/fmt/ostream.h
fmtlib/fmt/posix.h
fmtlib/fmt/printf.h
fmtlib/fmt/ranges.h
fmtlib/fmt/time.h)
cppfmt STATIC
fmtlib/format.cc
fmtlib/os.cc
fmtlib/fmt/chrono.h
fmtlib/fmt/color.h
fmtlib/fmt/compile.h
fmtlib/fmt/core.h
fmtlib/fmt/format-inl.h
fmtlib/fmt/format.h
fmtlib/fmt/locale.h
fmtlib/fmt/os.h
fmtlib/fmt/ostream.h
fmtlib/fmt/posix.h
fmtlib/fmt/printf.h
fmtlib/fmt/ranges.h
fmtlib/fmt/time.h)
target_include_directories(cppfmt PUBLIC fmtlib)
add_library(lnavfileio STATIC
grep_proc.hh
line_buffer.hh
shared_buffer.hh
grep_proc.cc
line_buffer.cc
shared_buffer.cc
)
target_include_directories(lnavfileio PRIVATE . ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(lnavfileio cppfmt pcrepp base BZip2::BZip2 ZLIB::ZLIB)
add_library(
diag STATIC
${GEN_SRCS}
config.h.in
all_logs_vtab.cc
ansi_scrubber.cc
archive_manager.cc
attr_line.cc
bin2c.hh
bookmarks.cc
bottom_status_source.cc
collation-functions.cc
column_namer.cc
command_executor.cc
curl_looper.cc
db_sub_source.cc
elem_to_json.cc
environ_vtab.cc
extension-functions.cc
field_overlay_source.cc
file_collection.cc
file_format.cc
file_vtab.cc
files_sub_source.cc
filter_observer.cc
filter_status_source.cc
filter_sub_source.cc
fs-extension-functions.cc
fstat_vtab.cc
fts_fuzzy_match.cc
grep_proc.cc
help_text.cc
help_text_formatter.cc
highlighter.cc
hist_source.cc
hotkeys.cc
input_dispatcher.cc
json-extension-functions.cc
yajlpp/json_op.cc
yajlpp/json_ptr.cc
line_buffer.cc
listview_curses.cc
lnav_commands.cc
lnav_config.cc
lnav_util.cc
log_accel.cc
log_actions.cc
log_data_helper.cc
log_data_table.cc
log_format.cc
log_format_loader.cc
log_level.cc
log_search_table.cc
logfile.cc
logfile_sub_source.cc
network-extension-functions.cc
data_scanner.cc
data_scanner_re.cc
data_parser.cc
papertrail_proc.cc
pcap_manager.cc
ptimec_rt.cc
pretty_printer.cc
pugixml/pugixml.cpp
readline_callbacks.cc
readline_curses.cc
readline_highlighters.cc
readline_possibilities.cc
regexp_vtab.cc
relative_time.cc
session_data.cc
sequence_matcher.cc
shared_buffer.cc
shlex.cc
sqlite-extension-func.cc
statusview_curses.cc
string-extension-functions.cc
sysclip.cc
piper_proc.cc
spectro_source.cc
sql_commands.cc
sql_util.cc
state-extension-functions.cc
styling.cc
string_attr_type.cc
text_format.cc
textfile_highlighters.cc
textfile_sub_source.cc
textview_curses.cc
top_status_source.cc
time-extension-functions.cc
timer.cc
unique_path.cc
unique_path.hh
view_curses.cc
view_helpers.cc
views_vtab.cc
vt52_curses.cc
vtab_module.cc
log_vtab_impl.cc
xml_util.cc
xpath_vtab.cc
xterm_mouse.cc
yajlpp/yajlpp.cc
yajl/yajl.c
yajl/yajl_alloc.c
yajl/yajl_alloc.h
yajl/yajl_buf.c
yajl/yajl_buf.h
yajl/yajl_bytestack.h
yajl/yajl_encode.c
yajl/yajl_encode.h
yajl/yajl_gen.c
yajl/yajl_lex.c
yajl/yajl_lex.h
yajl/yajl_parser.c
yajl/yajl_parser.h
yajl/yajl_tree.c
yajl/yajl_version.c
spookyhash/SpookyV2.cpp
third-party/sqlite/ext/series.c
third-party/sqlite/ext/dbdump.c
all_logs_vtab.hh
archive_manager.hh
archive_manager.cfg.hh
attr_line.hh
auto_fd.hh
auto_mem.hh
big_array.hh
bottom_status_source.hh
bound_tags.hh
byte_array.hh
command_executor.hh
column_namer.hh
curl_looper.hh
doc_status_source.hh
elem_to_json.hh
field_overlay_source.hh
file_collection.hh
file_format.hh
files_sub_source.hh
filter_observer.hh
filter_status_source.hh
filter_sub_source.hh
fstat_vtab.hh
fts_fuzzy_match.hh
grep_highlighter.hh
help_text.hh
help_text_formatter.hh
highlighter.hh
hotkeys.hh
input_dispatcher.hh
k_merge_tree.h
log_actions.hh
log_data_helper.hh
log_data_table.hh
log_format.hh
log_format_ext.hh
log_format_fwd.hh
log_format_impls.cc
log_gutter_source.hh
log_level.hh
log_search_table.hh
logfile.hh
logfile_fwd.hh
logfile_stats.hh
optional.hpp
papertrail_proc.hh
pcap_manager.hh
plain_text_source.hh
pretty_printer.hh
preview_status_source.hh
ptimec.hh
pugixml/pugiconfig.hpp
pugixml/pugixml.hpp
readline_callbacks.hh
readline_context.hh
readline_possibilities.hh
regexp_vtab.hh
relative_time.hh
styling.hh
ring_span.hh
safe/accessmode.h
safe/defaulttypes.h
safe/mutableref.h
safe/safe.h
sequence_sink.hh
shlex.hh
shlex.resolver.hh
simdutf8check.h
spectro_source.hh
sqlitepp.hh
sql_help.hh
sql_util.hh
strong_int.hh
string_attr_type.hh
sysclip.hh
sysclip.cfg.hh
term_extra.hh
termios_guard.hh
text_format.hh
textfile_highlighters.hh
textfile_sub_source.hh
textview_curses.hh
textview_curses_fwd.hh
time_T.hh
timer.hh
top_status_source.hh
url_loader.hh
view_helpers.hh
view_helpers.examples.hh
views_vtab.hh
vis_line.hh
vtab_module.hh
vtab_module_json.hh
yajlpp/yajlpp.hh
yajlpp/yajlpp_def.hh
xml_util.hh
xpath_vtab.hh
mapbox/recursive_wrapper.hpp
mapbox/variant.hpp
mapbox/variant_io.hpp
mapbox/variant_visitor.hpp
yajl/api/yajl_common.h
yajl/api/yajl_gen.h
yajl/api/yajl_parse.h
yajl/api/yajl_tree.h
ghc/filesystem.hpp
ghc/fs_fwd.hpp
ghc/fs_impl.hpp
ghc/fs_std.hpp
ghc/fs_std_fwd.hpp
ghc/fs_std_impl.hpp
ww898/cp_utf8.hpp
log_level_re.cc)
diag STATIC
${GEN_SRCS}
config.h.in
all_logs_vtab.cc
ansi_scrubber.cc
archive_manager.cc
attr_line.cc
bin2c.hh
bookmarks.cc
bottom_status_source.cc
collation-functions.cc
column_namer.cc
command_executor.cc
curl_looper.cc
db_sub_source.cc
elem_to_json.cc
environ_vtab.cc
extension-functions.cc
field_overlay_source.cc
file_collection.cc
file_format.cc
file_vtab.cc
files_sub_source.cc
filter_observer.cc
filter_status_source.cc
filter_sub_source.cc
fs-extension-functions.cc
fstat_vtab.cc
fts_fuzzy_match.cc
help_text.cc
help_text_formatter.cc
highlighter.cc
hist_source.cc
hotkeys.cc
input_dispatcher.cc
json-extension-functions.cc
listview_curses.cc
lnav_commands.cc
lnav_config.cc
lnav_util.cc
log_accel.cc
log_actions.cc
log_data_helper.cc
log_data_table.cc
log_format.cc
log_format_loader.cc
log_level.cc
log_search_table.cc
logfile.cc
logfile_sub_source.cc
network-extension-functions.cc
data_scanner.cc
data_scanner_re.cc
data_parser.cc
papertrail_proc.cc
pcap_manager.cc
pretty_printer.cc
pugixml/pugixml.cpp
readline_callbacks.cc
readline_curses.cc
readline_highlighters.cc
readline_possibilities.cc
regexp_vtab.cc
relative_time.cc
session_data.cc
sequence_matcher.cc
shlex.cc
sqlite-extension-func.cc
statusview_curses.cc
string-extension-functions.cc
sysclip.cc
piper_proc.cc
spectro_source.cc
sql_commands.cc
sql_util.cc
state-extension-functions.cc
styling.cc
string_attr_type.cc
text_format.cc
textfile_highlighters.cc
textfile_sub_source.cc
textview_curses.cc
top_status_source.cc
time-extension-functions.cc
timer.cc
unique_path.cc
unique_path.hh
view_curses.cc
view_helpers.cc
views_vtab.cc
vt52_curses.cc
vtab_module.cc
log_vtab_impl.cc
xml_util.cc
xpath_vtab.cc
xterm_mouse.cc
spookyhash/SpookyV2.cpp
third-party/sqlite/ext/series.c
third-party/sqlite/ext/dbdump.c
all_logs_vtab.hh
archive_manager.hh
archive_manager.cfg.hh
attr_line.hh
auto_fd.hh
auto_mem.hh
big_array.hh
bottom_status_source.hh
bound_tags.hh
byte_array.hh
command_executor.hh
column_namer.hh
curl_looper.hh
doc_status_source.hh
elem_to_json.hh
field_overlay_source.hh
file_collection.hh
file_format.hh
files_sub_source.hh
filter_observer.hh
filter_status_source.hh
filter_sub_source.hh
fstat_vtab.hh
fts_fuzzy_match.hh
grep_highlighter.hh
help_text.hh
help_text_formatter.hh
highlighter.hh
hotkeys.hh
input_dispatcher.hh
k_merge_tree.h
log_actions.hh
log_data_helper.hh
log_data_table.hh
log_format.hh
log_format_ext.hh
log_format_fwd.hh
log_format_impls.cc
log_gutter_source.hh
log_level.hh
log_search_table.hh
logfile.hh
logfile_fwd.hh
logfile_stats.hh
optional.hpp
papertrail_proc.hh
pcap_manager.hh
plain_text_source.hh
pretty_printer.hh
preview_status_source.hh
pugixml/pugiconfig.hpp
pugixml/pugixml.hpp
readline_callbacks.hh
readline_context.hh
readline_possibilities.hh
regexp_vtab.hh
relative_time.hh
styling.hh
ring_span.hh
safe/accessmode.h
safe/defaulttypes.h
safe/mutableref.h
safe/safe.h
sequence_sink.hh
shlex.hh
shlex.resolver.hh
simdutf8check.h
spectro_source.hh
sqlitepp.hh
sql_help.hh
sql_util.hh
strong_int.hh
string_attr_type.hh
sysclip.hh
sysclip.cfg.hh
term_extra.hh
termios_guard.hh
text_format.hh
textfile_highlighters.hh
textfile_sub_source.hh
textview_curses.hh
textview_curses_fwd.hh
time_T.hh
timer.hh
top_status_source.hh
url_loader.hh
view_helpers.hh
view_helpers.examples.hh
views_vtab.hh
vis_line.hh
vtab_module.hh
vtab_module_json.hh
xml_util.hh
xpath_vtab.hh
mapbox/recursive_wrapper.hpp
mapbox/variant.hpp
mapbox/variant_io.hpp
mapbox/variant_visitor.hpp
ghc/filesystem.hpp
ghc/fs_fwd.hpp
ghc/fs_impl.hpp
ghc/fs_std.hpp
ghc/fs_std_fwd.hpp
ghc/fs_std_impl.hpp
ww898/cp_utf8.hpp
log_level_re.cc)
set(lnav_SRCS lnav.cc)
target_include_directories(diag PUBLIC . fmtlib ${CMAKE_CURRENT_BINARY_DIR}
third-party)
third-party)
target_link_libraries(
diag
base
pcrepp
tailerservice
tailerpp
tailercommon
logfmt
${lnav_LIBS})
diag
base
lnavdt
lnavfileio
pcrepp
tailerservice
tailerpp
tailercommon
logfmt
yajlpp
${lnav_LIBS})
target_compile_definitions(diag PRIVATE SQLITE_OMIT_LOAD_EXTENSION)
check_library_exists(util openpty "" HAVE_LIBUTIL)
if(HAVE_LIBUTIL)
target_link_libraries(diag util)
endif()
add_executable(test_yajlpp yajlpp/test_yajlpp.cc)
target_link_libraries(test_yajlpp diag ${lnav_LIBS})
add_test(NAME test_yajlpp COMMAND test_yajlpp)
add_executable(drive_json_op yajlpp/drive_json_op.cc)
target_link_libraries(drive_json_op diag ${lnav_LIBS})
if (HAVE_LIBUTIL)
target_link_libraries(diag util)
endif ()
add_executable(lnav ${lnav_SRCS})
target_link_libraries(lnav diag)

@ -21,48 +21,54 @@
* 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
* 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 "all_logs_vtab.hh"
#include "config.h"
#include "string_attr_type.hh"
static auto intern_lifetime = intern_string::get_table_lifetime();
all_logs_vtab::all_logs_vtab()
: log_vtab_impl(intern_string::lookup("all_logs")),
alv_value_meta(intern_string::lookup("log_format"),
value_kind_t::VALUE_TEXT,
0),
alv_msg_meta(intern_string::lookup("log_msg_format"),
value_kind_t::VALUE_TEXT,
1),
alv_schema_meta(intern_string::lookup("log_msg_schema"),
value_kind_t::VALUE_TEXT,
2) {
alv_value_meta(
intern_string::lookup("log_format"), value_kind_t::VALUE_TEXT, 0),
alv_msg_meta(
intern_string::lookup("log_msg_format"), value_kind_t::VALUE_TEXT, 1),
alv_schema_meta(
intern_string::lookup("log_msg_schema"), value_kind_t::VALUE_TEXT, 2)
{
this->alv_value_meta.lvm_identifier = true;
this->alv_msg_meta.lvm_identifier = true;
this->alv_schema_meta.lvm_identifier = true;
}
void all_logs_vtab::get_columns(std::vector<vtab_column> &cols) const
void
all_logs_vtab::get_columns(std::vector<vtab_column>& cols) const
{
cols.emplace_back(vtab_column(this->alv_value_meta.lvm_name.get())
.with_comment("The name of the log file format"));
cols.emplace_back(vtab_column(this->alv_msg_meta.lvm_name.get())
.with_comment("The message format with variables replaced by hash marks"));
cols.emplace_back(this->alv_schema_meta.lvm_name.get(), SQLITE3_TEXT, "", true,
cols.emplace_back(
vtab_column(this->alv_msg_meta.lvm_name.get())
.with_comment(
"The message format with variables replaced by hash marks"));
cols.emplace_back(this->alv_schema_meta.lvm_name.get(),
SQLITE3_TEXT,
"",
true,
"The ID for the message schema");
}
void all_logs_vtab::extract(std::shared_ptr<logfile> lf, uint64_t line_number,
shared_buffer_ref &line,
std::vector<logline_value> &values)
void
all_logs_vtab::extract(std::shared_ptr<logfile> lf,
uint64_t line_number,
shared_buffer_ref& line,
std::vector<logline_value>& values)
{
auto format = lf->get_format();
values.emplace_back(this->alv_value_meta, format->get_name());
@ -98,7 +104,8 @@ void all_logs_vtab::extract(std::shared_ptr<logfile> lf, uint64_t line_number,
values.emplace_back(this->alv_schema_meta, schema_ref);
}
bool all_logs_vtab::is_valid(log_cursor &lc, logfile_sub_source &lss)
bool
all_logs_vtab::is_valid(log_cursor& lc, logfile_sub_source& lss)
{
auto cl = lss.at(lc.lc_curr_line);
auto lf = lss.find(cl);
@ -111,7 +118,8 @@ bool all_logs_vtab::is_valid(log_cursor &lc, logfile_sub_source &lss)
return true;
}
bool all_logs_vtab::next(log_cursor &lc, logfile_sub_source &lss)
bool
all_logs_vtab::next(log_cursor& lc, logfile_sub_source& lss)
{
lc.lc_curr_line = lc.lc_curr_line + vis_line_t(1);
lc.lc_sub_index = 0;

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -32,27 +32,26 @@
#include <array>
#include "log_vtab_impl.hh"
#include "data_parser.hh"
#include "log_vtab_impl.hh"
/**
* A virtual table that provides access to all log messages from all formats.
*/
class all_logs_vtab : public log_vtab_impl {
public:
all_logs_vtab();
void get_columns(std::vector<vtab_column> &cols) const override;
void get_columns(std::vector<vtab_column>& cols) const override;
void extract(std::shared_ptr<logfile> lf,
uint64_t line_number,
shared_buffer_ref &line,
std::vector<logline_value> &values) override;
shared_buffer_ref& line,
std::vector<logline_value>& values) override;
bool is_valid(log_cursor &lc, logfile_sub_source &lss) override;
bool is_valid(log_cursor& lc, logfile_sub_source& lss) override;
bool next(log_cursor &lc, logfile_sub_source &lss) override;
bool next(log_cursor& lc, logfile_sub_source& lss) override;
private:
logline_value_meta alv_value_meta;
@ -62,4 +61,4 @@ private:
std::array<char, data_parser::schema_id_t::STRING_SIZE> alv_schema_buffer{};
};
#endif //LNAV_ALL_LOGS_VTAB_HH
#endif // LNAV_ALL_LOGS_VTAB_HH

@ -21,44 +21,46 @@
* 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
* 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 ansi_scrubber.cc
*/
#include "config.h"
#include <algorithm>
#include "ansi_scrubber.hh"
#include "base/opt_util.hh"
#include "view_curses.hh"
#include "config.h"
#include "pcrepp/pcrepp.hh"
#include "ansi_scrubber.hh"
#include "view_curses.hh"
using namespace std;
static pcrepp &ansi_regex()
static pcrepp&
ansi_regex()
{
static pcrepp retval("\x1b\\[([\\d=;\\?]*)([a-zA-Z])");
return retval;
}
void scrub_ansi_string(std::string &str, string_attrs_t &sa)
void
scrub_ansi_string(std::string& str, string_attrs_t& sa)
{
pcre_context_static<60> context;
pcrepp & regex = ansi_regex();
pcrepp& regex = ansi_regex();
pcre_input pi(str);
replace(str.begin(), str.end(), '\0', ' ');
while (regex.match(context, pi)) {
pcre_context::capture_t *caps = context.all();
struct line_range lr;
pcre_context::capture_t* caps = context.all();
struct line_range lr;
bool has_attrs = false;
attr_t attrs = 0;
attr_t attrs = 0;
auto bg = nonstd::optional<int>();
auto fg = nonstd::optional<int>();
auto role = nonstd::optional<int>();
@ -67,7 +69,8 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
switch (pi.get_substr_start(&caps[2])[0]) {
case 'm':
for (lpc = caps[1].c_begin;
lpc != string::npos && lpc < (size_t) caps[1].c_end;) {
lpc != string::npos && lpc < (size_t) caps[1].c_end;)
{
int ansi_code = 0;
if (sscanf(&(str[lpc]), "%d", &ansi_code) == 1) {
@ -110,9 +113,10 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
case 'C': {
unsigned int spaces = 0;
if (sscanf(&(str[caps[1].c_begin]), "%u", &spaces) == 1 &&
spaces > 0) {
str.insert((unsigned long) caps[0].c_end, spaces, ' ');
if (sscanf(&(str[caps[1].c_begin]), "%u", &spaces) == 1
&& spaces > 0) {
str.insert(
(std::string::size_type) caps[0].c_end, spaces, ' ');
}
break;
}
@ -120,11 +124,13 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
case 'H': {
unsigned int row = 0, spaces = 0;
if (sscanf(&(str[caps[1].c_begin]), "%u;%u", &row, &spaces) == 2 &&
spaces > 1) {
if (sscanf(&(str[caps[1].c_begin]), "%u;%u", &row, &spaces) == 2
&& spaces > 1) {
int ispaces = spaces - 1;
if (ispaces > caps[0].c_begin) {
str.insert((unsigned long) caps[0].c_end, ispaces - caps[0].c_begin, ' ');
str.insert((unsigned long) caps[0].c_end,
ispaces - caps[0].c_begin,
' ');
}
}
break;
@ -142,8 +148,7 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
break;
}
}
str.erase(str.begin() + caps[0].c_begin,
str.begin() + caps[0].c_end);
str.erase(str.begin() + caps[0].c_begin, str.begin() + caps[0].c_end);
if (has_attrs) {
for (auto rit = sa.rbegin(); rit != sa.rend(); rit++) {
@ -153,7 +158,7 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
rit->sa_range.lr_end = caps[0].c_begin;
}
lr.lr_start = caps[0].c_begin;
lr.lr_end = -1;
lr.lr_end = -1;
if (attrs) {
sa.emplace_back(lr, &view_curses::VC_STYLE, attrs);
}
@ -172,7 +177,8 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
}
}
void add_ansi_vars(std::map<std::string, std::string> &vars)
void
add_ansi_vars(std::map<std::string, std::string>& vars)
{
vars["ansi_csi"] = ANSI_CSI;
vars["ansi_norm"] = ANSI_NORM;

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -37,22 +37,22 @@
#include "attr_line.hh"
#define ANSI_CSI "\x1b["
#define ANSI_CHAR_ATTR "m"
#define ANSI_BOLD_PARAM "1"
#define ANSI_BOLD_START ANSI_CSI ANSI_BOLD_PARAM ANSI_CHAR_ATTR
#define ANSI_UNDERLINE_START ANSI_CSI "4m"
#define ANSI_NORM ANSI_CSI "0m"
#define ANSI_STRIKE_PARAM "9"
#define ANSI_STRIKE_START ANSI_CSI ANSI_STRIKE_PARAM ANSI_CHAR_ATTR
#define ANSI_CSI "\x1b["
#define ANSI_CHAR_ATTR "m"
#define ANSI_BOLD_PARAM "1"
#define ANSI_BOLD_START ANSI_CSI ANSI_BOLD_PARAM ANSI_CHAR_ATTR
#define ANSI_UNDERLINE_START ANSI_CSI "4m"
#define ANSI_NORM ANSI_CSI "0m"
#define ANSI_STRIKE_PARAM "9"
#define ANSI_STRIKE_START ANSI_CSI ANSI_STRIKE_PARAM ANSI_CHAR_ATTR
#define ANSI_BOLD(msg) ANSI_BOLD_START msg ANSI_NORM
#define ANSI_UNDERLINE(msg) ANSI_UNDERLINE_START msg ANSI_NORM
#define ANSI_BOLD(msg) ANSI_BOLD_START msg ANSI_NORM
#define ANSI_UNDERLINE(msg) ANSI_UNDERLINE_START msg ANSI_NORM
#define ANSI_ROLE(msg) ANSI_CSI "%dO" msg ANSI_NORM
#define XANSI_COLOR(col) "3" #col
#define ANSI_ROLE(msg) ANSI_CSI "%dO" msg ANSI_NORM
#define XANSI_COLOR(col) "3" #col
#define ANSI_COLOR_PARAM(col) XANSI_COLOR(col)
#define ANSI_COLOR(col) ANSI_CSI XANSI_COLOR(col) "m"
#define ANSI_COLOR(col) ANSI_CSI XANSI_COLOR(col) "m"
/**
* Check a string for ANSI escape sequences, process them, remove them, and add
@ -61,12 +61,12 @@
* @param str The string to check for ANSI escape sequences.
* @param sa The container for any style attributes.
*/
void scrub_ansi_string(std::string &str, string_attrs_t &sa);
void scrub_ansi_string(std::string& str, string_attrs_t& sa);
/**
* Populate a variable map with strings that contain escape sequences that
* might be useful to script writers.
*/
void add_ansi_vars(std::map<std::string, std::string> &vars);
void add_ansi_vars(std::map<std::string, std::string>& vars);
#endif

@ -21,36 +21,35 @@
* 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
* 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 archive_manager.cc
*/
#include "config.h"
#include <unistd.h>
#include "config.h"
#if HAVE_ARCHIVE_H
#include "archive.h"
#include "archive_entry.h"
# include "archive.h"
# include "archive_entry.h"
#endif
#include "archive_manager.cfg.hh"
#include "archive_manager.hh"
#include "auto_fd.hh"
#include "auto_mem.hh"
#include "fmt/format.h"
#include "base/fs_util.hh"
#include "base/humanize.hh"
#include "base/injector.hh"
#include "base/lnav_log.hh"
#include "base/humanize.hh"
#include "base/paths.hh"
#include "fmt/format.h"
#include "lnav_util.hh"
#include "archive_manager.hh"
#include "archive_manager.cfg.hh"
namespace fs = ghc::filesystem;
namespace archive_manager {
@ -59,32 +58,37 @@ class archive_lock {
public:
class guard {
public:
explicit guard(archive_lock& arc_lock) : g_lock(arc_lock) {
explicit guard(archive_lock& arc_lock) : g_lock(arc_lock)
{
this->g_lock.lock();
};
~guard() {
~guard()
{
this->g_lock.unlock();
};
private:
archive_lock &g_lock;
archive_lock& g_lock;
};
void lock() const {
void lock() const
{
lockf(this->lh_fd, F_LOCK, 0);
};
void unlock() const {
void unlock() const
{
lockf(this->lh_fd, F_ULOCK, 0);
};
explicit archive_lock(const fs::path& archive_path) {
explicit archive_lock(const fs::path& archive_path)
{
auto lock_path = archive_path;
lock_path += ".lck";
this->lh_fd = lnav::filesystem::openp(lock_path, O_CREAT | O_RDWR, 0600);
this->lh_fd
= lnav::filesystem::openp(lock_path, O_CREAT | O_RDWR, 0600);
log_perror(fcntl(this->lh_fd, F_SETFD, FD_CLOEXEC));
};
@ -96,7 +100,8 @@ public:
* Enables a subset of the supported archive formats to speed up detection,
* since some formats, like xar are unlikely to be used.
*/
static void enable_desired_archive_formats(archive *arc)
static void
enable_desired_archive_formats(archive* arc)
{
archive_read_support_format_7zip(arc);
archive_read_support_format_cpio(arc);
@ -107,7 +112,8 @@ static void enable_desired_archive_formats(archive *arc)
}
#endif
bool is_archive(const fs::path& filename)
bool
is_archive(const fs::path& filename)
{
#if HAVE_ARCHIVE_H
auto_mem<archive> arc(archive_read_free);
@ -120,7 +126,7 @@ bool is_archive(const fs::path& filename)
log_debug("read open %s", filename.c_str());
auto r = archive_read_open_filename(arc, filename.c_str(), 128 * 1024);
if (r == ARCHIVE_OK) {
struct archive_entry *entry;
struct archive_entry* entry;
auto format_name = archive_format_name(arc);
@ -145,8 +151,8 @@ bool is_archive(const fs::path& filename)
return false;
}
}
log_info("detected archive: %s -- %s",
filename.c_str(), format_name);
log_info(
"detected archive: %s -- %s", filename.c_str(), format_name);
return true;
} else {
log_info("archive read header failed: %s -- %s",
@ -163,14 +169,14 @@ bool is_archive(const fs::path& filename)
return false;
}
static
fs::path archive_cache_path()
static fs::path
archive_cache_path()
{
return lnav::paths::workdir() / "archives";
}
fs::path
filename_to_tmp_path(const std::string &filename)
filename_to_tmp_path(const std::string& filename)
{
auto fn_path = fs::path(filename);
auto basename = fn_path.filename().string();
@ -195,14 +201,14 @@ filename_to_tmp_path(const std::string &filename)
#if HAVE_ARCHIVE_H
static walk_result_t
copy_data(const std::string& filename,
struct archive *ar,
struct archive_entry *entry,
struct archive *aw,
const fs::path &entry_path,
struct extract_progress *ep)
struct archive* ar,
struct archive_entry* entry,
struct archive* aw,
const fs::path& entry_path,
struct extract_progress* ep)
{
int r;
const void *buff;
const void* buff;
size_t size, total = 0, next_space_check = 0;
la_int64_t offset;
@ -213,7 +219,9 @@ copy_data(const std::string& filename,
if (tmp_space.available < cfg.amc_min_free_space) {
return Err(fmt::format(
FMT_STRING("available space on disk ({}) is below the minimum-free threshold ({}). Unable to unpack '{}' to '{}'"),
FMT_STRING("available space on disk ({}) is below the "
"minimum-free threshold ({}). Unable to unpack "
"'{}' to '{}'"),
humanize::file_size(tmp_space.available),
humanize::file_size(cfg.amc_min_free_space),
entry_path.filename().string(),
@ -244,12 +252,11 @@ copy_data(const std::string& filename,
}
}
static walk_result_t extract(const std::string &filename, const extract_cb &cb)
static walk_result_t
extract(const std::string& filename, const extract_cb& cb)
{
static int FLAGS = ARCHIVE_EXTRACT_TIME
| ARCHIVE_EXTRACT_PERM
| ARCHIVE_EXTRACT_ACL
| ARCHIVE_EXTRACT_FFLAGS;
static int FLAGS = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM
| ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;
auto tmp_path = filename_to_tmp_path(filename);
auto arc_lock = archive_lock(tmp_path);
@ -267,9 +274,9 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
}
}
if (file_count > 0) {
fs::last_write_time(
done_path, std::chrono::system_clock::now());
log_info("%s: archive has already been extracted!", done_path.c_str());
fs::last_write_time(done_path, std::chrono::system_clock::now());
log_info("%s: archive has already been extracted!",
done_path.c_str());
return Ok();
} else {
log_warning("%s: archive cache has been damaged, re-extracting",
@ -289,17 +296,16 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, FLAGS);
archive_write_disk_set_standard_lookup(ext);
if (archive_read_open_filename(arc, filename.c_str(), 10240) != ARCHIVE_OK) {
if (archive_read_open_filename(arc, filename.c_str(), 10240) != ARCHIVE_OK)
{
return Err(fmt::format("unable to open archive: {} -- {}",
filename,
archive_error_string(arc)));
}
log_info("extracting %s to %s",
filename.c_str(),
tmp_path.c_str());
log_info("extracting %s to %s", filename.c_str(), tmp_path.c_str());
while (true) {
struct archive_entry *entry;
struct archive_entry* entry;
auto r = archive_read_next_header(arc, &entry);
if (r == ARCHIVE_EOF) {
log_info("all done");
@ -321,22 +327,21 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
desired_pathname = fs::path(filename).filename();
}
auto entry_path = tmp_path / desired_pathname;
auto prog = cb(entry_path,
archive_entry_size_is_set(entry) ?
archive_entry_size(entry) : -1);
auto prog = cb(
entry_path,
archive_entry_size_is_set(entry) ? archive_entry_size(entry) : -1);
archive_entry_copy_pathname(wentry, entry_path.c_str());
auto entry_mode = archive_entry_mode(wentry);
archive_entry_set_perm(
wentry, S_IRUSR | (S_ISDIR(entry_mode) ? S_IXUSR|S_IWUSR : 0));
wentry, S_IRUSR | (S_ISDIR(entry_mode) ? S_IXUSR | S_IWUSR : 0));
r = archive_write_header(ext, wentry);
if (r < ARCHIVE_OK) {
return Err(fmt::format("unable to write entry: {} -- {}",
entry_path.string(),
archive_error_string(ext)));
}
else if (!archive_entry_size_is_set(entry) ||
archive_entry_size(entry) > 0) {
} else if (!archive_entry_size_is_set(entry)
|| archive_entry_size(entry) > 0) {
TRY(copy_data(filename, arc, entry, ext, entry_path, prog));
}
r = archive_write_finish_entry(ext);
@ -355,12 +360,12 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
}
#endif
walk_result_t walk_archive_files(
const std::string &filename,
const extract_cb &cb,
const std::function<void(
const fs::path&,
const fs::directory_entry &)>& callback)
walk_result_t
walk_archive_files(
const std::string& filename,
const extract_cb& cb,
const std::function<void(const fs::path&, const fs::directory_entry&)>&
callback)
{
#if HAVE_ARCHIVE_H
auto tmp_path = filename_to_tmp_path(filename);
@ -385,7 +390,8 @@ walk_result_t walk_archive_files(
#endif
}
void cleanup_cache()
void
cleanup_cache()
{
(void) std::async(std::launch::async, []() {
auto now = std::chrono::system_clock::now();
@ -421,4 +427,4 @@ void cleanup_cache()
});
}
}
} // namespace archive_manager

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -41,6 +41,6 @@ struct config {
std::chrono::seconds amc_cache_ttl{std::chrono::hours(48)};
};
}
} // namespace archive_manager
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -33,8 +33,8 @@
#define lnav_archive_manager_hh
#include <atomic>
#include <string>
#include <functional>
#include <string>
#include <utility>
#include "base/result.h"
@ -43,34 +43,33 @@
namespace archive_manager {
struct extract_progress {
extract_progress(ghc::filesystem::path path,
ssize_t total) : ep_path(std::move(path)),
ep_total_size(total)
{}
extract_progress(ghc::filesystem::path path, ssize_t total)
: ep_path(std::move(path)), ep_total_size(total)
{
}
const ghc::filesystem::path ep_path;
const ssize_t ep_total_size;
std::atomic<size_t> ep_out_size{0};
};
using extract_cb = std::function<extract_progress *(
const ghc::filesystem::path &, ssize_t)>;
using extract_cb
= std::function<extract_progress*(const ghc::filesystem::path&, ssize_t)>;
bool is_archive(const ghc::filesystem::path& filename);
ghc::filesystem::path filename_to_tmp_path(const std::string &filename);
ghc::filesystem::path filename_to_tmp_path(const std::string& filename);
using walk_result_t = Result<void, std::string>;
walk_result_t walk_archive_files(
const std::string &filename,
const extract_cb &cb,
const std::function<void(
const ghc::filesystem::path &,
const ghc::filesystem::directory_entry &)> &);
const std::string& filename,
const extract_cb& cb,
const std::function<void(const ghc::filesystem::path&,
const ghc::filesystem::directory_entry&)>&);
void cleanup_cache();
}
} // namespace archive_manager
#endif

@ -21,22 +21,23 @@
* 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
* 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 <algorithm>
#include "auto_mem.hh"
#include "attr_line.hh"
#include "ansi_scrubber.hh"
#include "auto_mem.hh"
#include "config.h"
#include "view_curses.hh"
#include "attr_line.hh"
attr_line_t &attr_line_t::with_ansi_string(const char *str, ...)
attr_line_t&
attr_line_t::with_ansi_string(const char* str, ...)
{
auto_mem<char> formatted_str;
va_list args;
@ -53,7 +54,8 @@ attr_line_t &attr_line_t::with_ansi_string(const char *str, ...)
return *this;
}
attr_line_t &attr_line_t::with_ansi_string(const std::string &str)
attr_line_t&
attr_line_t::with_ansi_string(const std::string& str)
{
this->al_string = str;
scrub_ansi_string(this->al_string, this->al_attrs);
@ -61,7 +63,10 @@ attr_line_t &attr_line_t::with_ansi_string(const std::string &str)
return *this;
}
attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_settings *tws)
attr_line_t&
attr_line_t::insert(size_t index,
const attr_line_t& al,
text_wrap_settings* tws)
{
if (index < this->al_string.length()) {
shift_string_attrs(this->al_attrs, index, al.al_string.length());
@ -69,10 +74,10 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
this->al_string.insert(index, al.al_string);
for (auto &sa : al.al_attrs) {
for (auto& sa : al.al_attrs) {
this->al_attrs.emplace_back(sa);
line_range &lr = this->al_attrs.back().sa_range;
line_range& lr = this->al_attrs.back().sa_range;
lr.shift(0, index);
if (lr.lr_end == -1) {
@ -80,7 +85,7 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
}
}
if (tws != nullptr && (int)this->al_string.length() > tws->tws_width) {
if (tws != nullptr && (int) this->al_string.length() > tws->tws_width) {
ssize_t start_pos = index;
ssize_t line_start = this->al_string.rfind('\n', start_pos);
@ -92,26 +97,27 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
ssize_t line_len = index - line_start;
ssize_t usable_width = tws->tws_width - tws->tws_indent;
ssize_t avail = std::max((ssize_t) 0, (ssize_t) tws->tws_width - line_len);
ssize_t avail
= std::max((ssize_t) 0, (ssize_t) tws->tws_width - line_len);
if (avail == 0) {
avail = INT_MAX;
}
while (start_pos < (int)this->al_string.length()) {
while (start_pos < (int) this->al_string.length()) {
ssize_t lpc;
// Find the end of a word or a breakpoint.
for (lpc = start_pos;
lpc < (int)this->al_string.length() &&
(isalnum(this->al_string[lpc]) ||
this->al_string[lpc] == ',' ||
this->al_string[lpc] == '_' ||
this->al_string[lpc] == '.' ||
this->al_string[lpc] == ';');
lpc++) {
if (this->al_string[lpc] == '-' ||
this->al_string[lpc] == '.') {
for (lpc = start_pos; lpc < (int) this->al_string.length()
&& (isalnum(this->al_string[lpc])
|| this->al_string[lpc] == ','
|| this->al_string[lpc] == '_'
|| this->al_string[lpc] == '.'
|| this->al_string[lpc] == ';');
lpc++)
{
if (this->al_string[lpc] == '-' || this->al_string[lpc] == '.')
{
lpc += 1;
break;
}
@ -126,15 +132,15 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
} else {
// There's still room to add stuff.
avail -= (lpc - start_pos);
while (lpc < (int)this->al_string.length() && avail) {
while (lpc < (int) this->al_string.length() && avail) {
if (this->al_string[lpc] == '\n') {
this->insert(lpc + 1, tws->tws_indent, ' ');
avail = usable_width;
lpc += 1 + tws->tws_indent;
break;
}
if (isalnum(this->al_string[lpc]) ||
this->al_string[lpc] == '_') {
if (isalnum(this->al_string[lpc])
|| this->al_string[lpc] == '_') {
break;
}
avail -= 1;
@ -147,10 +153,10 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
start_pos += 1 + tws->tws_indent;
avail = usable_width;
for (lpc = start_pos;
lpc < (int)this->al_string.length() &&
this->al_string[lpc] == ' ';
lpc++) {
for (lpc = start_pos; lpc < (int) this->al_string.length()
&& this->al_string[lpc] == ' ';
lpc++)
{
}
if (lpc != start_pos) {
@ -164,7 +170,8 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
return *this;
}
attr_line_t attr_line_t::subline(size_t start, size_t len) const
attr_line_t
attr_line_t::subline(size_t start, size_t len) const
{
if (len == std::string::npos) {
len = this->al_string.length() - start;
@ -174,16 +181,17 @@ attr_line_t attr_line_t::subline(size_t start, size_t len) const
attr_line_t retval;
retval.al_string = this->al_string.substr(start, len);
for (auto &sa : this->al_attrs) {
for (auto& sa : this->al_attrs) {
if (!lr.intersects(sa.sa_range)) {
continue;
}
retval.al_attrs.emplace_back(lr.intersection(sa.sa_range)
.shift(lr.lr_start, -lr.lr_start),
sa.sa_type, sa.sa_value);
retval.al_attrs.emplace_back(
lr.intersection(sa.sa_range).shift(lr.lr_start, -lr.lr_start),
sa.sa_type,
sa.sa_value);
line_range &last_lr = retval.al_attrs.back().sa_range;
line_range& last_lr = retval.al_attrs.back().sa_range;
ensure(last_lr.lr_end <= (int) retval.al_string.length());
}
@ -191,7 +199,8 @@ attr_line_t attr_line_t::subline(size_t start, size_t len) const
return retval;
}
void attr_line_t::split_lines(std::vector<attr_line_t> &lines) const
void
attr_line_t::split_lines(std::vector<attr_line_t>& lines) const
{
size_t pos = 0, next_line;
@ -202,12 +211,13 @@ void attr_line_t::split_lines(std::vector<attr_line_t> &lines) const
lines.emplace_back(this->subline(pos));
}
attr_line_t &attr_line_t::right_justify(unsigned long width)
attr_line_t&
attr_line_t::right_justify(unsigned long width)
{
long padding = width - this->length();
if (padding > 0) {
this->al_string.insert(0, padding, ' ');
for (auto &al_attr : this->al_attrs) {
for (auto& al_attr : this->al_attrs) {
if (al_attr.sa_range.lr_start > 0) {
al_attr.sa_range.lr_start += padding;
}
@ -220,7 +230,8 @@ attr_line_t &attr_line_t::right_justify(unsigned long width)
return *this;
}
size_t attr_line_t::nearest_text(size_t x) const
size_t
attr_line_t::nearest_text(size_t x) const
{
if (x > 0 && x >= (size_t) this->length()) {
if (this->empty()) {
@ -237,18 +248,18 @@ size_t attr_line_t::nearest_text(size_t x) const
return x;
}
void attr_line_t::apply_hide()
void
attr_line_t::apply_hide()
{
auto& sa = this->al_attrs;
for (auto &sattr : sa) {
if (sattr.sa_type == &SA_HIDDEN &&
sattr.sa_range.length() > 3) {
struct line_range &lr = sattr.sa_range;
for (auto& sattr : sa) {
if (sattr.sa_type == &SA_HIDDEN && sattr.sa_range.length() > 3) {
struct line_range& lr = sattr.sa_range;
std::for_each(sa.begin(), sa.end(), [&] (string_attr &attr) {
if (attr.sa_type == &view_curses::VC_STYLE &&
lr.contains(attr.sa_range)) {
std::for_each(sa.begin(), sa.end(), [&](string_attr& attr) {
if (attr.sa_type == &view_curses::VC_STYLE
&& lr.contains(attr.sa_range)) {
attr.sa_type = &SA_REMOVED;
}
});
@ -258,7 +269,6 @@ void attr_line_t::apply_hide()
sattr.sa_type = &view_curses::VC_ROLE;
sattr.sa_value.sav_int = view_colors::VCR_HIDDEN;
lr.lr_end = lr.lr_start + 3;
}
}
}

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,14 +32,14 @@
#ifndef attr_line_hh
#define attr_line_hh
#include <limits.h>
#include <string>
#include <vector>
#include <limits.h>
#include "base/intern_string.hh"
#include "base/lnav_log.hh"
#include "base/string_util.hh"
#include "base/intern_string.hh"
#include "string_attr_type.hh"
/**
@ -49,9 +49,11 @@ struct line_range {
int lr_start;
int lr_end;
explicit line_range(int start = -1, int end = -1) : lr_start(start), lr_end(end) { };
explicit line_range(int start = -1, int end = -1)
: lr_start(start), lr_end(end){};
bool is_valid() const {
bool is_valid() const
{
return this->lr_start != -1;
}
@ -60,19 +62,23 @@ struct line_range {
return this->lr_end == -1 ? INT_MAX : this->lr_end - this->lr_start;
};
bool contains(int pos) const {
bool contains(int pos) const
{
return this->lr_start <= pos && pos < this->lr_end;
};
bool contains(const struct line_range &other) const {
bool contains(const struct line_range& other) const
{
return this->contains(other.lr_start) && other.lr_end <= this->lr_end;
};
bool intersects(const struct line_range &other) const {
bool intersects(const struct line_range& other) const
{
return this->contains(other.lr_start) || this->contains(other.lr_end);
};
line_range intersection(const struct line_range &other) const {
line_range intersection(const struct line_range& other) const
{
int actual_end;
if (this->lr_end == -1) {
@ -85,7 +91,8 @@ struct line_range {
return line_range{std::max(this->lr_start, other.lr_start), actual_end};
};
line_range &shift(int32_t start, int32_t amount) {
line_range& shift(int32_t start, int32_t amount)
{
if (this->lr_start >= start) {
this->lr_start = std::max(0, this->lr_start + amount);
}
@ -99,35 +106,46 @@ struct line_range {
return *this;
};
void ltrim(const char *str) {
void ltrim(const char* str)
{
while (this->lr_start < this->lr_end && isspace(str[this->lr_start])) {
this->lr_start += 1;
}
};
bool operator<(const struct line_range &rhs) const
bool operator<(const struct line_range& rhs) const
{
if (this->lr_start < rhs.lr_start) { return true; }
else if (this->lr_start > rhs.lr_start) { return false; }
if (this->lr_start < rhs.lr_start) {
return true;
} else if (this->lr_start > rhs.lr_start) {
return false;
}
if (this->lr_end == rhs.lr_end) { return false; }
if (this->lr_end == rhs.lr_end) {
return false;
}
if (this->lr_end < rhs.lr_end) { return true; }
if (this->lr_end < rhs.lr_end) {
return true;
}
return false;
};
bool operator==(const struct line_range &rhs) const {
bool operator==(const struct line_range& rhs) const
{
return (this->lr_start == rhs.lr_start && this->lr_end == rhs.lr_end);
};
const char *substr(const std::string &str) const {
const char* substr(const std::string& str) const
{
if (this->lr_start == -1) {
return str.c_str();
}
return &(str.c_str()[this->lr_start]);
}
size_t sublen(const std::string &str) const {
size_t sublen(const std::string& str) const
{
if (this->lr_start == -1) {
return str.length();
}
@ -142,53 +160,67 @@ struct line_range {
* Container for attribute values for a substring.
*/
typedef union {
const void *sav_ptr;
const void* sav_ptr;
int64_t sav_int;
} string_attr_value_t;
struct string_attr {
string_attr(const struct line_range &lr, string_attr_type_t type, void *val)
: sa_range(lr), sa_type(type) {
string_attr(const struct line_range& lr, string_attr_type_t type, void* val)
: sa_range(lr), sa_type(type)
{
require(lr.is_valid());
require(type);
this->sa_value.sav_ptr = val;
};
string_attr(const struct line_range &lr, string_attr_type_t type, std::string val)
: sa_range(lr), sa_type(type), sa_str_value(std::move(val)) {
string_attr(const struct line_range& lr,
string_attr_type_t type,
std::string val)
: sa_range(lr), sa_type(type), sa_str_value(std::move(val))
{
require(lr.is_valid());
require(type);
};
string_attr(const struct line_range &lr, string_attr_type_t type, intern_string_t val)
: sa_range(lr), sa_type(type) {
string_attr(const struct line_range& lr,
string_attr_type_t type,
intern_string_t val)
: sa_range(lr), sa_type(type)
{
require(lr.is_valid());
require(type);
this->sa_value.sav_ptr = val.unwrap();
};
string_attr(const struct line_range &lr, string_attr_type_t type, int64_t val = 0)
: sa_range(lr), sa_type(type) {
string_attr(const struct line_range& lr,
string_attr_type_t type,
int64_t val = 0)
: sa_range(lr), sa_type(type)
{
require(lr.is_valid());
require(type);
this->sa_value.sav_int = val;
};
string_attr(const struct line_range &lr, string_attr_type_t type, string_attr_value_t val)
: sa_range(lr), sa_type(type), sa_value(val) {
string_attr(const struct line_range& lr,
string_attr_type_t type,
string_attr_value_t val)
: sa_range(lr), sa_type(type), sa_value(val)
{
require(lr.is_valid());
require(type);
};
string_attr() : sa_type(nullptr) { };
string_attr() : sa_type(nullptr){};
bool operator<(const struct string_attr &rhs) const
bool operator<(const struct string_attr& rhs) const
{
return this->sa_range < rhs.sa_range;
};
intern_string_t to_string() const {
return intern_string_t((const intern_string *) this->sa_value.sav_ptr);
intern_string_t to_string() const
{
return intern_string_t((const intern_string*) this->sa_value.sav_ptr);
};
struct line_range sa_range;
@ -201,7 +233,9 @@ struct string_attr {
typedef std::vector<string_attr> string_attrs_t;
inline string_attrs_t::const_iterator
find_string_attr(const string_attrs_t &sa, string_attr_type_t type, int start = 0)
find_string_attr(const string_attrs_t& sa,
string_attr_type_t type,
int start = 0)
{
string_attrs_t::const_iterator iter;
@ -215,7 +249,9 @@ find_string_attr(const string_attrs_t &sa, string_attr_type_t type, int start =
}
inline nonstd::optional<const string_attr*>
get_string_attr(const string_attrs_t &sa, string_attr_type_t type, int start = 0)
get_string_attr(const string_attrs_t& sa,
string_attr_type_t type,
int start = 0)
{
auto iter = find_string_attr(sa, type, start);
@ -228,7 +264,9 @@ get_string_attr(const string_attrs_t &sa, string_attr_type_t type, int start = 0
template<typename T>
inline string_attrs_t::const_iterator
find_string_attr_containing(const string_attrs_t &sa, string_attr_type_t type, T x)
find_string_attr_containing(const string_attrs_t& sa,
string_attr_type_t type,
T x)
{
string_attrs_t::const_iterator iter;
@ -242,7 +280,7 @@ find_string_attr_containing(const string_attrs_t &sa, string_attr_type_t type, T
}
inline string_attrs_t::iterator
find_string_attr(string_attrs_t &sa, const struct line_range &lr)
find_string_attr(string_attrs_t& sa, const struct line_range& lr)
{
string_attrs_t::iterator iter;
@ -256,13 +294,13 @@ find_string_attr(string_attrs_t &sa, const struct line_range &lr)
}
inline string_attrs_t::const_iterator
find_string_attr(const string_attrs_t &sa, size_t near)
find_string_attr(const string_attrs_t& sa, size_t near)
{
string_attrs_t::const_iterator iter, nearest = sa.end();
ssize_t last_diff = INT_MAX;
for (iter = sa.begin(); iter != sa.end(); ++iter) {
auto &lr = iter->sa_range;
auto& lr = iter->sa_range;
if (!lr.is_valid() || !lr.contains(near)) {
continue;
@ -280,13 +318,13 @@ find_string_attr(const string_attrs_t &sa, size_t near)
template<typename T>
inline string_attrs_t::const_iterator
rfind_string_attr_if(const string_attrs_t &sa, ssize_t near, T predicate)
rfind_string_attr_if(const string_attrs_t& sa, ssize_t near, T predicate)
{
string_attrs_t::const_iterator iter, nearest = sa.end();
ssize_t last_diff = INT_MAX;
for (iter = sa.begin(); iter != sa.end(); ++iter) {
auto &lr = iter->sa_range;
auto& lr = iter->sa_range;
if (lr.lr_start > near) {
continue;
@ -307,7 +345,7 @@ rfind_string_attr_if(const string_attrs_t &sa, ssize_t near, T predicate)
}
inline struct line_range
find_string_attr_range(const string_attrs_t &sa, string_attr_type_t type)
find_string_attr_range(const string_attrs_t& sa, string_attr_type_t type)
{
auto iter = find_string_attr(sa, type);
@ -318,7 +356,8 @@ find_string_attr_range(const string_attrs_t &sa, string_attr_type_t type)
return line_range();
}
inline void remove_string_attr(string_attrs_t &sa, const struct line_range &lr)
inline void
remove_string_attr(string_attrs_t& sa, const struct line_range& lr)
{
string_attrs_t::iterator iter;
@ -327,7 +366,8 @@ inline void remove_string_attr(string_attrs_t &sa, const struct line_range &lr)
}
}
inline void remove_string_attr(string_attrs_t &sa, string_attr_type_t type)
inline void
remove_string_attr(string_attrs_t& sa, string_attr_type_t type)
{
for (auto iter = sa.begin(); iter != sa.end();) {
if (iter->sa_type == type) {
@ -338,22 +378,25 @@ inline void remove_string_attr(string_attrs_t &sa, string_attr_type_t type)
}
}
inline void shift_string_attrs(string_attrs_t &sa, int32_t start, int32_t amount)
inline void
shift_string_attrs(string_attrs_t& sa, int32_t start, int32_t amount)
{
for (auto &iter : sa) {
for (auto& iter : sa) {
iter.sa_range.shift(start, amount);
}
}
struct text_wrap_settings {
text_wrap_settings() : tws_indent(2), tws_width(80) {};
text_wrap_settings() : tws_indent(2), tws_width(80){};
text_wrap_settings &with_indent(int indent) {
text_wrap_settings& with_indent(int indent)
{
this->tws_indent = indent;
return *this;
};
text_wrap_settings &with_width(int width) {
text_wrap_settings& with_width(int width)
{
this->tws_width = width;
return *this;
};
@ -367,62 +410,80 @@ struct text_wrap_settings {
*/
class attr_line_t {
public:
attr_line_t() {
attr_line_t()
{
this->al_attrs.reserve(RESERVE_SIZE);
};
attr_line_t(std::string str) : al_string(std::move(str)) {
attr_line_t(std::string str) : al_string(std::move(str))
{
this->al_attrs.reserve(RESERVE_SIZE);
};
attr_line_t(const char *str) : al_string(str) {
attr_line_t(const char* str) : al_string(str)
{
this->al_attrs.reserve(RESERVE_SIZE);
};
static inline attr_line_t from_ansi_str(const char *str) {
static inline attr_line_t from_ansi_str(const char* str)
{
attr_line_t retval;
return retval.with_ansi_string("%s", str);
};
/** @return The string itself. */
std::string &get_string() { return this->al_string; };
std::string& get_string()
{
return this->al_string;
};
const std::string &get_string() const { return this->al_string; };
const std::string& get_string() const
{
return this->al_string;
};
/** @return The attributes for the string. */
string_attrs_t &get_attrs() { return this->al_attrs; };
string_attrs_t& get_attrs()
{
return this->al_attrs;
};
const string_attrs_t &get_attrs() const { return this->al_attrs; };
const string_attrs_t& get_attrs() const
{
return this->al_attrs;
};
attr_line_t &with_string(const std::string &str) {
attr_line_t& with_string(const std::string& str)
{
this->al_string = str;
return *this;
}
attr_line_t &with_ansi_string(const char *str, ...);
attr_line_t& with_ansi_string(const char* str, ...);
attr_line_t &with_ansi_string(const std::string &str);
attr_line_t& with_ansi_string(const std::string& str);
attr_line_t &with_attr(const string_attr &sa) {
attr_line_t& with_attr(const string_attr& sa)
{
this->al_attrs.push_back(sa);
return *this;
};
attr_line_t &ensure_space() {
if (!this->al_string.empty() &&
this->al_string.back() != ' ' &&
this->al_string.back() != '[') {
attr_line_t& ensure_space()
{
if (!this->al_string.empty() && this->al_string.back() != ' '
&& this->al_string.back() != '[')
{
this->append(1, ' ');
}
return *this;
};
template<typename S, typename T = void *>
attr_line_t &append(S str,
string_attr_type_t type = nullptr,
T val = T()) {
template<typename S, typename T = void*>
attr_line_t& append(S str, string_attr_type_t type = nullptr, T val = T())
{
size_t start_len = this->al_string.length();
this->al_string.append(str);
@ -434,24 +495,31 @@ public:
return *this;
};
attr_line_t &append(const char *str, size_t len) {
attr_line_t& append(const char* str, size_t len)
{
this->al_string.append(str, len);
return *this;
};
attr_line_t &insert(size_t index, const attr_line_t &al, text_wrap_settings *tws = nullptr);
attr_line_t& insert(size_t index,
const attr_line_t& al,
text_wrap_settings* tws = nullptr);
attr_line_t &append(const attr_line_t &al, text_wrap_settings *tws = nullptr) {
attr_line_t& append(const attr_line_t& al,
text_wrap_settings* tws = nullptr)
{
return this->insert(this->al_string.length(), al, tws);
};
attr_line_t &append(size_t len, char c) {
attr_line_t& append(size_t len, char c)
{
this->al_string.append(len, c);
return *this;
};
attr_line_t &insert(size_t index, size_t len, char c) {
attr_line_t& insert(size_t index, size_t len, char c)
{
this->al_string.insert(index, len, c);
shift_string_attrs(this->al_attrs, index, len);
@ -459,7 +527,8 @@ public:
return *this;
}
attr_line_t &insert(size_t index, const char *str) {
attr_line_t& insert(size_t index, const char* str)
{
this->al_string.insert(index, str);
shift_string_attrs(this->al_attrs, index, strlen(str));
@ -467,7 +536,8 @@ public:
return *this;
}
attr_line_t &erase(size_t pos, size_t len = std::string::npos) {
attr_line_t& erase(size_t pos, size_t len = std::string::npos)
{
this->al_string.erase(pos, len);
shift_string_attrs(this->al_attrs, pos, -((int32_t) len));
@ -475,19 +545,21 @@ public:
return *this;
};
attr_line_t &erase_utf8_chars(size_t start) {
attr_line_t& erase_utf8_chars(size_t start)
{
auto byte_index = utf8_char_to_byte_index(this->al_string, start);
this->erase(byte_index);
return *this;
};
attr_line_t &right_justify(unsigned long width);
attr_line_t& right_justify(unsigned long width);
ssize_t length() const {
ssize_t length() const
{
size_t retval = this->al_string.length();
for (const auto &al_attr : this->al_attrs) {
for (const auto& al_attr : this->al_attrs) {
retval = std::max(retval, (size_t) al_attr.sa_range.lr_start);
if (al_attr.sa_range.lr_end != -1) {
retval = std::max(retval, (size_t) al_attr.sa_range.lr_end);
@ -497,14 +569,16 @@ public:
return retval;
};
std::string get_substring(const line_range &lr) const {
std::string get_substring(const line_range& lr) const
{
if (!lr.is_valid()) {
return "";
}
return this->al_string.substr(lr.lr_start, lr.length());
};
string_attrs_t::const_iterator find_attr(size_t near) const {
string_attrs_t::const_iterator find_attr(size_t near) const
{
near = std::min(near, this->al_string.length() - 1);
while (near > 0 && isspace(this->al_string[near])) {
@ -514,12 +588,13 @@ public:
return find_string_attr(this->al_attrs, near);
};
bool empty() const {
bool empty() const
{
return this->length() == 0;
};
/** Clear the string and the attributes for the string. */
attr_line_t &clear()
attr_line_t& clear()
{
this->al_string.clear();
this->al_attrs.clear();
@ -529,7 +604,7 @@ public:
attr_line_t subline(size_t start, size_t len = std::string::npos) const;
void split_lines(std::vector<attr_line_t> &lines) const;
void split_lines(std::vector<attr_line_t>& lines) const;
size_t nearest_text(size_t x) const;
@ -538,7 +613,7 @@ public:
private:
const static size_t RESERVE_SIZE = 128;
std::string al_string;
std::string al_string;
string_attrs_t al_attrs;
};

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,14 +32,14 @@
#ifndef auto_fd_hh
#define auto_fd_hh
#include <exception>
#include <new>
#include <string>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <new>
#include <string>
#include <exception>
#include <unistd.h>
#include "base/lnav_log.hh"
#include "base/result.h"
@ -51,7 +51,6 @@
*/
class auto_fd {
public:
/**
* Wrapper for the posix pipe(2) function that stores the file descriptor
* results in an auto_fd array.
@ -60,7 +59,7 @@ public:
* contains the reader end of the pipe and the second contains the writer.
* @return The result of the pipe(2) function.
*/
static int pipe(auto_fd *af)
static int pipe(auto_fd* af)
{
int retval, fd[2];
@ -80,7 +79,8 @@ public:
* @param fd The file descriptor to duplicate.
* @return A new auto_fd that contains the duplicated file descriptor.
*/
static auto_fd dup_of(int fd) {
static auto_fd dup_of(int fd)
{
if (fd == -1) {
return auto_fd{};
}
@ -99,8 +99,7 @@ public:
*
* @param fd The file descriptor to be managed.
*/
explicit auto_fd(int fd = -1)
: af_fd(fd)
explicit auto_fd(int fd = -1) : af_fd(fd)
{
require(fd >= -1);
};
@ -112,9 +111,7 @@ public:
*
* @param af The source of the file descriptor.
*/
auto_fd(auto_fd && af) noexcept
: af_fd(af.release()) {
};
auto_fd(auto_fd&& af) noexcept : af_fd(af.release()){};
/**
* Const copy constructor. The file descriptor from the source will be
@ -122,8 +119,7 @@ public:
*
* @param af The source of the file descriptor.
*/
auto_fd(const auto_fd &af)
: af_fd(-1)
auto_fd(const auto_fd& af) : af_fd(-1)
{
if (af.af_fd != -1 && (this->af_fd = dup(af.af_fd)) == -1) {
throw std::bad_alloc();
@ -139,7 +135,10 @@ public:
};
/** @return The file descriptor as a plain integer. */
operator int() const { return this->af_fd; };
operator int() const
{
return this->af_fd;
};
/**
* Replace the current descriptor with the given one. The current
@ -148,7 +147,7 @@ public:
* @param fd The file descriptor to store in this object.
* @return *this
*/
auto_fd &operator=(int fd)
auto_fd& operator=(int fd)
{
require(fd >= -1);
@ -162,7 +161,8 @@ public:
* @param af The old manager of the file descriptor.
* @return *this
*/
auto_fd &operator=(auto_fd && af) noexcept {
auto_fd& operator=(auto_fd&& af) noexcept
{
this->reset(af.release());
return *this;
};
@ -173,7 +173,7 @@ public:
*
* @return A pointer to the internal integer.
*/
int *out()
int* out()
{
this->reset();
return &this->af_fd;
@ -218,7 +218,8 @@ public:
}
};
void close_on_exec() const {
void close_on_exec() const
{
if (this->af_fd == -1) {
return;
}
@ -226,12 +227,13 @@ public:
}
private:
int af_fd; /*< The managed file descriptor. */
int af_fd; /*< The managed file descriptor. */
};
class auto_pipe {
public:
static Result<auto_pipe, std::string> for_child_fd(int child_fd) {
static Result<auto_pipe, std::string> for_child_fd(int child_fd)
{
auto_pipe retval(child_fd);
if (retval.open() == -1) {
@ -245,70 +247,73 @@ public:
: ap_child_flags(child_flags), ap_child_fd(child_fd)
{
switch (child_fd) {
case STDIN_FILENO:
this->ap_child_flags = O_RDONLY;
break;
case STDOUT_FILENO:
case STDERR_FILENO:
this->ap_child_flags = O_WRONLY;
break;
case STDIN_FILENO:
this->ap_child_flags = O_RDONLY;
break;
case STDOUT_FILENO:
case STDERR_FILENO:
this->ap_child_flags = O_WRONLY;
break;
}
};
int open() {
int open()
{
return auto_fd::pipe(this->ap_fd);
};
void close() {
void close()
{
this->ap_fd[0].reset();
this->ap_fd[1].reset();
};
auto_fd &read_end() {
auto_fd& read_end()
{
return this->ap_fd[0];
};
auto_fd &write_end() {
auto_fd& write_end()
{
return this->ap_fd[1];
};
void after_fork(pid_t child_pid) {
void after_fork(pid_t child_pid)
{
int new_fd;
switch (child_pid) {
case -1:
this->close();
break;
case 0:
if (this->ap_child_flags == O_RDONLY) {
this->write_end().reset();
if (this->read_end().get() == -1) {
this->read_end() = ::open("/dev/null", O_RDONLY);
case -1:
this->close();
break;
case 0:
if (this->ap_child_flags == O_RDONLY) {
this->write_end().reset();
if (this->read_end().get() == -1) {
this->read_end() = ::open("/dev/null", O_RDONLY);
}
new_fd = this->read_end().get();
} else {
this->read_end().reset();
if (this->write_end().get() == -1) {
this->write_end() = ::open("/dev/null", O_WRONLY);
}
new_fd = this->write_end().get();
}
new_fd = this->read_end().get();
}
else {
this->read_end().reset();
if (this->write_end().get() == -1) {
this->write_end() = ::open("/dev/null", O_WRONLY);
if (this->ap_child_fd != -1) {
if (new_fd != this->ap_child_fd) {
dup2(new_fd, this->ap_child_fd);
this->close();
}
}
new_fd = this->write_end().get();
}
if (this->ap_child_fd != -1) {
if (new_fd != this->ap_child_fd) {
dup2(new_fd, this->ap_child_fd);
this->close();
break;
default:
if (this->ap_child_flags == O_RDONLY) {
this->read_end().reset();
} else {
this->write_end().reset();
}
}
break;
default:
if (this->ap_child_flags == O_RDONLY) {
this->read_end().reset();
}
else {
this->write_end().reset();
}
break;
break;
}
};

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,15 +32,15 @@
#ifndef lnav_auto_mem_hh
#define lnav_auto_mem_hh
#include <exception>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <exception>
#include "base/result.h"
typedef void (*free_func_t)(void *);
typedef void (*free_func_t)(void*);
/**
* Resource management class for memory allocated by a custom allocator.
@ -51,126 +51,149 @@ typedef void (*free_func_t)(void *);
template<class T, free_func_t default_free = free>
class auto_mem {
public:
explicit auto_mem(T *ptr = nullptr)
: am_ptr(ptr), am_free_func(default_free) {
};
explicit auto_mem(T* ptr = nullptr)
: am_ptr(ptr), am_free_func(default_free){};
auto_mem(const auto_mem &am) = delete;
auto_mem(const auto_mem& am) = delete;
template<typename F>
explicit auto_mem(F free_func) noexcept
: am_ptr(nullptr), am_free_func((free_func_t)free_func) { };
: am_ptr(nullptr), am_free_func((free_func_t) free_func){};
auto_mem(auto_mem &&other) noexcept
: am_ptr(other.release()),
am_free_func(other.am_free_func) {
};
auto_mem(auto_mem&& other) noexcept
: am_ptr(other.release()), am_free_func(other.am_free_func){};
~auto_mem() {
~auto_mem()
{
this->reset();
};
operator T *() const { return this->am_ptr; };
operator T*() const
{
return this->am_ptr;
};
auto_mem &operator =(T *ptr)
auto_mem& operator=(T* ptr)
{
this->reset(ptr);
return *this;
};
auto_mem &operator=(auto_mem &) = delete;
auto_mem& operator=(auto_mem&) = delete;
auto_mem &operator =(auto_mem && am) noexcept
auto_mem& operator=(auto_mem&& am) noexcept
{
this->reset(am.release());
this->am_free_func = am.am_free_func;
return *this;
};
T *release()
T* release()
{
T *retval = this->am_ptr;
T* retval = this->am_ptr;
this->am_ptr = nullptr;
return retval;
};
T *in() const
T* in() const
{
return this->am_ptr;
};
T **out()
T** out()
{
this->reset();
return &this->am_ptr;
};
void reset(T *ptr = nullptr)
void reset(T* ptr = nullptr)
{
if (this->am_ptr != ptr) {
if (this->am_ptr != nullptr) {
this->am_free_func((void *)this->am_ptr);
this->am_free_func((void*) this->am_ptr);
}
this->am_ptr = ptr;
}
};
private:
T * am_ptr;
void (*am_free_func)(void *);
T* am_ptr;
void (*am_free_func)(void*);
};
template<typename T, void(*free_func) (T *)>
template<typename T, void (*free_func)(T*)>
class static_root_mem {
public:
static_root_mem() {
static_root_mem()
{
memset(&this->srm_value, 0, sizeof(T));
};
~static_root_mem() { free_func(&this->srm_value); };
~static_root_mem()
{
free_func(&this->srm_value);
};
const T *operator->() const { return &this->srm_value; };
const T* operator->() const
{
return &this->srm_value;
};
const T &in() const { return this->srm_value; };
const T& in() const
{
return this->srm_value;
};
T *inout() {
T* inout()
{
free_func(&this->srm_value);
memset(&this->srm_value, 0, sizeof(T));
return &this->srm_value;
};
private:
static_root_mem &operator =(T &) { return *this; };
static_root_mem& operator=(T&)
{
return *this;
};
static_root_mem &operator =(static_root_mem &) { return *this; };
static_root_mem& operator=(static_root_mem&)
{
return *this;
};
T srm_value;
};
class auto_buffer {
public:
static auto_buffer alloc(size_t size) {
return auto_buffer{ (char *) malloc(size), size };
static auto_buffer alloc(size_t size)
{
return auto_buffer{(char*) malloc(size), size};
}
auto_buffer(auto_buffer&& other) noexcept
: ab_buffer(other.ab_buffer), ab_size(other.ab_size) {
: ab_buffer(other.ab_buffer), ab_size(other.ab_size)
{
other.ab_buffer = nullptr;
other.ab_size = 0;
}
~auto_buffer() {
~auto_buffer()
{
free(this->ab_buffer);
this->ab_buffer = nullptr;
this->ab_size = 0;
}
char *in() {
char* in()
{
return this->ab_buffer;
}
std::pair<char *, size_t> release() {
std::pair<char*, size_t> release()
{
auto retval = std::make_pair(this->ab_buffer, this->ab_size);
this->ab_buffer = nullptr;
@ -178,16 +201,18 @@ public:
return retval;
}
size_t size() const {
size_t size() const
{
return this->ab_size;
}
void expand_by(size_t amount) {
void expand_by(size_t amount)
{
if (amount == 0) {
return;
}
auto new_size = this->ab_size + amount;
auto new_buffer = (char *) realloc(this->ab_buffer, new_size);
auto new_buffer = (char*) realloc(this->ab_buffer, new_size);
if (new_buffer == nullptr) {
throw std::bad_alloc();
@ -197,15 +222,16 @@ public:
this->ab_size = new_size;
}
auto_buffer& shrink_to(size_t new_size) {
auto_buffer& shrink_to(size_t new_size)
{
this->ab_size = new_size;
return *this;
}
private:
auto_buffer(char *buffer, size_t size) : ab_buffer(buffer), ab_size(size) {
}
auto_buffer(char* buffer, size_t size) : ab_buffer(buffer), ab_size(size) {}
char *ab_buffer;
char* ab_buffer;
size_t ab_size;
};

@ -21,23 +21,24 @@
* 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
* 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 "auto_pid.hh"
#include <unistd.h>
#include "lnav_log.hh"
#include "config.h"
#include "fmt/format.h"
#include "auto_pid.hh"
#include "lnav_log.hh"
namespace lnav {
namespace pid {
Result<auto_pid<process_state::RUNNING>, std::string> from_fork()
Result<auto_pid<process_state::running>, std::string>
from_fork()
{
auto pid = ::fork();
@ -49,7 +50,7 @@ Result<auto_pid<process_state::RUNNING>, std::string> from_fork()
log_debug("started child: %d", pid);
}
return Ok(auto_pid<process_state::RUNNING>(pid));
}
}
return Ok(auto_pid<process_state::running>(pid));
}
} // namespace pid
} // namespace lnav

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,50 +32,58 @@
#ifndef auto_pid_hh
#define auto_pid_hh
#include <errno.h>
#include <signal.h>
#include <cerrno>
#include <csignal>
#include <sys/types.h>
#include <sys/wait.h>
#include "base/result.h"
#include "base/lnav_log.hh"
#include "base/result.h"
#include "mapbox/variant.hpp"
enum class process_state {
RUNNING,
FINISHED,
running,
finished,
};
template<process_state ProcState>
class auto_pid {
public:
explicit auto_pid(pid_t child, int status = 0) : ap_child(child),
ap_status(status)
{};
explicit auto_pid(pid_t child, int status = 0)
: ap_child(child), ap_status(status)
{
}
auto_pid(const auto_pid &other) = delete;
auto_pid(const auto_pid& other) = delete;
auto_pid(auto_pid &&other) noexcept
: ap_child(std::move(other).release()),
ap_status(other.ap_status)
{};
auto_pid(auto_pid&& other) noexcept
: ap_child(std::move(other).release()), ap_status(other.ap_status)
{
}
~auto_pid() noexcept
{ this->reset(); };
{
this->reset();
}
auto_pid &operator=(auto_pid &&other) noexcept
auto_pid& operator=(auto_pid&& other) noexcept
{
this->reset(std::move(other).release());
this->ap_status = other.ap_status;
return *this;
};
}
auto_pid& operator=(const auto_pid& other) = delete;
pid_t in() const
{ return this->ap_child; }
{
return this->ap_child;
}
bool in_child() const
{
static_assert(ProcState == process_state::RUNNING,
static_assert(ProcState == process_state::running,
"this method is only available in the RUNNING state");
return this->ap_child == 0;
};
@ -87,31 +95,31 @@ public:
int status() const
{
static_assert(ProcState == process_state::FINISHED,
static_assert(ProcState == process_state::finished,
"wait_for_child() must be called first");
return this->ap_status;
};
bool was_normal_exit() const
{
static_assert(ProcState == process_state::FINISHED,
static_assert(ProcState == process_state::finished,
"wait_for_child() must be called first");
return WIFEXITED(this->ap_status);
}
int exit_status() const
{
static_assert(ProcState == process_state::FINISHED,
static_assert(ProcState == process_state::finished,
"wait_for_child() must be called first");
return WEXITSTATUS(this->ap_status);
}
using poll_result = mapbox::util::variant<
auto_pid<process_state::RUNNING>,
auto_pid<process_state::FINISHED>
>;
using poll_result
= mapbox::util::variant<auto_pid<process_state::running>,
auto_pid<process_state::finished>>;
poll_result poll() && {
poll_result poll() &&
{
if (this->ap_child != -1) {
auto rc = waitpid(this->ap_child, &this->ap_status, WNOHANG);
@ -120,20 +128,21 @@ public:
}
}
return auto_pid<process_state::FINISHED>(
return auto_pid<process_state::finished>(
std::exchange(this->ap_child, -1), this->ap_status);
}
auto_pid<process_state::FINISHED> wait_for_child(int options = 0) &&
auto_pid<process_state::finished> wait_for_child(int options = 0) &&
{
if (this->ap_child != -1) {
while ((waitpid(this->ap_child,
&this->ap_status,
options)) < 0 && (errno == EINTR)) { ;
while ((waitpid(this->ap_child, &this->ap_status, options)) < 0
&& (errno == EINTR))
{
;
}
}
return auto_pid<process_state::FINISHED>(
return auto_pid<process_state::finished>(
std::exchange(this->ap_child, -1), this->ap_status);
}
@ -141,7 +150,7 @@ public:
{
if (this->ap_child != child) {
this->ap_status = 0;
if (ProcState == process_state::RUNNING && this->ap_child != -1) {
if (ProcState == process_state::running && this->ap_child != -1) {
log_debug("sending SIGTERM to child: %d", this->ap_child);
kill(this->ap_child, SIGTERM);
}
@ -156,8 +165,8 @@ private:
namespace lnav {
namespace pid {
Result<auto_pid<process_state::RUNNING>, std::string> from_fork();
}
}
Result<auto_pid<process_state::running>, std::string> from_fork();
} // namespace pid
} // namespace lnav
#endif

@ -21,20 +21,21 @@
* 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
* 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 "config.h"
#include "ptimec.hh"
size_t date_time_scanner::ftime(char *dst, size_t len, const exttm &tm) const
size_t
date_time_scanner::ftime(char* dst, size_t len, const exttm& tm) const
{
off_t off = 0;
@ -43,7 +44,8 @@ size_t date_time_scanner::ftime(char *dst, size_t len, const exttm &tm) const
return (size_t) off;
}
bool next_format(const char * const fmt[], int &index, int &locked_index)
bool
next_format(const char* const fmt[], int& index, int& locked_index)
{
bool retval = true;
@ -52,40 +54,35 @@ bool next_format(const char * const fmt[], int &index, int &locked_index)
if (fmt[index] == nullptr) {
retval = false;
}
}
else if (index == locked_index) {
} else if (index == locked_index) {
retval = false;
}
else {
} 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)
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;
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)) {
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])) {
if (time_len > 1 && time_dest[0] == '+' && isdigit(time_dest[1])) {
char time_cp[time_len + 1];
int gmt_int, off;
@ -105,7 +102,8 @@ const char *date_time_scanner::scan(const char *time_dest,
}
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;
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;
@ -113,8 +111,7 @@ const char *date_time_scanner::scan(const char *time_dest,
found = true;
break;
}
}
else if (time_fmt == PTIMEC_FORMAT_STR) {
} else if (time_fmt == PTIMEC_FORMAT_STR) {
ptime_func func = PTIMEC_FORMATS[curr_time_fmt].pf_func;
off_t off = 0;
@ -129,8 +126,10 @@ const char *date_time_scanner::scan(const char *time_dest,
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)) {
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);
@ -140,13 +139,12 @@ const char *date_time_scanner::scan(const char *time_dest,
secs2wday(tv_out, &tm_out->et_tm);
this->dts_fmt_lock = curr_time_fmt;
this->dts_fmt_len = retval - time_dest;
this->dts_fmt_len = retval - time_dest;
found = true;
break;
}
}
else {
} else {
off_t off = 0;
#ifdef HAVE_STRUCT_TM_TM_ZONE
@ -154,14 +152,19 @@ const char *date_time_scanner::scan(const char *time_dest,
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)) {
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)) {
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);
@ -176,7 +179,7 @@ const char *date_time_scanner::scan(const char *time_dest,
secs2wday(tv_out, &tm_out->et_tm);
this->dts_fmt_lock = curr_time_fmt;
this->dts_fmt_len = retval - time_dest;
this->dts_fmt_len = retval - time_dest;
found = true;
break;
@ -197,8 +200,7 @@ const char *date_time_scanner::scan(const char *time_dest,
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)) {
} 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;
@ -209,15 +211,16 @@ const char *date_time_scanner::scan(const char *time_dest,
return retval;
}
void date_time_scanner::to_localtime(time_t t, exttm &tm_out)
void
date_time_scanner::to_localtime(time_t t, 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) {
if (t < this->dts_local_offset_valid || t >= this->dts_local_offset_expiry)
{
time_t new_gmt;
localtime_r(&t, &tm_out.et_tm);
@ -230,10 +233,9 @@ void date_time_scanner::to_localtime(time_t t, exttm &tm_out)
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 {
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);
}

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,11 +32,11 @@
#ifndef lnav_date_time_scanner_hh
#define lnav_date_time_scanner_hh
#include <time.h>
#include <sys/types.h>
#include <string>
#include <sys/types.h>
#include <time.h>
#include "time_util.hh"
/**
@ -47,11 +47,13 @@
* an exttm struct to a string using the ftime() method.
*/
struct date_time_scanner {
date_time_scanner() {
date_time_scanner()
{
this->clear();
};
void clear() {
void clear()
{
this->dts_base_time = 0;
memset(&this->dts_base_tm, 0, sizeof(this->dts_base_tm));
this->dts_fmt_lock = -1;
@ -61,12 +63,14 @@ struct date_time_scanner {
/**
* Unlock this scanner so that the format is rediscovered.
*/
void unlock() {
void unlock()
{
this->dts_fmt_lock = -1;
this->dts_fmt_len = -1;
}
void set_base_time(time_t base_time) {
void set_base_time(time_t base_time)
{
this->dts_base_time = base_time;
localtime_r(&base_time, &this->dts_base_tm.et_tm);
};
@ -78,7 +82,7 @@ struct date_time_scanner {
* 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);
void to_localtime(time_t t, struct exttm& tm_out);
bool dts_keep_base_tz{false};
bool dts_local_time{false};
@ -92,19 +96,20 @@ struct date_time_scanner {
static const int EXPIRE_TIME = 15 * 60;
const char *scan(const char *time_src,
const char* scan(const char* time_src,
size_t time_len,
const char * const time_fmt[],
struct exttm *tm_out,
struct timeval &tv_out,
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) const;
size_t ftime(char* dst, size_t len, const struct exttm& tm) const;
bool convert_to_timeval(const char *time_src,
bool convert_to_timeval(const char* time_src,
ssize_t time_len,
const char * const time_fmt[],
struct timeval &tv_out) {
const char* const time_fmt[],
struct timeval& tv_out)
{
struct exttm tm;
if (time_len == -1) {
@ -116,12 +121,13 @@ struct date_time_scanner {
return false;
};
bool convert_to_timeval(const std::string &time_src,
struct timeval &tv_out) {
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(),
nullptr, &tm, tv_out) != nullptr) {
if (this->scan(time_src.c_str(), time_src.size(), nullptr, &tm, tv_out)
!= nullptr)
{
return true;
}
return false;

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -35,13 +35,14 @@
namespace lnav {
namespace enums {
template <typename E>
constexpr auto to_underlying(E e) noexcept
template<typename E>
constexpr auto
to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
}
}
} // namespace enums
} // namespace lnav
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -43,28 +43,31 @@ public:
file_off_t fr_offset{0};
file_ssize_t fr_size{0};
void clear() {
void clear()
{
this->fr_offset = 0;
this->fr_size = 0;
}
ssize_t next_offset() const {
ssize_t next_offset() const
{
return this->fr_offset + this->fr_size;
}
bool empty() const {
bool empty() const
{
return fr_size == 0;
}
};
struct source_location {
source_location()
: sl_source(intern_string::lookup("unknown")),
sl_line_number(-1) {
: sl_source(intern_string::lookup("unknown")), sl_line_number(-1)
{
}
source_location(intern_string_t source, int line)
: sl_source(source), sl_line_number(line) {};
: sl_source(source), sl_line_number(line){};
intern_string_t sl_source;
int sl_line_number;

@ -21,23 +21,23 @@
* 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
* 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 "fs_util.hh"
#include "config.h"
#include "fmt/format.h"
#include "fs_util.hh"
#include "opt_util.hh"
namespace lnav {
namespace filesystem {
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
open_temp_file(const ghc::filesystem::path& pattern)
{
auto pattern_str = pattern.string();
char pattern_copy[pattern_str.size() + 1];
@ -46,13 +46,15 @@ open_temp_file(const ghc::filesystem::path &pattern)
strcpy(pattern_copy, pattern_str.c_str());
if ((fd = mkstemp(pattern_copy)) == -1) {
return Err(fmt::format("unable to create temporary file: {} -- {}",
pattern.string(), strerror(errno)));
pattern.string(),
strerror(errno)));
}
return Ok(std::make_pair(ghc::filesystem::path(pattern_copy), fd));
}
Result<std::string, std::string> read_file(const ghc::filesystem::path &path)
Result<std::string, std::string>
read_file(const ghc::filesystem::path& path)
{
try {
ghc::filesystem::ifstream file_stream(path);
@ -70,11 +72,12 @@ Result<std::string, std::string> read_file(const ghc::filesystem::path &path)
}
}
std::string build_path(const std::vector<ghc::filesystem::path> &paths)
std::string
build_path(const std::vector<ghc::filesystem::path>& paths)
{
std::string retval;
for (const auto &path : paths) {
for (const auto& path : paths) {
if (path.empty()) {
continue;
}
@ -90,5 +93,5 @@ std::string build_path(const std::vector<ghc::filesystem::path> &paths)
return retval;
}
}
}
} // namespace filesystem
} // namespace lnav

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -33,32 +33,38 @@
#include <string>
#include <vector>
#include "result.h"
#include "ghc/filesystem.hpp"
#include "result.h"
namespace lnav {
namespace filesystem {
inline int statp(const ghc::filesystem::path &path, struct stat *buf) {
inline int
statp(const ghc::filesystem::path& path, struct stat* buf)
{
return stat(path.c_str(), buf);
}
inline int openp(const ghc::filesystem::path &path, int flags) {
inline int
openp(const ghc::filesystem::path& path, int flags)
{
return open(path.c_str(), flags);
}
inline int openp(const ghc::filesystem::path &path, int flags, mode_t mode) {
inline int
openp(const ghc::filesystem::path& path, int flags, mode_t mode)
{
return open(path.c_str(), flags, mode);
}
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern);
Result<std::pair<ghc::filesystem::path, int>, std::string> open_temp_file(
const ghc::filesystem::path& pattern);
Result<std::string, std::string> read_file(const ghc::filesystem::path &path);
Result<std::string, std::string> read_file(const ghc::filesystem::path& path);
std::string build_path(const std::vector<ghc::filesystem::path> &paths);
std::string build_path(const std::vector<ghc::filesystem::path>& paths);
}
}
} // namespace filesystem
} // namespace lnav
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -33,12 +33,11 @@
#include <utility>
template<typename F, typename FrontArg>
decltype(auto) bind_mem(F&& f, FrontArg&& frontArg)
decltype(auto)
bind_mem(F&& f, FrontArg&& frontArg)
{
return [f=std::forward<F>(f),
frontArg = std::forward<FrontArg>(frontArg)]
(auto&&...backArgs)
{
return [f = std::forward<F>(f),
frontArg = std::forward<FrontArg>(frontArg)](auto&&... backArgs) {
return (frontArg->*f)(std::forward<decltype(backArgs)>(backArgs)...);
};
}
@ -46,13 +45,23 @@ decltype(auto) bind_mem(F&& f, FrontArg&& frontArg)
struct noop_func {
struct anything {
template<class T>
operator T(){ return {}; }
operator T()
{
return {};
}
// optional reference support. Somewhat evil.
template<class T>
operator T&()const{ static T t{}; return t; }
operator T&() const
{
static T t{};
return t;
}
};
template<class...Args>
anything operator()(Args&&...)const{return {};}
template<class... Args>
anything operator()(Args&&...) const
{
return {};
}
};
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -44,7 +44,9 @@ namespace futures {
* @return The new future.
*/
template<class T>
std::future<std::decay_t<T>> make_ready_future( T&& t ) {
std::future<std::decay_t<T>>
make_ready_future(T&& t)
{
std::promise<std::decay_t<T>> pr;
auto r = pr.get_future();
pr.set_value(std::forward<T>(t));
@ -64,9 +66,10 @@ public:
* @param processor The function to execute with the result of a future.
*/
explicit future_queue(std::function<void(T&)> processor)
: fq_processor(processor) {};
: fq_processor(processor){};
~future_queue() {
~future_queue()
{
this->pop_to();
}
@ -77,7 +80,8 @@ public:
*
* @param f The future to add to the queue.
*/
void push_back(std::future<T>&& f) {
void push_back(std::future<T>&& f)
{
this->fq_deque.emplace_back(std::move(f));
this->pop_to(MAX_QUEUE_SIZE);
}
@ -88,7 +92,8 @@ public:
*
* @param size The new desired size of the queue.
*/
void pop_to(size_t size = 0) {
void pop_to(size_t size = 0)
{
while (this->fq_deque.size() > size) {
auto v = this->fq_deque.front().get();
this->fq_processor(v);
@ -100,7 +105,7 @@ public:
std::deque<std::future<T>> fq_deque;
};
}
}
} // namespace futures
} // namespace lnav
#endif

@ -21,27 +21,34 @@
* 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
* 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 <cmath>
#include <vector>
#include "fmt/format.h"
#include "humanize.hh"
#include "config.h"
#include "fmt/format.h"
namespace humanize {
std::string file_size(file_ssize_t value)
std::string
file_size(file_ssize_t value)
{
static const double LN1024 = log(1024.0);
static const std::vector<const char *> UNITS = {
" ", "K", "M", "G", "T", "P", "E",
static const std::vector<const char*> UNITS = {
" ",
"K",
"M",
"G",
"T",
"P",
"E",
};
if (value < 0) {
@ -52,8 +59,8 @@ std::string file_size(file_ssize_t value)
return "0.0 B";
}
auto exp = floor(std::min(log(value) / LN1024,
(double) (UNITS.size() - 1)));
auto exp
= floor(std::min(log(value) / LN1024, (double) (UNITS.size() - 1)));
auto divisor = pow(1024, exp);
return fmt::format(FMT_STRING("{:.1f}{}B"),
@ -61,7 +68,8 @@ std::string file_size(file_ssize_t value)
UNITS[exp]);
}
const std::string& sparkline(double value, nonstd::optional<double> upper_opt)
const std::string&
sparkline(double value, nonstd::optional<double> upper_opt)
{
static const std::string ZERO = " ";
static const std::string BARS[] = {
@ -91,4 +99,4 @@ const std::string& sparkline(double value, nonstd::optional<double> upper_opt)
return BARS[index];
}
}
} // namespace humanize

@ -21,21 +21,21 @@
* 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
* 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 <iostream>
#include "doctest/doctest.h"
#include "base/humanize.hh"
TEST_CASE("humanize::file_size") {
#include "config.h"
#include "doctest/doctest.h"
TEST_CASE("humanize::file_size")
{
CHECK(humanize::file_size(0) == "0.0 B");
CHECK(humanize::file_size(1) == "1.0 B");
CHECK(humanize::file_size(1024) == "1.0KB");

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -48,6 +48,6 @@ std::string file_size(file_ssize_t value);
const std::string& sparkline(double value, nonstd::optional<double> upper);
}
} // namespace humanize
#endif

@ -21,22 +21,23 @@
* 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
* 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 "humanize.network.hh"
#include "config.h"
#include "pcrepp/pcrepp.hh"
namespace humanize {
namespace network {
namespace path {
nonstd::optional<::network::path> from_str(const char *str)
nonstd::optional<::network::path>
from_str(const char* str)
{
static const pcrepp REMOTE_PATTERN(
"(?:(?<username>[\\w\\._\\-]+)@)?"
@ -60,11 +61,11 @@ nonstd::optional<::network::path> from_str(const char *str)
path = ".";
}
return ::network::path{
{ username, locality_hostname, nonstd::nullopt },
{username, locality_hostname, nonstd::nullopt},
path,
};
}
}
}
}
} // namespace path
} // namespace network
} // namespace humanize

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -32,15 +32,16 @@
#include <string>
#include "optional.hpp"
#include "network.tcp.hh"
#include "fmt/format.h"
#include "network.tcp.hh"
#include "optional.hpp"
namespace fmt {
template<>
struct formatter<network::locality> {
constexpr auto parse(format_parse_context& ctx) {
constexpr auto parse(format_parse_context& ctx)
{
auto it = ctx.begin(), end = ctx.end();
// Check if reached the end of the range:
@ -51,24 +52,25 @@ struct formatter<network::locality> {
return it;
}
template <typename FormatContext>
auto format(const network::locality& l, FormatContext& ctx) {
template<typename FormatContext>
auto format(const network::locality& l, FormatContext& ctx)
{
bool is_ipv6 = l.l_hostname.find(':') != std::string::npos;
return format_to(
ctx.out(),
"{}{}{}{}{}",
l.l_username.value_or(std::string()),
l.l_username ? "@" : "",
is_ipv6 ? "[" : "",
l.l_hostname,
is_ipv6 ? "]" : "");
return format_to(ctx.out(),
"{}{}{}{}{}",
l.l_username.value_or(std::string()),
l.l_username ? "@" : "",
is_ipv6 ? "[" : "",
l.l_hostname,
is_ipv6 ? "]" : "");
}
};
template<>
struct formatter<network::path> {
constexpr auto parse(format_parse_context& ctx) {
constexpr auto parse(format_parse_context& ctx)
{
auto it = ctx.begin(), end = ctx.end();
// Check if reached the end of the range:
@ -79,32 +81,30 @@ struct formatter<network::path> {
return it;
}
template <typename FormatContext>
auto format(const network::path& p, FormatContext& ctx) {
template<typename FormatContext>
auto format(const network::path& p, FormatContext& ctx)
{
return format_to(
ctx.out(),
"{}:{}",
p.p_locality,
p.p_path == "." ? "" : p.p_path);
ctx.out(), "{}:{}", p.p_locality, p.p_path == "." ? "" : p.p_path);
}
};
}
} // namespace fmt
namespace humanize {
namespace network {
namespace path {
nonstd::optional<::network::path> from_str(const char *str);
nonstd::optional<::network::path> from_str(const char* str);
inline nonstd::optional<::network::path> from_str(const std::string &str)
inline nonstd::optional<::network::path>
from_str(const std::string& str)
{
return from_str(str.c_str());
}
}
}
}
} // namespace path
} // namespace network
} // namespace humanize
#endif

@ -21,21 +21,20 @@
* 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
* 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 <iostream>
#include "doctest/doctest.h"
#include "base/humanize.network.hh"
#include "config.h"
#include "doctest/doctest.h"
TEST_CASE("humanize::network::path") {
TEST_CASE("humanize::network::path")
{
{
auto rp_opt = humanize::network::path::from_str("foobar");
CHECK(!rp_opt);
@ -70,8 +69,8 @@ TEST_CASE("humanize::network::path") {
CHECK(!rp.p_locality.l_service.has_value());
CHECK(rp.p_path == "/var/log");
CHECK(fmt::format("{}", rp.p_locality) ==
"dean@[fe80::184f:c67:baf1:fe02%en0]");
CHECK(fmt::format("{}", rp.p_locality)
== "dean@[fe80::184f:c67:baf1:fe02%en0]");
}
{
@ -85,13 +84,13 @@ TEST_CASE("humanize::network::path") {
CHECK(!rp.p_locality.l_service.has_value());
CHECK(rp.p_path == "/var/log");
CHECK(fmt::format("{}", rp.p_locality) ==
"[fe80::184f:c67:baf1:fe02%en0]");
CHECK(fmt::format("{}", rp.p_locality)
== "[fe80::184f:c67:baf1:fe02%en0]");
}
{
auto rp_opt = humanize::network::path::from_str(
"host1.example.com:/var/log");
auto rp_opt
= humanize::network::path::from_str("host1.example.com:/var/log");
CHECK(rp_opt.has_value());
auto rp = *rp_opt;

@ -21,35 +21,37 @@
* 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
* 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 <chrono>
#include "humanize.time.hh"
#include "config.h"
#include "fmt/format.h"
#include "time_util.hh"
#include "humanize.time.hh"
namespace humanize {
namespace time {
using namespace std::chrono_literals;
point point::from_tv(const timeval &tv)
point
point::from_tv(const timeval& tv)
{
return point(tv);
}
std::string point::as_time_ago() const
std::string
point::as_time_ago() const
{
struct timeval current_time = this->p_recent_point
.value_or(current_timeval());
const char *fmt;
struct timeval current_time
= this->p_recent_point.value_or(current_timeval());
const char* fmt;
char buffer[64];
int amount;
@ -57,7 +59,8 @@ std::string point::as_time_ago() const
current_time.tv_sec = convert_log_time_to_local(current_time.tv_sec);
}
auto delta = std::chrono::seconds(current_time.tv_sec - this->p_past_point.tv_sec);
auto delta
= std::chrono::seconds(current_time.tv_sec - this->p_past_point.tv_sec);
if (delta < 0s) {
return "in the future";
} else if (delta < 1min) {
@ -66,7 +69,8 @@ std::string point::as_time_ago() const
return "one minute ago";
} else if (delta < 1h) {
fmt = "%d minutes ago";
amount = std::chrono::duration_cast<std::chrono::minutes>(delta).count();
amount
= std::chrono::duration_cast<std::chrono::minutes>(delta).count();
} else if (delta < 2h) {
return "one hour ago";
} else if (delta < 24h) {
@ -89,7 +93,8 @@ std::string point::as_time_ago() const
return std::string(buffer);
}
std::string point::as_precise_time_ago() const
std::string
point::as_precise_time_ago() const
{
struct timeval now, diff;
@ -121,31 +126,33 @@ std::string point::as_precise_time_ago() const
}
}
duration duration::from_tv(const struct timeval &tv)
duration
duration::from_tv(const struct timeval& tv)
{
return duration{tv};
}
std::string duration::to_string() const
std::string
duration::to_string() const
{
/* 24h22m33s111 */
static const struct rel_interval {
uint64_t length;
const char *format;
const char *symbol;
const char* format;
const char* symbol;
} intervals[] = {
{ 1000, "%03lld%s", "" },
{ 60, "%lld%s", "s" },
{ 60, "%lld%s", "m" },
{ 24, "%lld%s", "h" },
{ 0, "%lld%s", "d" },
{1000, "%03lld%s", ""},
{60, "%lld%s", "s"},
{60, "%lld%s", "m"},
{24, "%lld%s", "h"},
{0, "%lld%s", "d"},
};
auto *curr_interval = intervals;
auto* curr_interval = intervals;
auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::seconds(this->d_timeval.tv_sec)) +
std::chrono::microseconds(this->d_timeval.tv_usec);
std::chrono::seconds(this->d_timeval.tv_sec))
+ std::chrono::microseconds(this->d_timeval.tv_usec);
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(usecs);
std::string retval;
bool neg = false;
@ -157,8 +164,8 @@ std::string duration::to_string() const
uint64_t remaining;
if (millis >= 10min) {
remaining = std::chrono::duration_cast<std::chrono::seconds>(millis)
.count();
remaining
= std::chrono::duration_cast<std::chrono::seconds>(millis).count();
curr_interval += 1;
} else {
remaining = millis.count();
@ -171,8 +178,7 @@ std::string duration::to_string() const
if (curr_interval->length) {
amount = remaining % curr_interval->length;
remaining = remaining / curr_interval->length;
}
else {
} else {
amount = remaining;
remaining = 0;
}
@ -181,7 +187,10 @@ std::string duration::to_string() const
break;
}
snprintf(segment, sizeof(segment), curr_interval->format, amount,
snprintf(segment,
sizeof(segment),
curr_interval->format,
amount,
curr_interval->symbol);
retval.insert(0, segment);
}
@ -193,5 +202,5 @@ std::string duration::to_string() const
return retval;
}
}
}
} // namespace time
} // namespace humanize

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,10 +30,10 @@
#ifndef lnav_humanize_time_hh
#define lnav_humanize_time_hh
#include <sys/time.h>
#include <string>
#include <sys/time.h>
#include "optional.hpp"
namespace humanize {
@ -41,15 +41,15 @@ namespace time {
class point {
public:
static point from_tv(const struct timeval &tv);
static point from_tv(const struct timeval& tv);
point &with_recent_point(const struct timeval &tv)
point& with_recent_point(const struct timeval& tv)
{
this->p_recent_point = tv;
return *this;
}
point &with_convert_to_local(bool convert_to_local)
point& with_convert_to_local(bool convert_to_local)
{
this->p_convert_to_local = convert_to_local;
return *this;
@ -60,9 +60,10 @@ public:
std::string as_precise_time_ago() const;
private:
explicit point(const struct timeval &tv) : p_past_point{tv.tv_sec,
tv.tv_usec}
{}
explicit point(const struct timeval& tv)
: p_past_point{tv.tv_sec, tv.tv_usec}
{
}
struct timeval p_past_point;
nonstd::optional<struct timeval> p_recent_point;
@ -74,13 +75,14 @@ public:
static duration from_tv(const struct timeval& tv);
std::string to_string() const;
private:
explicit duration(const struct timeval& tv) : d_timeval(tv) {}
struct timeval d_timeval;
};
}
}
} // namespace time
} // namespace humanize
#endif

@ -21,18 +21,17 @@
* 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
* 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 <chrono>
#include <iostream>
#include "doctest/doctest.h"
#include "config.h"
#include "doctest/doctest.h"
#include "humanize.time.hh"
TEST_CASE("time ago")
@ -42,87 +41,82 @@ TEST_CASE("time ago")
time_t t1 = 1610000000;
auto t1_chrono = std::chrono::seconds(t1);
auto p1 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) t1 + 5, 0});
auto p1 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) t1 + 5, 0});
CHECK(p1.as_time_ago() == "just now");
CHECK(p1.as_precise_time_ago() == " 5 seconds ago");
auto p2 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) t1 + 65, 0});
auto p2 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) t1 + 65, 0});
CHECK(p2.as_time_ago() == "one minute ago");
CHECK(p2.as_precise_time_ago() == " 1 minute and 5 seconds ago");
auto p3 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) t1 + (3 * 60 + 5), 0});
auto p3 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) t1 + (3 * 60 + 5), 0});
CHECK(p3.as_time_ago() == "3 minutes ago");
CHECK(p3.as_precise_time_ago() == " 3 minutes and 5 seconds ago");
auto p4 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 65min).count(), 0});
auto p4 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 65min).count(), 0});
CHECK(p4.as_time_ago() == "one hour ago");
CHECK(p4.as_precise_time_ago() == "one hour ago");
auto p5 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 3h).count(), 0});
auto p5 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 3h).count(), 0});
CHECK(p5.as_time_ago() == "3 hours ago");
CHECK(p5.as_precise_time_ago() == "3 hours ago");
auto p6 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 25h).count(), 0});
auto p6 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 25h).count(), 0});
CHECK(p6.as_time_ago() == "one day ago");
CHECK(p6.as_precise_time_ago() == "one day ago");
auto p7 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 50h).count(), 0});
auto p7 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 50h).count(), 0});
CHECK(p7.as_time_ago() == "2 days ago");
CHECK(p7.as_precise_time_ago() == "2 days ago");
auto p8 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 370 * 24h).count(), 0});
auto p8 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 370 * 24h).count(), 0});
CHECK(p8.as_time_ago() == "over a year ago");
CHECK(p8.as_precise_time_ago() == "over a year ago");
auto p9 = humanize::time::point::from_tv({t1, 0})
.with_recent_point({(time_t) (t1_chrono + 800 * 24h).count(), 0});
auto p9 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
{(time_t) (t1_chrono + 800 * 24h).count(), 0});
CHECK(p9.as_time_ago() == "over 2 years ago");
CHECK(p9.as_precise_time_ago() == "over 2 years ago");
CHECK(humanize::time::point::from_tv({1610000000, 0})
.with_recent_point({(time_t) 1612000000, 0})
.as_time_ago() == "23 days ago");
.as_time_ago()
== "23 days ago");
}
TEST_CASE("duration to_string") {
TEST_CASE("duration to_string")
{
std::string val;
val = humanize::time::duration::from_tv({25 * 60 * 60, 123000})
.to_string();
val = humanize::time::duration::from_tv({25 * 60 * 60, 123000}).to_string();
CHECK(val == "1d1h0m0s");
val = humanize::time::duration::from_tv({10, 123000})
.to_string();
val = humanize::time::duration::from_tv({10, 123000}).to_string();
CHECK(val == "10s123");
val = humanize::time::duration::from_tv({10, 0})
.to_string();
val = humanize::time::duration::from_tv({10, 0}).to_string();
CHECK(val == "10s000");
val = humanize::time::duration::from_tv({0, 100000})
.to_string();
val = humanize::time::duration::from_tv({0, 100000}).to_string();
CHECK(val == "100");
val = humanize::time::duration::from_tv({0, 0})
.to_string();
val = humanize::time::duration::from_tv({0, 0}).to_string();
CHECK(val == "");
val = humanize::time::duration::from_tv({0, -10000})
.to_string();
val = humanize::time::duration::from_tv({0, -10000}).to_string();
CHECK(val == "-010");
val = humanize::time::duration::from_tv({-10, 0})
.to_string();
val = humanize::time::duration::from_tv({-10, 0}).to_string();
CHECK(val == "-10s000");
}

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -38,55 +38,60 @@ namespace injector {
namespace details {
template<typename I, typename R, typename ...Args>
std::function<std::shared_ptr<I>()> create_factory(R (*)(Args...)) {
return []() {
return std::make_shared<I>(::injector::get<Args>()...);
};
template<typename I, typename R, typename... Args>
std::function<std::shared_ptr<I>()>
create_factory(R (*)(Args...))
{
return []() { return std::make_shared<I>(::injector::get<Args>()...); };
}
template<typename I,
std::enable_if_t<has_injectable<I>::value, bool> = true>
std::function<std::shared_ptr<I>()> create_factory() {
typename I::injectable *i = nullptr;
template<typename I, std::enable_if_t<has_injectable<I>::value, bool> = true>
std::function<std::shared_ptr<I>()>
create_factory()
{
typename I::injectable* i = nullptr;
return create_factory<I>(i);
}
template<typename I,
std::enable_if_t<!has_injectable<I>::value, bool> = true>
std::function<std::shared_ptr<I>()> create_factory() noexcept {
return []() {
return std::make_shared<I>();
};
template<typename I, std::enable_if_t<!has_injectable<I>::value, bool> = true>
std::function<std::shared_ptr<I>()>
create_factory() noexcept
{
return []() { return std::make_shared<I>(); };
}
}
} // namespace details
template<typename T, typename...Annotations>
template<typename T, typename... Annotations>
struct bind : singleton_storage<T, Annotations...> {
static bool to_singleton() noexcept {
static bool to_singleton() noexcept
{
static T storage;
singleton_storage<T, Annotations...>::ss_data = &storage;
return true;
}
template<typename...Args>
static bool to_instance(T* (*f)(Args...)) noexcept {
singleton_storage<T, Annotations...>::ss_data = f(::injector::get<Args>()...);
template<typename... Args>
static bool to_instance(T* (*f)(Args...)) noexcept
{
singleton_storage<T, Annotations...>::ss_data
= f(::injector::get<Args>()...);
return true;
}
static bool to_instance(T* data) noexcept {
static bool to_instance(T* data) noexcept
{
singleton_storage<T, Annotations...>::ss_data = data;
return true;
}
template<typename I>
static bool to() noexcept {
singleton_storage<T, Annotations...>::ss_factory =
details::create_factory<I>();
static bool to() noexcept
{
singleton_storage<T, Annotations...>::ss_factory
= details::create_factory<I>();
return true;
}
};
@ -96,15 +101,17 @@ struct bind_multiple : multiple_storage<T> {
bind_multiple() noexcept = default;
template<typename I>
bind_multiple& add() noexcept {
multiple_storage<T>::get_factories()[typeid(I).name()] =
details::create_factory<I>();
bind_multiple& add() noexcept
{
multiple_storage<T>::get_factories()[typeid(I).name()]
= details::create_factory<I>();
return *this;
}
template<typename I, typename...Annotations>
bind_multiple& add_singleton() noexcept {
template<typename I, typename... Annotations>
bind_multiple& add_singleton() noexcept
{
auto factory = details::create_factory<I>();
auto single = factory();
@ -112,14 +119,13 @@ struct bind_multiple : multiple_storage<T> {
bind<T, Annotations...>::to_instance(single.get());
}
bind<I, Annotations...>::to_instance(single.get());
multiple_storage<T>::get_factories()[typeid(I).name()] = [single]() {
return single;
};
multiple_storage<T>::get_factories()[typeid(I).name()]
= [single]() { return single; };
return *this;
}
};
}
} // namespace injector
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,12 +32,12 @@
#ifndef lnav_injector_hh
#define lnav_injector_hh
#include <assert.h>
#include <map>
#include <memory>
#include <vector>
#include <type_traits>
#include <vector>
#include <assert.h>
#include "base/lnav_log.hh"
@ -46,40 +46,45 @@ namespace injector {
template<typename Annotation>
void force_linking(Annotation anno);
template<class ...>
template<class...>
using void_t = void;
template <class, class = void>
struct has_injectable : std::false_type {};
template<class, class = void>
struct has_injectable : std::false_type {
};
template <class T>
struct has_injectable<T, void_t<typename T::injectable>> : std::true_type
{};
template<class T>
struct has_injectable<T, void_t<typename T::injectable>> : std::true_type {
};
template<typename T, typename...Annotations>
template<typename T, typename... Annotations>
struct singleton_storage {
static T *get() {
static T* get()
{
static int _[] = {0, (force_linking(Annotations{}), 0)...};
(void)_;
(void) _;
assert(ss_data != nullptr);
return ss_data;
}
static std::shared_ptr<T> create() {
static std::shared_ptr<T> create()
{
static int _[] = {0, (force_linking(Annotations{}), 0)...};
(void)_;
(void) _;
return ss_factory();
}
protected:
static T *ss_data;
static T* ss_data;
static std::function<std::shared_ptr<T>()> ss_factory;
};
template<typename T, typename...Annotations>
T *singleton_storage<T, Annotations...>::ss_data = nullptr;
template<typename T, typename... Annotations>
T* singleton_storage<T, Annotations...>::ss_data = nullptr;
template<typename T, typename...Annotations>
std::function<std::shared_ptr<T>()> singleton_storage<T, Annotations...>::ss_factory;
template<typename T, typename... Annotations>
std::function<std::shared_ptr<T>()>
singleton_storage<T, Annotations...>::ss_factory;
template<typename T>
struct Impl {
@ -88,7 +93,8 @@ struct Impl {
template<typename T>
struct multiple_storage {
static std::vector<std::shared_ptr<T>> create() {
static std::vector<std::shared_ptr<T>> create()
{
std::vector<std::shared_ptr<T>> retval;
for (const auto& pair : get_factories()) {
@ -96,28 +102,35 @@ struct multiple_storage {
}
return retval;
}
protected:
using factory_map_t = std::map<std::string, std::function<std::shared_ptr<T>()>>;
using factory_map_t
= std::map<std::string, std::function<std::shared_ptr<T>()>>;
static factory_map_t& get_factories() {
static factory_map_t& get_factories()
{
static factory_map_t retval;
return retval;
}
};
template<typename T, typename...Annotations,
std::enable_if_t<std::is_reference<T>::value, bool> = true>
T get()
template<typename T,
typename... Annotations,
std::enable_if_t<std::is_reference<T>::value, bool> = true>
T
get()
{
using plain_t = std::remove_const_t<std::remove_reference_t<T>>;
return *singleton_storage<plain_t, Annotations...>::get();
}
template<typename T, typename...Annotations,
std::enable_if_t<std::is_pointer<T>::value, bool> = true>
T get()
template<typename T,
typename... Annotations,
std::enable_if_t<std::is_pointer<T>::value, bool> = true>
T
get()
{
using plain_t = std::remove_const_t<std::remove_pointer_t<T>>;
@ -125,31 +138,38 @@ T get()
}
template<class T>
struct is_shared_ptr : std::false_type {};
struct is_shared_ptr : std::false_type {
};
template<class T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {
};
template<class T>
struct is_vector : std::false_type {};
struct is_vector : std::false_type {
};
template<class T>
struct is_vector<std::vector<T>> : std::true_type {};
struct is_vector<std::vector<T>> : std::true_type {
};
template<typename T, typename...Annotations,
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
T get()
template<typename T,
typename... Annotations,
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
T
get()
{
return singleton_storage<typename T::element_type, Annotations...>::create();
return singleton_storage<typename T::element_type,
Annotations...>::create();
}
template<typename T,
std::enable_if_t<is_vector<T>::value, bool> = true>
T get()
template<typename T, std::enable_if_t<is_vector<T>::value, bool> = true>
T
get()
{
return multiple_storage<typename T::value_type::element_type>::create();
}
}
} // namespace injector
#endif

@ -21,26 +21,27 @@
* 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
* 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 intern_string.cc
*/
#include "config.h"
#include <string.h>
#include <mutex>
#include "intern_string.hh"
#include <string.h>
#include "config.h"
const static int TABLE_SIZE = 4095;
struct intern_string::intern_table {
~intern_table() {
~intern_table()
{
for (auto is : this->it_table) {
auto curr = is;
@ -53,10 +54,11 @@ struct intern_string::intern_table {
}
}
intern_string *it_table[TABLE_SIZE];
intern_string* it_table[TABLE_SIZE];
};
intern_table_lifetime intern_string::get_table_lifetime()
intern_table_lifetime
intern_string::get_table_lifetime()
{
static intern_table_lifetime retval = std::make_shared<intern_table>();
@ -64,22 +66,23 @@ intern_table_lifetime intern_string::get_table_lifetime()
}
unsigned long
hash_str(const char *str, size_t len)
hash_str(const char* str, size_t len)
{
unsigned long retval = 5381;
for (size_t lpc = 0; lpc < len; lpc++) {
/* retval * 33 + c */
retval = ((retval << 5) + retval) + (unsigned char)str[lpc];
retval = ((retval << 5) + retval) + (unsigned char) str[lpc];
}
return retval;
}
const intern_string *intern_string::lookup(const char *str, ssize_t len) noexcept
const intern_string*
intern_string::lookup(const char* str, ssize_t len) noexcept
{
unsigned long h;
intern_string *curr;
intern_string* curr;
if (len == -1) {
len = strlen(str);
@ -94,7 +97,8 @@ const intern_string *intern_string::lookup(const char *str, ssize_t len) noexcep
curr = tab->it_table[h];
while (curr != nullptr) {
if (curr->is_str.size() == len && strncmp(curr->is_str.c_str(), str, len) == 0) {
if (curr->is_str.size() == len
&& strncmp(curr->is_str.c_str(), str, len) == 0) {
return curr;
}
curr = curr->is_next;
@ -106,22 +110,24 @@ const intern_string *intern_string::lookup(const char *str, ssize_t len) noexcep
return curr;
}
}
const intern_string *intern_string::lookup(const string_fragment &sf) noexcept
const intern_string*
intern_string::lookup(const string_fragment& sf) noexcept
{
return lookup(sf.data(), sf.length());
}
const intern_string *intern_string::lookup(const std::string &str) noexcept
const intern_string*
intern_string::lookup(const std::string& str) noexcept
{
return lookup(str.c_str(), str.size());
}
bool intern_string::startswith(const char *prefix) const
bool
intern_string::startswith(const char* prefix) const
{
const char *curr = this->is_str.data();
const char* curr = this->is_str.data();
while (*prefix != '\0' && *prefix == *curr) {
prefix += 1;
@ -131,7 +137,8 @@ bool intern_string::startswith(const char *prefix) const
return *prefix == '\0';
}
void string_fragment::trim(const char *tokens)
void
string_fragment::trim(const char* tokens)
{
while (this->sf_begin < this->sf_end) {
bool found = false;
@ -165,7 +172,8 @@ void string_fragment::trim(const char *tokens)
}
}
nonstd::optional<string_fragment> string_fragment::consume_n(int amount) const
nonstd::optional<string_fragment>
string_fragment::consume_n(int amount) const
{
if (amount > this->length()) {
return nonstd::nullopt;

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,72 +32,81 @@
#ifndef intern_string_hh
#define intern_string_hh
#include <string>
#include <string.h>
#include <sys/types.h>
#include <string>
#include "fmt/format.h"
#include "optional.hpp"
#include "strnatcmp.h"
#include "fmt/format.h"
struct string_fragment {
using iterator = const char *;
explicit string_fragment(const char *str = "", int begin = 0, int end = -1)
: sf_string(str), sf_begin(begin), sf_end(end == -1 ? strlen(str) : end) {
};
using iterator = const char*;
explicit string_fragment(const unsigned char *str, int begin = 0, int end = -1)
: sf_string((const char *) str),
sf_begin(begin),
sf_end(end == -1 ? strlen((const char *) str) : end) {
};
explicit string_fragment(const char* str = "", int begin = 0, int end = -1)
: sf_string(str), sf_begin(begin),
sf_end(end == -1 ? strlen(str) : end){};
string_fragment(const std::string &str)
: sf_string(str.c_str()), sf_begin(0), sf_end(str.length()) {
explicit string_fragment(const unsigned char* str,
int begin = 0,
int end = -1)
: sf_string((const char*) str), sf_begin(begin),
sf_end(end == -1 ? strlen((const char*) str) : end){};
string_fragment(const std::string& str)
: sf_string(str.c_str()), sf_begin(0), sf_end(str.length())
{
}
bool is_valid() const {
bool is_valid() const
{
return this->sf_begin != -1;
};
int length() const {
int length() const
{
return this->sf_end - this->sf_begin;
};
const char *data() const {
const char* data() const
{
return &this->sf_string[this->sf_begin];
}
iterator begin() const {
iterator begin() const
{
return &this->sf_string[this->sf_begin];
}
iterator end() const {
iterator end() const
{
return &this->sf_string[this->sf_end];
}
bool empty() const {
bool empty() const
{
return !this->is_valid() || length() == 0;
};
char operator[](int index) const {
char operator[](int index) const
{
return this->sf_string[sf_begin + index];
};
bool operator==(const std::string &str) const {
bool operator==(const std::string& str) const
{
if (this->length() != (int) str.length()) {
return false;
}
return memcmp(&this->sf_string[this->sf_begin],
str.c_str(),
str.length()) == 0;
return memcmp(
&this->sf_string[this->sf_begin], str.c_str(), str.length())
== 0;
};
bool operator==(const string_fragment &sf) const {
bool operator==(const string_fragment& sf) const
{
if (this->length() != sf.length()) {
return false;
}
@ -105,27 +114,32 @@ struct string_fragment {
return memcmp(this->data(), sf.data(), sf.length()) == 0;
};
bool iequal(const string_fragment &sf) const {
bool iequal(const string_fragment& sf) const
{
if (this->length() != sf.length()) {
return false;
}
return strnatcasecmp(this->length(), this->data(),
sf.length(), sf.data()) == 0;
return strnatcasecmp(
this->length(), this->data(), sf.length(), sf.data())
== 0;
};
bool operator==(const char *str) const {
bool operator==(const char* str) const
{
size_t len = strlen(str);
return len == (size_t) this->length() &&
strncmp(this->data(), str, this->length()) == 0;
return len == (size_t) this->length()
&& strncmp(this->data(), str, this->length()) == 0;
};
bool operator!=(const char *str) const {
bool operator!=(const char* str) const
{
return !(*this == str);
}
bool startswith(const char *prefix) const {
bool startswith(const char* prefix) const
{
auto iter = this->begin();
while (*prefix != '\0' && *prefix == *iter && iter < this->end()) {
@ -136,15 +150,14 @@ struct string_fragment {
return *prefix == '\0';
}
string_fragment substr(int begin) const {
string_fragment substr(int begin) const
{
return string_fragment{
this->sf_string,
this->sf_begin + begin,
this->sf_end
};
this->sf_string, this->sf_begin + begin, this->sf_end};
}
nonstd::optional<size_t> find(char ch) const {
nonstd::optional<size_t> find(char ch) const
{
for (int lpc = this->sf_begin; lpc < this->sf_end; lpc++) {
if (this->sf_string[lpc] == ch) {
return lpc;
@ -155,7 +168,8 @@ struct string_fragment {
}
template<typename P>
nonstd::optional<string_fragment> consume(P predicate) const {
nonstd::optional<string_fragment> consume(P predicate) const
{
int consumed = 0;
while (consumed < this->length()) {
if (!predicate(this->data()[consumed])) {
@ -179,7 +193,8 @@ struct string_fragment {
nonstd::optional<string_fragment> consume_n(int amount) const;
template<typename P>
string_fragment skip(P predicate) const {
string_fragment skip(P predicate) const
{
int offset = 0;
while (offset < this->length() && predicate(this->data()[offset])) {
offset += 1;
@ -192,10 +207,12 @@ struct string_fragment {
};
}
using split_result = nonstd::optional<std::pair<string_fragment, string_fragment>>;
using split_result
= nonstd::optional<std::pair<string_fragment, string_fragment>>;
template<typename P>
split_result split_while(P& predicate) const {
split_result split_while(P& predicate) const
{
int consumed = 0;
while (consumed < this->length()) {
if (!predicate(this->data()[consumed])) {
@ -219,14 +236,14 @@ struct string_fragment {
this->sf_string,
this->sf_begin + consumed,
this->sf_end,
}
);
});
}
struct tag1 {
const char t_value;
bool operator()(char ch) const {
bool operator()(char ch) const
{
return this->t_value == ch;
}
};
@ -234,7 +251,8 @@ struct string_fragment {
struct quoted_string_body {
bool qs_in_escape{false};
bool operator()(char ch) {
bool operator()(char ch)
{
if (this->qs_in_escape) {
this->qs_in_escape = false;
return true;
@ -249,80 +267,93 @@ struct string_fragment {
}
};
const char *to_string(char *buf) const {
const char* to_string(char* buf) const
{
memcpy(buf, this->data(), this->length());
buf[this->length()] = '\0';
return buf;
};
std::string to_string() const {
std::string to_string() const
{
return {this->data(), (size_t) this->length()};
}
void clear() {
void clear()
{
this->sf_begin = 0;
this->sf_end = 0;
};
void invalidate() {
void invalidate()
{
this->sf_begin = -1;
this->sf_end = -1;
};
void trim(const char *tokens);
void trim(const char* tokens);
const char *sf_string;
const char* sf_string;
int sf_begin;
int sf_end;
};
inline bool operator<(const char *left, const string_fragment &right) {
inline bool
operator<(const char* left, const string_fragment& right)
{
int rc = strncmp(left, right.data(), right.length());
return rc < 0;
}
inline bool operator<(const string_fragment &left, const char *right) {
inline bool
operator<(const string_fragment& left, const char* right)
{
return strncmp(left.data(), right, left.length()) < 0;
}
class intern_string {
public:
static const intern_string *lookup(const char *str, ssize_t len) noexcept;
static const intern_string* lookup(const char* str, ssize_t len) noexcept;
static const intern_string *lookup(const string_fragment &sf) noexcept;
static const intern_string* lookup(const string_fragment& sf) noexcept;
static const intern_string *lookup(const std::string &str) noexcept;
static const intern_string* lookup(const std::string& str) noexcept;
const char *get() const {
const char* get() const
{
return this->is_str.c_str();
};
size_t size() const {
size_t size() const
{
return this->is_str.size();
}
std::string to_string() const {
std::string to_string() const
{
return this->is_str;
}
string_fragment to_string_fragment() const {
string_fragment to_string_fragment() const
{
return string_fragment{this->is_str};
}
bool startswith(const char *prefix) const;
bool startswith(const char* prefix) const;
struct intern_table;
static std::shared_ptr<intern_table> get_table_lifetime();
private:
friend intern_table;
intern_string(const char *str, ssize_t len)
: is_next(nullptr), is_str(str, (size_t) len) {
intern_string(const char* str, ssize_t len)
: is_next(nullptr), is_str(str, (size_t) len)
{
}
intern_string *is_next;
intern_string* is_next;
std::string is_str;
};
@ -330,97 +361,112 @@ using intern_table_lifetime = std::shared_ptr<intern_string::intern_table>;
class intern_string_t {
public:
using iterator = const char *;
intern_string_t(const intern_string *is = nullptr) : ist_interned_string(is) {
using iterator = const char*;
intern_string_t(const intern_string* is = nullptr) : ist_interned_string(is)
{
}
const intern_string *unwrap() const {
const intern_string* unwrap() const
{
return this->ist_interned_string;
}
void clear() {
void clear()
{
this->ist_interned_string = nullptr;
};
bool empty() const {
bool empty() const
{
return this->ist_interned_string == nullptr;
}
const char *get() const {
const char* get() const
{
if (this->empty()) {
return "";
}
return this->ist_interned_string->get();
}
iterator begin() const {
iterator begin() const
{
return this->get();
}
iterator end() const {
iterator end() const
{
return this->get() + this->size();
}
size_t size() const {
size_t size() const
{
if (this->ist_interned_string == nullptr) {
return 0;
}
return this->ist_interned_string->size();
}
size_t hash() const {
size_t hash() const
{
auto ptr = (uintptr_t) this->ist_interned_string;
return ptr;
}
std::string to_string() const {
std::string to_string() const
{
if (this->ist_interned_string == nullptr) {
return "";
}
return this->ist_interned_string->to_string();
}
string_fragment to_string_fragment() const {
string_fragment to_string_fragment() const
{
if (this->ist_interned_string == nullptr) {
return string_fragment{"", 0, 0};
}
return this->ist_interned_string->to_string_fragment();
}
bool operator<(const intern_string_t &rhs) const {
bool operator<(const intern_string_t& rhs) const
{
return strcmp(this->get(), rhs.get()) < 0;
}
bool operator==(const intern_string_t &rhs) const {
bool operator==(const intern_string_t& rhs) const
{
return this->ist_interned_string == rhs.ist_interned_string;
}
bool operator!=(const intern_string_t &rhs) const {
bool operator!=(const intern_string_t& rhs) const
{
return !(*this == rhs);
}
bool operator==(const char *rhs) const {
bool operator==(const char* rhs) const
{
return strcmp(this->get(), rhs) == 0;
}
bool operator!=(const char *rhs) const {
bool operator!=(const char* rhs) const
{
return strcmp(this->get(), rhs) != 0;
}
private:
const intern_string *ist_interned_string;
const intern_string* ist_interned_string;
};
unsigned long hash_str(const char *str, size_t len);
unsigned long hash_str(const char* str, size_t len);
namespace fmt {
template<>
struct formatter<string_fragment> : formatter<string_view> {
template<typename FormatContext>
auto format(const string_fragment &sf, FormatContext &ctx)
auto format(const string_fragment& sf, FormatContext& ctx)
{
return formatter<string_view>::format(
string_view{sf.data(), (size_t) sf.length()}, ctx);
@ -430,61 +476,80 @@ struct formatter<string_fragment> : formatter<string_view> {
template<>
struct formatter<intern_string_t> : formatter<string_view> {
template<typename FormatContext>
auto format(const intern_string_t& is, FormatContext &ctx)
auto format(const intern_string_t& is, FormatContext& ctx)
{
return formatter<string_view>::format(
string_view{is.get(), (size_t) is.size()}, ctx);
}
};
}
} // namespace fmt
namespace std {
template <>
struct hash<const intern_string_t> {
std::size_t operator()(const intern_string_t &ist) const {
return ist.hash();
}
};
}
template<>
struct hash<const intern_string_t> {
std::size_t operator()(const intern_string_t& ist) const
{
return ist.hash();
}
};
} // namespace std
inline bool operator<(const char *left, const intern_string_t &right) {
inline bool
operator<(const char* left, const intern_string_t& right)
{
int rc = strncmp(left, right.get(), right.size());
return rc < 0;
}
inline bool operator<(const intern_string_t &left, const char *right) {
inline bool
operator<(const intern_string_t& left, const char* right)
{
return strncmp(left.get(), right, left.size()) < 0;
}
inline bool operator==(const intern_string_t &left, const string_fragment &sf) {
return ((int) left.size() == sf.length()) &&
(memcmp(left.get(), sf.data(), left.size()) == 0);
inline bool
operator==(const intern_string_t& left, const string_fragment& sf)
{
return ((int) left.size() == sf.length())
&& (memcmp(left.get(), sf.data(), left.size()) == 0);
}
inline bool operator==(const string_fragment &left, const intern_string_t &right) {
return (left.length() == (int) right.size()) &&
(memcmp(left.data(), right.get(), left.length()) == 0);
inline bool
operator==(const string_fragment& left, const intern_string_t& right)
{
return (left.length() == (int) right.size())
&& (memcmp(left.data(), right.get(), left.length()) == 0);
}
namespace std {
inline string to_string(const string_fragment &s) {
return {s.data(), (size_t) s.length()};
}
inline string
to_string(const string_fragment& s)
{
return {s.data(), (size_t) s.length()};
}
inline string to_string(const intern_string_t &s) {
return s.to_string();
}
inline string
to_string(const intern_string_t& s)
{
return s.to_string();
}
} // namespace std
inline string_fragment to_string_fragment(const string_fragment &s) {
inline string_fragment
to_string_fragment(const string_fragment& s)
{
return s;
}
inline string_fragment to_string_fragment(const intern_string_t &s) {
inline string_fragment
to_string_fragment(const intern_string_t& s)
{
return string_fragment(s.get(), 0, s.size());
}
inline string_fragment to_string_fragment(const std::string &s) {
inline string_fragment
to_string_fragment(const std::string& s)
{
return string_fragment(s.c_str(), 0, s.length());
}

@ -21,28 +21,27 @@
* 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
* 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 <cctype>
#include <iostream>
#include "doctest/doctest.h"
#include "intern_string.hh"
#include "config.h"
#include "doctest/doctest.h"
TEST_CASE("consume")
{
auto is_eq = string_fragment::tag1{'='};
auto is_dq = string_fragment::tag1{'"'};
auto is_colon = string_fragment::tag1{':'};
const char *pair = "foo = bar";
const char* pair = "foo = bar";
auto sf = string_fragment(pair);
auto split_sf = sf.split_while(isalnum);
@ -64,7 +63,7 @@ TEST_CASE("consume")
auto no_value = sf.consume(is_colon);
CHECK(!no_value.has_value());
const char *qs = R"("foo \" bar")";
const char* qs = R"("foo \" bar")";
auto qs_sf = string_fragment{qs};
auto qs_body = qs_sf.consume(is_dq);

@ -25,10 +25,10 @@
* SUCH DAMAGE.
*/
#include "config.h"
#include "is_utf8.hh"
#include "config.h"
/*
Check if the given unsigned char * is a valid utf-8 sequence.
@ -56,240 +56,236 @@
-----------------------------------------------------------------------------
Returns the first erroneous byte position, and give in
`faulty_bytes` the number of actually existing bytes taking part in this error.
`faulty_bytes` the number of actually existing bytes taking part in this
error.
*/
ssize_t is_utf8(unsigned char *str, size_t len, const char **message, int *faulty_bytes)
ssize_t
is_utf8(unsigned char* str, size_t len, const char** message, int* faulty_bytes)
{
size_t i = 0;
*message = nullptr;
*faulty_bytes = 0;
while (i < len)
{
while (i < len) {
if (str[i] == '\n') {
*message = nullptr;
return i;
}
if (str[i] <= 0x7F) /* 00..7F */
{
if (str[i] <= 0x7F) /* 00..7F */ {
i += 1;
}
else if (str[i] >= 0xC2 && str[i] <= 0xDF) /* C2..DF 80..BF */
{
if (i + 1 < len) /* Expect a 2nd byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
{
*message = "After a first byte between C2 and DF, expecting a 2nd byte between 80 and BF";
} else if (str[i] >= 0xC2 && str[i] <= 0xDF) /* C2..DF 80..BF */ {
if (i + 1 < len) /* Expect a 2nd byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
*message
= "After a first byte between C2 and DF, expecting a "
"2nd byte between 80 and BF";
*faulty_bytes = 2;
return i;
}
}
else
{
*message = "After a first byte between C2 and DF, expecting a 2nd byte.";
} else {
*message
= "After a first byte between C2 and DF, expecting a 2nd "
"byte.";
*faulty_bytes = 1;
return i;
}
i += 2;
}
else if (str[i] == 0xE0) /* E0 A0..BF 80..BF */
{
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
{
if (str[i + 1] < 0xA0 || str[i + 1] > 0xBF)
{
*message = "After a first byte of E0, expecting a 2nd byte between A0 and BF.";
} else if (str[i] == 0xE0) /* E0 A0..BF 80..BF */ {
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
if (str[i + 1] < 0xA0 || str[i + 1] > 0xBF) {
*message
= "After a first byte of E0, expecting a 2nd byte "
"between A0 and BF.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte of E0, expecting a 3nd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte of E0, expecting a 3nd byte "
"between 80 and BF.";
*faulty_bytes = 3;
return i;
}
}
else
{
*message = "After a first byte of E0, expecting two following bytes.";
} else {
*message
= "After a first byte of E0, expecting two following "
"bytes.";
*faulty_bytes = 1;
return i;
}
i += 3;
}
else if (str[i] >= 0xE1 && str[i] <= 0xEC) /* E1..EC 80..BF 80..BF */
} else if (str[i] >= 0xE1 && str[i] <= 0xEC) /* E1..EC 80..BF 80..BF */
{
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
{
*message = "After a first byte between E1 and EC, expecting the 2nd byte between 80 and BF.";
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
*message
= "After a first byte between E1 and EC, expecting the "
"2nd byte between 80 and BF.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte between E1 and EC, expecting the 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte between E1 and EC, expecting the "
"3rd byte between 80 and BF.";
*faulty_bytes = 3;
return i;
}
}
else
{
*message = "After a first byte between E1 and EC, expecting two following bytes.";
} else {
*message
= "After a first byte between E1 and EC, expecting two "
"following bytes.";
*faulty_bytes = 1;
return i;
}
i += 3;
}
else if (str[i] == 0xED) /* ED 80..9F 80..BF */
{
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0x9F)
{
*message = "After a first byte of ED, expecting 2nd byte between 80 and 9F.";
} else if (str[i] == 0xED) /* ED 80..9F 80..BF */ {
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0x9F) {
*message
= "After a first byte of ED, expecting 2nd byte "
"between 80 and 9F.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte of ED, expecting 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte of ED, expecting 3rd byte "
"between 80 and BF.";
*faulty_bytes = 3;
return i;
}
}
else
{
*message = "After a first byte of ED, expecting two following bytes.";
} else {
*message
= "After a first byte of ED, expecting two following "
"bytes.";
*faulty_bytes = 1;
return i;
}
i += 3;
}
else if (str[i] >= 0xEE && str[i] <= 0xEF) /* EE..EF 80..BF 80..BF */
} else if (str[i] >= 0xEE && str[i] <= 0xEF) /* EE..EF 80..BF 80..BF */
{
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
{
*message = "After a first byte between EE and EF, expecting 2nd byte between 80 and BF.";
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
*message
= "After a first byte between EE and EF, expecting 2nd "
"byte between 80 and BF.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte between EE and EF, expecting 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte between EE and EF, expecting 3rd "
"byte between 80 and BF.";
*faulty_bytes = 3;
return i;
}
}
else
{
*message = "After a first byte between EE and EF, two following bytes.";
} else {
*message
= "After a first byte between EE and EF, two following "
"bytes.";
*faulty_bytes = 1;
return i;
}
i += 3;
}
else if (str[i] == 0xF0) /* F0 90..BF 80..BF 80..BF */
{
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
{
if (str[i + 1] < 0x90 || str[i + 1] > 0xBF)
{
*message = "After a first byte of F0, expecting 2nd byte between 90 and BF.";
} else if (str[i] == 0xF0) /* F0 90..BF 80..BF 80..BF */ {
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
if (str[i + 1] < 0x90 || str[i + 1] > 0xBF) {
*message
= "After a first byte of F0, expecting 2nd byte "
"between 90 and BF.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte of F0, expecting 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte of F0, expecting 3rd byte "
"between 80 and BF.";
*faulty_bytes = 3;
return i;
}
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
{
*message = "After a first byte of F0, expecting 4th byte between 80 and BF.";
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
*message
= "After a first byte of F0, expecting 4th byte "
"between 80 and BF.";
*faulty_bytes = 4;
return i;
}
}
else
{
*message = "After a first byte of F0, expecting three following bytes.";
} else {
*message
= "After a first byte of F0, expecting three following "
"bytes.";
*faulty_bytes = 1;
return i;
}
i += 4;
}
else if (str[i] >= 0xF1 && str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */
{
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
{
*message = "After a first byte of F1, F2, or F3, expecting a 2nd byte between 80 and BF.";
} else if (str[i] >= 0xF1
&& str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */ {
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
*message
= "After a first byte of F1, F2, or F3, expecting a "
"2nd byte between 80 and BF.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte of F1, F2, or F3, expecting a 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte of F1, F2, or F3, expecting a "
"3rd byte between 80 and BF.";
*faulty_bytes = 3;
return i;
}
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
{
*message = "After a first byte of F1, F2, or F3, expecting a 4th byte between 80 and BF.";
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
*message
= "After a first byte of F1, F2, or F3, expecting a "
"4th byte between 80 and BF.";
*faulty_bytes = 4;
return i;
}
}
else
{
*message = "After a first byte of F1, F2, or F3, expecting three following bytes.";
} else {
*message
= "After a first byte of F1, F2, or F3, expecting three "
"following bytes.";
*faulty_bytes = 1;
return i;
}
i += 4;
}
else if (str[i] == 0xF4) /* F4 80..8F 80..BF 80..BF */
{
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
{
if (str[i + 1] < 0x80 || str[i + 1] > 0x8F)
{
*message = "After a first byte of F4, expecting 2nd byte between 80 and 8F.";
} else if (str[i] == 0xF4) /* F4 80..8F 80..BF 80..BF */ {
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
if (str[i + 1] < 0x80 || str[i + 1] > 0x8F) {
*message
= "After a first byte of F4, expecting 2nd byte "
"between 80 and 8F.";
*faulty_bytes = 2;
return i;
}
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
{
*message = "After a first byte of F4, expecting 3rd byte between 80 and BF.";
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
*message
= "After a first byte of F4, expecting 3rd byte "
"between 80 and BF.";
*faulty_bytes = 3;
return i;
}
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
{
*message = "After a first byte of F4, expecting 4th byte between 80 and BF.";
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
*message
= "After a first byte of F4, expecting 4th byte "
"between 80 and BF.";
*faulty_bytes = 4;
return i;
}
}
else
{
*message = "After a first byte of F4, expecting three following bytes.";
} else {
*message
= "After a first byte of F4, expecting three following "
"bytes.";
*faulty_bytes = 1;
return i;
}
i += 4;
}
else
{
*message = "Expecting bytes in the following ranges: 00..7F C2..F4.";
} else {
*message
= "Expecting bytes in the following ranges: 00..7F C2..F4.";
*faulty_bytes = 1;
return i;
}

@ -28,9 +28,12 @@
#ifndef _IS_UTF8_H
#define _IS_UTF8_H
#include <sys/types.h>
#include <stdlib.h>
#include <sys/types.h>
ssize_t is_utf8(unsigned char *str, size_t len, const char **message, int *faulty_bytes);
ssize_t is_utf8(unsigned char* str,
size_t len,
const char** message,
int* faulty_bytes);
#endif /* _IS_UTF8_H */

@ -21,30 +21,32 @@
* 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
* 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 isc.cc
*/
#include "config.h"
#include <algorithm>
#include "isc.hh"
#include "config.h"
namespace isc {
void service_base::start()
void
service_base::start()
{
log_debug("starting service thread for: %s", this->s_name.c_str());
this->s_thread = std::thread(&service_base::run, this);
this->s_started = true;
}
void *service_base::run()
void*
service_base::run()
{
log_info("BEGIN isc thread: %s", this->s_name.c_str());
while (this->s_looping) {
@ -66,7 +68,8 @@ void *service_base::run()
return nullptr;
}
void service_base::stop()
void
service_base::stop()
{
if (this->s_started) {
log_debug("stopping service thread: %s", this->s_name.c_str());
@ -81,8 +84,9 @@ void service_base::stop()
}
}
supervisor::supervisor(service_list servs, service_base *parent)
: s_service_list(std::move(servs)), s_parent(parent) {
supervisor::supervisor(service_list servs, service_base* parent)
: s_service_list(std::move(servs)), s_parent(parent)
{
for (auto& serv : this->s_service_list) {
serv->start();
}
@ -93,7 +97,8 @@ supervisor::~supervisor()
this->stop_children();
}
void supervisor::stop_children()
void
supervisor::stop_children()
{
for (auto& serv : this->s_service_list) {
serv->stop();
@ -101,29 +106,31 @@ void supervisor::stop_children()
this->cleanup_children();
}
void supervisor::cleanup_children()
void
supervisor::cleanup_children()
{
this->s_service_list.erase(
std::remove_if(
this->s_service_list.begin(), this->s_service_list.end(),
[this](auto &child) {
if (child->is_looping()) {
return false;
}
child->stop();
if (this->s_parent != nullptr) {
this->s_parent->child_finished(child);
}
return true;
}),
std::remove_if(this->s_service_list.begin(),
this->s_service_list.end(),
[this](auto& child) {
if (child->is_looping()) {
return false;
}
child->stop();
if (this->s_parent != nullptr) {
this->s_parent->child_finished(child);
}
return true;
}),
this->s_service_list.end());
}
void supervisor::add_child_service(std::shared_ptr<service_base> new_service)
void
supervisor::add_child_service(std::shared_ptr<service_base> new_service)
{
this->s_service_list.emplace_back(new_service);
new_service->start();
}
}
} // namespace isc

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -30,19 +30,19 @@
*/
#include <atomic>
#include <deque>
#include <chrono>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <utility>
#include "injector.hh"
#include "time_util.hh"
#include "safe/safe.h"
#include "time_util.hh"
#ifndef lnav_isc_hh
#define lnav_isc_hh
# define lnav_isc_hh
namespace isc {
@ -50,28 +50,33 @@ struct msg {
std::function<void()> m_callback;
};
inline msg empty_msg() {
return { []() { } };
inline msg
empty_msg()
{
return {[]() {}};
}
class msg_port {
public:
msg_port() = default;
void send(msg&& m) {
safe::WriteAccess<safe_message_list, std::unique_lock> writable_msgs(this->mp_messages);
void send(msg&& m)
{
safe::WriteAccess<safe_message_list, std::unique_lock> writable_msgs(
this->mp_messages);
writable_msgs->emplace_back(m);
this->sp_cond.notify_all();
}
template<class Rep, class Period>
void process_for(const std::chrono::duration<Rep, Period>& rel_time) {
void process_for(const std::chrono::duration<Rep, Period>& rel_time)
{
std::deque<msg> tmp_msgs;
{
safe::WriteAccess<safe_message_list, std::unique_lock> writable_msgs(
this->mp_messages);
safe::WriteAccess<safe_message_list, std::unique_lock>
writable_msgs(this->mp_messages);
if (writable_msgs->empty()) {
this->sp_cond.template wait_for(writable_msgs.lock, rel_time);
@ -80,12 +85,13 @@ public:
tmp_msgs.swap(*writable_msgs);
}
while (!tmp_msgs.empty()) {
auto &m = tmp_msgs.front();
auto& m = tmp_msgs.front();
m.m_callback();
tmp_msgs.pop_front();
}
}
private:
using message_list = std::deque<msg>;
using safe_message_list = safe::Safe<message_list>;
@ -99,11 +105,12 @@ using service_list = std::vector<std::shared_ptr<service_base>>;
struct supervisor {
explicit supervisor(service_list servs = {},
service_base *parent = nullptr);
service_base* parent = nullptr);
~supervisor();
bool empty() const {
bool empty() const
{
return this->s_service_list.empty();
}
@ -112,39 +119,46 @@ struct supervisor {
void stop_children();
void cleanup_children();
protected:
service_list s_service_list;
service_base *s_parent;
service_base* s_parent;
};
class service_base : public std::enable_shared_from_this<service_base> {
public:
explicit service_base(std::string name)
: s_name(std::move(name)), s_children({}, this) {
: s_name(std::move(name)), s_children({}, this)
{
}
virtual ~service_base() = default;
bool is_looping() const {
bool is_looping() const
{
return this->s_looping;
}
msg_port& get_port() {
msg_port& get_port()
{
return this->s_port;
}
friend supervisor;
private:
void start();
void stop();
protected:
virtual void *run();
virtual void loop_body() {};
virtual void child_finished(std::shared_ptr<service_base> child) {};
virtual void stopped() {};
virtual std::chrono::milliseconds compute_timeout(mstime_t current_time) const {
virtual void* run();
virtual void loop_body(){};
virtual void child_finished(std::shared_ptr<service_base> child){};
virtual void stopped(){};
virtual std::chrono::milliseconds compute_timeout(
mstime_t current_time) const
{
using namespace std::literals::chrono_literals;
return 1s;
@ -162,36 +176,37 @@ template<typename T>
class service : public service_base {
public:
explicit service(std::string sub_name = "")
: service_base(std::string(__PRETTY_FUNCTION__) + " " + sub_name) {
: service_base(std::string(__PRETTY_FUNCTION__) + " " + sub_name)
{
}
template<typename F>
void send(F msg) {
this->s_port.send({
[lifetime = this->shared_from_this(), this, msg]() {
msg(*(static_cast<T *>(this)));
}
});
void send(F msg)
{
this->s_port.send({[lifetime = this->shared_from_this(), this, msg]() {
msg(*(static_cast<T*>(this)));
}});
}
template<typename F, class Rep, class Period>
void send_and_wait(F msg,
const std::chrono::duration<Rep, Period>& rel_time) {
const std::chrono::duration<Rep, Period>& rel_time)
{
msg_port reply_port;
this->s_port.send({
[lifetime = this->shared_from_this(), this, &reply_port, msg]() {
msg(*(static_cast<T *>(this)));
this->s_port.send(
{[lifetime = this->shared_from_this(), this, &reply_port, msg]() {
msg(*(static_cast<T*>(this)));
reply_port.send(empty_msg());
}
});
}});
reply_port.template process_for(rel_time);
}
};
template<typename T, typename Service, typename...Annotations>
template<typename T, typename Service, typename... Annotations>
struct to {
void send(std::function<void(T&)> cb) {
void send(std::function<void(T&)> cb)
{
auto& service = injector::get<T&, Service>();
service.send(cb);
@ -199,19 +214,21 @@ struct to {
template<class Rep, class Period>
void send_and_wait(std::function<void(T)> cb,
const std::chrono::duration<Rep, Period>& rel_time) {
const std::chrono::duration<Rep, Period>& rel_time)
{
auto& service = injector::get<T&, Service>();
service.send_and_wait(cb, rel_time);
}
void send_and_wait(std::function<void(T)> cb) {
void send_and_wait(std::function<void(T)> cb)
{
using namespace std::literals::chrono_literals;
this->send_and_wait(cb, 48h);
}
};
}
} // namespace isc
#endif

@ -21,30 +21,32 @@
* 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
* 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 lnav.gzip.cc
*/
#include "config.h"
#include "lnav.gzip.hh"
#include <zlib.h>
#include "config.h"
#include "fmt/format.h"
#include "lnav.gzip.hh"
namespace lnav {
namespace gzip {
bool is_gzipped(const char *buffer, size_t len)
bool
is_gzipped(const char* buffer, size_t len)
{
return len > 2 && buffer[0] == '\037' && buffer[1] == '\213';
}
Result<auto_buffer, std::string> compress(const void* input, size_t len)
Result<auto_buffer, std::string>
compress(const void* input, size_t len)
{
auto retval = auto_buffer::alloc(len + 4096);
@ -52,14 +54,16 @@ Result<auto_buffer, std::string> compress(const void* input, size_t len)
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.avail_in = (uInt)len;
zs.next_in = (Bytef *)input;
zs.avail_out = (uInt)retval.size();
zs.next_out = (Bytef *)retval.in();
zs.avail_in = (uInt) len;
zs.next_in = (Bytef*) input;
zs.avail_out = (uInt) retval.size();
zs.next_out = (Bytef*) retval.in();
auto rc = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
auto rc = deflateInit2(
&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
if (rc != Z_OK) {
return Err(fmt::format("unable to initialize compressor -- {}", zError(rc)));
return Err(
fmt::format("unable to initialize compressor -- {}", zError(rc)));
}
rc = deflate(&zs, Z_FINISH);
if (rc != Z_STREAM_END) {
@ -67,20 +71,20 @@ Result<auto_buffer, std::string> compress(const void* input, size_t len)
}
rc = deflateEnd(&zs);
if (rc != Z_OK) {
return Err(fmt::format("unable to finalize compression -- {}", zError(rc)));
return Err(
fmt::format("unable to finalize compression -- {}", zError(rc)));
}
return Ok(std::move(retval.shrink_to(zs.total_out)));
}
Result<auto_buffer, std::string> uncompress(const std::string& src,
const void *buffer,
size_t size)
Result<auto_buffer, std::string>
uncompress(const std::string& src, const void* buffer, size_t size)
{
auto uncomp = auto_buffer::alloc(size * 2);
z_stream strm;
int err;
strm.next_in = (Bytef *) buffer;
strm.next_in = (Bytef*) buffer;
strm.avail_in = size;
strm.total_out = 0;
strm.zalloc = Z_NULL;
@ -88,7 +92,8 @@ Result<auto_buffer, std::string> uncompress(const std::string& src,
if ((err = inflateInit2(&strm, (16 + MAX_WBITS))) != Z_OK) {
return Err(fmt::format("invalid gzip data: {} -- {}",
src, strm.msg ? strm.msg : zError(err)));
src,
strm.msg ? strm.msg : zError(err)));
}
bool done = false;
@ -98,7 +103,7 @@ Result<auto_buffer, std::string> uncompress(const std::string& src,
uncomp.expand_by(size / 2);
}
strm.next_out = (Bytef *) (uncomp.in() + strm.total_out);
strm.next_out = (Bytef*) (uncomp.in() + strm.total_out);
strm.avail_out = uncomp.size() - strm.total_out;
// Inflate another chunk.
@ -108,17 +113,19 @@ Result<auto_buffer, std::string> uncompress(const std::string& src,
} else if (err != Z_OK) {
inflateEnd(&strm);
return Err(fmt::format("unable to uncompress: {} -- {}",
src, strm.msg ? strm.msg : zError(err)));
src,
strm.msg ? strm.msg : zError(err)));
}
}
if (inflateEnd(&strm) != Z_OK) {
return Err(fmt::format("unable to uncompress: {} -- {}",
src, strm.msg ? strm.msg : zError(err)));
src,
strm.msg ? strm.msg : zError(err)));
}
return Ok(std::move(uncomp.shrink_to(strm.total_out)));
}
}
}
} // namespace gzip
} // namespace lnav

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -40,15 +40,15 @@
namespace lnav {
namespace gzip {
bool is_gzipped(const char *buffer, size_t len);
bool is_gzipped(const char* buffer, size_t len);
Result<auto_buffer, std::string> compress(const void *input, size_t len);
Result<auto_buffer, std::string> compress(const void* input, size_t len);
Result<auto_buffer, std::string> uncompress(const std::string& src,
const void *buffer,
const void* buffer,
size_t size);
}
}
} // namespace gzip
} // namespace lnav
#endif

@ -21,35 +21,35 @@
* 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
* 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 <zlib.h>
#include <iostream>
#include "doctest/doctest.h"
#include <zlib.h>
#include "base/lnav.gzip.hh"
#include "config.h"
#include "doctest/doctest.h"
TEST_CASE("lnav::gzip::uncompress") {
TEST_CASE("lnav::gzip::uncompress")
{
{
auto u_res = lnav::gzip::uncompress("empty", nullptr, 0);
CHECK(u_res.isErr());
CHECK(u_res.unwrapErr() ==
"unable to uncompress: empty -- buffer error");
CHECK(u_res.unwrapErr()
== "unable to uncompress: empty -- buffer error");
}
{
auto u_res = lnav::gzip::uncompress("garbage", "abc", 3);
CHECK(u_res.isErr());
CHECK(u_res.unwrapErr() ==
"unable to uncompress: garbage -- incorrect header check");
CHECK(u_res.unwrapErr()
== "unable to uncompress: garbage -- incorrect header check");
}
}

@ -21,101 +21,104 @@
* 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
* 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 lnav_log.cc
*/
#include "config.h"
#include <time.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <sys/resource.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
# include <execinfo.h>
#endif
#if BACKWARD_HAS_DW == 1
#include "backward-cpp/backward.hpp"
# include "backward-cpp/backward.hpp"
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <algorithm>
#include <mutex>
#include <thread>
#include <vector>
#include <algorithm>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#ifdef HAVE_PCRE_H
#include <pcre.h>
# include <pcre.h>
#elif HAVE_PCRE_PCRE_H
#include <pcre/pcre.h>
# include <pcre/pcre.h>
#else
#error "pcre.h not found?"
# error "pcre.h not found?"
#endif
#if defined HAVE_NCURSESW_CURSES_H
# include <ncursesw/termcap.h>
# include <ncursesw/curses.h>
# include <ncursesw/curses.h>
# include <ncursesw/termcap.h>
#elif defined HAVE_NCURSESW_H
# include <termcap.h>
# include <ncursesw.h>
# include <ncursesw.h>
# include <termcap.h>
#elif defined HAVE_NCURSES_CURSES_H
# include <ncurses/termcap.h>
# include <ncurses/curses.h>
# include <ncurses/curses.h>
# include <ncurses/termcap.h>
#elif defined HAVE_NCURSES_H
# include <termcap.h>
# include <ncurses.h>
# include <ncurses.h>
# include <termcap.h>
#elif defined HAVE_CURSES_H
# include <termcap.h>
# include <curses.h>
# include <curses.h>
# include <termcap.h>
#else
# error "SysV or X/Open-compatible Curses header file required"
# error "SysV or X/Open-compatible Curses header file required"
#endif
#include "opt_util.hh"
#include "lnav_log.hh"
#include "enum_util.hh"
#include "auto_mem.hh"
#include "enum_util.hh"
#include "lnav_log.hh"
#include "opt_util.hh"
static const size_t BUFFER_SIZE = 256 * 1024;
static const size_t MAX_LOG_LINE_SIZE = 2048;
static const char *CRASH_MSG =
"\n"
"\n"
"==== GURU MEDITATION ====\n"
"Unfortunately, lnav has crashed, sorry for the inconvenience.\n"
"\n"
"You can help improve lnav by sending the following file to " PACKAGE_BUGREPORT " :\n"
" %s\n"
"=========================\n";
nonstd::optional<FILE *> lnav_log_file;
static const char* CRASH_MSG
= "\n"
"\n"
"==== GURU MEDITATION ====\n"
"Unfortunately, lnav has crashed, sorry for the inconvenience.\n"
"\n"
"You can help improve lnav by sending the following file "
"to " PACKAGE_BUGREPORT
" :\n"
" %s\n"
"=========================\n";
nonstd::optional<FILE*> lnav_log_file;
lnav_log_level_t lnav_log_level = lnav_log_level_t::DEBUG;
const char *lnav_log_crash_dir;
nonstd::optional<const struct termios *> lnav_log_orig_termios;
const char* lnav_log_crash_dir;
nonstd::optional<const struct termios*> lnav_log_orig_termios;
// NOTE: This mutex is leaked so that it is not destroyed during exit.
// Otherwise, any attempts to log will fail.
static std::mutex *lnav_log_mutex = new std::mutex();
static std::mutex* lnav_log_mutex = new std::mutex();
static std::vector<log_state_dumper*>& DUMPER_LIST()
static std::vector<log_state_dumper*>&
DUMPER_LIST()
{
static std::vector<log_state_dumper*> retval;
@ -141,14 +144,9 @@ static struct {
off_t lr_frag_start;
off_t lr_frag_end;
char lr_data[BUFFER_SIZE];
} log_ring = {
0,
BUFFER_SIZE,
0,
{}
};
} log_ring = {0, BUFFER_SIZE, 0, {}};
static const char *LEVEL_NAMES[] = {
static const char* LEVEL_NAMES[] = {
"T",
"D",
"I",
@ -156,38 +154,40 @@ static const char *LEVEL_NAMES[] = {
"E",
};
static char *log_alloc()
static char*
log_alloc()
{
off_t data_end = log_ring.lr_length + MAX_LOG_LINE_SIZE;
if (data_end >= (off_t)BUFFER_SIZE) {
const char *new_start = &log_ring.lr_data[MAX_LOG_LINE_SIZE];
if (data_end >= (off_t) BUFFER_SIZE) {
const char* new_start = &log_ring.lr_data[MAX_LOG_LINE_SIZE];
new_start = (const char *)memchr(
new_start = (const char*) memchr(
new_start, '\n', log_ring.lr_length - MAX_LOG_LINE_SIZE);
log_ring.lr_frag_start = new_start - log_ring.lr_data;
log_ring.lr_frag_end = log_ring.lr_length;
log_ring.lr_length = 0;
assert(log_ring.lr_frag_start >= 0);
assert(log_ring.lr_frag_start <= (off_t)BUFFER_SIZE);
assert(log_ring.lr_frag_start <= (off_t) BUFFER_SIZE);
} else if (data_end >= log_ring.lr_frag_start) {
const char *new_start = &log_ring.lr_data[log_ring.lr_frag_start];
const char* new_start = &log_ring.lr_data[log_ring.lr_frag_start];
new_start = (const char *)memchr(
new_start = (const char*) memchr(
new_start, '\n', log_ring.lr_frag_end - log_ring.lr_frag_start);
assert(new_start != nullptr);
log_ring.lr_frag_start = new_start - log_ring.lr_data;
assert(log_ring.lr_frag_start >= 0);
assert(log_ring.lr_frag_start <= (off_t)BUFFER_SIZE);
assert(log_ring.lr_frag_start <= (off_t) BUFFER_SIZE);
}
return &log_ring.lr_data[log_ring.lr_length];
}
void log_argv(int argc, char *argv[])
void
log_argv(int argc, char* argv[])
{
const char *log_path = getenv("LNAV_LOG_PATH");
const char* log_path = getenv("LNAV_LOG_PATH");
if (log_path != nullptr) {
lnav_log_file = make_optional_from_nullable(fopen(log_path, "a"));
@ -199,15 +199,17 @@ void log_argv(int argc, char *argv[])
}
}
void log_set_thread_prefix(std::string prefix)
void
log_set_thread_prefix(std::string prefix)
{
// thread_log_prefix = std::move(prefix);
}
void log_host_info()
void
log_host_info()
{
char cwd[MAXPATHLEN];
const char *jittarget;
const char* jittarget;
struct utsname un;
struct rusage ru;
int pcre_jit;
@ -242,8 +244,7 @@ void log_host_info()
log_info(" egid=%d", getegid());
if (getcwd(cwd, sizeof(cwd)) == nullptr) {
log_info(" ERROR: getcwd failed");
}
else {
} else {
log_info(" cwd=%s", cwd);
}
log_info("Executable:");
@ -253,13 +254,25 @@ void log_host_info()
log_rusage(lnav_log_level_t::INFO, ru);
}
void log_rusage_raw(enum lnav_log_level_t level, const char *src_file, int line_number, const struct rusage &ru)
void
log_rusage_raw(enum lnav_log_level_t level,
const char* src_file,
int line_number,
const struct rusage& ru)
{
log_msg(level, src_file, line_number, "rusage:");
log_msg(level, src_file, line_number, " utime=%d.%06d",
ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
log_msg(level, src_file, line_number, " stime=%d.%06d",
ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
log_msg(level,
src_file,
line_number,
" utime=%d.%06d",
ru.ru_utime.tv_sec,
ru.ru_utime.tv_usec);
log_msg(level,
src_file,
line_number,
" stime=%d.%06d",
ru.ru_stime.tv_sec,
ru.ru_stime.tv_usec);
log_msg(level, src_file, line_number, " maxrss=%ld", ru.ru_maxrss);
log_msg(level, src_file, line_number, " ixrss=%ld", ru.ru_ixrss);
log_msg(level, src_file, line_number, " idrss=%ld", ru.ru_idrss);
@ -276,8 +289,12 @@ void log_rusage_raw(enum lnav_log_level_t level, const char *src_file, int line_
log_msg(level, src_file, line_number, " nivcsw=%ld", ru.ru_nivcsw);
}
void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
const char *fmt, ...)
void
log_msg(lnav_log_level_t level,
const char* src_file,
int line_number,
const char* fmt,
...)
{
struct timeval curr_time;
struct tm localtm;
@ -294,7 +311,7 @@ void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
{
// get the base name of the file. NB: can't use basename() since it
// can modify its argument
const char *last_slash = src_file;
const char* last_slash = src_file;
for (int lpc = 0; src_file[lpc]; lpc++) {
if (src_file[lpc] == '/' || src_file[lpc] == '\\') {
@ -309,20 +326,20 @@ void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
gettimeofday(&curr_time, nullptr);
localtime_r(&curr_time.tv_sec, &localtm);
auto line = log_alloc();
prefix_size = snprintf(
line, MAX_LOG_LINE_SIZE,
"%4d-%02d-%02dT%02d:%02d:%02d.%03d %s t%u %s:%d ",
localtm.tm_year + 1900,
localtm.tm_mon + 1,
localtm.tm_mday,
localtm.tm_hour,
localtm.tm_min,
localtm.tm_sec,
(int)(curr_time.tv_usec / 1000),
LEVEL_NAMES[lnav::enums::to_underlying(level)],
current_thid.t_id,
src_file,
line_number);
prefix_size = snprintf(line,
MAX_LOG_LINE_SIZE,
"%4d-%02d-%02dT%02d:%02d:%02d.%03d %s t%u %s:%d ",
localtm.tm_year + 1900,
localtm.tm_mon + 1,
localtm.tm_mday,
localtm.tm_hour,
localtm.tm_min,
localtm.tm_sec,
(int) (curr_time.tv_usec / 1000),
LEVEL_NAMES[lnav::enums::to_underlying(level)],
current_thid.t_id,
src_file,
line_number);
#if 0
if (!thread_log_prefix.empty()) {
prefix_size += snprintf(
@ -331,9 +348,9 @@ void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
thread_log_prefix.c_str());
}
#endif
rc = vsnprintf(&line[prefix_size], MAX_LOG_LINE_SIZE - prefix_size,
fmt, args);
if (rc >= (ssize_t)(MAX_LOG_LINE_SIZE - prefix_size)) {
rc = vsnprintf(
&line[prefix_size], MAX_LOG_LINE_SIZE - prefix_size, fmt, args);
if (rc >= (ssize_t) (MAX_LOG_LINE_SIZE - prefix_size)) {
rc = MAX_LOG_LINE_SIZE - prefix_size - 1;
}
line[prefix_size + rc] = '\n';
@ -345,7 +362,8 @@ void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
va_end(args);
}
void log_msg_extra(const char *fmt, ...)
void
log_msg_extra(const char* fmt, ...)
{
std::lock_guard<std::mutex> mg(*lnav_log_mutex);
va_list args;
@ -361,7 +379,8 @@ void log_msg_extra(const char *fmt, ...)
va_end(args);
}
void log_msg_extra_complete()
void
log_msg_extra_complete()
{
std::lock_guard<std::mutex> mg(*lnav_log_mutex);
auto line = log_alloc();
@ -375,13 +394,14 @@ void log_msg_extra_complete()
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
static void sigabrt(int sig, siginfo_t *info, void *ctx)
static void
sigabrt(int sig, siginfo_t* info, void* ctx)
{
char crash_path[1024], latest_crash_path[1024];
int fd;
#ifdef HAVE_EXECINFO_H
int frame_count;
void *frames[128];
void* frames[128];
#endif
struct tm localtm;
time_t curr_time;
@ -398,45 +418,53 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
#endif
curr_time = time(nullptr);
localtime_r(&curr_time, &localtm);
snprintf(crash_path, sizeof(crash_path),
"%s/crash-%4d-%02d-%02d-%02d-%02d-%02d.%d.log",
lnav_log_crash_dir,
localtm.tm_year + 1900,
localtm.tm_mon + 1,
localtm.tm_mday,
localtm.tm_hour,
localtm.tm_min,
localtm.tm_sec,
getpid());
snprintf(latest_crash_path, sizeof(latest_crash_path),
"%s/latest-crash.log", lnav_log_crash_dir);
if ((fd = open(crash_path, O_CREAT|O_TRUNC|O_RDWR, 0600)) != -1) {
if (log_ring.lr_frag_start < (off_t)BUFFER_SIZE) {
(void)write(fd, &log_ring.lr_data[log_ring.lr_frag_start],
log_ring.lr_frag_end - log_ring.lr_frag_start);
snprintf(crash_path,
sizeof(crash_path),
"%s/crash-%4d-%02d-%02d-%02d-%02d-%02d.%d.log",
lnav_log_crash_dir,
localtm.tm_year + 1900,
localtm.tm_mon + 1,
localtm.tm_mday,
localtm.tm_hour,
localtm.tm_min,
localtm.tm_sec,
getpid());
snprintf(latest_crash_path,
sizeof(latest_crash_path),
"%s/latest-crash.log",
lnav_log_crash_dir);
if ((fd = open(crash_path, O_CREAT | O_TRUNC | O_RDWR, 0600)) != -1) {
if (log_ring.lr_frag_start < (off_t) BUFFER_SIZE) {
(void) write(fd,
&log_ring.lr_data[log_ring.lr_frag_start],
log_ring.lr_frag_end - log_ring.lr_frag_start);
}
(void)write(fd, log_ring.lr_data, log_ring.lr_length);
(void) write(fd, log_ring.lr_data, log_ring.lr_length);
#ifdef HAVE_EXECINFO_H
backtrace_symbols_fd(frames, frame_count, fd);
#endif
#if BACKWARD_HAS_DW == 1
{
ucontext_t *uctx = static_cast<ucontext_t *>(ctx);
void *error_addr = nullptr;
ucontext_t* uctx = static_cast<ucontext_t*>(ctx);
void* error_addr = nullptr;
#ifdef REG_RIP // x86_64
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_RIP]);
#elif defined(REG_EIP) // x86_32
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_EIP]);
#endif
# ifdef REG_RIP // x86_64
error_addr
= reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
# elif defined(REG_EIP) // x86_32
error_addr
= reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
# endif
backward::StackTrace st;
if (error_addr) {
st.load_from(error_addr, 32, reinterpret_cast<void *>(uctx),
st.load_from(error_addr,
32,
reinterpret_cast<void*>(uctx),
info->si_addr);
} else {
st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr);
st.load_here(32, reinterpret_cast<void*>(uctx), info->si_addr);
}
backward::TraceResolver tr;
@ -445,7 +473,8 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
auto trace = tr.resolve(st[lpc]);
char buf[1024];
snprintf(buf, sizeof(buf),
snprintf(buf,
sizeof(buf),
"Frame %lu:%s:%s (%s:%d)\n",
lpc,
trace.object_filename.c_str(),
@ -466,9 +495,10 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
lsd->log_state();
}
if (log_ring.lr_frag_start < (off_t)BUFFER_SIZE) {
write(fd, &log_ring.lr_data[log_ring.lr_frag_start],
log_ring.lr_frag_end - log_ring.lr_frag_start);
if (log_ring.lr_frag_start < (off_t) BUFFER_SIZE) {
write(fd,
&log_ring.lr_data[log_ring.lr_frag_start],
log_ring.lr_frag_end - log_ring.lr_frag_start);
}
write(fd, log_ring.lr_data, log_ring.lr_length);
if (getenv("DUMP_CRASH") != nullptr) {
@ -530,7 +560,6 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
int status;
while (wait(&status) < 0) {
}
break;
}
@ -543,7 +572,8 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
}
#pragma GCC diagnostic pop
void log_install_handlers()
void
log_install_handlers()
{
const size_t stack_size = 8 * 1024 * 1024;
const int sigs[] = {
@ -575,15 +605,17 @@ void log_install_handlers()
}
}
void log_abort()
void
log_abort()
{
raise(SIGABRT);
_exit(1);
}
void log_pipe_err(int fd)
void
log_pipe_err(int fd)
{
std::thread reader([fd] () {
std::thread reader([fd]() {
char buffer[1024];
bool done = false;
@ -596,8 +628,7 @@ void log_pipe_err(int fd)
done = true;
break;
default:
while (buffer[rc - 1] == '\n' ||
buffer[rc - 1] == '\r') {
while (buffer[rc - 1] == '\n' || buffer[rc - 1] == '\r') {
rc -= 1;
}

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,13 +32,14 @@
#ifndef lnav_log_hh
#define lnav_log_hh
#include <string>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <string>
#ifndef lnav_dead2
#define lnav_dead2 __attribute__((noreturn))
# define lnav_dead2 __attribute__((noreturn))
#endif
#include "optional.hpp"
@ -53,12 +54,18 @@ enum class lnav_log_level_t : uint32_t {
ERROR,
};
void log_argv(int argc, char *argv[]);
void log_argv(int argc, char* argv[]);
void log_host_info();
void log_rusage_raw(enum lnav_log_level_t level, const char *src_file, int line_number, const struct rusage &ru);
void log_msg(enum lnav_log_level_t level, const char *src_file, int line_number,
const char *fmt, ...);
void log_msg_extra(const char *fmt, ...);
void log_rusage_raw(enum lnav_log_level_t level,
const char* src_file,
int line_number,
const struct rusage& ru);
void log_msg(enum lnav_log_level_t level,
const char* src_file,
int line_number,
const char* fmt,
...);
void log_msg_extra(const char* fmt, ...);
void log_msg_extra_complete();
void log_install_handlers();
void log_abort() lnav_dead2;
@ -71,7 +78,7 @@ public:
virtual ~log_state_dumper();
virtual void log_state() {
virtual void log_state(){
};
@ -88,9 +95,9 @@ public:
virtual void log_crash_recover() = 0;
};
extern nonstd::optional<FILE *> lnav_log_file;
extern const char *lnav_log_crash_dir;
extern nonstd::optional<const struct termios *> lnav_log_orig_termios;
extern nonstd::optional<FILE*> lnav_log_file;
extern const char* lnav_log_crash_dir;
extern nonstd::optional<const struct termios*> lnav_log_orig_termios;
extern enum lnav_log_level_t lnav_log_level;
#define log_msg_wrapper(level, fmt...) \
@ -98,40 +105,43 @@ extern enum lnav_log_level_t lnav_log_level;
if (lnav_log_level <= level) { \
log_msg(level, __FILE__, __LINE__, fmt); \
} \
} \
while (false)
} while (false)
#define log_rusage(level, ru) \
log_rusage_raw(level, __FILE__, __LINE__, ru);
#define log_rusage(level, ru) log_rusage_raw(level, __FILE__, __LINE__, ru);
#define log_error(fmt...) \
log_msg_wrapper(lnav_log_level_t::ERROR, fmt);
#define log_error(fmt...) log_msg_wrapper(lnav_log_level_t::ERROR, fmt);
#define log_warning(fmt...) \
log_msg_wrapper(lnav_log_level_t::WARNING, fmt);
#define log_warning(fmt...) log_msg_wrapper(lnav_log_level_t::WARNING, fmt);
#define log_info(fmt...) \
log_msg_wrapper(lnav_log_level_t::INFO, fmt);
#define log_info(fmt...) log_msg_wrapper(lnav_log_level_t::INFO, fmt);
#define log_debug(fmt...) \
log_msg_wrapper(lnav_log_level_t::DEBUG, fmt);
#define log_debug(fmt...) log_msg_wrapper(lnav_log_level_t::DEBUG, fmt);
#define log_trace(fmt...) \
log_msg_wrapper(lnav_log_level_t::TRACE, fmt);
#define log_trace(fmt...) log_msg_wrapper(lnav_log_level_t::TRACE, fmt);
#define require(e) \
((void) ((e) ? 0 : lnav_require (#e, __FILE__, __LINE__)))
#define require(e) ((void) ((e) ? 0 : lnav_require(#e, __FILE__, __LINE__)))
#define lnav_require(e, file, line) \
(log_msg(lnav_log_level_t::ERROR, file, line, "failed precondition `%s'", e), log_abort(), 1)
(log_msg( \
lnav_log_level_t::ERROR, file, line, "failed precondition `%s'", e), \
log_abort(), \
1)
#define ensure(e) \
((void) ((e) ? 0 : lnav_ensure (#e, __FILE__, __LINE__)))
#define ensure(e) ((void) ((e) ? 0 : lnav_ensure(#e, __FILE__, __LINE__)))
#define lnav_ensure(e, file, line) \
(log_msg(lnav_log_level_t::ERROR, file, line, "failed postcondition `%s'", e), log_abort(), 1)
(log_msg( \
lnav_log_level_t::ERROR, file, line, "failed postcondition `%s'", e), \
log_abort(), \
1)
#define log_perror(e) \
((void) ((e != -1) ? 0 : lnav_log_perror (#e, __FILE__, __LINE__)))
#define log_perror(e) \
((void) ((e != -1) ? 0 : lnav_log_perror(#e, __FILE__, __LINE__)))
#define lnav_log_perror(e, file, line) \
(log_msg(lnav_log_level_t::ERROR, file, line, "syscall failed `%s' -- %s", e, strerror(errno)), 1)
(log_msg(lnav_log_level_t::ERROR, \
file, \
line, \
"syscall failed `%s' -- %s", \
e, \
strerror(errno)), \
1)
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -41,17 +41,20 @@
* @param step The granularity.
*/
template<typename Size, typename Step>
inline int rounddown(Size size, Step step)
inline int
rounddown(Size size, Step step)
{
return size - (size % step);
}
inline int rounddown_offset(size_t size, int step, int offset)
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)
inline size_t
roundup_size(size_t size, int step)
{
size_t retval = size + step;

@ -21,27 +21,26 @@
* 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
* 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 "network.tcp.hh"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "config.h"
#include "fmt/format.h"
#include "network.tcp.hh"
namespace network {
namespace tcp {
Result<auto_fd, std::string> connect(const char *hostname,
const char *servname)
Result<auto_fd, std::string>
connect(const char* hostname, const char* servname)
{
struct addrinfo hints, *ai;
@ -52,7 +51,9 @@ Result<auto_fd, std::string> connect(const char *hostname,
if (rc != 0) {
return Err(fmt::format("unable to resolve {}:{} -- {}",
hostname, servname, gai_strerror(rc)));
hostname,
servname,
gai_strerror(rc)));
}
auto retval = auto_fd(socket(ai->ai_family, ai->ai_socktype, 0));
@ -60,11 +61,13 @@ Result<auto_fd, std::string> connect(const char *hostname,
rc = ::connect(retval, ai->ai_addr, ai->ai_addrlen);
if (rc != 0) {
return Err(fmt::format("unable to connect to {}:{} -- {}",
hostname, servname, strerror(rc)));
hostname,
servname,
strerror(rc)));
}
return Ok(retval);
}
}
}
} // namespace tcp
} // namespace network

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -40,11 +40,11 @@ namespace network {
struct locality {
locality(nonstd::optional<std::string> username,
std::string hostname,
nonstd::optional<std::string> service) :
l_username(std::move(username)),
l_hostname(std::move(hostname)),
l_service(std::move(service))
{}
nonstd::optional<std::string> service)
: l_username(std::move(username)), l_hostname(std::move(hostname)),
l_service(std::move(service))
{
}
nonstd::optional<std::string> l_username;
std::string l_hostname;
@ -55,11 +55,13 @@ struct path {
locality p_locality;
std::string p_path;
path(locality l, std::string path) : p_locality(std::move(l)),
p_path(std::move(path))
{}
path(locality l, std::string path)
: p_locality(std::move(l)), p_path(std::move(path))
{
}
path home() const {
path home() const
{
return {
this->p_locality,
".",
@ -69,10 +71,10 @@ struct path {
namespace tcp {
Result<auto_fd, std::string> connect(const char *hostname,
const char *servname);
Result<auto_fd, std::string> connect(const char* hostname,
const char* servname);
}
}
} // namespace network
#endif

@ -21,21 +21,19 @@
* 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
* 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 <iostream>
#include "config.h"
#include "doctest/doctest.h"
#include "network.tcp.hh"
TEST_CASE ("bad hostname")
TEST_CASE("bad hostname")
{
auto connect_res = network::tcp::connect("foobar.bazzer", "http");
CHECK(connect_res.unwrapErr() ==
@ -43,7 +41,7 @@ TEST_CASE ("bad hostname")
"provided, or not known");
}
TEST_CASE ("bad servname")
TEST_CASE("bad servname")
{
auto connect_res = network::tcp::connect("www.cnn.com", "non-existent");
CHECK(connect_res.unwrapErr() ==

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -37,36 +37,47 @@
namespace detail {
template <class T>
typename std::enable_if<std::is_void<T>::value, T>::type
void_or_nullopt()
{
return;
}
template<class T>
typename std::enable_if<std::is_void<T>::value, T>::type
void_or_nullopt()
{
return;
}
template <class T>
typename std::enable_if<not std::is_void<T>::value, T>::type
void_or_nullopt()
{
return nonstd::nullopt;
}
template<class T>
typename std::enable_if<not std::is_void<T>::value, T>::type
void_or_nullopt()
{
return nonstd::nullopt;
}
template <class T>
struct is_optional : std::false_type {};
template<class T>
struct is_optional : std::false_type {
};
template <class T>
struct is_optional<nonstd::optional<T>> : std::true_type {};
}
template<class T>
struct is_optional<nonstd::optional<T>> : std::true_type {
};
} // namespace detail
template <class T, class F, std::enable_if_t<detail::is_optional<std::decay_t<T>>::value, int> = 0>
auto operator|(T&& t, F f) -> decltype(detail::void_or_nullopt<decltype(f(std::forward<T>(t).operator*()))>()) {
template<class T,
class F,
std::enable_if_t<detail::is_optional<std::decay_t<T>>::value, int> = 0>
auto
operator|(T&& t, F f)
-> decltype(detail::void_or_nullopt<decltype(f(std::forward<T>(t).
operator*()))>())
{
using return_type = decltype(f(std::forward<T>(t).operator*()));
if (t) return f(std::forward<T>(t).operator*());
else return detail::void_or_nullopt<return_type>();
if (t)
return f(std::forward<T>(t).operator*());
else
return detail::void_or_nullopt<return_type>();
}
template< class T >
optional_constexpr nonstd::optional< typename std::decay<T>::type > make_optional_from_nullable( T && v )
template<class T>
optional_constexpr nonstd::optional<typename std::decay<T>::type>
make_optional_from_nullable(T&& v)
{
if (v != nullptr) {
return nonstd::optional<typename std::decay<T>::type>(
@ -75,8 +86,9 @@ optional_constexpr nonstd::optional< typename std::decay<T>::type > make_optiona
return nonstd::nullopt;
}
template<template <typename, typename...> class C, typename T>
nonstd::optional<T> cget(const C<T> &container, size_t index)
template<template<typename, typename...> class C, typename T>
nonstd::optional<T>
cget(const C<T>& container, size_t index)
{
if (index < container.size()) {
return container[index];
@ -85,7 +97,9 @@ nonstd::optional<T> cget(const C<T> &container, size_t index)
return nonstd::nullopt;
}
inline nonstd::optional<const char *> getenv_opt(const char *name) {
inline nonstd::optional<const char*>
getenv_opt(const char* name)
{
return make_optional_from_nullable(getenv(name));
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,32 +30,38 @@
#include "config.h"
#ifdef __CYGWIN__
#include <sstream>
#include <iostream>
# include <iostream>
# include <sstream>
#endif
#include "paths.hh"
#include "fmt/format.h"
#include "paths.hh"
namespace lnav {
namespace paths {
#ifdef __CYGWIN__
char* windows_to_unix_file_path(char* input) {
char*
windows_to_unix_file_path(char* input)
{
if (input == nullptr) {
return nullptr;
return nullptr;
}
std::string file_path;
file_path.assign(input);
// Replace the slashes
std::replace(file_path.begin(), file_path.end(), WINDOWS_FILE_PATH_SEPARATOR, UNIX_FILE_PATH_SEPARATOR);
std::replace(file_path.begin(),
file_path.end(),
WINDOWS_FILE_PATH_SEPARATOR,
UNIX_FILE_PATH_SEPARATOR);
// Convert the drive letter to lowercase
std::transform(file_path.begin(), file_path.begin() + 1, file_path.begin(),
[](unsigned char character) {
return std::tolower(character);
});
std::transform(
file_path.begin(),
file_path.begin() + 1,
file_path.begin(),
[](unsigned char character) { return std::tolower(character); });
// Remove the colon
const auto drive_letter = file_path.substr(0, 1);
@ -70,7 +76,8 @@ char* windows_to_unix_file_path(char* input) {
}
#endif
ghc::filesystem::path dotlnav()
ghc::filesystem::path
dotlnav()
{
#ifdef __CYGWIN__
auto home_env = windows_to_unix_file_path(getenv("APPDATA"));
@ -110,7 +117,8 @@ ghc::filesystem::path dotlnav()
return ghc::filesystem::current_path();
}
ghc::filesystem::path workdir()
ghc::filesystem::path
workdir()
{
auto subdir_name = fmt::format("lnav-user-{}-work", getuid());
auto tmp_path = ghc::filesystem::temp_directory_path();
@ -118,5 +126,5 @@ ghc::filesystem::path workdir()
return tmp_path / ghc::filesystem::path(subdir_name);
}
}
}
} // namespace paths
} // namespace lnav

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -52,7 +52,7 @@ ghc::filesystem::path dotlnav();
ghc::filesystem::path workdir();
}
}
} // namespace paths
} // namespace lnav
#endif

@ -21,30 +21,31 @@
* 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
* 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 <iterator>
#include <regex>
#include <sstream>
#include "lnav_log.hh"
#include "is_utf8.hh"
#include "string_util.hh"
void scrub_to_utf8(char *buffer, size_t length)
#include "config.h"
#include "is_utf8.hh"
#include "lnav_log.hh"
void
scrub_to_utf8(char* buffer, size_t length)
{
const char *msg;
const char* msg;
int faulty_bytes;
while (true) {
ssize_t utf8_end = is_utf8(
(unsigned char *) buffer, length, &msg, &faulty_bytes);
ssize_t utf8_end
= is_utf8((unsigned char*) buffer, length, &msg, &faulty_bytes);
if (msg == nullptr) {
break;
@ -55,7 +56,8 @@ void scrub_to_utf8(char *buffer, size_t length)
}
}
size_t unquote(char *dst, const char *str, size_t len)
size_t
unquote(char* dst, const char* str, size_t len)
{
if (str[0] == 'r' || str[0] == 'u') {
str += 1;
@ -70,8 +72,7 @@ size_t unquote(char *dst, const char *str, size_t len)
dst[index] = str[lpc];
if (str[lpc] == quote_char) {
lpc += 1;
}
else if (str[lpc] == '\\' && (lpc + 1) < len) {
} else if (str[lpc] == '\\' && (lpc + 1) < len) {
switch (str[lpc + 1]) {
case 'n':
dst[index] = '\n';
@ -94,7 +95,8 @@ size_t unquote(char *dst, const char *str, size_t len)
return index;
}
size_t unquote_w3c(char *dst, const char *str, size_t len)
size_t
unquote_w3c(char* dst, const char* str, size_t len)
{
size_t index = 0;
@ -111,7 +113,8 @@ size_t unquote_w3c(char *dst, const char *str, size_t len)
return index;
}
void truncate_to(std::string &str, size_t max_char_len)
void
truncate_to(std::string& str, size_t max_char_len)
{
static const std::string ELLIPSIS = "\u22ef";
@ -139,23 +142,25 @@ void truncate_to(std::string &str, size_t max_char_len)
auto chars_to_remove = (str_char_len - max_char_len) + 1;
auto midpoint = str_char_len / 2;
auto chars_to_keep_at_front = midpoint - (chars_to_remove / 2);
auto bytes_to_keep_at_front =
utf8_char_to_byte_index(str, chars_to_keep_at_front);
auto remove_up_to_bytes =
utf8_char_to_byte_index(str, chars_to_keep_at_front + chars_to_remove);
auto bytes_to_keep_at_front
= utf8_char_to_byte_index(str, chars_to_keep_at_front);
auto remove_up_to_bytes = utf8_char_to_byte_index(
str, chars_to_keep_at_front + chars_to_remove);
auto bytes_to_remove = remove_up_to_bytes - bytes_to_keep_at_front;
str.erase(bytes_to_keep_at_front, bytes_to_remove);
str.insert(bytes_to_keep_at_front, ELLIPSIS);
}
bool is_url(const char *fn)
bool
is_url(const char* fn)
{
static const auto url_re = std::regex("^(file|https?|ftps?|scp|sftp):.*");
return std::regex_match(fn, url_re);
}
size_t abbreviate_str(char *str, size_t len, size_t max_len)
size_t
abbreviate_str(char* str, size_t len, size_t max_len)
{
size_t last_start = 1;
@ -184,7 +189,8 @@ size_t abbreviate_str(char *str, size_t len, size_t max_len)
return len;
}
void split_ws(const std::string &str, std::vector<std::string> &toks_out)
void
split_ws(const std::string& str, std::vector<std::string>& toks_out)
{
std::stringstream ss(str);
std::string buf;
@ -194,14 +200,16 @@ void split_ws(const std::string &str, std::vector<std::string> &toks_out)
}
}
std::string repeat(const std::string& input, size_t num)
std::string
repeat(const std::string& input, size_t num)
{
std::ostringstream os;
std::fill_n(std::ostream_iterator<std::string>(os), num, input);
return os.str();
}
std::string center_str(const std::string &subject, size_t width)
std::string
center_str(const std::string& subject, size_t width)
{
std::string retval = subject;
@ -219,18 +227,23 @@ std::string center_str(const std::string &subject, size_t width)
}
template<typename T>
size_t strtonum(T &num_out, const char *string, size_t len)
size_t
strtonum(T& num_out, const char* string, size_t len)
{
size_t retval = 0;
T sign = 1;
num_out = 0;
for (; retval < len && isspace(string[retval]); retval++);
for (; retval < len && isspace(string[retval]); retval++) {
;
}
for (; retval < len && string[retval] == '-'; retval++) {
sign *= -1;
}
for (; retval < len && string[retval] == '+'; retval++);
for (; retval < len && string[retval] == '+'; retval++) {
;
}
for (; retval < len && isdigit(string[retval]); retval++) {
num_out *= 10;
num_out += string[retval] - '0';
@ -240,11 +253,10 @@ size_t strtonum(T &num_out, const char *string, size_t len)
return retval;
}
template
size_t strtonum<long long>(long long &num_out, const char *string, size_t len);
template size_t strtonum<long long>(long long& num_out,
const char* string,
size_t len);
template
size_t strtonum<long>(long &num_out, const char *string, size_t len);
template size_t strtonum<long>(long& num_out, const char* string, size_t len);
template
size_t strtonum<int>(int &num_out, const char *string, size_t len);
template size_t strtonum<int>(int& num_out, const char* string, size_t len);

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,38 +30,45 @@
#ifndef lnav_string_util_hh
#define lnav_string_util_hh
#include <string.h>
#include <string>
#include <vector>
#include <string.h>
#include "ww898/cp_utf8.hpp"
void scrub_to_utf8(char *buffer, size_t length);
void scrub_to_utf8(char* buffer, size_t length);
inline bool is_line_ending(char ch) {
inline bool
is_line_ending(char ch)
{
return ch == '\r' || ch == '\n';
}
size_t unquote(char *dst, const char *str, size_t len);
size_t unquote(char* dst, const char* str, size_t len);
size_t unquote_w3c(char *dst, const char *str, size_t len);
size_t unquote_w3c(char* dst, const char* str, size_t len);
inline bool startswith(const char *str, const char *prefix)
inline bool
startswith(const char* str, const char* prefix)
{
return strncmp(str, prefix, strlen(prefix)) == 0;
}
inline bool startswith(const std::string &str, const char *prefix)
inline bool
startswith(const std::string& str, const char* prefix)
{
return startswith(str.c_str(), prefix);
}
inline bool startswith(const std::string &str, const std::string& prefix)
inline bool
startswith(const std::string& str, const std::string& prefix)
{
return startswith(str.c_str(), prefix.c_str());
}
inline bool endswith(const char *str, const char *suffix)
inline bool
endswith(const char* str, const char* suffix)
{
size_t len = strlen(str), suffix_len = strlen(suffix);
@ -73,7 +80,8 @@ inline bool endswith(const char *str, const char *suffix)
}
template<int N>
inline bool endswith(const std::string& str, const char (&suffix) [N])
inline bool
endswith(const std::string& str, const char (&suffix)[N])
{
if (N - 1 > str.length()) {
return false;
@ -82,19 +90,23 @@ inline bool endswith(const std::string& str, const char (&suffix) [N])
return strcmp(&str[str.size() - (N - 1)], suffix) == 0;
}
void truncate_to(std::string &str, size_t max_char_len);
void truncate_to(std::string& str, size_t max_char_len);
inline std::string trim(const std::string &str)
inline std::string
trim(const std::string& str)
{
std::string::size_type start, end;
for (start = 0; start < str.size() && isspace(str[start]); start++);
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--);
for (start = 0; start < str.size() && isspace(str[start]); start++)
;
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--)
;
return str.substr(start, end - start);
}
inline std::string tolower(const char *str)
inline std::string
tolower(const char* str)
{
std::string retval;
@ -105,12 +117,14 @@ inline std::string tolower(const char *str)
return retval;
}
inline std::string tolower(const std::string &str)
inline std::string
tolower(const std::string& str)
{
return tolower(str.c_str());
}
inline std::string toupper(const char *str)
inline std::string
toupper(const char* str)
{
std::string retval;
@ -121,19 +135,22 @@ inline std::string toupper(const char *str)
return retval;
}
inline std::string toupper(const std::string &str)
inline std::string
toupper(const std::string& str)
{
return toupper(str.c_str());
}
inline ssize_t utf8_char_to_byte_index(const std::string &str, ssize_t ch_index)
inline ssize_t
utf8_char_to_byte_index(const std::string& str, ssize_t ch_index)
{
ssize_t retval = 0;
while (ch_index > 0) {
auto ch_len = ww898::utf::utf8::char_size([&str, retval]() {
return std::make_pair(str[retval], str.length() - retval - 1);
}).unwrapOr(1);
auto ch_len
= ww898::utf::utf8::char_size([&str, retval]() {
return std::make_pair(str[retval], str.length() - retval - 1);
}).unwrapOr(1);
retval += ch_len;
ch_index -= 1;
@ -142,7 +159,8 @@ inline ssize_t utf8_char_to_byte_index(const std::string &str, ssize_t ch_index)
return retval;
}
inline Result<size_t, const char *> utf8_string_length(const char *str, ssize_t len = -1)
inline Result<size_t, const char*>
utf8_string_length(const char* str, ssize_t len = -1)
{
size_t retval = 0;
@ -151,9 +169,10 @@ inline Result<size_t, const char *> utf8_string_length(const char *str, ssize_t
}
for (ssize_t byte_index = 0; byte_index < len;) {
auto ch_size = TRY(ww898::utf::utf8::char_size([str, len, byte_index]() {
return std::make_pair(str[byte_index], len - byte_index);
}));
auto ch_size
= TRY(ww898::utf::utf8::char_size([str, len, byte_index]() {
return std::make_pair(str[byte_index], len - byte_index);
}));
byte_index += ch_size;
retval += 1;
}
@ -161,22 +180,23 @@ inline Result<size_t, const char *> utf8_string_length(const char *str, ssize_t
return Ok(retval);
}
inline Result<size_t, const char *> utf8_string_length(const std::string& str)
inline Result<size_t, const char*>
utf8_string_length(const std::string& str)
{
return utf8_string_length(str.c_str(), str.length());
}
bool is_url(const char *fn);
bool is_url(const char* fn);
size_t abbreviate_str(char *str, size_t len, size_t max_len);
size_t abbreviate_str(char* str, size_t len, size_t max_len);
void split_ws(const std::string &str, std::vector<std::string> &toks_out);
void split_ws(const std::string& str, std::vector<std::string>& toks_out);
std::string repeat(const std::string& input, size_t num);
std::string center_str(const std::string& subject, size_t width);
template<typename T>
size_t strtonum(T &num_out, const char *data, size_t len);
size_t strtonum(T& num_out, const char* data, size_t len);
#endif

@ -21,22 +21,21 @@
* 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
* 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 <iostream>
#include "doctest/doctest.h"
#include "base/string_util.hh"
#include "base/strnatcmp.h"
#include "base/string_util.hh"
#include "config.h"
#include "doctest/doctest.h"
TEST_CASE ("endswith")
TEST_CASE("endswith")
{
std::string hw("hello");
@ -44,7 +43,7 @@ TEST_CASE ("endswith")
CHECK(endswith(hw, "lo") == true);
}
TEST_CASE ("truncate_to")
TEST_CASE("truncate_to")
{
const std::string orig = "0123456789abcdefghijklmnopqrstuvwxyz";
std::string str;
@ -74,16 +73,17 @@ TEST_CASE ("truncate_to")
CHECK(str == "01\u22efyz");
}
TEST_CASE("strnatcmp") {
TEST_CASE("strnatcmp")
{
{
constexpr const char *n1 = "010";
constexpr const char *n2 = "020";
constexpr const char* n1 = "010";
constexpr const char* n2 = "020";
CHECK(strnatcmp(strlen(n1), n1, strlen(n2), n2) < 0);
}
{
constexpr const char *n1 = "2";
constexpr const char *n2 = "10";
constexpr const char* n1 = "2";
constexpr const char* n2 = "10";
CHECK(strnatcmp(strlen(n1), n1, strlen(n2), n2) < 0);
}

@ -21,8 +21,8 @@
* 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
* 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.
*/

@ -21,27 +21,29 @@
* 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
* 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 <chrono>
#include "time_util.hh"
#include "config.h"
static time_t BAD_DATE = -1;
time_t tm2sec(const struct tm *t)
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 };
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;
@ -57,7 +59,7 @@ time_t tm2sec(const struct tm *t)
/* Find number of days since 1st March 1900 (in the Gregorian calendar). */
days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
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 */
@ -65,15 +67,16 @@ time_t tm2sec(const struct tm *t)
if (secs < 0) {
return BAD_DATE;
} /* must have overflowed */
else {
} /* 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 */
} /* must be a valid time */
}
static const int SECSPERMIN = 60;
@ -86,19 +89,16 @@ 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
};
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 },
{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 }
};
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
void secs2wday(const struct timeval &tv, struct tm *res)
void
secs2wday(const struct timeval& tv, struct tm* res)
{
long days, rem;
time_t lcltime;
@ -118,21 +118,21 @@ void secs2wday(const struct timeval &tv, struct tm *res)
res->tm_wday += DAYSPERWEEK;
}
struct tm *secs2tm(lnav::time64_t tim, struct tm *res)
struct tm*
secs2tm(lnav::time64_t tim, struct tm* res)
{
long days, rem;
lnav::time64_t lcltime;
int y;
int yleap;
const unsigned short int *ip;
const unsigned short int* ip;
/* base decision about std/dst time on current time */
lcltime = tim;
days = ((long)lcltime) / SECSPERDAY;
rem = ((long)lcltime) % SECSPERDAY;
while (rem < 0)
{
days = ((long) lcltime) / SECSPERDAY;
rem = ((long) lcltime) % SECSPERDAY;
while (rem < 0) {
rem += SECSPERDAY;
--days;
}
@ -149,21 +149,16 @@ struct tm *secs2tm(lnav::time64_t tim, struct tm *res)
/* compute year & day of year */
y = EPOCH_YEAR;
if (days >= 0)
{
for (;;)
{
if (days >= 0) {
for (;;) {
yleap = isleap(y);
if (days < year_lengths[yleap])
break;
y++;
days -= year_lengths[yleap];
}
}
else
{
do
{
} else {
do {
--y;
yleap = isleap(y);
days += year_lengths[yleap];
@ -184,14 +179,15 @@ struct tm *secs2tm(lnav::time64_t tim, struct tm *res)
return (res);
}
struct timeval exttm::to_timeval() const
struct timeval
exttm::to_timeval() const
{
struct timeval retval;
retval.tv_sec = tm2sec(&this->et_tm);
retval.tv_usec =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::nanoseconds(this->et_nsec)).count();
retval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::nanoseconds(this->et_nsec))
.count();
return retval;
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,11 +30,13 @@
#ifndef lnav_time_util_hh
#define lnav_time_util_hh
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <inttypes.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include "config.h"
namespace lnav {
@ -42,18 +44,19 @@ using time64_t = uint64_t;
}
struct tm *secs2tm(lnav::time64_t tim, struct tm *res);
struct tm* secs2tm(lnav::time64_t tim, struct tm* res);
/**
* Convert the time stored in a 'tm' struct into epoch time.
*
* @param t The 'tm' structure to convert to epoch time.
* @return The given time in seconds since the epoch.
*/
time_t tm2sec(const struct tm *t);
void secs2wday(const struct timeval &tv, struct tm *res);
time_t tm2sec(const struct tm* t);
void secs2wday(const struct timeval& tv, struct tm* res);
inline
time_t convert_log_time_to_local(time_t value) {
inline time_t
convert_log_time_to_local(time_t value)
{
struct tm tm;
localtime_r(&value, &tm);
@ -88,37 +91,41 @@ struct exttm {
unsigned int et_flags;
long et_gmtoff;
bool operator==(const exttm &other) const {
bool operator==(const exttm& other) const
{
return memcmp(this, &other, sizeof(exttm)) == 0;
};
struct timeval to_timeval() const;
};
inline
bool operator<(const struct timeval &left, time_t right) {
inline bool
operator<(const struct timeval& left, time_t right)
{
return left.tv_sec < right;
}
inline
bool operator<(time_t left, const struct timeval &right) {
inline bool
operator<(time_t left, const struct timeval& right)
{
return left < right.tv_sec;
}
inline
bool operator<(const struct timeval &left, const struct timeval &right) {
return left.tv_sec < right.tv_sec ||
((left.tv_sec == right.tv_sec) && (left.tv_usec < right.tv_usec));
inline bool
operator<(const struct timeval& left, const struct timeval& right)
{
return left.tv_sec < right.tv_sec
|| ((left.tv_sec == right.tv_sec) && (left.tv_usec < right.tv_usec));
}
inline
bool operator!=(const struct timeval &left, const struct timeval &right) {
return left.tv_sec != right.tv_sec ||
left.tv_usec != right.tv_usec;
inline bool
operator!=(const struct timeval& left, const struct timeval& right)
{
return left.tv_sec != right.tv_sec || left.tv_usec != right.tv_usec;
}
inline
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
inline struct timeval
operator-(const struct timeval& lhs, const struct timeval& rhs)
{
struct timeval diff;
@ -128,7 +135,9 @@ struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
typedef int64_t mstime_t;
inline mstime_t getmstime() {
inline mstime_t
getmstime()
{
struct timeval tv;
gettimeofday(&tv, nullptr);
@ -136,7 +145,9 @@ inline mstime_t getmstime() {
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
}
inline struct timeval current_timeval() {
inline struct timeval
current_timeval()
{
struct timeval retval;
gettimeofday(&retval, nullptr);
@ -144,7 +155,9 @@ inline struct timeval current_timeval() {
return retval;
}
inline struct timespec current_timespec() {
inline struct timespec
current_timespec()
{
struct timespec retval;
clock_gettime(CLOCK_REALTIME, &retval);
@ -152,12 +165,14 @@ inline struct timespec current_timespec() {
return retval;
}
inline time_t day_num(time_t ti)
inline time_t
day_num(time_t ti)
{
return ti / (24 * 60 * 60);
}
inline time_t hour_num(time_t ti)
inline time_t
hour_num(time_t ti)
{
return ti / (60 * 60);
}

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -33,6 +33,7 @@
#define lnav_big_array_hh
#include <sys/mman.h>
#include <unistd.h>
#include "base/math_util.hh"
@ -40,11 +41,13 @@ template<typename T>
struct big_array {
static const size_t DEFAULT_INCREMENT = 100 * 1000;
big_array() : ba_ptr(nullptr), ba_size(0), ba_capacity(0) {
big_array()
: ba_ptr(nullptr), ba_size(0), ba_capacity(0){
};
};
bool reserve(size_t size) {
bool reserve(size_t size)
{
if (size < this->ba_capacity) {
return false;
}
@ -55,67 +58,77 @@ struct big_array {
}
this->ba_capacity = size + DEFAULT_INCREMENT;
void *result = mmap(nullptr,
roundup_size(this->ba_capacity * sizeof(T),
getpagesize()),
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE,
-1,
0);
void* result
= mmap(nullptr,
roundup_size(this->ba_capacity * sizeof(T), getpagesize()),
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
ensure(result != MAP_FAILED);
this->ba_ptr = (T *) result;
this->ba_ptr = (T*) result;
return true;
};
void clear() {
void clear()
{
this->ba_size = 0;
};
size_t size() const {
size_t size() const
{
return this->ba_size;
};
void shrink_to(size_t new_size) {
void shrink_to(size_t new_size)
{
require(new_size <= this->ba_size);
this->ba_size = new_size;
}
bool empty() const {
bool empty() const
{
return this->ba_size == 0;
};
void push_back(const T &val) {
void push_back(const T& val)
{
this->ba_ptr[this->ba_size] = val;
this->ba_size += 1;
};
T &operator[](size_t index) {
T& operator[](size_t index)
{
return this->ba_ptr[index];
};
const T &operator[](size_t index) const {
const T& operator[](size_t index) const
{
return this->ba_ptr[index];
};
T &back() {
T& back()
{
return this->ba_ptr[this->ba_size - 1];
}
typedef T *iterator;
typedef T* iterator;
iterator begin() {
iterator begin()
{
return this->ba_ptr;
};
iterator end() {
iterator end()
{
return this->ba_ptr + this->ba_size;
};
T *ba_ptr;
T* ba_ptr;
size_t ba_size;
size_t ba_capacity;
};

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,21 +32,24 @@
#ifndef lnav_bin2c_hh
#define lnav_bin2c_hh
#include <zlib.h>
#include <memory>
#include <assert.h>
#include <sys/types.h>
#include <memory>
#include <zlib.h>
#include "base/intern_string.hh"
struct bin_src_file {
bin_src_file(const char *name, const unsigned char *data,
size_t compressed_size, size_t size)
bin_src_file(const char* name,
const unsigned char* data,
size_t compressed_size,
size_t size)
: bsf_name(name), bsf_data(new unsigned char[size + 1]), bsf_size(size)
{
uLongf zsize = size;
auto rc = uncompress(this->bsf_data.get(), &zsize, data, compressed_size);
auto rc
= uncompress(this->bsf_data.get(), &zsize, data, compressed_size);
assert(rc == Z_OK);
assert(zsize == size);
this->bsf_data[size] = '\0';
@ -57,13 +60,13 @@ struct bin_src_file {
return string_fragment{this->bsf_data.get(), 0, (int) this->bsf_size};
}
const char *get_name() const
const char* get_name() const
{
return this->bsf_name;
}
private:
const char *bsf_name;
const char* bsf_name;
std::unique_ptr<unsigned char[]> bsf_data;
ssize_t bsf_size;
};

@ -21,18 +21,18 @@
* 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
* 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 bookmarks.cc
*/
#include "config.h"
#include "bookmarks.hh"
#include "config.h"
using namespace std;
set<string> bookmark_metadata::KNOWN_TAGS;

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,11 +32,11 @@
#ifndef bookmarks_hh
#define bookmarks_hh
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <algorithm>
#include "base/lnav_log.hh"
@ -47,18 +47,18 @@ struct bookmark_metadata {
std::string bm_comment;
std::vector<std::string> bm_tags;
void add_tag(const std::string &tag) {
if (std::find(this->bm_tags.begin(),
this->bm_tags.end(),
tag) == this->bm_tags.end()) {
void add_tag(const std::string& tag)
{
if (std::find(this->bm_tags.begin(), this->bm_tags.end(), tag)
== this->bm_tags.end())
{
this->bm_tags.push_back(tag);
}
};
bool remove_tag(const std::string &tag) {
auto iter = std::find(this->bm_tags.begin(),
this->bm_tags.end(),
tag);
bool remove_tag(const std::string& tag)
{
auto iter = std::find(this->bm_tags.begin(), this->bm_tags.end(), tag);
bool retval = false;
if (iter != this->bm_tags.end()) {
@ -68,13 +68,14 @@ struct bookmark_metadata {
return retval;
};
bool empty() const {
return this->bm_name.empty() &&
this->bm_comment.empty() &&
this->bm_tags.empty();
bool empty() const
{
return this->bm_name.empty() && this->bm_comment.empty()
&& this->bm_tags.empty();
};
void clear() {
void clear()
{
this->bm_comment.clear();
this->bm_tags.clear();
};
@ -98,9 +99,9 @@ class bookmark_vector : public std::vector<LineType> {
typedef std::vector<LineType> base_vector;
public:
typedef typename base_vector::size_type size_type;
typedef typename base_vector::iterator iterator;
typedef typename base_vector::const_iterator const_iterator;
typedef typename base_vector::size_type size_type;
typedef typename base_vector::iterator iterator;
typedef typename base_vector::const_iterator const_iterator;
/**
* Insert a bookmark into this vector, but only if it is not already in the
@ -118,15 +119,15 @@ public:
if (lb == this->end() || *lb != vl) {
this->insert(lb, vl);
retval = this->end();
}
else {
} else {
retval = lb;
}
return retval;
};
std::pair<iterator, iterator> equal_range(LineType start, LineType stop) {
std::pair<iterator, iterator> equal_range(LineType start, LineType stop)
{
auto lb = std::lower_bound(this->begin(), this->end(), start);
if (stop == LineType(-1)) {
@ -163,19 +164,22 @@ public:
*/
class bookmark_type_t {
public:
typedef std::vector<bookmark_type_t *>::iterator type_iterator;
typedef std::vector<bookmark_type_t*>::iterator type_iterator;
static type_iterator type_begin() {
static type_iterator type_begin()
{
return get_all_types().begin();
};
static type_iterator type_end() {
static type_iterator type_end()
{
return get_all_types().end();
};
static bookmark_type_t *find_type(const std::string &name) {
static bookmark_type_t* find_type(const std::string& name)
{
auto iter = find_if(type_begin(), type_end(), mark_eq(name));
bookmark_type_t *retval = nullptr;
bookmark_type_t* retval = nullptr;
if (iter != type_end()) {
retval = (*iter);
@ -183,36 +187,41 @@ public:
return retval;
};
static std::vector<bookmark_type_t *> &get_all_types() {
static std::vector<bookmark_type_t *> all_types;
static std::vector<bookmark_type_t*>& get_all_types()
{
static std::vector<bookmark_type_t*> all_types;
return all_types;
};
explicit bookmark_type_t(std::string name) : bt_name(std::move(name)) {
explicit bookmark_type_t(std::string name) : bt_name(std::move(name))
{
get_all_types().push_back(this);
};
const std::string &get_name() const {
const std::string& get_name() const
{
return this->bt_name;
};
private:
struct mark_eq {
explicit mark_eq(const std::string &name) : me_name(name) { };
explicit mark_eq(const std::string& name) : me_name(name){};
bool operator()(bookmark_type_t *bt) {
bool operator()(bookmark_type_t* bt)
{
return bt->bt_name == this->me_name;
};
const std::string &me_name;
const std::string& me_name;
};
const std::string bt_name;
};
template<typename LineType>
LineType bookmark_vector<LineType>::next(LineType start) const
LineType
bookmark_vector<LineType>::next(LineType start) const
{
LineType retval(-1);
@ -229,7 +238,8 @@ LineType bookmark_vector<LineType>::next(LineType start) const
}
template<typename LineType>
LineType bookmark_vector<LineType>::prev(LineType start) const
LineType
bookmark_vector<LineType>::prev(LineType start) const
{
LineType retval(-1);
@ -237,7 +247,7 @@ LineType bookmark_vector<LineType>::prev(LineType start) const
auto lb = lower_bound(this->cbegin(), this->cend(), start);
if (lb != this->cbegin()) {
lb -= 1;
lb -= 1;
retval = *lb;
}
@ -251,7 +261,7 @@ LineType bookmark_vector<LineType>::prev(LineType start) const
*/
template<typename LineType>
struct bookmarks {
typedef std::map<bookmark_type_t *, bookmark_vector<LineType> > type;
typedef std::map<const bookmark_type_t*, bookmark_vector<LineType> > type;
};
#endif

@ -21,16 +21,15 @@
* 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
* 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 "bottom_status_source.hh"
#include "config.h"
bottom_status_source::bottom_status_source()
{
@ -59,22 +58,22 @@ bottom_status_source::bottom_status_source()
this->bss_line_error.set_share(1);
}
void bottom_status_source::update_line_number(listview_curses *lc)
void
bottom_status_source::update_line_number(listview_curses* lc)
{
status_field &sf = this->bss_fields[BSF_LINE_NUMBER];
status_field& sf = this->bss_fields[BSF_LINE_NUMBER];
if (lc->get_inner_height() == 0) {
sf.set_value(" L0");
}
else {
} else {
sf.set_value(" L%'d", (int) lc->get_top());
}
if (lc->get_inner_height() > 0) {
std::vector<attr_line_t> rows(1);
lc->get_data_source()->
listview_value_for_rows(*lc, lc->get_top(), rows);
lc->get_data_source()->listview_value_for_rows(
*lc, lc->get_top(), rows);
auto& sa = rows[0].get_attrs();
auto iter = find_string_attr(sa, &SA_ERROR);
if (iter != sa.end()) {
@ -87,9 +86,10 @@ void bottom_status_source::update_line_number(listview_curses *lc)
}
}
void bottom_status_source::update_search_term(textview_curses &tc)
void
bottom_status_source::update_search_term(textview_curses& tc)
{
auto &sf = this->bss_fields[BSF_SEARCH_TERM];
auto& sf = this->bss_fields[BSF_SEARCH_TERM];
auto search_term = tc.get_current_search();
if (search_term.empty()) {
@ -102,74 +102,73 @@ void bottom_status_source::update_search_term(textview_curses &tc)
this->update_loading(0, 0);
}
void bottom_status_source::update_percent(listview_curses *lc)
void
bottom_status_source::update_percent(listview_curses* lc)
{
status_field &sf = this->bss_fields[BSF_PERCENT];
vis_line_t top = lc->get_top();
vis_line_t bottom, height;
status_field& sf = this->bss_fields[BSF_PERCENT];
vis_line_t top = lc->get_top();
vis_line_t bottom, height;
unsigned long width;
double percent;
double percent;
lc->get_dimensions(height, width);
if (lc->get_inner_height() > 0) {
bottom = std::min(top + height - vis_line_t(1),
vis_line_t(lc->get_inner_height() - 1));
percent = (double)(bottom + 1);
percent /= (double)lc->get_inner_height();
percent = (double) (bottom + 1);
percent /= (double) lc->get_inner_height();
percent *= 100.0;
}
else {
} else {
percent = 0.0;
}
sf.set_value("%3d%% ", (int)percent);
sf.set_value("%3d%% ", (int) percent);
}
void bottom_status_source::update_marks(listview_curses *lc)
void
bottom_status_source::update_marks(listview_curses* lc)
{
auto *tc = static_cast<textview_curses *>(lc);
vis_bookmarks &bm = tc->get_bookmarks();
status_field &sf = this->bss_fields[BSF_HITS];
auto* tc = static_cast<textview_curses*>(lc);
vis_bookmarks& bm = tc->get_bookmarks();
status_field& sf = this->bss_fields[BSF_HITS];
if (bm.find(&textview_curses::BM_SEARCH) != bm.end()) {
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_SEARCH];
bookmark_vector<vis_line_t>& bv = bm[&textview_curses::BM_SEARCH];
if (!bv.empty() || !tc->get_current_search().empty()) {
bookmark_vector<vis_line_t>::iterator lb;
lb = std::lower_bound(bv.begin(), bv.end(), tc->get_top());
if (lb != bv.end() && *lb == tc->get_top()) {
sf.set_value(
" Hit %'d of %'d for ",
std::distance(bv.begin(), lb) + 1, tc->get_match_count());
sf.set_value(" Hit %'d of %'d for ",
std::distance(bv.begin(), lb) + 1,
tc->get_match_count());
} else {
sf.set_value(" %'d hits for ", tc->get_match_count());
}
} else {
sf.clear();
}
}
else {
} else {
sf.clear();
}
}
void bottom_status_source::update_hits(textview_curses *tc)
void
bottom_status_source::update_hits(textview_curses* tc)
{
status_field & sf = this->bss_fields[BSF_HITS];
status_field& sf = this->bss_fields[BSF_HITS];
view_colors::role_t new_role;
if (tc->is_searching()) {
this->bss_hit_spinner += 1;
if (this->bss_hit_spinner % 2) {
new_role = view_colors::VCR_ACTIVE_STATUS;
}
else{
} else {
new_role = view_colors::VCR_ACTIVE_STATUS2;
}
sf.set_cylon(true);
}
else {
} else {
new_role = view_colors::VCR_STATUS;
sf.set_cylon(false);
}
@ -178,13 +177,14 @@ void bottom_status_source::update_hits(textview_curses *tc)
this->update_marks(tc);
}
void bottom_status_source::update_loading(file_off_t off, file_size_t total)
void
bottom_status_source::update_loading(file_off_t off, file_size_t total)
{
auto &sf = this->bss_fields[BSF_LOADING];
auto& sf = this->bss_fields[BSF_LOADING];
require(off >= 0);
if (total == 0 || (size_t)off == total) {
if (total == 0 || (size_t) off == total) {
sf.set_cylon(false);
sf.set_role(view_colors::VCR_STATUS);
if (this->bss_paused) {
@ -192,9 +192,8 @@ void bottom_status_source::update_loading(file_off_t off, file_size_t total)
} else {
sf.clear();
}
}
else {
int pct = (int)(((double)off / (double)total) * 100.0);
} else {
int pct = (int) (((double) off / (double) total) * 100.0);
if (this->bss_load_percent != pct) {
this->bss_load_percent = pct;
@ -206,34 +205,32 @@ void bottom_status_source::update_loading(file_off_t off, file_size_t total)
}
}
size_t bottom_status_source::statusview_fields()
size_t
bottom_status_source::statusview_fields()
{
size_t retval;
if (this->bss_prompt.empty() &&
this->bss_error.empty() &&
this->bss_line_error.empty()) {
if (this->bss_prompt.empty() && this->bss_error.empty()
&& this->bss_line_error.empty())
{
retval = BSF__MAX;
}
else{
} else {
retval = 1;
}
return retval;
}
status_field &bottom_status_source::statusview_value_for_field(int field)
status_field&
bottom_status_source::statusview_value_for_field(int field)
{
if (!this->bss_error.empty()) {
return this->bss_error;
}
else if (!this->bss_prompt.empty()) {
} else if (!this->bss_prompt.empty()) {
return this->bss_prompt;
}
else if (!this->bss_line_error.empty()) {
} else if (!this->bss_line_error.empty()) {
return this->bss_line_error;
}
else {
return this->get_field((field_t)field);
} else {
return this->get_field((field_t) field);
}
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -33,12 +33,12 @@
#include <string>
#include "grep_proc.hh"
#include "textview_curses.hh"
#include "statusview_curses.hh"
#include "textview_curses.hh"
class bottom_status_source
: public status_data_source,
public grep_proc_control {
: public status_data_source
, public grep_proc_control {
public:
typedef enum {
BSF_LINE_NUMBER,
@ -53,9 +53,12 @@ public:
bottom_status_source();
status_field &get_field(field_t id) { return this->bss_fields[id]; };
status_field& get_field(field_t id)
{
return this->bss_fields[id];
};
void set_prompt(const std::string &prompt)
void set_prompt(const std::string& prompt)
{
this->bss_prompt.set_value(prompt);
};
@ -67,17 +70,17 @@ public:
size_t statusview_fields() override;
status_field &statusview_value_for_field(int field) override;
status_field& statusview_value_for_field(int field) override;
void update_line_number(listview_curses *lc);
void update_line_number(listview_curses* lc);
void update_search_term(textview_curses &tc);
void update_search_term(textview_curses& tc);
void update_percent(listview_curses *lc);
void update_percent(listview_curses* lc);
void update_marks(listview_curses *lc);
void update_marks(listview_curses* lc);
void update_hits(textview_curses *tc);
void update_hits(textview_curses* tc);
void update_loading(file_off_t off, file_size_t total);
@ -86,9 +89,9 @@ private:
status_field bss_error{1024, view_colors::VCR_ALERT_STATUS};
status_field bss_line_error{1024, view_colors::VCR_ALERT_STATUS};
status_field bss_fields[BSF__MAX];
int bss_hit_spinner{0};
int bss_load_percent{0};
bool bss_paused{false};
int bss_hit_spinner{0};
int bss_load_percent{0};
bool bss_paused{false};
};
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,10 +32,13 @@
#ifndef lnav_bound_tags_hh
#define lnav_bound_tags_hh
struct last_relative_time_tag {};
struct last_relative_time_tag {
};
struct sqlite_db_tag {};
struct sqlite_db_tag {
};
struct sql_cmd_map_tag {};
struct sql_cmd_map_tag {
};
#endif

@ -21,21 +21,21 @@
* 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
* 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 byte_array_hh
#define byte_array_hh
#include <ostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <string>
#include <ostream>
#include "base/lnav_log.hh"
template<size_t COUNT, typename T = unsigned char>
@ -43,24 +43,24 @@ struct byte_array {
static constexpr size_t BYTE_COUNT = COUNT * sizeof(T);
static constexpr size_t STRING_SIZE = BYTE_COUNT * 2 + 1;
byte_array() { };
byte_array(){};
byte_array(const byte_array &other)
byte_array(const byte_array& other)
{
memcpy(this->ba_data, other.ba_data, BYTE_COUNT);
};
bool operator<(const byte_array &other) const
bool operator<(const byte_array& other) const
{
return memcmp(this->ba_data, other.ba_data, BYTE_COUNT) < 0;
};
bool operator!=(const byte_array &other) const
bool operator!=(const byte_array& other) const
{
return memcmp(this->ba_data, other.ba_data, BYTE_COUNT) != 0;
};
bool operator==(const byte_array &other) const
bool operator==(const byte_array& other) const
{
return memcmp(this->ba_data, other.ba_data, BYTE_COUNT) == 0;
};
@ -70,7 +70,7 @@ struct byte_array {
memset(this->ba_data, 0, BYTE_COUNT);
};
void to_string(char *buffer) const
void to_string(char* buffer) const
{
require(buffer != nullptr);
@ -87,10 +87,14 @@ struct byte_array {
return std::string(buffer);
}
const unsigned char *in() const { return this->ba_data; };
const unsigned char* in() const
{
return this->ba_data;
};
T *out(int offset = 0) {
T *ptr = (T *)this->ba_data;
T* out(int offset = 0)
{
T* ptr = (T*) this->ba_data;
return &ptr[offset];
};
@ -99,7 +103,8 @@ struct byte_array {
};
template<size_t COUNT, typename T = unsigned char>
std::ostream& operator<<(std::ostream& os, const byte_array<COUNT, T>& ba)
std::ostream&
operator<<(std::ostream& os, const byte_array<COUNT, T>& ba)
{
os << ba.to_string();
return os;

@ -21,34 +21,33 @@
* 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
* 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 logfile_sub_source.hh
*/
#include "config.h"
#include <string.h>
#include <sqlite3.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sqlite3.h>
#include <string.h>
#include <sys/socket.h>
#include "log_level.hh"
#include "base/strnatcmp.h"
#include "config.h"
#include "log_level.hh"
#define MAX_ADDR_LEN 128
#define MAX_ADDR_LEN 128
static int try_inet_pton(int p_len, const char *p, char *n)
static int
try_inet_pton(int p_len, const char* p, char* n)
{
static int ADDR_FAMILIES[] = { AF_INET, AF_INET6 };
static int ADDR_FAMILIES[] = {AF_INET, AF_INET6};
char buf[MAX_ADDR_LEN + 1];
int retval = AF_MAX;
int retval = AF_MAX;
strncpy(buf, p, p_len);
buf[p_len] = '\0';
@ -62,13 +61,14 @@ static int try_inet_pton(int p_len, const char *p, char *n)
return retval;
}
static int convert_v6_to_v4(int family, char *n)
static int
convert_v6_to_v4(int family, char* n)
{
struct in6_addr *ia = (struct in6_addr *)n;
struct in6_addr* ia = (struct in6_addr*) n;
if (family == AF_INET6 &&
(IN6_IS_ADDR_V4COMPAT(ia) ||
IN6_IS_ADDR_V4MAPPED(ia))) {
if (family == AF_INET6
&& (IN6_IS_ADDR_V4COMPAT(ia) || IN6_IS_ADDR_V4MAPPED(ia)))
{
family = AF_INET;
memmove(n, n + 12, sizeof(struct in_addr));
}
@ -76,15 +76,12 @@ static int convert_v6_to_v4(int family, char *n)
return family;
}
static
int ipaddress(void *ptr,
int a_len, const void *a_in,
int b_len, const void *b_in)
static int
ipaddress(void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
{
char a_addr[sizeof(struct in6_addr)],
b_addr[sizeof(struct in6_addr)];
const char *a_str = (const char *)a_in, *b_str = (const char *)b_in;
int a_family, b_family, retval;
char a_addr[sizeof(struct in6_addr)], b_addr[sizeof(struct in6_addr)];
const char *a_str = (const char*) a_in, *b_str = (const char*) b_in;
int a_family, b_family, retval;
if ((a_len > MAX_ADDR_LEN) || (b_len > MAX_ADDR_LEN)) {
return strnatcasecmp(a_len, a_str, b_len, b_str);
@ -100,26 +97,21 @@ int ipaddress(void *ptr,
if (a_family == AF_MAX && b_family == AF_MAX) {
return strnatcasecmp(a_len, a_str, b_len, b_str);
}
else if (a_family == AF_MAX && b_family != AF_MAX) {
} else if (a_family == AF_MAX && b_family != AF_MAX) {
retval = -1;
}
else if (a_family != AF_MAX && b_family == AF_MAX) {
} else if (a_family != AF_MAX && b_family == AF_MAX) {
retval = 1;
}
else {
} else {
a_family = convert_v6_to_v4(a_family, a_addr);
b_family = convert_v6_to_v4(b_family, b_addr);
if (a_family == b_family) {
retval = memcmp(a_addr, b_addr,
a_family == AF_INET ?
sizeof(struct in_addr) :
sizeof(struct in6_addr));
}
else if (a_family == AF_INET) {
retval = memcmp(a_addr,
b_addr,
a_family == AF_INET ? sizeof(struct in_addr)
: sizeof(struct in6_addr));
} else if (a_family == AF_INET) {
retval = -1;
}
else {
} else {
retval = 1;
}
}
@ -127,40 +119,37 @@ int ipaddress(void *ptr,
return retval;
}
static
int sql_strnatcmp(void *ptr,
int a_len, const void *a_in,
int b_len, const void *b_in)
static int
sql_strnatcmp(
void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
{
return strnatcmp(a_len, (char *)a_in, b_len, (char *)b_in);
return strnatcmp(a_len, (char*) a_in, b_len, (char*) b_in);
}
static
int sql_strnatcasecmp(void *ptr,
int a_len, const void *a_in,
int b_len, const void *b_in)
static int
sql_strnatcasecmp(
void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
{
return strnatcasecmp(a_len, (char *)a_in, b_len, (char *)b_in);
return strnatcasecmp(a_len, (char*) a_in, b_len, (char*) b_in);
}
static
int sql_loglevelcmp(void *ptr,
int a_len, const void *a_in,
int b_len, const void *b_in)
static int
sql_loglevelcmp(
void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
{
return levelcmp((const char *)a_in, a_len,
(const char *)b_in, b_len);
return levelcmp((const char*) a_in, a_len, (const char*) b_in, b_len);
}
int register_collation_functions(sqlite3 *db)
int
register_collation_functions(sqlite3* db)
{
sqlite3_create_collation(db, "ipaddress", SQLITE_UTF8, nullptr, ipaddress);
sqlite3_create_collation(db, "naturalcase", SQLITE_UTF8, nullptr,
sql_strnatcmp);
sqlite3_create_collation(db, "naturalnocase", SQLITE_UTF8, nullptr,
sql_strnatcasecmp);
sqlite3_create_collation(db, "loglevel", SQLITE_UTF8, nullptr,
sql_loglevelcmp);
sqlite3_create_collation(
db, "naturalcase", SQLITE_UTF8, nullptr, sql_strnatcmp);
sqlite3_create_collation(
db, "naturalnocase", SQLITE_UTF8, nullptr, sql_strnatcasecmp);
sqlite3_create_collation(
db, "loglevel", SQLITE_UTF8, nullptr, sql_loglevelcmp);
return 0;
}

@ -21,52 +21,55 @@
* 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
* 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 column_namer.cc
*/
#include "config.h"
#include <algorithm>
#include "base/string_util.hh"
#include "sql_util.hh"
#include "column_namer.hh"
#include "base/lnav_log.hh"
#include "column_namer.hh"
#include "base/string_util.hh"
#include "config.h"
#include "sql_util.hh"
bool column_namer::existing_name(const std::string &in_name) const
bool
column_namer::existing_name(const std::string& in_name) const
{
if (std::binary_search(std::begin(sql_keywords),
std::end(sql_keywords),
toupper(in_name))) {
if (std::binary_search(
std::begin(sql_keywords), std::end(sql_keywords), toupper(in_name)))
{
return true;
}
if (std::find(this->cn_builtin_names.begin(),
this->cn_builtin_names.end(),
in_name) != this->cn_builtin_names.end()) {
in_name)
!= this->cn_builtin_names.end())
{
return true;
}
if (std::find(this->cn_names.begin(),
this->cn_names.end(),
in_name) != this->cn_names.end()) {
if (std::find(this->cn_names.begin(), this->cn_names.end(), in_name)
!= this->cn_names.end())
{
return true;
}
return false;
}
std::string column_namer::add_column(const std::string &in_name)
std::string
column_namer::add_column(const std::string& in_name)
{
std::string base_name = in_name, retval;
size_t buf_size;
int num = 0;
size_t buf_size;
int num = 0;
buf_size = in_name.length() + 64;
char buffer[buf_size];

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -33,16 +33,16 @@
#define lnav_column_namer_hh
#include <string>
#include <vector>
#include <unordered_map>
#include <vector>
class column_namer {
public:
column_namer() : cn_builtin_names({"col"}) {}
bool existing_name(const std::string &in_name) const;
bool existing_name(const std::string& in_name) const;
std::string add_column(const std::string &in_name);
std::string add_column(const std::string& in_name);
std::vector<std::string> cn_builtin_names;
std::vector<std::string> cn_names;

@ -21,32 +21,31 @@
* 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
* 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 <vector>
#include "command_executor.hh"
#include "base/fs_util.hh"
#include "base/string_util.hh"
#include "base/injector.hh"
#include "yajlpp/json_ptr.hh"
#include "base/string_util.hh"
#include "bound_tags.hh"
#include "config.h"
#include "db_sub_source.hh"
#include "lnav.hh"
#include "lnav_config.hh"
#include "lnav_util.hh"
#include "log_format_loader.hh"
#include "papertrail_proc.hh"
#include "service_tags.hh"
#include "shlex.hh"
#include "lnav_util.hh"
#include "sql_util.hh"
#include "lnav_config.hh"
#include "service_tags.hh"
#include "bound_tags.hh"
#include "command_executor.hh"
#include "db_sub_source.hh"
#include "papertrail_proc.hh"
#include "yajlpp/json_ptr.hh"
using namespace std;
@ -59,12 +58,13 @@ SELECT count(*) AS total, min(log_line) AS log_line, log_msg_format
ORDER BY total DESC
)";
int sql_progress(const struct log_cursor &lc)
int
sql_progress(const struct log_cursor& lc)
{
static sig_atomic_t sql_counter = 0;
size_t total = lnav_data.ld_log_source.text_line_count();
off_t off = lc.lc_curr_line;
off_t off = lc.lc_curr_line;
if (off < 0) {
return 0;
@ -89,7 +89,8 @@ int sql_progress(const struct log_cursor &lc)
return 0;
}
void sql_progress_finished()
void
sql_progress_finished()
{
if (lnav_data.ld_window == nullptr) {
return;
@ -102,9 +103,14 @@ void sql_progress_finished()
lnav_data.ld_views[LNV_DB].redo_search();
}
Result<string, string> execute_from_file(exec_context &ec, const ghc::filesystem::path &path, int line_number, char mode, const string &cmdline);
Result<string, string> execute_from_file(exec_context& ec,
const ghc::filesystem::path& path,
int line_number,
char mode,
const string& cmdline);
Result<string, string> execute_command(exec_context &ec, const string &cmdline)
Result<string, string>
execute_command(exec_context& ec, const string& cmdline)
{
vector<string> args;
@ -117,8 +123,7 @@ Result<string, string> execute_command(exec_context &ec, const string &cmdline)
if ((iter = lnav_commands.find(args[0])) == lnav_commands.end()) {
return ec.make_error("unknown command - {}", args[0]);
}
else {
} else {
return iter->second->c_func(ec, cmdline, args);
}
}
@ -126,9 +131,10 @@ Result<string, string> execute_command(exec_context &ec, const string &cmdline)
return ec.make_error("no command to execute");
}
Result<string, string> execute_sql(exec_context &ec, const string &sql, string &alt_msg)
Result<string, string>
execute_sql(exec_context& ec, const string& sql, string& alt_msg)
{
db_label_source &dls = lnav_data.ld_db_row_source;
db_label_source& dls = lnav_data.ld_db_row_source;
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
struct timeval start_tv, end_tv;
string stmt_str = trim(sql);
@ -143,8 +149,8 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
vector<string> args;
split_ws(stmt_str, args);
auto sql_cmd_map = injector::get<
readline_context::command_map_t *, sql_cmd_map_tag>();
auto sql_cmd_map = injector::get<readline_context::command_map_t*,
sql_cmd_map_tag>();
auto cmd_iter = sql_cmd_map->find(args[0]);
if (cmd_iter != sql_cmd_map->end()) {
@ -159,40 +165,36 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
ec.ec_accumulator->clear();
pair<string, int> source = ec.ec_source.top();
sql_progress_guard progress_guard(sql_progress,
sql_progress_finished,
source.first,
source.second);
sql_progress_guard progress_guard(
sql_progress, sql_progress_finished, source.first, source.second);
gettimeofday(&start_tv, nullptr);
retcode = sqlite3_prepare_v2(lnav_data.ld_db.in(),
stmt_str.c_str(),
-1,
stmt.out(),
nullptr);
retcode = sqlite3_prepare_v2(
lnav_data.ld_db.in(), stmt_str.c_str(), -1, stmt.out(), nullptr);
if (retcode != SQLITE_OK) {
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
const char* errmsg = sqlite3_errmsg(lnav_data.ld_db);
alt_msg = "";
return ec.make_error("{}", errmsg);
}
else if (stmt == nullptr) {
} else if (stmt == nullptr) {
alt_msg = "";
return ec.make_error("No statement given");
}
#ifdef HAVE_SQLITE3_STMT_READONLY
else if (ec.is_read_only() && !sqlite3_stmt_readonly(stmt.in())) {
else if (ec.is_read_only() && !sqlite3_stmt_readonly(stmt.in()))
{
return ec.make_error(
"modifying statements are not allowed in this context: {}", sql);
}
#endif
else {
else
{
bool done = false;
int param_count;
param_count = sqlite3_bind_parameter_count(stmt.in());
for (int lpc = 0; lpc < param_count; lpc++) {
map<string, string>::iterator ov_iter;
const char *name;
const char* name;
name = sqlite3_bind_parameter_name(stmt.in(), lpc + 1);
ov_iter = ec.ec_override.find(name);
@ -202,12 +204,11 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
ov_iter->second.c_str(),
ov_iter->second.length(),
SQLITE_TRANSIENT);
}
else if (name[0] == '$') {
const auto &lvars = ec.ec_local_vars.top();
const auto &gvars = ec.ec_global_vars;
} else if (name[0] == '$') {
const auto& lvars = ec.ec_local_vars.top();
const auto& gvars = ec.ec_global_vars;
map<string, string>::const_iterator local_var, global_var;
const char *env_value;
const char* env_value;
if (lnav_data.ld_window) {
char buf[32];
@ -216,45 +217,48 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
getmaxyx(lnav_data.ld_window, lines, cols);
if (strcmp(name, "$LINES") == 0) {
snprintf(buf, sizeof(buf), "%d", lines);
sqlite3_bind_text(stmt.in(), lpc + 1,
buf, -1,
SQLITE_TRANSIENT);
sqlite3_bind_text(
stmt.in(), lpc + 1, buf, -1, SQLITE_TRANSIENT);
} else if (strcmp(name, "$COLS") == 0) {
snprintf(buf, sizeof(buf), "%d", cols);
sqlite3_bind_text(stmt.in(), lpc + 1,
buf, -1,
SQLITE_TRANSIENT);
sqlite3_bind_text(
stmt.in(), lpc + 1, buf, -1, SQLITE_TRANSIENT);
}
}
if ((local_var = lvars.find(&name[1])) != lvars.end()) {
sqlite3_bind_text(stmt.in(), lpc + 1,
local_var->second.c_str(), -1,
sqlite3_bind_text(stmt.in(),
lpc + 1,
local_var->second.c_str(),
-1,
SQLITE_TRANSIENT);
}
else if ((global_var = gvars.find(&name[1])) != gvars.end()) {
sqlite3_bind_text(stmt.in(), lpc + 1,
global_var->second.c_str(), -1,
} else if ((global_var = gvars.find(&name[1])) != gvars.end()) {
sqlite3_bind_text(stmt.in(),
lpc + 1,
global_var->second.c_str(),
-1,
SQLITE_TRANSIENT);
} else if ((env_value = getenv(&name[1])) != nullptr) {
sqlite3_bind_text(
stmt.in(), lpc + 1, env_value, -1, SQLITE_STATIC);
}
else if ((env_value = getenv(&name[1])) != nullptr) {
sqlite3_bind_text(stmt.in(), lpc + 1, env_value, -1, SQLITE_STATIC);
}
}
else if (name[0] == ':' && ec.ec_line_values != nullptr) {
} else if (name[0] == ':' && ec.ec_line_values != nullptr) {
for (auto& lv : *ec.ec_line_values) {
if (lv.lv_meta.lvm_name != &name[1]) {
continue;
}
switch (lv.lv_meta.lvm_kind) {
case value_kind_t::VALUE_BOOLEAN:
sqlite3_bind_int64(stmt.in(), lpc + 1, lv.lv_value.i);
sqlite3_bind_int64(
stmt.in(), lpc + 1, lv.lv_value.i);
break;
case value_kind_t::VALUE_FLOAT:
sqlite3_bind_double(stmt.in(), lpc + 1, lv.lv_value.d);
sqlite3_bind_double(
stmt.in(), lpc + 1, lv.lv_value.d);
break;
case value_kind_t::VALUE_INTEGER:
sqlite3_bind_int64(stmt.in(), lpc + 1, lv.lv_value.i);
sqlite3_bind_int64(
stmt.in(), lpc + 1, lv.lv_value.i);
break;
case value_kind_t::VALUE_NULL:
sqlite3_bind_null(stmt.in(), lpc + 1);
@ -268,8 +272,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
break;
}
}
}
else {
} else {
sqlite3_bind_null(stmt.in(), lpc + 1);
log_warning("Could not bind variable: %s", name);
}
@ -294,7 +297,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
break;
default: {
const char *errmsg;
const char* errmsg;
log_error("sqlite3_step error code: %d", retcode);
errmsg = sqlite3_errmsg(lnav_data.ld_db);
@ -304,12 +307,12 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
}
}
if (!dls.dls_rows.empty() && !ec.ec_local_vars.empty() &&
!ec.ec_dry_run) {
auto &vars = ec.ec_local_vars.top();
if (!dls.dls_rows.empty() && !ec.ec_local_vars.empty()
&& !ec.ec_dry_run) {
auto& vars = ec.ec_local_vars.top();
for (unsigned int lpc = 0; lpc < dls.dls_headers.size(); lpc++) {
const auto &column_name = dls.dls_headers[lpc].hm_name;
const auto& column_name = dls.dls_headers[lpc].hm_name;
if (sql_ident_needs_quote(column_name.c_str())) {
continue;
@ -342,8 +345,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
if (!ec.ec_accumulator->empty()) {
retval = ec.ec_accumulator->get_string();
}
else if (!dls.dls_rows.empty()) {
} else if (!dls.dls_rows.empty()) {
if (lnav_data.ld_flags & LNF_HEADLESS) {
if (ec.ec_local_vars.size() == 1) {
ensure_view(&lnav_data.ld_views[LNV_DB]);
@ -351,14 +353,14 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
retval = "";
alt_msg = "";
}
else if (dls.dls_rows.size() == 1) {
auto &row = dls.dls_rows[0];
} else if (dls.dls_rows.size() == 1) {
auto& row = dls.dls_rows[0];
if (dls.dls_headers.size() == 1) {
retval = row[0];
} else {
for (unsigned int lpc = 0; lpc < dls.dls_headers.size(); lpc++) {
for (unsigned int lpc = 0; lpc < dls.dls_headers.size();
lpc++) {
if (lpc > 0) {
retval.append("; ");
}
@ -367,29 +369,31 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
retval.append(row[lpc]);
}
}
}
else {
} else {
int row_count = dls.dls_rows.size();
char row_count_buf[128];
struct timeval diff_tv;
timersub(&end_tv, &start_tv, &diff_tv);
snprintf(row_count_buf, sizeof(row_count_buf),
ANSI_BOLD("%'d") " row%s matched in "
ANSI_BOLD("%ld.%03ld") " seconds",
snprintf(row_count_buf,
sizeof(row_count_buf),
ANSI_BOLD("%'d") " row%s matched in " ANSI_BOLD(
"%ld.%03ld") " seconds",
row_count,
row_count == 1 ? "" : "s",
diff_tv.tv_sec,
std::max((long) diff_tv.tv_usec / 1000, 1L));
retval = row_count_buf;
alt_msg = HELP_MSG_2(
y, Y,
y,
Y,
"to move forward/backward through query results "
"in the log view");
"in the log view");
}
}
#ifdef HAVE_SQLITE3_STMT_READONLY
else if (sqlite3_stmt_readonly(stmt.in())) {
else if (sqlite3_stmt_readonly(stmt.in()))
{
retval = "info: No rows matched";
alt_msg = "";
@ -405,25 +409,27 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
return Ok(retval);
}
static Result<string, string> execute_file_contents(exec_context &ec, const ghc::filesystem::path &path, bool multiline)
static Result<string, string>
execute_file_contents(exec_context& ec,
const ghc::filesystem::path& path,
bool multiline)
{
static ghc::filesystem::path stdin_path("-");
static ghc::filesystem::path dev_stdin_path("/dev/stdin");
string retval;
FILE *file;
FILE* file;
if (path == stdin_path || path == dev_stdin_path) {
if (isatty(STDIN_FILENO)) {
return ec.make_error("stdin has already been consumed");
}
file = stdin;
}
else if ((file = fopen(path.c_str(), "r")) == nullptr) {
} else if ((file = fopen(path.c_str(), "r")) == nullptr) {
return ec.make_error("unable to open file");
}
int line_number = 0, starting_line_number = 0;
int line_number = 0, starting_line_number = 0;
auto_mem<char> line;
size_t line_max_size;
ssize_t line_size;
@ -448,7 +454,8 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
case ';':
case '|':
if (mode) {
retval = TRY(execute_from_file(ec, path, starting_line_number, mode, trim(cmdline)));
retval = TRY(execute_from_file(
ec, path, starting_line_number, mode, trim(cmdline)));
}
starting_line_number = line_number;
@ -458,17 +465,17 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
default:
if (multiline) {
cmdline += line;
}
else {
retval = TRY(execute_from_file(ec, path, line_number, ':', line.in()));
} else {
retval = TRY(execute_from_file(
ec, path, line_number, ':', line.in()));
}
break;
}
}
if (mode) {
retval = TRY(execute_from_file(ec, path, starting_line_number, mode, trim(cmdline)));
retval = TRY(execute_from_file(
ec, path, starting_line_number, mode, trim(cmdline)));
}
if (file == stdin) {
@ -483,7 +490,8 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
return Ok(retval);
}
Result<string, string> execute_file(exec_context &ec, const string &path_and_args, bool multiline)
Result<string, string>
execute_file(exec_context& ec, const string& path_and_args, bool multiline)
{
available_scripts scripts;
vector<string> split_args;
@ -508,8 +516,8 @@ Result<string, string> execute_file(exec_context &ec, const string &path_and_arg
add_ansi_vars(vars);
snprintf(env_arg_name, sizeof(env_arg_name), "%d",
(int) split_args.size() - 1);
snprintf(
env_arg_name, sizeof(env_arg_name), "%d", (int) split_args.size() - 1);
vars["#"] = env_arg_name;
for (size_t lpc = 0; lpc < split_args.size(); lpc++) {
@ -560,22 +568,27 @@ Result<string, string> execute_file(exec_context &ec, const string &path_and_arg
}
if (!paths_to_exec.empty()) {
for (auto &path_iter : paths_to_exec) {
retval = TRY(
execute_file_contents(ec, path_iter.sm_path, multiline));
for (auto& path_iter : paths_to_exec) {
retval
= TRY(execute_file_contents(ec, path_iter.sm_path, multiline));
}
}
ec.ec_local_vars.pop();
if (paths_to_exec.empty()) {
return ec.make_error("unknown script -- {} -- {}",
script_name, open_error);
return ec.make_error(
"unknown script -- {} -- {}", script_name, open_error);
}
return Ok(retval);
}
Result<string, string> execute_from_file(exec_context &ec, const ghc::filesystem::path &path, int line_number, char mode, const string &cmdline)
Result<string, string>
execute_from_file(exec_context& ec,
const ghc::filesystem::path& path,
int line_number,
char mode,
const string& cmdline)
{
string retval, alt_msg;
auto _sg = ec.enter_source(path.string(), line_number);
@ -585,9 +598,8 @@ Result<string, string> execute_from_file(exec_context &ec, const ghc::filesystem
retval = TRY(execute_command(ec, cmdline));
break;
case '/':
lnav_data.ld_view_stack.top() | [cmdline] (auto tc) {
tc->execute_search(cmdline.substr(1));
};
lnav_data.ld_view_stack.top() |
[cmdline](auto tc) { tc->execute_search(cmdline.substr(1)); };
break;
case ';':
setup_logline_table(ec);
@ -609,15 +621,16 @@ Result<string, string> execute_from_file(exec_context &ec, const ghc::filesystem
return Ok(retval);
}
Result<string, string> execute_any(exec_context &ec, const string &cmdline_with_mode)
Result<string, string>
execute_any(exec_context& ec, const string& cmdline_with_mode)
{
string retval, alt_msg, cmdline = cmdline_with_mode.substr(1);
auto _cleanup = finally([&ec] {
if (ec.is_read_write() &&
// only rebuild in a script or non-interactive mode so we don't
// block the UI.
(lnav_data.ld_flags & LNF_HEADLESS ||
ec.ec_path_stack.size() > 1)) {
(lnav_data.ld_flags & LNF_HEADLESS || ec.ec_path_stack.size() > 1))
{
rescan_files();
rebuild_indexes_repeatedly();
}
@ -628,9 +641,8 @@ Result<string, string> execute_any(exec_context &ec, const string &cmdline_with_
retval = TRY(execute_command(ec, cmdline));
break;
case '/':
lnav_data.ld_view_stack.top() | [cmdline] (auto tc) {
tc->execute_search(cmdline.substr(1));
};
lnav_data.ld_view_stack.top() |
[cmdline](auto tc) { tc->execute_search(cmdline.substr(1)); };
break;
case ';':
setup_logline_table(ec);
@ -648,38 +660,40 @@ Result<string, string> execute_any(exec_context &ec, const string &cmdline_with_
return Ok(retval);
}
void execute_init_commands(exec_context &ec, vector<pair<Result<string, string>, string> > &msgs)
void
execute_init_commands(exec_context& ec,
vector<pair<Result<string, string>, string> >& msgs)
{
if (lnav_data.ld_cmd_init_done) {
return;
}
db_label_source &dls = lnav_data.ld_db_row_source;
db_label_source& dls = lnav_data.ld_db_row_source;
int option_index = 1;
log_info("Executing initial commands");
for (auto &cmd : lnav_data.ld_commands) {
for (auto& cmd : lnav_data.ld_commands) {
string alt_msg;
wait_for_children();
ec.ec_source.emplace("command-option", option_index++);
switch (cmd.at(0)) {
case ':':
msgs.emplace_back(execute_command(ec, cmd.substr(1)), alt_msg);
break;
case '/':
lnav_data.ld_view_stack.top() | [cmd] (auto tc) {
tc->execute_search(cmd.substr(1));
};
break;
case ';':
setup_logline_table(ec);
msgs.emplace_back(execute_sql(ec, cmd.substr(1), alt_msg), alt_msg);
break;
case '|':
msgs.emplace_back(execute_file(ec, cmd.substr(1)), alt_msg);
break;
case ':':
msgs.emplace_back(execute_command(ec, cmd.substr(1)), alt_msg);
break;
case '/':
lnav_data.ld_view_stack.top() |
[cmd](auto tc) { tc->execute_search(cmd.substr(1)); };
break;
case ';':
setup_logline_table(ec);
msgs.emplace_back(execute_sql(ec, cmd.substr(1), alt_msg),
alt_msg);
break;
case '|':
msgs.emplace_back(execute_file(ec, cmd.substr(1)), alt_msg);
break;
}
rescan_files();
@ -691,16 +705,13 @@ void execute_init_commands(exec_context &ec, vector<pair<Result<string, string>,
if (!lnav_data.ld_pt_search.empty()) {
#ifdef HAVE_LIBCURL
auto pt = make_shared<papertrail_proc>(
lnav_data.ld_pt_search.substr(3),
lnav_data.ld_pt_min_time,
lnav_data.ld_pt_max_time);
lnav_data.ld_active_files.fc_file_names[lnav_data.ld_pt_search]
.with_fd(pt->copy_fd());
isc::to<curl_looper&, services::curl_streamer_t>()
.send([pt](auto& clooper) {
clooper.add_request(pt);
});
auto pt = make_shared<papertrail_proc>(lnav_data.ld_pt_search.substr(3),
lnav_data.ld_pt_min_time,
lnav_data.ld_pt_max_time);
lnav_data.ld_active_files.fc_file_names[lnav_data.ld_pt_search].with_fd(
pt->copy_fd());
isc::to<curl_looper&, services::curl_streamer_t>().send(
[pt](auto& clooper) { clooper.add_request(pt); });
#endif
}
@ -711,9 +722,10 @@ void execute_init_commands(exec_context &ec, vector<pair<Result<string, string>,
lnav_data.ld_cmd_init_done = true;
}
int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
int
sql_callback(exec_context& ec, sqlite3_stmt* stmt)
{
auto &dls = lnav_data.ld_db_row_source;
auto& dls = lnav_data.ld_db_row_source;
if (!sqlite3_stmt_busy(stmt)) {
dls.clear();
@ -721,8 +733,8 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
return 0;
}
stacked_bar_chart<std::string> &chart = dls.dls_chart;
view_colors &vc = view_colors::singleton();
stacked_bar_chart<std::string>& chart = dls.dls_chart;
view_colors& vc = view_colors::singleton();
int ncols = sqlite3_column_count(stmt);
int row_number;
int lpc, retval = 0;
@ -731,14 +743,14 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
dls.dls_rows.resize(row_number + 1);
if (dls.dls_headers.empty()) {
for (lpc = 0; lpc < ncols; lpc++) {
int type = sqlite3_column_type(stmt, lpc);
int type = sqlite3_column_type(stmt, lpc);
string colname = sqlite3_column_name(stmt, lpc);
bool graphable;
bool graphable;
graphable = ((type == SQLITE_INTEGER || type == SQLITE_FLOAT) &&
!binary_search(lnav_data.ld_db_key_names.begin(),
lnav_data.ld_db_key_names.end(),
colname));
graphable = ((type == SQLITE_INTEGER || type == SQLITE_FLOAT)
&& !binary_search(lnav_data.ld_db_key_names.begin(),
lnav_data.ld_db_key_names.end(),
colname));
dls.push_header(colname, type, graphable);
if (graphable) {
@ -748,13 +760,15 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
}
}
for (lpc = 0; lpc < ncols; lpc++) {
const char *value = (const char *)sqlite3_column_text(stmt, lpc);
db_label_source::header_meta &hm = dls.dls_headers[lpc];
const char* value = (const char*) sqlite3_column_text(stmt, lpc);
db_label_source::header_meta& hm = dls.dls_headers[lpc];
dls.push_column(value);
if ((hm.hm_column_type == SQLITE_TEXT ||
hm.hm_column_type == SQLITE_NULL) && hm.hm_sub_type == 0) {
sqlite3_value *raw_value = sqlite3_column_value(stmt, lpc);
if ((hm.hm_column_type == SQLITE_TEXT
|| hm.hm_column_type == SQLITE_NULL)
&& hm.hm_sub_type == 0)
{
sqlite3_value* raw_value = sqlite3_column_value(stmt, lpc);
switch (sqlite3_value_type(raw_value)) {
case SQLITE_TEXT:
@ -768,12 +782,13 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
return retval;
}
future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &fd)
future<string>
pipe_callback(exec_context& ec, const string& cmdline, auto_fd& fd)
{
auto out = ec.get_output();
if (out) {
FILE *file = *out;
FILE* file = *out;
return std::async(std::launch::async, [&fd, file]() {
char buffer[1024];
@ -791,8 +806,10 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
});
} else {
auto pp = make_shared<piper_proc>(
fd, false, lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.out.XXXXXX")
fd,
false,
lnav::filesystem::open_temp_file(
ghc::filesystem::temp_directory_path() / "lnav.out.XXXXXX")
.map([](auto pair) {
ghc::filesystem::remove(pair.first);
@ -805,7 +822,8 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
lnav_data.ld_pipers.push_back(pp);
snprintf(desc,
sizeof(desc), "[%d] Output of %s",
sizeof(desc),
"[%d] Output of %s",
exec_count++,
cmdline.c_str());
lnav_data.ld_active_files.fc_file_names[desc]
@ -822,9 +840,10 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
}
}
void add_global_vars(exec_context &ec)
void
add_global_vars(exec_context& ec)
{
for (const auto &iter : lnav_config.lc_global_vars) {
for (const auto& iter : lnav_config.lc_global_vars) {
shlex subber(iter.second);
string str;
@ -838,7 +857,8 @@ void add_global_vars(exec_context &ec)
}
}
std::string exec_context::get_error_prefix()
std::string
exec_context::get_error_prefix()
{
if (this->ec_source.size() <= 1) {
return "error: ";
@ -849,7 +869,8 @@ std::string exec_context::get_error_prefix()
return fmt::format("{}:{}: error: ", source.first, source.second);
}
void exec_context::set_output(const string &name, FILE *file, int (*closer)(FILE *))
void
exec_context::set_output(const string& name, FILE* file, int (*closer)(FILE*))
{
log_info("redirecting command output to: %s", name.c_str());
this->ec_output_stack.back().second | [](auto out) {
@ -857,10 +878,12 @@ void exec_context::set_output(const string &name, FILE *file, int (*closer)(FILE
out.second(out.first);
}
};
this->ec_output_stack.back() = std::make_pair(name, std::make_pair(file, closer));
this->ec_output_stack.back()
= std::make_pair(name, std::make_pair(file, closer));
}
void exec_context::clear_output()
void
exec_context::clear_output()
{
log_info("redirecting command output to screen");
this->ec_output_stack.back().second | [](auto out) {
@ -871,23 +894,24 @@ void exec_context::clear_output()
this->ec_output_stack.back() = std::make_pair("default", nonstd::nullopt);
}
exec_context::exec_context(std::vector<logline_value> *line_values,
exec_context::exec_context(std::vector<logline_value>* line_values,
sql_callback_t sql_callback,
pipe_callback_t pipe_callback)
: ec_line_values(line_values),
ec_accumulator(std::make_unique<attr_line_t>()),
ec_sql_callback(sql_callback),
ec_pipe_callback(pipe_callback) {
ec_sql_callback(sql_callback), ec_pipe_callback(pipe_callback)
{
this->ec_local_vars.push(std::map<std::string, std::string>());
this->ec_path_stack.emplace_back(".");
this->ec_source.emplace("command", 1);
this->ec_output_stack.emplace_back("screen", nonstd::nullopt);
}
exec_context::output_guard::output_guard(exec_context &context,
exec_context::output_guard::output_guard(exec_context& context,
std::string name,
const nonstd::optional<output_t> &file)
: sg_context(context) {
const nonstd::optional<output_t>& file)
: sg_context(context)
{
if (file) {
log_info("redirecting command output to: %s", name.c_str());
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,26 +30,30 @@
#ifndef LNAV_COMMAND_EXECUTOR_H
#define LNAV_COMMAND_EXECUTOR_H
#include <sqlite3.h>
#include <future>
#include <stack>
#include <string>
#include "fmt/format.h"
#include "optional.hpp"
#include <sqlite3.h>
#include "auto_fd.hh"
#include "bookmarks.hh"
#include "fmt/format.h"
#include "ghc/filesystem.hpp"
#include "optional.hpp"
#include "shlex.resolver.hh"
#include "vis_line.hh"
struct exec_context;
class attr_line_t;
class logline_value;
typedef int (*sql_callback_t)(exec_context &ec, sqlite3_stmt *stmt);
int sql_callback(exec_context &ec, sqlite3_stmt *stmt);
typedef int (*sql_callback_t)(exec_context& ec, sqlite3_stmt* stmt);
int sql_callback(exec_context& ec, sqlite3_stmt* stmt);
typedef std::future<std::string> (*pipe_callback_t)(
exec_context &ec, const std::string &cmdline, auto_fd &fd);
typedef std::future<std::string> (*pipe_callback_t)(exec_context& ec,
const std::string& cmdline,
auto_fd& fd);
struct exec_context {
enum class perm_t {
@ -57,38 +61,44 @@ struct exec_context {
READ_ONLY,
};
using output_t = std::pair<FILE *, int(*)(FILE *)>;
using output_t = std::pair<FILE*, int (*)(FILE*)>;
exec_context(std::vector<logline_value> *line_values = nullptr,
exec_context(std::vector<logline_value>* line_values = nullptr,
sql_callback_t sql_callback = ::sql_callback,
pipe_callback_t pipe_callback = nullptr);
bool is_read_write() const {
bool is_read_write() const
{
return this->ec_perms == perm_t::READ_WRITE;
}
bool is_read_only() const {
bool is_read_only() const
{
return this->ec_perms == perm_t::READ_ONLY;
}
exec_context& with_perms(perm_t perms) {
exec_context& with_perms(perm_t perms)
{
this->ec_perms = perms;
return *this;
}
std::string get_error_prefix();
template<typename ...Args>
Result<std::string, std::string> make_error(
fmt::string_view format_str, const Args& ...args) {
return Err(this->get_error_prefix() +
fmt::vformat(format_str, fmt::make_format_args(args...)));
template<typename... Args>
Result<std::string, std::string> make_error(fmt::string_view format_str,
const Args&... args)
{
return Err(this->get_error_prefix()
+ fmt::vformat(format_str, fmt::make_format_args(args...)));
}
nonstd::optional<FILE *> get_output() {
nonstd::optional<FILE*> get_output()
{
for (auto iter = this->ec_output_stack.rbegin();
iter != this->ec_output_stack.rend();
++iter) {
++iter)
{
if (iter->second && (*iter->second).first) {
return (*iter->second).first;
}
@ -97,38 +107,40 @@ struct exec_context {
return nonstd::nullopt;
}
void set_output(const std::string& name, FILE *file, int (*closer)(FILE *));
void set_output(const std::string& name, FILE* file, int (*closer)(FILE*));
void clear_output();
struct source_guard {
source_guard(exec_context &context) : sg_context(context) {
}
source_guard(exec_context& context) : sg_context(context) {}
~source_guard() {
~source_guard()
{
this->sg_context.ec_source.pop();
}
exec_context &sg_context;
exec_context& sg_context;
};
struct output_guard {
explicit output_guard(exec_context &context,
explicit output_guard(exec_context& context,
std::string name = "default",
const nonstd::optional<output_t>& file = nonstd::nullopt);
const nonstd::optional<output_t>& file
= nonstd::nullopt);
~output_guard();
exec_context &sg_context;
exec_context& sg_context;
};
source_guard enter_source(const std::string& path, int line_number) {
source_guard enter_source(const std::string& path, int line_number)
{
this->ec_source.emplace(path, line_number);
return {*this};
}
scoped_resolver create_resolver() {
scoped_resolver create_resolver()
{
return {
&this->ec_local_vars.top(),
&this->ec_global_vars,
@ -140,13 +152,14 @@ struct exec_context {
perm_t ec_perms{perm_t::READ_WRITE};
std::map<std::string, std::string> ec_override;
std::vector<logline_value> *ec_line_values;
std::stack<std::map<std::string, std::string> > ec_local_vars;
std::vector<logline_value>* ec_line_values;
std::stack<std::map<std::string, std::string>> ec_local_vars;
std::map<std::string, std::string> ec_global_vars;
std::vector<ghc::filesystem::path> ec_path_stack;
std::stack<std::pair<std::string, int>> ec_source;
std::vector<std::pair<std::string, nonstd::optional<output_t>>> ec_output_stack;
std::vector<std::pair<std::string, nonstd::optional<output_t>>>
ec_output_stack;
std::unique_ptr<attr_line_t> ec_accumulator;
@ -154,19 +167,29 @@ struct exec_context {
pipe_callback_t ec_pipe_callback;
};
Result<std::string, std::string> execute_command(exec_context &ec, const std::string &cmdline);
Result<std::string, std::string> execute_sql(exec_context &ec, const std::string &sql, std::string &alt_msg);
Result<std::string, std::string> execute_file(exec_context &ec, const std::string &path_and_args, bool multiline = true);
Result<std::string, std::string> execute_any(exec_context &ec, const std::string &cmdline);
void execute_init_commands(exec_context &ec, std::vector<std::pair<Result<std::string, std::string>, std::string> > &msgs);
std::future<std::string> pipe_callback(
exec_context &ec, const std::string &cmdline, auto_fd &fd);
int sql_progress(const struct log_cursor &lc);
Result<std::string, std::string> execute_command(exec_context& ec,
const std::string& cmdline);
Result<std::string, std::string> execute_sql(exec_context& ec,
const std::string& sql,
std::string& alt_msg);
Result<std::string, std::string> execute_file(exec_context& ec,
const std::string& path_and_args,
bool multiline = true);
Result<std::string, std::string> execute_any(exec_context& ec,
const std::string& cmdline);
void execute_init_commands(
exec_context& ec,
std::vector<std::pair<Result<std::string, std::string>, std::string>>&
msgs);
std::future<std::string> pipe_callback(exec_context& ec,
const std::string& cmdline,
auto_fd& fd);
int sql_progress(const struct log_cursor& lc);
void sql_progress_finished();
void add_global_vars(exec_context &ec);
void add_global_vars(exec_context& ec);
#endif //LNAV_COMMAND_EXECUTOR_H
#endif // LNAV_COMMAND_EXECUTOR_H

@ -21,46 +21,47 @@
* 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
* 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 curl_looper.cc
*/
#include "config.h"
#include <algorithm>
#include "config.h"
#if defined(HAVE_LIBCURL)
#include <curl/multi.h>
# include <curl/multi.h>
#include "curl_looper.hh"
# include "curl_looper.hh"
using namespace std;
struct curl_request_eq {
explicit curl_request_eq(const std::string &name) : cre_name(name) {
};
explicit curl_request_eq(const std::string& name) : cre_name(name){};
bool operator()(const std::shared_ptr<curl_request>& cr) const {
bool operator()(const std::shared_ptr<curl_request>& cr) const
{
return this->cre_name == cr->get_name();
};
bool operator()(const pair<mstime_t, std::shared_ptr<curl_request>> &pair) const {
bool operator()(
const pair<mstime_t, std::shared_ptr<curl_request>>& pair) const
{
return this->cre_name == pair.second->get_name();
};
const std::string &cre_name;
const std::string& cre_name;
};
int curl_request::debug_cb(CURL *handle,
curl_infotype type,
char *data,
size_t size,
void *userp) {
curl_request *cr = (curl_request *) userp;
int
curl_request::debug_cb(
CURL* handle, curl_infotype type, char* data, size_t size, void* userp)
{
curl_request* cr = (curl_request*) userp;
bool write_to_log;
switch (type) {
@ -71,8 +72,7 @@ int curl_request::debug_cb(CURL *handle,
case CURLINFO_HEADER_OUT:
if (lnav_log_level == lnav_log_level_t::TRACE) {
write_to_log = true;
}
else {
} else {
write_to_log = false;
}
break;
@ -91,7 +91,8 @@ int curl_request::debug_cb(CURL *handle,
return 0;
}
void curl_looper::loop_body()
void
curl_looper::loop_body()
{
mstime_t current_time = getmstime();
@ -104,7 +105,8 @@ void curl_looper::loop_body()
this->requeue_requests(current_time + 5);
}
void curl_looper::perform_io()
void
curl_looper::perform_io()
{
if (this->cl_handle_to_request.empty()) {
return;
@ -114,57 +116,54 @@ void curl_looper::perform_io()
auto timeout = this->compute_timeout(current_time);
int running_handles;
curl_multi_wait(this->cl_curl_multi,
nullptr,
0,
timeout.count(),
nullptr);
curl_multi_wait(this->cl_curl_multi, nullptr, 0, timeout.count(), nullptr);
curl_multi_perform(this->cl_curl_multi, &running_handles);
}
void curl_looper::requeue_requests(mstime_t up_to_time)
void
curl_looper::requeue_requests(mstime_t up_to_time)
{
while (!this->cl_poll_queue.empty() &&
this->cl_poll_queue.front().first <= up_to_time) {
while (!this->cl_poll_queue.empty()
&& this->cl_poll_queue.front().first <= up_to_time)
{
auto cr = this->cl_poll_queue.front().second;
log_debug("%s:polling request is ready again -- %p",
cr->get_name().c_str(), cr.get());
cr->get_name().c_str(),
cr.get());
this->cl_handle_to_request[cr->get_handle()] = cr;
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
this->cl_poll_queue.erase(this->cl_poll_queue.begin());
}
}
void curl_looper::check_for_new_requests() {
void
curl_looper::check_for_new_requests()
{
while (!this->cl_new_requests.empty()) {
auto cr = this->cl_new_requests.back();
log_info("%s:new curl request %p",
cr->get_name().c_str(),
cr.get());
log_info("%s:new curl request %p", cr->get_name().c_str(), cr.get());
this->cl_handle_to_request[cr->get_handle()] = cr;
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
this->cl_new_requests.pop_back();
}
while (!this->cl_close_requests.empty()) {
const std::string &name = this->cl_close_requests.back();
auto all_iter = find_if(
this->cl_all_requests.begin(),
this->cl_all_requests.end(),
curl_request_eq(name));
const std::string& name = this->cl_close_requests.back();
auto all_iter = find_if(this->cl_all_requests.begin(),
this->cl_all_requests.end(),
curl_request_eq(name));
log_info("attempting to close request -- %s", name.c_str());
if (all_iter != this->cl_all_requests.end()) {
auto cr = *all_iter;
log_info("%s:closing request -- %p",
cr->get_name().c_str(), cr.get());
log_info(
"%s:closing request -- %p", cr->get_name().c_str(), cr.get());
(*all_iter)->close();
auto act_iter = this->cl_handle_to_request.find(cr->get_handle());
if (act_iter != this->cl_handle_to_request.end()) {
curl_multi_remove_handle(this->cl_curl_multi,
cr->get_handle());
curl_multi_remove_handle(this->cl_curl_multi, cr->get_handle());
this->cl_handle_to_request.erase(act_iter);
}
auto poll_iter = find_if(this->cl_poll_queue.begin(),
@ -174,8 +173,7 @@ void curl_looper::check_for_new_requests() {
this->cl_poll_queue.erase(poll_iter);
}
this->cl_all_requests.erase(all_iter);
}
else {
} else {
log_error("Unable to find request with the name -- %s",
name.c_str());
}
@ -184,18 +182,19 @@ void curl_looper::check_for_new_requests() {
}
}
void curl_looper::check_for_finished_requests()
void
curl_looper::check_for_finished_requests()
{
CURLMsg *msg;
CURLMsg* msg;
int msgs_left;
while ((msg = curl_multi_info_read(this->cl_curl_multi, &msgs_left)) !=
nullptr) {
while ((msg = curl_multi_info_read(this->cl_curl_multi, &msgs_left))
!= nullptr) {
if (msg->msg != CURLMSG_DONE) {
continue;
}
CURL *easy = msg->easy_handle;
CURL* easy = msg->easy_handle;
auto iter = this->cl_handle_to_request.find(easy);
curl_multi_remove_handle(this->cl_curl_multi, easy);
@ -207,15 +206,15 @@ void curl_looper::check_for_finished_requests()
delay_ms = cr->complete(msg->data.result);
if (delay_ms < 0) {
log_info("%s:curl_request %p finished, deleting...",
cr->get_name().c_str(), cr.get());
cr->get_name().c_str(),
cr.get());
auto all_iter = find(this->cl_all_requests.begin(),
this->cl_all_requests.end(),
cr);
if (all_iter != this->cl_all_requests.end()) {
this->cl_all_requests.erase(all_iter);
}
}
else {
} else {
log_debug("%s:curl_request %p is polling, requeueing in %d",
cr->get_name().c_str(),
cr.get(),
@ -227,16 +226,18 @@ void curl_looper::check_for_finished_requests()
}
}
std::chrono::milliseconds curl_looper::compute_timeout(mstime_t current_time) const
std::chrono::milliseconds
curl_looper::compute_timeout(mstime_t current_time) const
{
std::chrono::milliseconds retval = 1s;
if (!this->cl_handle_to_request.empty()) {
retval = 1ms;
} else if (!this->cl_poll_queue.empty()) {
retval = std::max(
1ms,
std::chrono::milliseconds(this->cl_poll_queue.front().first - current_time));
retval
= std::max(1ms,
std::chrono::milliseconds(
this->cl_poll_queue.front().first - current_time));
}
ensure(retval.count() > 0);

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,6 +32,8 @@
#ifndef curl_looper_hh
#define curl_looper_hh
#include "config.h"
#include <atomic>
#include <map>
#include <string>
@ -46,95 +48,100 @@ typedef int CURLcode;
class curl_request {
public:
curl_request(const std::string &name) {
};
curl_request(const std::string& name){};
};
class curl_looper : public isc::service<curl_looper> {
public:
void start() { };
void stop() { };
void add_request(std::shared_ptr<curl_request> cr) { };
void close_request(const std::string &name) { };
void process_all() { };
void start(){};
void stop(){};
void add_request(std::shared_ptr<curl_request> cr){};
void close_request(const std::string& name){};
void process_all(){};
};
#else
#include <mutex>
#include <thread>
#include <condition_variable>
# include <condition_variable>
# include <mutex>
# include <thread>
#include <curl/curl.h>
# include <curl/curl.h>
#include "auto_mem.hh"
#include "base/lnav_log.hh"
#include "base/time_util.hh"
# include "auto_mem.hh"
# include "base/lnav_log.hh"
# include "base/time_util.hh"
class curl_request {
public:
curl_request(std::string name)
: cr_name(std::move(name)),
cr_open(true),
cr_handle(curl_easy_cleanup),
cr_completions(0) {
: cr_name(std::move(name)), cr_open(true), cr_handle(curl_easy_cleanup),
cr_completions(0)
{
this->cr_handle.reset(curl_easy_init());
curl_easy_setopt(this->cr_handle, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(this->cr_handle, CURLOPT_ERRORBUFFER, this->cr_error_buffer);
curl_easy_setopt(
this->cr_handle, CURLOPT_ERRORBUFFER, this->cr_error_buffer);
curl_easy_setopt(this->cr_handle, CURLOPT_DEBUGFUNCTION, debug_cb);
curl_easy_setopt(this->cr_handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(this->cr_handle, CURLOPT_VERBOSE, 1);
if (getenv("SSH_AUTH_SOCK") != nullptr) {
curl_easy_setopt(this->cr_handle, CURLOPT_SSH_AUTH_TYPES,
#ifdef CURLSSH_AUTH_AGENT
CURLSSH_AUTH_AGENT|
#endif
CURLSSH_AUTH_PASSWORD);
curl_easy_setopt(this->cr_handle,
CURLOPT_SSH_AUTH_TYPES,
# ifdef CURLSSH_AUTH_AGENT
CURLSSH_AUTH_AGENT |
# endif
CURLSSH_AUTH_PASSWORD);
}
};
virtual ~curl_request() = default;
const std::string &get_name() const {
const std::string& get_name() const
{
return this->cr_name;
};
virtual void close() {
virtual void close()
{
this->cr_open = false;
};
bool is_open() const {
bool is_open() const
{
return this->cr_open;
};
CURL *get_handle() const {
CURL* get_handle() const
{
return this->cr_handle;
};
int get_completions() const {
int get_completions() const
{
return this->cr_completions;
};
virtual long complete(CURLcode result) {
virtual long complete(CURLcode result)
{
double total_time = 0, download_size = 0, download_speed = 0;
this->cr_completions += 1;
curl_easy_getinfo(this->cr_handle, CURLINFO_TOTAL_TIME, &total_time);
log_debug("%s: total_time=%f", this->cr_name.c_str(), total_time);
curl_easy_getinfo(this->cr_handle, CURLINFO_SIZE_DOWNLOAD, &download_size);
curl_easy_getinfo(
this->cr_handle, CURLINFO_SIZE_DOWNLOAD, &download_size);
log_debug("%s: download_size=%f", this->cr_name.c_str(), download_size);
curl_easy_getinfo(this->cr_handle, CURLINFO_SPEED_DOWNLOAD, &download_speed);
log_debug("%s: download_speed=%f", this->cr_name.c_str(), download_speed);
curl_easy_getinfo(
this->cr_handle, CURLINFO_SPEED_DOWNLOAD, &download_speed);
log_debug(
"%s: download_speed=%f", this->cr_name.c_str(), download_speed);
return -1;
};
protected:
static int debug_cb(CURL *handle,
curl_infotype type,
char *data,
size_t size,
void *userp);
static int debug_cb(
CURL* handle, curl_infotype type, char* data, size_t size, void* userp);
const std::string cr_name;
bool cr_open;
@ -145,12 +152,13 @@ protected:
class curl_looper : public isc::service<curl_looper> {
public:
curl_looper()
: cl_curl_multi(curl_multi_cleanup) {
curl_looper() : cl_curl_multi(curl_multi_cleanup)
{
this->cl_curl_multi.reset(curl_multi_init());
};
void process_all() {
void process_all()
{
this->check_for_new_requests();
this->requeue_requests(LONG_MAX);
@ -162,14 +170,16 @@ public:
}
};
void add_request(const std::shared_ptr<curl_request>& cr) {
void add_request(const std::shared_ptr<curl_request>& cr)
{
require(cr != nullptr);
this->cl_all_requests.emplace_back(cr);
this->cl_new_requests.emplace_back(cr);
};
void close_request(const std::string &name) {
void close_request(const std::string& name)
{
this->cl_close_requests.emplace_back(name);
};
@ -181,14 +191,16 @@ private:
void check_for_new_requests();
void check_for_finished_requests();
void requeue_requests(mstime_t up_to_time);
std::chrono::milliseconds compute_timeout(mstime_t current_time) const override;
std::chrono::milliseconds compute_timeout(
mstime_t current_time) const override;
auto_mem<CURLM> cl_curl_multi;
std::vector<std::shared_ptr<curl_request>> cl_all_requests;
std::vector<std::shared_ptr<curl_request>> cl_new_requests;
std::vector<std::shared_ptr<curl_request> > cl_all_requests;
std::vector<std::shared_ptr<curl_request> > cl_new_requests;
std::vector<std::string> cl_close_requests;
std::map<CURL *, std::shared_ptr<curl_request>> cl_handle_to_request;
std::vector<std::pair<mstime_t, std::shared_ptr<curl_request>>> cl_poll_queue;
std::map<CURL*, std::shared_ptr<curl_request> > cl_handle_to_request;
std::vector<std::pair<mstime_t, std::shared_ptr<curl_request> > >
cl_poll_queue;
};
#endif

@ -21,44 +21,44 @@
* 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
* 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 <algorithm>
#include "spookyhash/SpookyV2.h"
#include "data_parser.hh"
#include "config.h"
#include "spookyhash/SpookyV2.h"
using namespace std;
data_format data_parser::FORMAT_SEMI("semi", DT_COMMA, DT_SEMI);
data_format data_parser::FORMAT_COMMA("comma", DT_INVALID, DT_COMMA);
data_format data_parser::FORMAT_PLAIN("plain", DT_INVALID, DT_INVALID);
data_parser::data_parser(data_scanner *ds)
data_parser::data_parser(data_scanner* ds)
: dp_errors("dp_errors", __FILE__, __LINE__),
dp_pairs("dp_pairs", __FILE__, __LINE__),
dp_msg_format(nullptr),
dp_msg_format_begin(ds->get_input().pi_offset),
dp_scanner(ds)
dp_pairs("dp_pairs", __FILE__, __LINE__), dp_msg_format(nullptr),
dp_msg_format_begin(ds->get_input().pi_offset), dp_scanner(ds)
{
if (TRACE_FILE != nullptr) {
fprintf(TRACE_FILE, "input %s\n", ds->get_input().get_string());
}
}
void data_parser::pairup(data_parser::schema_id_t *schema,
data_parser::element_list_t &pairs_out,
data_parser::element_list_t &in_list, int group_depth)
void
data_parser::pairup(data_parser::schema_id_t* schema,
data_parser::element_list_t& pairs_out,
data_parser::element_list_t& in_list,
int group_depth)
{
element_list_t ELEMENT_LIST_T(el_stack), ELEMENT_LIST_T(free_row),
ELEMENT_LIST_T(key_comps), ELEMENT_LIST_T(value),
ELEMENT_LIST_T(prefix);
ELEMENT_LIST_T(key_comps), ELEMENT_LIST_T(value),
ELEMENT_LIST_T(prefix);
SpookyHash context;
require(in_list.el_format.df_name != nullptr);
@ -67,14 +67,12 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
FORMAT_TRACE(in_list);
for (auto iter = in_list.begin();
iter != in_list.end();
++iter) {
for (auto iter = in_list.begin(); iter != in_list.end(); ++iter) {
if (iter->e_token == DNT_GROUP) {
element_list_t ELEMENT_LIST_T(group_pairs);
this->pairup(nullptr, group_pairs, *iter->e_sub_elements,
group_depth + 1);
this->pairup(
nullptr, group_pairs, *iter->e_sub_elements, group_depth + 1);
if (!group_pairs.empty()) {
iter->assign_elements(group_pairs);
}
@ -87,15 +85,13 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
el_stack.PUSH_BACK(*iter);
}
} else if (iter->e_token == in_list.el_format.df_terminator) {
this->end_of_value(el_stack, key_comps, value, in_list,
group_depth);
this->end_of_value(
el_stack, key_comps, value, in_list, group_depth);
key_comps.PUSH_BACK(*iter);
} else if (iter->e_token == in_list.el_format.df_qualifier) {
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
value.SPLICE(
value.end(), key_comps, key_comps.begin(), key_comps.end());
strip(value, element_if(DT_WHITE));
if (!value.empty()) {
el_stack.PUSH_BACK(element(value, DNT_VALUE));
@ -107,8 +103,7 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
if (!key_comps.empty()) {
do {
--key_iter;
if (key_iter->e_token ==
in_list.el_format.df_appender) {
if (key_iter->e_token == in_list.el_format.df_appender) {
++key_iter;
value.SPLICE(value.end(),
key_comps,
@ -116,8 +111,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
key_iter);
key_comps.POP_FRONT();
found = true;
} else if (key_iter->e_token ==
in_list.el_format.df_terminator) {
} else if (key_iter->e_token
== in_list.el_format.df_terminator) {
std::vector<element> key_copy;
value.SPLICE(value.end(),
@ -148,24 +143,21 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
if (!found && !el_stack.empty() && !key_comps.empty()) {
element_list_t::iterator value_iter;
if (el_stack.size() > 1 &&
in_list.el_format.df_appender != DT_INVALID &&
in_list.el_format.df_terminator != DT_INVALID) {
if (el_stack.size() > 1
&& in_list.el_format.df_appender != DT_INVALID
&& in_list.el_format.df_terminator != DT_INVALID)
{
/* If we're expecting a terminator and haven't found it */
/* then this is part of the value. */
continue;
}
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
value.SPLICE(
value.end(), key_comps, key_comps.begin(), key_comps.end());
value_iter = value.end();
std::advance(value_iter, -1);
key_comps.SPLICE(key_comps.begin(),
value,
value_iter,
value.end());
key_comps.SPLICE(
key_comps.begin(), value, value_iter, value.end());
key_comps.resize(1);
}
@ -198,8 +190,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
// Only perform the free-row logic at the top level, if we're in a group
// assume it is a list.
if (group_depth < 1 && el_stack.empty()) {
free_row.SPLICE(free_row.begin(),
key_comps, key_comps.begin(), key_comps.end());
free_row.SPLICE(
free_row.begin(), key_comps, key_comps.begin(), key_comps.end());
} else {
this->end_of_value(el_stack, key_comps, value, in_list, group_depth);
}
@ -216,9 +208,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
element_list_t ELEMENT_LIST_T(free_pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
el_stack.front().e_capture.
c_begin;
blank.e_capture.c_begin = blank.e_capture.c_end
= el_stack.front().e_capture.c_begin;
blank.e_token = DNT_KEY;
free_pair_subs.PUSH_BACK(blank);
free_pair_subs.PUSH_BACK(el_stack.front());
@ -240,8 +231,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
if (schema != nullptr) {
size_t key_len;
const char *key_val =
this->get_element_string(el_stack.front(), key_len);
const char* key_val
= this->get_element_string(el_stack.front(), key_len);
context.Update(key_val, key_len);
}
@ -249,9 +240,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
element_list_t ELEMENT_LIST_T(free_pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
free_row.front().e_capture.
c_begin;
blank.e_capture.c_begin = blank.e_capture.c_end
= free_row.front().e_capture.c_begin;
blank.e_token = DNT_KEY;
free_pair_subs.PUSH_BACK(blank);
free_pair_subs.PUSH_BACK(free_row.front());
@ -266,22 +256,21 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
has_value = true;
}
pair_subs.SPLICE(pair_subs.begin(),
el_stack,
el_stack.begin(),
kv_iter);
pair_subs.SPLICE(
pair_subs.begin(), el_stack, el_stack.begin(), kv_iter);
if (!has_value) {
element_list_t ELEMENT_LIST_T(blank_value);
pcre_input &pi = this->dp_scanner->get_input();
const char *str = pi.get_string();
pcre_input& pi = this->dp_scanner->get_input();
const char* str = pi.get_string();
struct element blank;
blank.e_token = DT_QUOTED_STRING;
blank.e_capture.c_begin = blank.e_capture.c_end =
pair_subs.front().e_capture.c_end;
if ((blank.e_capture.c_begin >= 0) &&
((size_t) blank.e_capture.c_begin < pi.pi_length)) {
blank.e_capture.c_begin = blank.e_capture.c_end
= pair_subs.front().e_capture.c_end;
if ((blank.e_capture.c_begin >= 0)
&& ((size_t) blank.e_capture.c_begin < pi.pi_length))
{
switch (str[blank.e_capture.c_begin]) {
case '=':
case ':':
@ -298,12 +287,12 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
}
if (pairs_out.size() == 1) {
element &pair = pairs_out.front();
element &evalue = pair.e_sub_elements->back();
element& pair = pairs_out.front();
element& evalue = pair.e_sub_elements->back();
if (evalue.e_token == DNT_VALUE &&
evalue.e_sub_elements != nullptr &&
evalue.e_sub_elements->size() > 1) {
if (evalue.e_token == DNT_VALUE && evalue.e_sub_elements != nullptr
&& evalue.e_sub_elements->size() > 1)
{
element_list_t::iterator next_sub;
next_sub = pair.e_sub_elements->begin();
@ -355,8 +344,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
element_list_t ELEMENT_LIST_T(pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
free_row.front().e_capture.c_begin;
blank.e_capture.c_begin = blank.e_capture.c_end
= free_row.front().e_capture.c_begin;
blank.e_token = DNT_KEY;
pair_subs.PUSH_BACK(blank);
pair_subs.PUSH_BACK(free_row.front());
@ -367,17 +356,15 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
// use the token ID since some columns values might vary
// between rows.
context.Update(" ", 1);
}
break;
} break;
default: {
size_t key_len;
const char *key_val = this->get_element_string(
free_row.front(), key_len);
const char* key_val
= this->get_element_string(free_row.front(), key_len);
context.Update(key_val, key_len);
}
break;
} break;
}
free_row.POP_FRONT();
@ -388,8 +375,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
element_list_t ELEMENT_LIST_T(pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
prefix.front().e_capture.c_begin;
blank.e_capture.c_begin = blank.e_capture.c_end
= prefix.front().e_capture.c_begin;
blank.e_token = DNT_KEY;
pair_subs.PUSH_BACK(blank);
pair_subs.PUSH_BACK(prefix.front());
@ -401,13 +388,13 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
}
if (schema != nullptr && this->dp_msg_format != nullptr) {
pcre_input &pi = this->dp_scanner->get_input();
for (auto &fiter : pairs_out) {
pcre_input& pi = this->dp_scanner->get_input();
for (auto& fiter : pairs_out) {
*(this->dp_msg_format) += this->get_string_up_to_value(fiter);
this->dp_msg_format->append("#");
}
if ((size_t) this->dp_msg_format_begin < pi.pi_length) {
const char *str = pi.get_string();
const char* str = pi.get_string();
pcre_context::capture_t last(this->dp_msg_format_begin,
pi.pi_length);
@ -426,7 +413,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
}
}
void data_parser::discover_format()
void
data_parser::discover_format()
{
pcre_context_static<30> pc;
std::stack<discover_format_state> state_stack;
@ -459,7 +447,7 @@ void data_parser::discover_format()
break;
case DT_EMPTY_CONTAINER: {
auto &curr_group = this->dp_group_stack.back();
auto& curr_group = this->dp_group_stack.back();
auto empty_list = element_list_t("_anon_", __FILE__, __LINE__);
discover_format_state dfs;
@ -468,7 +456,7 @@ void data_parser::discover_format()
empty_list.el_format = dfs.dfs_format;
curr_group.PUSH_BACK(element());
auto &empty = curr_group.back();
auto& empty = curr_group.back();
empty.e_capture.c_begin = elem.e_capture.c_begin + 1;
empty.e_capture.c_end = elem.e_capture.c_begin + 1;
empty.e_token = DNT_GROUP;
@ -486,15 +474,16 @@ void data_parser::discover_format()
auto riter = this->dp_group_stack.rbegin();
++riter;
state_stack.top().finalize();
this->dp_group_stack.back().el_format =
state_stack.top().dfs_format;
this->dp_group_stack.back().el_format
= state_stack.top().dfs_format;
state_stack.pop();
if (!this->dp_group_stack.back().empty()) {
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
DNT_GROUP));
(*riter).PUSH_BACK(
element(this->dp_group_stack.back(), DNT_GROUP));
} else {
(*riter).PUSH_BACK(element());
riter->back().e_capture.c_begin = elem.e_capture.c_begin;
riter->back().e_capture.c_begin
= elem.e_capture.c_begin;
riter->back().e_capture.c_end = elem.e_capture.c_begin;
riter->back().e_token = DNT_GROUP;
riter->back().assign_elements(
@ -519,10 +508,10 @@ void data_parser::discover_format()
++riter;
if (!this->dp_group_stack.back().empty()) {
state_stack.top().finalize();
this->dp_group_stack.back().el_format = state_stack.top().dfs_format;
this->dp_group_stack.back().el_format
= state_stack.top().dfs_format;
state_stack.pop();
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
DNT_GROUP));
(*riter).PUSH_BACK(element(this->dp_group_stack.back(), DNT_GROUP));
}
this->dp_group_stack.pop_back();
}
@ -531,11 +520,12 @@ void data_parser::discover_format()
this->dp_group_stack.back().el_format = state_stack.top().dfs_format;
}
void data_parser::end_of_value(data_parser::element_list_t &el_stack,
data_parser::element_list_t &key_comps,
data_parser::element_list_t &value,
const data_parser::element_list_t &in_list,
int group_depth)
void
data_parser::end_of_value(data_parser::element_list_t& el_stack,
data_parser::element_list_t& key_comps,
data_parser::element_list_t& value,
const data_parser::element_list_t& in_list,
int group_depth)
{
key_comps.remove_if(element_if(in_list.el_format.df_terminator));
key_comps.remove_if(element_if(DT_COMMA));
@ -543,24 +533,24 @@ void data_parser::end_of_value(data_parser::element_list_t &el_stack,
value.remove_if(element_if(DT_COMMA));
strip(key_comps, element_if(DT_WHITE));
strip(value, element_if(DT_WHITE));
if ((el_stack.empty() || el_stack.back().e_token != DNT_KEY) &&
value.empty() && key_comps.size() > 1 &&
(key_comps.front().e_token == DT_WORD ||
key_comps.front().e_token == DT_SYMBOL)) {
if ((el_stack.empty() || el_stack.back().e_token != DNT_KEY)
&& value.empty() && key_comps.size() > 1
&& (key_comps.front().e_token == DT_WORD
|| key_comps.front().e_token == DT_SYMBOL))
{
element_list_t::iterator key_iter, key_end;
bool found_value = false;
int word_count = 0;
key_iter = key_comps.begin();
key_end = key_comps.begin();
for (; key_iter != key_comps.end(); ++key_iter) {
if (key_iter->e_token == DT_WORD ||
key_iter->e_token == DT_SYMBOL) {
if (key_iter->e_token == DT_WORD || key_iter->e_token == DT_SYMBOL)
{
word_count += 1;
if (found_value) {
key_end = key_comps.begin();
}
} else if (key_iter->e_token == DT_WHITE) {
} else {
if (!found_value) {
key_end = key_iter;
@ -571,20 +561,15 @@ void data_parser::end_of_value(data_parser::element_list_t &el_stack,
if (word_count != 1) {
key_end = key_comps.begin();
}
value.SPLICE(value.end(),
key_comps,
key_end,
key_comps.end());
value.SPLICE(value.end(), key_comps, key_end, key_comps.end());
strip(key_comps, element_if(DT_WHITE));
if (!key_comps.empty()) {
el_stack.PUSH_BACK(element(key_comps, DNT_KEY, false));
}
key_comps.CLEAR();
} else {
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
value.SPLICE(
value.end(), key_comps, key_comps.begin(), key_comps.end());
}
strip(value, element_if(DT_WHITE));
strip(value, element_if(DT_COLON));
@ -602,34 +587,34 @@ void data_parser::end_of_value(data_parser::element_list_t &el_stack,
value.CLEAR();
}
void data_parser::parse()
void
data_parser::parse()
{
this->discover_format();
this->pairup(&this->dp_schema_id,
this->dp_pairs,
this->dp_group_stack.front());
this->pairup(
&this->dp_schema_id, this->dp_pairs, this->dp_group_stack.front());
}
std::string
data_parser::get_element_string(const data_parser::element &elem) const
data_parser::get_element_string(const data_parser::element& elem) const
{
pcre_input &pi = this->dp_scanner->get_input();
pcre_input& pi = this->dp_scanner->get_input();
return pi.get_substr(&elem.e_capture);
}
std::string
data_parser::get_string_up_to_value(const data_parser::element &elem)
data_parser::get_string_up_to_value(const data_parser::element& elem)
{
pcre_input &pi = this->dp_scanner->get_input();
const element &val_elem = elem.e_token == DNT_PAIR ?
elem.e_sub_elements->back() : elem;
pcre_input& pi = this->dp_scanner->get_input();
const element& val_elem
= elem.e_token == DNT_PAIR ? elem.e_sub_elements->back() : elem;
if (this->dp_msg_format_begin <= val_elem.e_capture.c_begin) {
pcre_context::capture_t leading_and_key = pcre_context::capture_t(
this->dp_msg_format_begin, val_elem.e_capture.c_begin);
const char *str = pi.get_string();
const char* str = pi.get_string();
if (leading_and_key.length() >= 2) {
switch (str[leading_and_key.c_end - 1]) {
case '\'':
@ -658,28 +643,30 @@ data_parser::get_string_up_to_value(const data_parser::element &elem)
return "";
}
const char *data_parser::get_element_string(const data_parser::element &elem,
size_t &len_out)
const char*
data_parser::get_element_string(const data_parser::element& elem,
size_t& len_out)
{
pcre_input &pi = this->dp_scanner->get_input();
pcre_input& pi = this->dp_scanner->get_input();
len_out = elem.e_capture.length();
return pi.get_substr_start(&elem.e_capture);
}
void data_parser::print(FILE *out, data_parser::element_list_t &el)
void
data_parser::print(FILE* out, data_parser::element_list_t& el)
{
fprintf(out, " %s\n",
this->dp_scanner->get_input().get_string());
for (auto &iter : el) {
fprintf(
out, " %s\n", this->dp_scanner->get_input().get_string());
for (auto& iter : el) {
iter.print(out, this->dp_scanner->get_input());
}
}
FILE *data_parser::TRACE_FILE;
FILE* data_parser::TRACE_FILE;
data_format_state_t dfs_prefix_next(data_format_state_t state,
data_token_t next_token)
data_format_state_t
dfs_prefix_next(data_format_state_t state, data_token_t next_token)
{
data_format_state_t retval = state;
@ -722,8 +709,8 @@ data_format_state_t dfs_prefix_next(data_format_state_t state,
return retval;
}
data_format_state_t dfs_semi_next(data_format_state_t state,
data_token_t next_token)
data_format_state_t
dfs_semi_next(data_format_state_t state, data_token_t next_token)
{
data_format_state_t retval = state;
@ -777,8 +764,8 @@ data_format_state_t dfs_semi_next(data_format_state_t state,
return retval;
}
data_format_state_t dfs_comma_next(data_format_state_t state,
data_token_t next_token)
data_format_state_t
dfs_comma_next(data_format_state_t state, data_token_t next_token)
{
data_format_state_t retval = state;
@ -872,25 +859,22 @@ data_format_state_t dfs_comma_next(data_format_state_t state,
}
data_parser::element::element()
: e_capture(-1, -1),
e_token(DT_INVALID),
e_sub_elements(nullptr)
: e_capture(-1, -1), e_token(DT_INVALID), e_sub_elements(nullptr)
{
}
data_parser::element::element(data_parser::element_list_t &subs,
data_token_t token, bool assign_subs_elements)
: e_capture(subs.front().e_capture.c_begin,
subs.back().e_capture.c_end),
e_token(token),
e_sub_elements(nullptr)
data_parser::element::element(data_parser::element_list_t& subs,
data_token_t token,
bool assign_subs_elements)
: e_capture(subs.front().e_capture.c_begin, subs.back().e_capture.c_end),
e_token(token), e_sub_elements(nullptr)
{
if (assign_subs_elements) {
this->assign_elements(subs);
}
}
data_parser::element::element(const data_parser::element &other)
data_parser::element::element(const data_parser::element& other)
{
/* require(other.e_sub_elements == nullptr); */
@ -908,8 +892,8 @@ data_parser::element::~element()
this->e_sub_elements = nullptr;
}
data_parser::element &
data_parser::element::operator=(const data_parser::element &other)
data_parser::element&
data_parser::element::operator=(const data_parser::element& other)
{
this->e_capture = other.e_capture;
this->e_token = other.e_token;
@ -920,41 +904,43 @@ data_parser::element::operator=(const data_parser::element &other)
return *this;
}
void data_parser::element::assign_elements(data_parser::element_list_t &subs)
void
data_parser::element::assign_elements(data_parser::element_list_t& subs)
{
if (this->e_sub_elements == nullptr) {
this->e_sub_elements = new element_list_t("_sub_", __FILE__,
__LINE__);
this->e_sub_elements = new element_list_t("_sub_", __FILE__, __LINE__);
this->e_sub_elements->el_format = subs.el_format;
}
this->e_sub_elements->SWAP(subs);
this->update_capture();
}
void data_parser::element::update_capture()
void
data_parser::element::update_capture()
{
if (this->e_sub_elements != nullptr && !this->e_sub_elements->empty()) {
this->e_capture.c_begin =
this->e_sub_elements->front().e_capture.c_begin;
this->e_capture.c_end =
this->e_sub_elements->back().e_capture.c_end;
this->e_capture.c_begin
= this->e_sub_elements->front().e_capture.c_begin;
this->e_capture.c_end = this->e_sub_elements->back().e_capture.c_end;
}
}
const data_parser::element &data_parser::element::get_pair_value() const
const data_parser::element&
data_parser::element::get_pair_value() const
{
require(this->e_token == DNT_PAIR);
return this->e_sub_elements->back();
}
data_token_t data_parser::element::value_token() const
data_token_t
data_parser::element::value_token() const
{
data_token_t retval = DT_INVALID;
if (this->e_token == DNT_VALUE) {
if (this->e_sub_elements != nullptr &&
this->e_sub_elements->size() == 1) {
if (this->e_sub_elements != nullptr
&& this->e_sub_elements->size() == 1) {
retval = this->e_sub_elements->front().e_token;
} else {
retval = DT_SYMBOL;
@ -965,18 +951,20 @@ data_token_t data_parser::element::value_token() const
return retval;
}
const data_parser::element &data_parser::element::get_value_elem() const
const data_parser::element&
data_parser::element::get_value_elem() const
{
if (this->e_token == DNT_VALUE) {
if (this->e_sub_elements != nullptr &&
this->e_sub_elements->size() == 1) {
if (this->e_sub_elements != nullptr
&& this->e_sub_elements->size() == 1) {
return this->e_sub_elements->front();
}
}
return *this;
}
const data_parser::element &data_parser::element::get_pair_elem() const
const data_parser::element&
data_parser::element::get_pair_elem() const
{
if (this->e_token == DNT_VALUE) {
return this->e_sub_elements->front();
@ -984,17 +972,19 @@ const data_parser::element &data_parser::element::get_pair_elem() const
return *this;
}
void data_parser::element::print(FILE *out, pcre_input &pi, int offset) const
void
data_parser::element::print(FILE* out, pcre_input& pi, int offset) const
{
int lpc;
if (this->e_sub_elements != nullptr) {
for (auto &e_sub_element : *this->e_sub_elements) {
for (auto& e_sub_element : *this->e_sub_elements) {
e_sub_element.print(out, pi, offset + 1);
}
}
fprintf(out, "%4s %3d:%-3d ",
fprintf(out,
"%4s %3d:%-3d ",
data_scanner::token2name(this->e_token),
this->e_capture.c_begin,
this->e_capture.c_end);
@ -1018,18 +1008,18 @@ void data_parser::element::print(FILE *out, pcre_input &pi, int offset) const
}
data_parser::discover_format_state::discover_format_state()
: dfs_prefix_state(DFS_INIT),
dfs_semi_state(DFS_INIT),
: dfs_prefix_state(DFS_INIT), dfs_semi_state(DFS_INIT),
dfs_comma_state(DFS_INIT)
{
memset(this->dfs_hist, 0, sizeof(this->dfs_hist));
}
void data_parser::discover_format_state::update_for_element(
const data_parser::element &elem)
void
data_parser::discover_format_state::update_for_element(
const data_parser::element& elem)
{
this->dfs_prefix_state = dfs_prefix_next(this->dfs_prefix_state,
elem.e_token);
this->dfs_prefix_state
= dfs_prefix_next(this->dfs_prefix_state, elem.e_token);
this->dfs_semi_state = dfs_semi_next(this->dfs_semi_state, elem.e_token);
this->dfs_comma_state = dfs_comma_next(this->dfs_comma_state, elem.e_token);
if (this->dfs_prefix_state != DFS_ERROR) {
@ -1043,7 +1033,8 @@ void data_parser::discover_format_state::update_for_element(
this->dfs_hist[elem.e_token] += 1;
}
void data_parser::discover_format_state::finalize()
void
data_parser::discover_format_state::finalize()
{
data_token_t qualifier = this->dfs_format.df_qualifier;
data_token_t separator = this->dfs_format.df_separator;
@ -1060,9 +1051,10 @@ void data_parser::discover_format_state::finalize()
} else if (this->dfs_comma_state != DFS_ERROR) {
this->dfs_format = FORMAT_COMMA;
if (separator == DT_COLON && this->dfs_hist[DT_COMMA] > 0) {
if (!((this->dfs_hist[DT_COLON] == this->dfs_hist[DT_COMMA]) ||
((this->dfs_hist[DT_COLON] - 1) ==
this->dfs_hist[DT_COMMA]))) {
if (!((this->dfs_hist[DT_COLON] == this->dfs_hist[DT_COMMA])
|| ((this->dfs_hist[DT_COLON] - 1)
== this->dfs_hist[DT_COMMA])))
{
separator = DT_INVALID;
if (this->dfs_hist[DT_COLON] == 1) {
prefix_term = DT_COLON;

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,30 +30,31 @@
#ifndef data_parser_hh
#define data_parser_hh
#include <stdio.h>
#include <iterator>
#include <list>
#include <stack>
#include <vector>
#include <iterator>
#include <stdio.h>
#include "base/lnav_log.hh"
#include "pcrepp/pcrepp.hh"
#include "byte_array.hh"
#include "data_scanner.hh"
#include "pcrepp/pcrepp.hh"
#define ELEMENT_LIST_T(var) var("" #var, __FILE__, __LINE__, group_depth)
#define PUSH_FRONT(elem) push_front(elem, __FILE__, __LINE__)
#define PUSH_BACK(elem) push_back(elem, __FILE__, __LINE__)
#define POP_FRONT(elem) pop_front(__FILE__, __LINE__)
#define POP_BACK(elem) pop_back(__FILE__, __LINE__)
#define CLEAR(elem) clear2(__FILE__, __LINE__)
#define SWAP(other) swap(other, __FILE__, __LINE__)
#define SPLICE(pos, other, first, last) splice(pos, other, first, last, \
__FILE__, __LINE__)
#define ELEMENT_LIST_T(var) var("" #var, __FILE__, __LINE__, group_depth)
#define PUSH_FRONT(elem) push_front(elem, __FILE__, __LINE__)
#define PUSH_BACK(elem) push_back(elem, __FILE__, __LINE__)
#define POP_FRONT(elem) pop_front(__FILE__, __LINE__)
#define POP_BACK(elem) pop_back(__FILE__, __LINE__)
#define CLEAR(elem) clear2(__FILE__, __LINE__)
#define SWAP(other) swap(other, __FILE__, __LINE__)
#define SPLICE(pos, other, first, last) \
splice(pos, other, first, last, __FILE__, __LINE__)
template<class Container, class UnaryPredicate>
void strip(Container &container, UnaryPredicate p)
void
strip(Container& container, UnaryPredicate p)
{
while (!container.empty() && p(container.front())) {
container.POP_FRONT();
@ -72,18 +73,14 @@ enum data_format_state_t {
};
struct data_format {
data_format(const char *name = nullptr,
data_format(const char* name = nullptr,
data_token_t appender = DT_INVALID,
data_token_t terminator = DT_INVALID) noexcept
: df_name(name),
df_appender(appender),
df_terminator(terminator),
df_qualifier(DT_INVALID),
df_separator(DT_COLON),
df_prefix_terminator(DT_INVALID)
{};
const char * df_name;
: df_name(name), df_appender(appender), df_terminator(terminator),
df_qualifier(DT_INVALID), df_separator(DT_COLON),
df_prefix_terminator(DT_INVALID){};
const char* df_name;
data_token_t df_appender;
data_token_t df_terminator;
data_token_t df_qualifier;
@ -98,117 +95,113 @@ data_format_state_t dfs_semi_next(data_format_state_t state,
data_format_state_t dfs_comma_next(data_format_state_t state,
data_token_t next_token);
#define LIST_INIT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
#define LIST_INIT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %s %d\n", \
this, \
fn, line, \
__func__, \
varname, \
group_depth); \
} \
this, \
fn, \
line, \
__func__, \
varname, \
group_depth); \
} \
} while (false)
#define LIST_DEINIT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s\n", \
this, \
fn, line, \
__func__); \
} \
#define LIST_DEINIT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, "%p %s:%d %s\n", this, fn, line, __func__); \
} \
} while (false)
#define ELEMENT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %s %d:%d\n", \
this, \
fn, line, \
__func__, \
#define ELEMENT_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %s %d:%d\n", \
this, \
fn, \
line, \
__func__, \
data_scanner::token2name(elem.e_token), \
elem.e_capture.c_begin, \
elem.e_capture.c_end); \
} \
elem.e_capture.c_begin, \
elem.e_capture.c_end); \
} \
} while (false)
#define LIST_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s\n", \
this, \
fn, line, \
__func__); \
} \
#define LIST_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, "%p %s:%d %s\n", this, fn, line, __func__); \
} \
} while (false)
#define SPLICE_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %d %p %d:%d\n", \
this, \
fn, line, \
__func__, \
(int)std::distance(this->begin(), pos), \
&other, \
(int)std::distance(other.begin(), first), \
(int)std::distance(last, other.end())); \
} \
#define SPLICE_TRACE \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %d %p %d:%d\n", \
this, \
fn, \
line, \
__func__, \
(int) std::distance(this->begin(), pos), \
&other, \
(int) std::distance(other.begin(), first), \
(int) std::distance(last, other.end())); \
} \
} while (false);
#define SWAP_TRACE(other) \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %p\n", \
this, \
fn, line, \
__func__, \
&other); \
} \
#define SWAP_TRACE(other) \
do { \
if (TRACE_FILE != NULL) { \
fprintf(TRACE_FILE, \
"%p %s:%d %s %p\n", \
this, \
fn, \
line, \
__func__, \
&other); \
} \
} while (false);
#define POINT_TRACE(name) \
do { \
if (TRACE_FILE) { \
fprintf(TRACE_FILE, \
"0x0 %s:%d point %s\n", \
__FILE__, __LINE__, \
name); \
} \
#define POINT_TRACE(name) \
do { \
if (TRACE_FILE) { \
fprintf( \
TRACE_FILE, "0x0 %s:%d point %s\n", __FILE__, __LINE__, name); \
} \
} while (false);
#define FORMAT_TRACE(elist) \
do { \
if (TRACE_FILE) { \
const data_format &df = elist.el_format; \
fprintf(TRACE_FILE, \
#define FORMAT_TRACE(elist) \
do { \
if (TRACE_FILE) { \
const data_format& df = elist.el_format; \
fprintf(TRACE_FILE, \
"%p %s:%d format %d %s %s %s %s %s\n", \
&elist, \
__FILE__, __LINE__, \
__FILE__, \
__LINE__, \
group_depth, \
data_scanner::token2name(df.df_appender), \
data_scanner::token2name(df.df_terminator), \
data_scanner::token2name(df.df_qualifier), \
data_scanner::token2name(df.df_separator), \
data_scanner::token2name(df.df_appender), \
data_scanner::token2name(df.df_terminator), \
data_scanner::token2name(df.df_qualifier), \
data_scanner::token2name(df.df_separator), \
data_scanner::token2name(df.df_prefix_terminator)); \
} \
} \
} while (false);
#define CONSUMED_TRACE(elist) \
do { \
if (TRACE_FILE) { \
fprintf(TRACE_FILE, \
#define CONSUMED_TRACE(elist) \
do { \
if (TRACE_FILE) { \
fprintf(TRACE_FILE, \
"%p %s:%d consumed\n", \
&elist, \
__FILE__, __LINE__); \
} \
__FILE__, \
__LINE__); \
} \
} while (false);
class data_parser {
@ -217,7 +210,7 @@ public:
static data_format FORMAT_COMMA;
static data_format FORMAT_PLAIN;
static FILE *TRACE_FILE;
static FILE* TRACE_FILE;
typedef byte_array<2, uint64_t> schema_id_t;
@ -225,35 +218,39 @@ public:
/* typedef std::list<element> element_list_t; */
class element_list_t : public std::list<element> {
public:
element_list_t(const char *varname, const char *fn, int line, int group_depth = -1)
public:
element_list_t(const char* varname,
const char* fn,
int line,
int group_depth = -1)
{
LIST_INIT_TRACE;
}
element_list_t()
{
const char *varname = "_anon2_";
const char *fn = __FILE__;
int line = __LINE__;
int group_depth = -1;
const char* varname = "_anon2_";
const char* fn = __FILE__;
int line = __LINE__;
int group_depth = -1;
LIST_INIT_TRACE;
};
element_list_t(const element_list_t &other) : std::list<element>(other) {
element_list_t(const element_list_t& other) : std::list<element>(other)
{
this->el_format = other.el_format;
}
~element_list_t()
{
const char *fn = __FILE__;
int line = __LINE__;
const char* fn = __FILE__;
int line = __LINE__;
LIST_DEINIT_TRACE;
};
void push_front(const element &elem, const char *fn, int line)
void push_front(const element& elem, const char* fn, int line)
{
ELEMENT_TRACE;
@ -261,7 +258,7 @@ public:
this->std::list<element>::push_front(elem);
};
void push_back(const element &elem, const char *fn, int line)
void push_back(const element& elem, const char* fn, int line)
{
ELEMENT_TRACE;
@ -269,38 +266,39 @@ public:
this->std::list<element>::push_back(elem);
};
void pop_front(const char *fn, int line)
void pop_front(const char* fn, int line)
{
LIST_TRACE;
this->std::list<element>::pop_front();
};
void pop_back(const char *fn, int line)
void pop_back(const char* fn, int line)
{
LIST_TRACE;
this->std::list<element>::pop_back();
};
void clear2(const char *fn, int line)
void clear2(const char* fn, int line)
{
LIST_TRACE;
this->std::list<element>::clear();
};
void swap(element_list_t &other, const char *fn, int line) {
void swap(element_list_t& other, const char* fn, int line)
{
SWAP_TRACE(other);
this->std::list<element>::swap(other);
}
void splice(iterator pos,
element_list_t &other,
element_list_t& other,
iterator first,
iterator last,
const char *fn,
const char* fn,
int line)
{
SPLICE_TRACE;
@ -314,64 +312,64 @@ public:
struct element {
element();
element(element_list_t &subs,
element(element_list_t& subs,
data_token_t token,
bool assign_subs_elements = true);
element(const element &other);
element(const element& other);
~element();
element & operator=(const element &other);
element& operator=(const element& other);
void assign_elements(element_list_t &subs);
void assign_elements(element_list_t& subs);
void update_capture();
const element &get_pair_value() const;
const element& get_pair_value() const;
data_token_t value_token() const;
const element &get_value_elem() const;
const element& get_value_elem() const;
const element &get_pair_elem() const;
const element& get_pair_elem() const;
void print(FILE *out, pcre_input &pi, int offset = 0) const;
void print(FILE* out, pcre_input& pi, int offset = 0) const;
pcre_context::capture_t e_capture;
data_token_t e_token;
data_token_t e_token;
element_list_t * e_sub_elements;
element_list_t* e_sub_elements;
};
struct element_cmp {
bool operator()(data_token_t token, const element &elem) const
bool operator()(data_token_t token, const element& elem) const
{
return token == elem.e_token || token == DT_ANY;
};
bool operator()(const element &elem, data_token_t token) const
bool operator()(const element& elem, data_token_t token) const
{
return (*this)(token, elem);
};
};
struct element_if {
element_if(data_token_t token) : ei_token(token) { };
element_if(data_token_t token) : ei_token(token){};
bool operator()(const element &a) const
bool operator()(const element& a) const
{
return a.e_token == this->ei_token;
};
private:
private:
data_token_t ei_token;
};
struct discover_format_state {
discover_format_state();
void update_for_element(const element &elem);
void update_for_element(const element& elem);
void finalize();
@ -383,28 +381,30 @@ private:
data_format dfs_format;
};
data_parser(data_scanner *ds);
data_parser(data_scanner* ds);
void pairup(schema_id_t *schema, element_list_t &pairs_out,
element_list_t &in_list, int group_depth = 0);
void pairup(schema_id_t* schema,
element_list_t& pairs_out,
element_list_t& in_list,
int group_depth = 0);
void discover_format();
void end_of_value(element_list_t &el_stack,
element_list_t &key_comps,
element_list_t &value,
const element_list_t &in_list,
void end_of_value(element_list_t& el_stack,
element_list_t& key_comps,
element_list_t& value,
const element_list_t& in_list,
int group_depth);
void parse();
std::string get_element_string(const element &elem) const;
std::string get_element_string(const element& elem) const;
std::string get_string_up_to_value(const element &elem);
std::string get_string_up_to_value(const element& elem);
const char *get_element_string(const element &elem, size_t &len_out);
const char* get_element_string(const element& elem, size_t& len_out);
void print(FILE *out, element_list_t &el);
void print(FILE* out, element_list_t& el);
std::vector<data_token_t> dp_group_token;
std::list<element_list_t> dp_group_stack;
@ -412,11 +412,11 @@ private:
element_list_t dp_errors;
element_list_t dp_pairs;
schema_id_t dp_schema_id;
std::string *dp_msg_format;
schema_id_t dp_schema_id;
std::string* dp_msg_format;
int dp_msg_format_begin;
private:
data_scanner *dp_scanner;
data_scanner* dp_scanner;
};
#endif

@ -21,137 +21,219 @@
* 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
* 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 "data_scanner.hh"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "config.h"
#include "pcrepp/pcrepp.hh"
#include "data_scanner.hh"
using namespace std;
static struct {
const char *name;
pcrepp pcre;
const char* name;
pcrepp pcre;
} MATCHERS[DT_TERMINAL_MAX] = {
{ "quot", pcrepp("\\A(?:(?:u|r)?\"((?:\\\\.|[^\"])+)\"|"
"(?:u|r)?'((?:\\\\.|[^'])+)')"), },
{ "url", pcrepp("\\A([\\w]+://[^\\s'\"\\[\\](){}]+[/a-zA-Z0-9\\-=&])"),
},
{ "path", pcrepp("\\A((?:/|\\./|\\.\\./)[\\w\\.\\-_\\~/]*)"),
},
{ "mac", pcrepp(
"\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F]){5})(?!:)"), },
{ "date",
pcrepp("\\A("
"\\d{4}/\\d{1,2}/\\d{1,2}|"
"\\d{4}-\\d{1,2}-\\d{1,2}|"
"\\d{2}/\\w{3}/\\d{4}"
")T?"), },
{ "time", pcrepp(
"\\A([\\s\\d]\\d:\\d\\d(?:(?!:\\d)|:\\d\\d(?:[\\.,]\\d{3,6})?Z?))\\b"), },
{
"quot",
pcrepp("\\A(?:(?:u|r)?\"((?:\\\\.|[^\"])+)\"|"
"(?:u|r)?'((?:\\\\.|[^'])+)')"),
},
{
"url",
pcrepp("\\A([\\w]+://[^\\s'\"\\[\\](){}]+[/a-zA-Z0-9\\-=&])"),
},
{
"path",
pcrepp("\\A((?:/|\\./|\\.\\./)[\\w\\.\\-_\\~/]*)"),
},
{
"mac",
pcrepp(
"\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F]){5})(?!:)"),
},
{
"date",
pcrepp("\\A("
"\\d{4}/\\d{1,2}/\\d{1,2}|"
"\\d{4}-\\d{1,2}-\\d{1,2}|"
"\\d{2}/\\w{3}/\\d{4}"
")T?"),
},
{
"time",
pcrepp("\\A([\\s\\d]\\d:\\d\\d(?:(?!:\\d)|:\\d\\d(?:[\\.,]\\d{3,6})?Z?)"
")\\b"),
},
/* { "qual", pcrepp("\\A([^\\s:=]+:[^\\s:=,]+(?!,)(?::[^\\s:=,]+)*)"), }, */
{ "ipv6", pcrepp("\\A(::|[:\\da-fA-F\\.]+[a-fA-F\\d](?:%\\w+)?)"), },
{ "hexd", pcrepp(
"\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F])+)"), },
{
"ipv6",
pcrepp("\\A(::|[:\\da-fA-F\\.]+[a-fA-F\\d](?:%\\w+)?)"),
},
{
"hexd",
pcrepp("\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F])+)"),
},
{ "xmlt", pcrepp(
"\\A(<\\??[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
"))*\\s*(?:/|\\?)>)"), },
{ "xmlo", pcrepp(
"\\A(<[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
"))*\\s*>)"), },
{
"xmlt",
pcrepp("\\A(<\\??[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
"))*\\s*(?:/|\\?)>)"),
},
{
"xmlo",
pcrepp("\\A(<[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
"))*\\s*>)"),
},
{ "xmlc", pcrepp("\\A(</[\\w:]+\\s*>)"), },
{
"xmlc",
pcrepp("\\A(</[\\w:]+\\s*>)"),
},
{ "coln", pcrepp("\\A(:)"),
{
"coln",
pcrepp("\\A(:)"),
},
{ "eq", pcrepp("\\A(=)"),
{
"eq",
pcrepp("\\A(=)"),
},
{ "comm", pcrepp("\\A(,)"),
{
"comm",
pcrepp("\\A(,)"),
},
{ "semi", pcrepp("\\A(;)"),
{
"semi",
pcrepp("\\A(;)"),
},
{ "empt", pcrepp("\\A(\\(\\)|\\{\\}|\\[\\])"),
{
"empt",
pcrepp("\\A(\\(\\)|\\{\\}|\\[\\])"),
},
{ "lcurly", pcrepp("\\A({)"),
{
"lcurly",
pcrepp("\\A({)"),
},
{ "rcurly", pcrepp("\\A(})"),
{
"rcurly",
pcrepp("\\A(})"),
},
{ "lsquare", pcrepp("\\A(\\[)"),
{
"lsquare",
pcrepp("\\A(\\[)"),
},
{ "rsquare", pcrepp("\\A(\\])"),
{
"rsquare",
pcrepp("\\A(\\])"),
},
{ "lparen", pcrepp("\\A(\\()"),
{
"lparen",
pcrepp("\\A(\\()"),
},
{ "rparen", pcrepp("\\A(\\))"),
{
"rparen",
pcrepp("\\A(\\))"),
},
{ "langle", pcrepp("\\A(\\<)"),
{
"langle",
pcrepp("\\A(\\<)"),
},
{ "rangle", pcrepp("\\A(\\>)"),
{
"rangle",
pcrepp("\\A(\\>)"),
},
{ "ipv4", pcrepp("\\A("
"(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?![\\d]))"),
{
"ipv4",
pcrepp("\\A("
"(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?![\\d]))"),
},
{ "uuid", pcrepp(
"\\A([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})"), },
{
"uuid",
pcrepp("\\A([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})"),
},
{ "vers", pcrepp(
"\\A("
"[0-9]+(?:\\.[0-9]+\\w*){2,}(?:-\\w+)?|"
"[0-9]+(?:\\.[0-9]+\\w*)+(?<!\\d[eE])-\\w+?"
")\\b"),
{
"vers",
pcrepp("\\A("
"[0-9]+(?:\\.[0-9]+\\w*){2,}(?:-\\w+)?|"
"[0-9]+(?:\\.[0-9]+\\w*)+(?<!\\d[eE])-\\w+?"
")\\b"),
},
{
"oct",
pcrepp("\\A(-?0[0-7]+\\b)"),
},
{ "oct", pcrepp("\\A(-?0[0-7]+\\b)"),
{
"pcnt",
pcrepp("\\A(-?[0-9]+(\\.[0-9]+)?[ ]*%\\b)"),
},
{ "pcnt", pcrepp("\\A(-?[0-9]+(\\.[0-9]+)?[ ]*%\\b)"),
{
"num",
pcrepp("\\A(-?[0-9]+(\\.[0-9]+)?([eE][\\-+][0-9]+)?)"
"\\b(?![\\._\\-][a-zA-Z])"),
},
{
"hex",
pcrepp("\\A(-?(?:0x|[0-9])[0-9a-fA-F]+)"
"\\b(?![\\._\\-][a-zA-Z])"),
},
{ "num", pcrepp("\\A(-?[0-9]+(\\.[0-9]+)?([eE][\\-+][0-9]+)?)"
"\\b(?![\\._\\-][a-zA-Z])"), },
{ "hex", pcrepp("\\A(-?(?:0x|[0-9])[0-9a-fA-F]+)"
"\\b(?![\\._\\-][a-zA-Z])"), },
{ "mail", pcrepp(
"\\A([a-zA-Z0-9\\._%+-]+@[a-zA-Z0-9\\.-]+\\.[a-zA-Z]+)\\b"), },
{ "cnst",
pcrepp("\\A(true|True|TRUE|false|False|FALSE|None|null)\\b") },
{ "word", pcrepp(
"\\A([a-zA-Z][a-z']+(?=[\\s\\(\\)!\\*:;'\\\"\\?,]|[\\.\\!,\\?]\\s|$))"),
{
"mail",
pcrepp("\\A([a-zA-Z0-9\\._%+-]+@[a-zA-Z0-9\\.-]+\\.[a-zA-Z]+)\\b"),
},
{"cnst", pcrepp("\\A(true|True|TRUE|false|False|FALSE|None|null)\\b")},
{
"word",
pcrepp("\\A([a-zA-Z][a-z']+(?=[\\s\\(\\)!\\*:;'\\\"\\?,]|[\\.\\!,\\?]"
"\\s|$))"),
},
{ "sym", pcrepp(
"\\A([^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]+"
"(?:::[^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]+)*)"),
{
"sym",
pcrepp(
"\\A([^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]+"
"(?:::[^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]"
"+)*)"),
},
{ "line", pcrepp("\\A(\r?\n|\r|;)"),
{
"line",
pcrepp("\\A(\r?\n|\r|;)"),
},
{ "wspc", pcrepp("\\A([ \\r\\t\\n]+)"),
{
"wspc",
pcrepp("\\A([ \\r\\t\\n]+)"),
},
{ "dot", pcrepp("\\A(\\.)"),
{
"dot",
pcrepp("\\A(\\.)"),
},
{ "gbg", pcrepp("\\A(.)"),
{
"gbg",
pcrepp("\\A(.)"),
},
};
const char *DNT_NAMES[DNT_MAX - DNT_KEY] = {
const char* DNT_NAMES[DNT_MAX - DNT_KEY] = {
"key",
"pair",
"val",
@ -164,24 +246,22 @@ const char *DNT_NAMES[DNT_MAX - DNT_KEY] = {
"grp",
};
const char *data_scanner::token2name(data_token_t token)
const char*
data_scanner::token2name(data_token_t token)
{
if (token < 0) {
return "inv";
}
else if (token < DT_TERMINAL_MAX) {
} else if (token < DT_TERMINAL_MAX) {
return MATCHERS[token].name;
}
else if (token == DT_ANY) {
} else if (token == DT_ANY) {
return "any";
}
else{
} else {
return DNT_NAMES[token - DNT_KEY];
}
}
static
bool find_string_end(const char *str, size_t &start, size_t length, char term)
static bool
find_string_end(const char* str, size_t& start, size_t length, char term)
{
for (; start < length; start++) {
if (str[start] == term) {
@ -198,29 +278,29 @@ bool find_string_end(const char *str, size_t &start, size_t length, char term)
return false;
}
static
void single_char_capture(pcre_context &pc, pcre_input &pi)
static void
single_char_capture(pcre_context& pc, pcre_input& pi)
{
pc.all()[0].c_begin = pi.pi_offset;
pc.all()[0].c_end = pi.pi_offset + 1;
pc.all()[1] = pc.all()[0];
pc.all()[0].c_end = pi.pi_offset + 1;
pc.all()[1] = pc.all()[0];
pc.set_count(2);
pi.pi_next_offset = pi.pi_offset + 1;
}
bool data_scanner::tokenize(pcre_context &pc, data_token_t &token_out)
bool
data_scanner::tokenize(pcre_context& pc, data_token_t& token_out)
{
const char *str = this->ds_pcre_input.get_string();
pcre_input &pi = this->ds_pcre_input;
int lpc;
const char* str = this->ds_pcre_input.get_string();
pcre_input& pi = this->ds_pcre_input;
int lpc;
token_out = data_token_t(-1);
if (this->ds_pcre_input.pi_next_offset > this->ds_pcre_input.pi_length) {
return false;
}
else if (this->ds_pcre_input.pi_next_offset ==
this->ds_pcre_input.pi_length) {
} else if (this->ds_pcre_input.pi_next_offset
== this->ds_pcre_input.pi_length) {
this->ds_pcre_input.pi_next_offset += 1;
token_out = DT_LINE;
return false;
@ -228,118 +308,113 @@ bool data_scanner::tokenize(pcre_context &pc, data_token_t &token_out)
for (lpc = 0; lpc < DT_TERMINAL_MAX; lpc++) {
switch (lpc) {
case DT_QUOTED_STRING: {
size_t str_start, str_end;
bool found = false;
pi.pi_offset = pi.pi_next_offset;
str_end = str_start = pi.pi_offset + 1;
switch (str[pi.pi_offset]) {
case 'u':
case 'r':
if (pi.pi_offset + 1 < pi.pi_length &&
(str[pi.pi_offset + 1] == '\'' ||
str[pi.pi_offset + 1] == '\"')) {
str_start += 1;
str_end += 1;
found = find_string_end(str,
str_end,
pi.pi_length,
str[pi.pi_offset + 1]);
}
break;
case '\'':
case '\"':
found = find_string_end(str,
str_end,
pi.pi_length,
str[pi.pi_offset]);
break;
}
if (found) {
token_out = data_token_t(DT_QUOTED_STRING);
pi.pi_next_offset = str_end;
pc.all()[0].c_begin = pi.pi_offset;
pc.all()[0].c_end = str_end;
pc.all()[1].c_begin = str_start;
pc.all()[1].c_end = str_end - 1;
pc.set_count(2);
return true;
}
}
break;
case DT_COLON: {
pi.pi_offset = pi.pi_next_offset;
if (str[pi.pi_offset] == ':') {
token_out = data_token_t(DT_COLON);
single_char_capture(pc, pi);
return true;
}
}
break;
case DT_QUOTED_STRING: {
size_t str_start, str_end;
bool found = false;
pi.pi_offset = pi.pi_next_offset;
str_end = str_start = pi.pi_offset + 1;
switch (str[pi.pi_offset]) {
case 'u':
case 'r':
if (pi.pi_offset + 1 < pi.pi_length
&& (str[pi.pi_offset + 1] == '\''
|| str[pi.pi_offset + 1] == '\"'))
{
str_start += 1;
str_end += 1;
found = find_string_end(str,
str_end,
pi.pi_length,
str[pi.pi_offset + 1]);
}
break;
case DT_EQUALS: {
pi.pi_offset = pi.pi_next_offset;
case '\'':
case '\"':
found = find_string_end(
str, str_end, pi.pi_length, str[pi.pi_offset]);
break;
}
if (found) {
token_out = data_token_t(DT_QUOTED_STRING);
pi.pi_next_offset = str_end;
pc.all()[0].c_begin = pi.pi_offset;
pc.all()[0].c_end = str_end;
pc.all()[1].c_begin = str_start;
pc.all()[1].c_end = str_end - 1;
pc.set_count(2);
return true;
}
} break;
if (str[pi.pi_offset] == '=') {
token_out = data_token_t(DT_EQUALS);
single_char_capture(pc, pi);
return true;
}
}
break;
case DT_COLON: {
pi.pi_offset = pi.pi_next_offset;
case DT_COMMA: {
pi.pi_offset = pi.pi_next_offset;
if (str[pi.pi_offset] == ':') {
token_out = data_token_t(DT_COLON);
single_char_capture(pc, pi);
return true;
}
} break;
if (str[pi.pi_offset] == ',') {
token_out = data_token_t(DT_COMMA);
single_char_capture(pc, pi);
return true;
}
}
break;
case DT_EQUALS: {
pi.pi_offset = pi.pi_next_offset;
case DT_SEMI: {
pi.pi_offset = pi.pi_next_offset;
if (str[pi.pi_offset] == '=') {
token_out = data_token_t(DT_EQUALS);
single_char_capture(pc, pi);
return true;
}
} break;
if (str[pi.pi_offset] == ';') {
token_out = data_token_t(DT_SEMI);
single_char_capture(pc, pi);
return true;
}
}
break;
case DT_COMMA: {
pi.pi_offset = pi.pi_next_offset;
default:
if (MATCHERS[lpc].pcre.match(pc, this->ds_pcre_input,
PCRE_ANCHORED)) {
switch (lpc) {
case DT_IPV6_ADDRESS:
if (pc.all()->length() <= INET6_ADDRSTRLEN) {
char in6str[INET6_ADDRSTRLEN];
char buf[sizeof(struct in6_addr)];
if (str[pi.pi_offset] == ',') {
token_out = data_token_t(DT_COMMA);
single_char_capture(pc, pi);
return true;
}
} break;
this->ds_pcre_input.get_substr(pc.all(), in6str);
case DT_SEMI: {
pi.pi_offset = pi.pi_next_offset;
if (inet_pton(AF_INET6, in6str, buf) == 1) {
if (str[pi.pi_offset] == ';') {
token_out = data_token_t(DT_SEMI);
single_char_capture(pc, pi);
return true;
}
} break;
default:
if (MATCHERS[lpc].pcre.match(
pc, this->ds_pcre_input, PCRE_ANCHORED)) {
switch (lpc) {
case DT_IPV6_ADDRESS:
if (pc.all()->length() <= INET6_ADDRSTRLEN) {
char in6str[INET6_ADDRSTRLEN];
char buf[sizeof(struct in6_addr)];
this->ds_pcre_input.get_substr(pc.all(),
in6str);
if (inet_pton(AF_INET6, in6str, buf) == 1) {
token_out = data_token_t(lpc);
return true;
}
}
this->ds_pcre_input.pi_next_offset
= this->ds_pcre_input.pi_offset;
break;
default:
token_out = data_token_t(lpc);
return true;
}
}
this->ds_pcre_input.pi_next_offset =
this->ds_pcre_input.pi_offset;
break;
default:
token_out = data_token_t(lpc);
return true;
}
}
break;
break;
}
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -36,7 +36,7 @@
#include "shared_buffer.hh"
enum data_token_t {
DT_INVALID = -1,
DT_INVALID = -1,
DT_QUOTED_STRING = 0,
DT_URL,
@ -91,7 +91,7 @@ enum data_token_t {
DT_TERMINAL_MAX = DT_GARBAGE + 1,
DNT_KEY = 50,
DNT_KEY = 50,
DNT_PAIR,
DNT_VALUE,
DNT_ROW,
@ -109,19 +109,24 @@ enum data_token_t {
class data_scanner {
public:
static const char *token2name(data_token_t token);
static const char* token2name(data_token_t token);
data_scanner(const std::string &line, size_t off = 0, size_t len = (size_t) -1)
: ds_line(line),
ds_pcre_input(ds_line.c_str(), off, len)
data_scanner(const std::string& line,
size_t off = 0,
size_t len = (size_t) -1)
: ds_line(line), ds_pcre_input(ds_line.c_str(), off, len)
{
if (!line.empty() && line[line.length() - 1] == '.') {
this->ds_pcre_input.pi_length -= 1;
}
};
data_scanner(shared_buffer_ref &line, size_t off = 0, size_t len = (size_t) -1)
: ds_sbr(line), ds_pcre_input(line.get_data(), off, len == (size_t) -1 ? line.length() : len)
data_scanner(shared_buffer_ref& line,
size_t off = 0,
size_t len = (size_t) -1)
: ds_sbr(line),
ds_pcre_input(
line.get_data(), off, len == (size_t) -1 ? line.length() : len)
{
require(len == (size_t) -1 || len <= line.length());
if (line.length() > 0 && line.get_data()[line.length() - 1] == '.') {
@ -129,12 +134,16 @@ public:
}
};
bool tokenize(pcre_context &pc, data_token_t &token_out);
bool tokenize2(pcre_context &pc, data_token_t &token_out);
bool tokenize(pcre_context& pc, data_token_t& token_out);
bool tokenize2(pcre_context& pc, data_token_t& token_out);
pcre_input &get_input() { return this->ds_pcre_input; };
pcre_input& get_input()
{
return this->ds_pcre_input;
};
void reset() {
void reset()
{
this->ds_pcre_input.reset_next_offset();
};

File diff suppressed because it is too large Load Diff

@ -21,29 +21,30 @@
* 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
* 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 <regex>
#include "db_sub_source.hh"
#include "base/date_time_scanner.hh"
#include "base/time_util.hh"
#include "config.h"
#include "yajlpp/json_ptr.hh"
#include "db_sub_source.hh"
const char *db_label_source::NULL_STR = "<NULL>";
const char* db_label_source::NULL_STR = "<NULL>";
constexpr size_t MAX_COLUMN_WIDTH = 120;
void db_label_source::text_value_for_line(textview_curses &tc, int row,
std::string &label_out,
text_sub_source::line_flags_t flags)
void
db_label_source::text_value_for_line(textview_curses& tc,
int row,
std::string& label_out,
text_sub_source::line_flags_t flags)
{
static const std::string TAB_SYMBOL = "\u21e5";
static const std::string LF_SYMBOL = "\u240a";
@ -55,12 +56,12 @@ void db_label_source::text_value_for_line(textview_curses &tc, int row,
*/
label_out.clear();
if (row >= (int)this->dls_rows.size()) {
if (row >= (int) this->dls_rows.size()) {
return;
}
for (int lpc = 0; lpc < (int)this->dls_rows[row].size(); lpc++) {
auto actual_col_size = std::min(MAX_COLUMN_WIDTH,
this->dls_headers[lpc].hm_column_size);
for (int lpc = 0; lpc < (int) this->dls_rows[row].size(); lpc++) {
auto actual_col_size
= std::min(MAX_COLUMN_WIDTH, this->dls_headers[lpc].hm_column_size);
auto raw_cell_str = std::string(this->dls_rows[row][lpc]);
std::string cell_str;
@ -83,8 +84,8 @@ void db_label_source::text_value_for_line(textview_curses &tc, int row,
truncate_to(cell_str, MAX_COLUMN_WIDTH);
auto cell_length = utf8_string_length(cell_str)
.unwrapOr(actual_col_size);
auto cell_length
= utf8_string_length(cell_str).unwrapOr(actual_col_size);
auto padding = actual_col_size - cell_length;
this->dls_cell_width[lpc] = cell_str.length() + padding;
if (this->dls_headers[lpc].hm_column_type != SQLITE3_TEXT) {
@ -98,13 +99,15 @@ void db_label_source::text_value_for_line(textview_curses &tc, int row,
}
}
void db_label_source::text_attrs_for_line(textview_curses &tc, int row,
string_attrs_t &sa)
void
db_label_source::text_attrs_for_line(textview_curses& tc,
int row,
string_attrs_t& sa)
{
struct line_range lr(0, 0);
struct line_range lr2(0, -1);
if (row >= (int)this->dls_rows.size()) {
if (row >= (int) this->dls_rows.size()) {
return;
}
for (size_t lpc = 0; lpc < this->dls_headers.size() - 1; lpc++) {
@ -119,30 +122,35 @@ void db_label_source::text_attrs_for_line(textview_curses &tc, int row,
int left = 0;
for (size_t lpc = 0; lpc < this->dls_headers.size(); lpc++) {
const char *row_value = this->dls_rows[row][lpc];
const char* row_value = this->dls_rows[row][lpc];
size_t row_len = strlen(row_value);
if (this->dls_headers[lpc].hm_graphable) {
double num_value;
if (sscanf(row_value, "%lf", &num_value) == 1) {
this->dls_chart.chart_attrs_for_value(tc, left, this->dls_headers[lpc].hm_name, num_value, sa);
this->dls_chart.chart_attrs_for_value(
tc, left, this->dls_headers[lpc].hm_name, num_value, sa);
}
}
if (row_len > 2 && row_len < MAX_COLUMN_WIDTH &&
((row_value[0] == '{' && row_value[row_len - 1] == '}') ||
(row_value[0] == '[' && row_value[row_len - 1] == ']'))) {
if (row_len > 2 && row_len < MAX_COLUMN_WIDTH
&& ((row_value[0] == '{' && row_value[row_len - 1] == '}')
|| (row_value[0] == '[' && row_value[row_len - 1] == ']')))
{
json_ptr_walk jpw;
if (jpw.parse(row_value, row_len) == yajl_status_ok &&
jpw.complete_parse() == yajl_status_ok) {
for (auto &jpw_value : jpw.jpw_values) {
if (jpw.parse(row_value, row_len) == yajl_status_ok
&& jpw.complete_parse() == yajl_status_ok)
{
for (auto& jpw_value : jpw.jpw_values) {
double num_value;
if (jpw_value.wt_type == yajl_t_number &&
sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) {
this->dls_chart.chart_attrs_for_value(tc, left,
jpw_value.wt_ptr, num_value, sa);
if (jpw_value.wt_type == yajl_t_number
&& sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value)
== 1)
{
this->dls_chart.chart_attrs_for_value(
tc, left, jpw_value.wt_ptr, num_value, sa);
}
}
}
@ -150,13 +158,15 @@ void db_label_source::text_attrs_for_line(textview_curses &tc, int row,
}
}
void db_label_source::push_header(const std::string &colstr, int type,
bool graphable)
void
db_label_source::push_header(const std::string& colstr,
int type,
bool graphable)
{
this->dls_headers.emplace_back(colstr);
this->dls_cell_width.push_back(0);
header_meta &hm = this->dls_headers.back();
header_meta& hm = this->dls_headers.back();
hm.hm_column_size = utf8_string_length(colstr).unwrapOr(colstr.length());
hm.hm_column_type = type;
@ -166,17 +176,17 @@ void db_label_source::push_header(const std::string &colstr, int type,
}
}
void db_label_source::push_column(const char *colstr)
void
db_label_source::push_column(const char* colstr)
{
view_colors &vc = view_colors::singleton();
view_colors& vc = view_colors::singleton();
int index = this->dls_rows.back().size();
double num_value = 0.0;
size_t value_len;
if (colstr == nullptr) {
colstr = NULL_STR;
}
else {
} else {
colstr = strdup(colstr);
if (colstr == nullptr) {
throw "out of memory";
@ -192,36 +202,39 @@ void db_label_source::push_column(const char *colstr)
tv.tv_sec = -1;
tv.tv_usec = -1;
}
if (!this->dls_time_column.empty() && tv < this->dls_time_column.back()) {
if (!this->dls_time_column.empty() && tv < this->dls_time_column.back())
{
this->dls_time_column_index = -1;
this->dls_time_column.clear();
}
else {
} else {
this->dls_time_column.push_back(tv);
}
}
this->dls_rows.back().push_back(colstr);
this->dls_headers[index].hm_column_size =
std::max(this->dls_headers[index].hm_column_size,
utf8_string_length(colstr, value_len).unwrapOr(value_len));
this->dls_headers[index].hm_column_size
= std::max(this->dls_headers[index].hm_column_size,
utf8_string_length(colstr, value_len).unwrapOr(value_len));
if (colstr != nullptr && this->dls_headers[index].hm_graphable) {
if (sscanf(colstr, "%lf", &num_value) != 1) {
num_value = 0.0;
}
this->dls_chart.add_value(this->dls_headers[index].hm_name, num_value);
}
else if (value_len > 2 &&
((colstr[0] == '{' && colstr[value_len - 1] == '}') ||
(colstr[0] == '[' && colstr[value_len - 1] == ']'))) {
} else if (value_len > 2
&& ((colstr[0] == '{' && colstr[value_len - 1] == '}')
|| (colstr[0] == '[' && colstr[value_len - 1] == ']')))
{
json_ptr_walk jpw;
if (jpw.parse(colstr, value_len) == yajl_status_ok &&
jpw.complete_parse() == yajl_status_ok) {
for (auto &jpw_value : jpw.jpw_values) {
if (jpw_value.wt_type == yajl_t_number &&
sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) {
if (jpw.parse(colstr, value_len) == yajl_status_ok
&& jpw.complete_parse() == yajl_status_ok)
{
for (auto& jpw_value : jpw.jpw_values) {
if (jpw_value.wt_type == yajl_t_number
&& sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value)
== 1)
{
this->dls_chart.add_value(jpw_value.wt_ptr, num_value);
this->dls_chart.with_attrs_for_ident(
jpw_value.wt_ptr, vc.attrs_for_ident(jpw_value.wt_ptr));
@ -231,14 +244,15 @@ void db_label_source::push_column(const char *colstr)
}
}
void db_label_source::clear()
void
db_label_source::clear()
{
this->dls_chart.clear();
this->dls_headers.clear();
for (size_t row = 0; row < this->dls_rows.size(); row++) {
for (size_t col = 0; col < this->dls_rows[row].size(); col++) {
if (this->dls_rows[row][col] != NULL_STR) {
free((void *)this->dls_rows[row][col]);
free((void*) this->dls_rows[row][col]);
}
}
}
@ -247,13 +261,12 @@ void db_label_source::clear()
this->dls_cell_width.clear();
}
long db_label_source::column_name_to_index(const std::string &name) const
long
db_label_source::column_name_to_index(const std::string& name) const
{
std::vector<header_meta>::const_iterator iter;
iter = std::find(this->dls_headers.begin(),
this->dls_headers.end(),
name);
iter = std::find(this->dls_headers.begin(), this->dls_headers.end(), name);
if (iter == this->dls_headers.end()) {
return -1;
}
@ -261,7 +274,8 @@ long db_label_source::column_name_to_index(const std::string &name) const
return std::distance(this->dls_headers.begin(), iter);
}
nonstd::optional<vis_line_t> db_label_source::row_for_time(struct timeval time_bucket)
nonstd::optional<vis_line_t>
db_label_source::row_for_time(struct timeval time_bucket)
{
std::vector<struct timeval>::iterator iter;
@ -274,7 +288,8 @@ nonstd::optional<vis_line_t> db_label_source::row_for_time(struct timeval time_b
return nonstd::nullopt;
}
size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
size_t
db_overlay_source::list_overlay_count(const listview_curses& lv)
{
size_t retval = 1;
@ -284,9 +299,9 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
return retval;
}
view_colors &vc = view_colors::singleton();
view_colors& vc = view_colors::singleton();
vis_line_t top = lv.get_top();
const std::vector<const char *> &cols = this->dos_labels->dls_rows[top];
const std::vector<const char*>& cols = this->dos_labels->dls_rows[top];
unsigned long width;
vis_line_t height;
@ -294,22 +309,24 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
this->dos_lines.clear();
for (size_t col = 0; col < cols.size(); col++) {
const char *col_value = cols[col];
const char* col_value = cols[col];
size_t col_len = strlen(col_value);
if (!(col_len >= 2 &&
((col_value[0] == '{' && col_value[col_len - 1] == '}') ||
(col_value[0] == '[' && col_value[col_len - 1] == ']')))) {
if (!(col_len >= 2
&& ((col_value[0] == '{' && col_value[col_len - 1] == '}')
|| (col_value[0] == '[' && col_value[col_len - 1] == ']'))))
{
continue;
}
json_ptr_walk jpw;
if (jpw.parse(col_value, col_len) == yajl_status_ok &&
jpw.complete_parse() == yajl_status_ok) {
if (jpw.parse(col_value, col_len) == yajl_status_ok
&& jpw.complete_parse() == yajl_status_ok)
{
{
const std::string &header = this->dos_labels->dls_headers[col].hm_name;
const std::string& header
= this->dos_labels->dls_headers[col].hm_name;
this->dos_lines.emplace_back(" JSON Column: " + header);
retval += 1;
@ -318,14 +335,13 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
stacked_bar_chart<std::string> chart;
int start_line = this->dos_lines.size();
chart.with_stacking_enabled(false)
.with_margins(3, 0);
chart.with_stacking_enabled(false).with_margins(3, 0);
for (auto &jpw_value : jpw.jpw_values) {
this->dos_lines.emplace_back(" " + jpw_value.wt_ptr + " = " +
jpw_value.wt_value);
for (auto& jpw_value : jpw.jpw_values) {
this->dos_lines.emplace_back(" " + jpw_value.wt_ptr + " = "
+ jpw_value.wt_value);
string_attrs_t &sa = this->dos_lines.back().get_attrs();
string_attrs_t& sa = this->dos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LTEE);
@ -335,8 +351,10 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
double num_value = 0.0;
if (jpw_value.wt_type == yajl_t_number &&
sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) {
if (jpw_value.wt_type == yajl_t_number
&& sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value)
== 1)
{
int attrs = vc.attrs_for_ident(jpw_value.wt_ptr);
chart.add_value(jpw_value.wt_ptr, num_value);
@ -349,15 +367,18 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
int curr_line = start_line;
for (auto iter = jpw.jpw_values.begin();
iter != jpw.jpw_values.end();
++iter, curr_line++) {
++iter, curr_line++)
{
double num_value = 0.0;
if (iter->wt_type == yajl_t_number &&
sscanf(iter->wt_value.c_str(), "%lf", &num_value) == 1) {
string_attrs_t &sa = this->dos_lines[curr_line].get_attrs();
if (iter->wt_type == yajl_t_number
&& sscanf(iter->wt_value.c_str(), "%lf", &num_value) == 1)
{
string_attrs_t& sa = this->dos_lines[curr_line].get_attrs();
int left = 3;
chart.chart_attrs_for_value(lv, left, iter->wt_ptr, num_value, sa);
chart.chart_attrs_for_value(
lv, left, iter->wt_ptr, num_value, sa);
}
}
}
@ -366,7 +387,7 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
if (retval > 1) {
this->dos_lines.emplace_back("");
string_attrs_t &sa = this->dos_lines.back().get_attrs();
string_attrs_t& sa = this->dos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER);
@ -380,29 +401,31 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
return retval;
}
bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
int bottom, vis_line_t row,
attr_line_t &value_out)
bool
db_overlay_source::list_value_for_overlay(const listview_curses& lv,
int y,
int bottom,
vis_line_t row,
attr_line_t& value_out)
{
view_colors &vc = view_colors::singleton();
view_colors& vc = view_colors::singleton();
if (y == 0) {
this->list_overlay_count(lv);
std::string &line = value_out.get_string();
db_label_source *dls = this->dos_labels;
string_attrs_t &sa = value_out.get_attrs();
std::string& line = value_out.get_string();
db_label_source* dls = this->dos_labels;
string_attrs_t& sa = value_out.get_attrs();
for (size_t lpc = 0;
lpc < this->dos_labels->dls_headers.size();
lpc++) {
for (size_t lpc = 0; lpc < this->dos_labels->dls_headers.size(); lpc++)
{
auto actual_col_size = std::min(
MAX_COLUMN_WIDTH, dls->dls_headers[lpc].hm_column_size);
std::string cell_title = dls->dls_headers[lpc].hm_name;
truncate_to(cell_title, MAX_COLUMN_WIDTH);
auto cell_length = utf8_string_length(cell_title)
.unwrapOr(actual_col_size);
auto cell_length
= utf8_string_length(cell_title).unwrapOr(actual_col_size);
int before, total_fill = actual_col_size - cell_length;
auto line_len_before = line.length();
@ -415,8 +438,8 @@ bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
struct line_range header_range(line_len_before, line.length());
int attrs =
vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) | A_REVERSE;
int attrs
= vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) | A_REVERSE;
if (!this->dos_labels->dls_headers[lpc].hm_graphable) {
attrs = A_UNDERLINE;
}
@ -427,8 +450,9 @@ bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD | A_UNDERLINE);
return true;
}
else if (this->dos_active && y >= 2 && ((size_t) y) < (this->dos_lines.size() + 2)) {
} else if (this->dos_active && y >= 2
&& ((size_t) y) < (this->dos_lines.size() + 2))
{
value_out = this->dos_lines[y - 2];
return true;
}

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,60 +30,68 @@
#ifndef db_sub_source_hh
#define db_sub_source_hh
#include <iterator>
#include <string>
#include <vector>
#include <iterator>
#include <sqlite3.h>
#include "textview_curses.hh"
#include "hist_source.hh"
#include "textview_curses.hh"
class db_label_source : public text_sub_source, public text_time_translator {
class db_label_source
: public text_sub_source
, public text_time_translator {
public:
~db_label_source() {
~db_label_source()
{
this->clear();
}
bool has_log_time_column() const {
bool has_log_time_column() const
{
return !this->dls_time_column.empty();
};
size_t text_line_count() {
size_t text_line_count()
{
return this->dls_rows.size();
};
size_t text_size_for_line(textview_curses &tc, int line, line_flags_t flags) {
size_t text_size_for_line(textview_curses& tc, int line, line_flags_t flags)
{
return this->text_line_width(tc);
};
size_t text_line_width(textview_curses &curses) {
size_t text_line_width(textview_curses& curses)
{
size_t retval = 0;
for (auto &dls_header : this->dls_headers) {
for (auto& dls_header : this->dls_headers) {
retval += dls_header.hm_column_size + 1;
}
return retval;
};
void text_value_for_line(textview_curses &tc,
void text_value_for_line(textview_curses& tc,
int row,
std::string &label_out,
std::string& label_out,
line_flags_t flags);
void text_attrs_for_line(textview_curses &tc, int row, string_attrs_t &sa);
void text_attrs_for_line(textview_curses& tc, int row, string_attrs_t& sa);
void push_header(const std::string &colstr, int type, bool graphable);
void push_header(const std::string& colstr, int type, bool graphable);
void push_column(const char *colstr);
void push_column(const char* colstr);
void clear();
long column_name_to_index(const std::string &name) const;
long column_name_to_index(const std::string& name) const;
nonstd::optional<vis_line_t> row_for_time(struct timeval time_bucket);
nonstd::optional<struct timeval> time_for_row(vis_line_t row) {
nonstd::optional<struct timeval> time_for_row(vis_line_t row)
{
if ((row < 0_vl) || (((size_t) row) >= this->dls_time_column.size())) {
return nonstd::nullopt;
}
@ -93,15 +101,13 @@ public:
struct header_meta {
explicit header_meta(std::string name)
: hm_name(std::move(name)),
hm_column_type(SQLITE3_TEXT),
hm_graphable(false),
hm_log_time(false),
hm_column_size(0) {
: hm_name(std::move(name)), hm_column_type(SQLITE3_TEXT),
hm_graphable(false), hm_log_time(false), hm_column_size(0){
};
};
bool operator==(const std::string &name) const {
bool operator==(const std::string& name) const
{
return this->hm_name == name;
};
@ -115,25 +121,26 @@ public:
stacked_bar_chart<std::string> dls_chart;
std::vector<header_meta> dls_headers;
std::vector<std::vector<const char *>> dls_rows;
std::vector<std::vector<const char*>> dls_rows;
std::vector<struct timeval> dls_time_column;
std::vector<size_t> dls_cell_width;
int dls_time_column_index{-1};
static const char *NULL_STR;
static const char* NULL_STR;
};
class db_overlay_source : public list_overlay_source {
public:
size_t list_overlay_count(const listview_curses &lv);
size_t list_overlay_count(const listview_curses& lv);
bool list_value_for_overlay(const listview_curses &lv,
int y, int bottom,
bool list_value_for_overlay(const listview_curses& lv,
int y,
int bottom,
vis_line_t row,
attr_line_t &value_out) override;
attr_line_t& value_out) override;
bool dos_active{false};
db_label_source *dos_labels{nullptr};
db_label_source* dos_labels{nullptr};
std::vector<attr_line_t> dos_lines;
};
#endif

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -34,8 +34,7 @@
#include "statusview_curses.hh"
class doc_status_source
: public status_data_source {
class doc_status_source : public status_data_source {
public:
typedef enum {
TSF_TITLE,
@ -45,7 +44,8 @@ public:
TSF__MAX
} field_t;
doc_status_source() {
doc_status_source()
{
this->tss_fields[TSF_TITLE].set_width(14);
this->tss_fields[TSF_TITLE].set_left_pad(1);
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
@ -57,19 +57,23 @@ public:
this->tss_fields[TSF_DESCRIPTION].set_role(view_colors::VCR_STATUS);
};
size_t statusview_fields() override {
size_t statusview_fields() override
{
return TSF__MAX;
};
status_field &statusview_value_for_field(int field) override {
status_field& statusview_value_for_field(int field) override
{
return this->tss_fields[field];
};
void set_title(const std::string &title) {
void set_title(const std::string& title)
{
this->tss_fields[TSF_TITLE].set_value(title);
}
void set_description(const std::string &description) {
void set_description(const std::string& description)
{
this->tss_fields[TSF_DESCRIPTION].set_value(description);
}

@ -21,26 +21,26 @@
* 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
* 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 <algorithm>
#include "elem_to_json.hh"
#include "config.h"
#include "yajlpp/yajlpp.hh"
using namespace std;
static
void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &elem)
static void
element_to_json(yajl_gen gen, data_parser& dp, const data_parser::element& elem)
{
size_t value_len;
const char *value_str = dp.get_element_string(elem, value_len);
const char* value_str = dp.get_element_string(elem, value_len);
switch (elem.value_token()) {
case DT_NUMBER: {
@ -48,20 +48,21 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
break;
}
case DNT_GROUP: {
elements_to_json(gen, dp, elem.get_value_elem().e_sub_elements, false);
elements_to_json(
gen, dp, elem.get_value_elem().e_sub_elements, false);
break;
}
case DNT_PAIR: {
const data_parser::element &pair_elem = elem.get_pair_elem();
string key_str = dp.get_element_string(pair_elem.e_sub_elements->front());
const data_parser::element& pair_elem = elem.get_pair_elem();
string key_str
= dp.get_element_string(pair_elem.e_sub_elements->front());
if (!key_str.empty()) {
yajlpp_map singleton_map(gen);
singleton_map.gen(key_str);
element_to_json(gen, dp, pair_elem.get_pair_value());
}
else {
} else {
element_to_json(gen, dp, pair_elem.get_pair_value());
}
break;
@ -69,11 +70,9 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
case DT_CONSTANT: {
if (strncasecmp("true", value_str, value_len) == 0) {
yajl_gen_bool(gen, true);
}
else if (strncasecmp("false", value_str, value_len) == 0) {
} else if (strncasecmp("false", value_str, value_len) == 0) {
yajl_gen_bool(gen, false);
}
else {
} else {
yajl_gen_null(gen);
}
break;
@ -84,22 +83,24 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
}
}
static
void map_elements_to_json2(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
static void
map_elements_to_json2(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el)
{
yajlpp_map root_map(gen);
int col = 0;
for (auto &iter : *el) {
const data_parser::element &pvalue = iter.get_pair_value();
for (auto& iter : *el) {
const data_parser::element& pvalue = iter.get_pair_value();
if (pvalue.value_token() == DT_INVALID) {
log_debug("invalid!!");
// continue;
}
std::string key_str = dp.get_element_string(
iter.e_sub_elements->front());
std::string key_str
= dp.get_element_string(iter.e_sub_elements->front());
if (key_str.empty()) {
char buffer[32];
@ -113,46 +114,51 @@ void map_elements_to_json2(yajl_gen gen, data_parser &dp, data_parser::element_l
}
}
static
void list_body_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
static void
list_body_elements_to_json(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el)
{
for (auto &iter : *el) {
for (auto& iter : *el) {
element_to_json(gen, dp, iter);
}
}
static
void list_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
static void
list_elements_to_json(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el)
{
yajlpp_array root_array(gen);
list_body_elements_to_json(gen, dp, el);
}
static
void map_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
static void
map_elements_to_json(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el)
{
bool unique_names = el->size() > 1;
vector<string> names;
for (auto &iter : *el) {
const data_parser::element &pvalue = iter.get_pair_value();
for (auto& iter : *el) {
const data_parser::element& pvalue = iter.get_pair_value();
if (pvalue.value_token() == DT_INVALID) {
log_debug("invalid!!");
// continue;
}
std::string key_str = dp.get_element_string(
iter.e_sub_elements->front());
std::string key_str
= dp.get_element_string(iter.e_sub_elements->front());
if (key_str.empty()) {
continue;
}
if (find(names.begin(), names.end(), key_str) != names.end()) {
unique_names = false;
break;
}
else {
} else {
names.push_back(key_str);
}
}
@ -161,30 +167,33 @@ void map_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_li
if (unique_names) {
map_elements_to_json2(gen, dp, el);
}
else {
} else {
list_elements_to_json(gen, dp, el);
}
}
void elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el, bool root)
void
elements_to_json(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el,
bool root)
{
if (el->empty()) {
yajl_gen_null(gen);
}
else {
} else {
switch (el->front().e_token) {
case DNT_PAIR: {
if (root && el->size() == 1) {
const data_parser::element &pair_elem = el->front().get_pair_elem();
const data_parser::element& pair_elem
= el->front().get_pair_elem();
std::string key_str = dp.get_element_string(
pair_elem.e_sub_elements->front());
if (key_str.empty() &&
el->front().get_pair_value().value_token() == DNT_GROUP) {
if (key_str.empty()
&& el->front().get_pair_value().value_token()
== DNT_GROUP) {
element_to_json(gen, dp, el->front().get_pair_value());
}
else {
} else {
yajlpp_map singleton_map(gen);
if (key_str.empty()) {
@ -193,8 +202,7 @@ void elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t
singleton_map.gen(key_str);
element_to_json(gen, dp, pair_elem.get_pair_value());
}
}
else {
} else {
map_elements_to_json(gen, dp, el);
}
break;

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,9 +30,12 @@
#ifndef elem_to_json_hh
#define elem_to_json_hh
#include "yajl/api/yajl_gen.h"
#include "data_parser.hh"
#include "yajl/api/yajl_gen.h"
void elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el, bool root = true);
void elements_to_json(yajl_gen gen,
data_parser& dp,
data_parser::element_list_t* el,
bool root = true);
#endif

@ -21,26 +21,26 @@
* 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
* 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 "environ_vtab.hh"
#include <stdlib.h>
#include <string.h>
#include "auto_mem.hh"
#include "base/lnav_log.hh"
#include "environ_vtab.hh"
#include "config.h"
using namespace std;
extern char **environ;
extern char** environ;
const char *ENVIRON_CREATE_STMT = R"(
const char* ENVIRON_CREATE_STMT = R"(
-- Access lnav's environment variables through this table.
CREATE TABLE environ (
name text PRIMARY KEY,
@ -49,27 +49,29 @@ CREATE TABLE environ (
)";
struct vtab {
sqlite3_vtab base;
sqlite3 * db;
sqlite3_vtab base;
sqlite3* db;
};
struct vtab_cursor {
sqlite3_vtab_cursor base;
char **env_cursor;
sqlite3_vtab_cursor base;
char** env_cursor;
};
static int vt_destructor(sqlite3_vtab *p_svt);
static int vt_destructor(sqlite3_vtab* p_svt);
static int vt_create(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **pp_vt,
char **pzErr)
static int
vt_create(sqlite3* db,
void* pAux,
int argc,
const char* const* argv,
sqlite3_vtab** pp_vt,
char** pzErr)
{
vtab *p_vt;
vtab* p_vt;
/* Allocate the sqlite3_vtab/vtab structure itself */
p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));
p_vt = (vtab*) sqlite3_malloc(sizeof(*p_vt));
if (p_vt == NULL) {
return SQLITE_NOMEM;
@ -85,10 +87,10 @@ static int vt_create(sqlite3 *db,
return rc;
}
static int vt_destructor(sqlite3_vtab *p_svt)
static int
vt_destructor(sqlite3_vtab* p_svt)
{
vtab *p_vt = (vtab *)p_svt;
vtab* p_vt = (vtab*) p_svt;
/* Free the SQLite structure */
sqlite3_free(p_vt);
@ -96,37 +98,44 @@ static int vt_destructor(sqlite3_vtab *p_svt)
return SQLITE_OK;
}
static int vt_connect(sqlite3 *db, void *p_aux,
int argc, const char *const *argv,
sqlite3_vtab **pp_vt, char **pzErr)
static int
vt_connect(sqlite3* db,
void* p_aux,
int argc,
const char* const* argv,
sqlite3_vtab** pp_vt,
char** pzErr)
{
return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}
static int vt_disconnect(sqlite3_vtab *pVtab)
static int
vt_disconnect(sqlite3_vtab* pVtab)
{
return vt_destructor(pVtab);
}
static int vt_destroy(sqlite3_vtab *p_vt)
static int
vt_destroy(sqlite3_vtab* p_vt)
{
return vt_destructor(p_vt);
}
static int vt_next(sqlite3_vtab_cursor *cur);
static int vt_next(sqlite3_vtab_cursor* cur);
static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
static int
vt_open(sqlite3_vtab* p_svt, sqlite3_vtab_cursor** pp_cursor)
{
vtab *p_vt = (vtab *)p_svt;
vtab* p_vt = (vtab*) p_svt;
p_vt->base.zErrMsg = NULL;
vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();
vtab_cursor* p_cur = (vtab_cursor*) new vtab_cursor();
if (p_cur == NULL) {
return SQLITE_NOMEM;
} else {
*pp_cursor = (sqlite3_vtab_cursor *)p_cur;
*pp_cursor = (sqlite3_vtab_cursor*) p_cur;
p_cur->base.pVtab = p_svt;
p_cur->env_cursor = environ;
@ -135,9 +144,10 @@ static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
return SQLITE_OK;
}
static int vt_close(sqlite3_vtab_cursor *cur)
static int
vt_close(sqlite3_vtab_cursor* cur)
{
vtab_cursor *p_cur = (vtab_cursor *)cur;
vtab_cursor* p_cur = (vtab_cursor*) cur;
/* Free cursor struct. */
delete p_cur;
@ -145,16 +155,18 @@ static int vt_close(sqlite3_vtab_cursor *cur)
return SQLITE_OK;
}
static int vt_eof(sqlite3_vtab_cursor *cur)
static int
vt_eof(sqlite3_vtab_cursor* cur)
{
vtab_cursor *vc = (vtab_cursor *)cur;
vtab_cursor* vc = (vtab_cursor*) cur;
return vc->env_cursor[0] == NULL;
}
static int vt_next(sqlite3_vtab_cursor *cur)
static int
vt_next(sqlite3_vtab_cursor* cur)
{
vtab_cursor *vc = (vtab_cursor *)cur;
vtab_cursor* vc = (vtab_cursor*) cur;
if (vc->env_cursor[0] != NULL) {
vc->env_cursor += 1;
@ -163,61 +175,69 @@ static int vt_next(sqlite3_vtab_cursor *cur)
return SQLITE_OK;
}
static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
static int
vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
{
vtab_cursor *vc = (vtab_cursor *)cur;
const char *eq = strchr(vc->env_cursor[0], '=');
vtab_cursor* vc = (vtab_cursor*) cur;
const char* eq = strchr(vc->env_cursor[0], '=');
switch (col) {
case 0:
sqlite3_result_text(ctx,
vc->env_cursor[0], eq - vc->env_cursor[0],
SQLITE_TRANSIENT);
break;
case 1:
sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
break;
case 0:
sqlite3_result_text(ctx,
vc->env_cursor[0],
eq - vc->env_cursor[0],
SQLITE_TRANSIENT);
break;
case 1:
sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
break;
}
return SQLITE_OK;
}
static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
static int
vt_rowid(sqlite3_vtab_cursor* cur, sqlite_int64* p_rowid)
{
vtab_cursor *p_cur = (vtab_cursor *)cur;
vtab_cursor* p_cur = (vtab_cursor*) cur;
*p_rowid = (int64_t)p_cur->env_cursor[0];
*p_rowid = (int64_t) p_cur->env_cursor[0];
return SQLITE_OK;
}
static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
static int
vt_best_index(sqlite3_vtab* tab, sqlite3_index_info* p_info)
{
return SQLITE_OK;
}
static int vt_filter(sqlite3_vtab_cursor *p_vtc,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv)
static int
vt_filter(sqlite3_vtab_cursor* p_vtc,
int idxNum,
const char* idxStr,
int argc,
sqlite3_value** argv)
{
return SQLITE_OK;
}
static int vt_update(sqlite3_vtab *tab,
int argc,
sqlite3_value **argv,
sqlite_int64 *rowid)
static int
vt_update(sqlite3_vtab* tab,
int argc,
sqlite3_value** argv,
sqlite_int64* rowid)
{
const char *name = (
argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : nullptr);
vtab *p_vt = (vtab *)tab;
const char* name
= (argc > 2 ? (const char*) sqlite3_value_text(argv[2]) : nullptr);
vtab* p_vt = (vtab*) tab;
int retval = SQLITE_ERROR;
if (argc != 1 &&
(argc < 3 ||
sqlite3_value_type(argv[2]) == SQLITE_NULL ||
sqlite3_value_type(argv[3]) == SQLITE_NULL ||
sqlite3_value_text(argv[2])[0] == '\0')) {
if (argc != 1
&& (argc < 3 || sqlite3_value_type(argv[2]) == SQLITE_NULL
|| sqlite3_value_type(argv[3]) == SQLITE_NULL
|| sqlite3_value_text(argv[2])[0] == '\0'))
{
tab->zErrMsg = sqlite3_mprintf(
"A non-empty name and value must be provided when inserting an "
"environment variable");
@ -233,8 +253,8 @@ static int vt_update(sqlite3_vtab *tab,
if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
int64_t index = sqlite3_value_int64(argv[0]);
const char *var = (const char *)index;
const char *eq = strchr(var, '=');
const char* var = (const char*) index;
const char* eq = strchr(var, '=');
size_t namelen = eq - var;
char name[namelen + 1];
@ -249,26 +269,26 @@ static int vt_update(sqlite3_vtab *tab,
rc = sqlite3_vtab_on_conflict(p_vt->db);
switch (rc) {
case SQLITE_FAIL:
case SQLITE_ABORT:
tab->zErrMsg = sqlite3_mprintf(
"An environment variable with the name '%s' already exists",
name);
return rc;
case SQLITE_IGNORE:
return SQLITE_OK;
case SQLITE_REPLACE:
break;
default:
return rc;
case SQLITE_FAIL:
case SQLITE_ABORT:
tab->zErrMsg = sqlite3_mprintf(
"An environment variable with the name '%s' already exists",
name);
return rc;
case SQLITE_IGNORE:
return SQLITE_OK;
case SQLITE_REPLACE:
break;
default:
return rc;
}
#endif
}
if (name != nullptr && argc == 4) {
const unsigned char *value = sqlite3_value_text(argv[3]);
const unsigned char* value = sqlite3_value_text(argv[3]);
setenv((const char *)name, (const char *)value, 1);
setenv((const char*) name, (const char*) value, 1);
return SQLITE_OK;
}
@ -277,37 +297,43 @@ static int vt_update(sqlite3_vtab *tab,
}
static sqlite3_module vtab_module = {
0, /* iVersion */
vt_create, /* xCreate - create a vtable */
vt_connect, /* xConnect - associate a vtable with a connection */
vt_best_index, /* xBestIndex - best index */
vt_disconnect, /* xDisconnect - disassociate a vtable with a connection */
vt_destroy, /* xDestroy - destroy a vtable */
vt_open, /* xOpen - open a cursor */
vt_close, /* xClose - close a cursor */
vt_filter, /* xFilter - configure scan constraints */
vt_next, /* xNext - advance a cursor */
vt_eof, /* xEof - inidicate end of result set*/
vt_column, /* xColumn - read data */
vt_rowid, /* xRowid - read data */
vt_update, /* xUpdate - write data */
NULL, /* xBegin - begin transaction */
NULL, /* xSync - sync transaction */
NULL, /* xCommit - commit transaction */
NULL, /* xRollback - rollback transaction */
NULL, /* xFindFunction - function overloading */
0, /* iVersion */
vt_create, /* xCreate - create a vtable */
vt_connect, /* xConnect - associate a vtable with a connection */
vt_best_index, /* xBestIndex - best index */
vt_disconnect, /* xDisconnect - disassociate a vtable with a connection */
vt_destroy, /* xDestroy - destroy a vtable */
vt_open, /* xOpen - open a cursor */
vt_close, /* xClose - close a cursor */
vt_filter, /* xFilter - configure scan constraints */
vt_next, /* xNext - advance a cursor */
vt_eof, /* xEof - inidicate end of result set*/
vt_column, /* xColumn - read data */
vt_rowid, /* xRowid - read data */
vt_update, /* xUpdate - write data */
NULL, /* xBegin - begin transaction */
NULL, /* xSync - sync transaction */
NULL, /* xCommit - commit transaction */
NULL, /* xRollback - rollback transaction */
NULL, /* xFindFunction - function overloading */
};
int register_environ_vtab(sqlite3 *db)
int
register_environ_vtab(sqlite3* db)
{
auto_mem<char, sqlite3_free> errmsg;
int rc;
rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
ensure(rc == SQLITE_OK);
if ((rc = sqlite3_exec(db,
if ((rc = sqlite3_exec(
db,
"CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
NULL, NULL, errmsg.out())) != SQLITE_OK) {
NULL,
NULL,
errmsg.out()))
!= SQLITE_OK)
{
fprintf(stderr, "unable to create environ table %s\n", errmsg.in());
}
return rc;

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -32,8 +32,8 @@
#include <sqlite3.h>
int register_environ_vtab(sqlite3 *db);
int register_environ_vtab(sqlite3* db);
extern const char *ENVIRON_CREATE_STMT;
extern const char* ENVIRON_CREATE_STMT;
#endif

File diff suppressed because it is too large Load Diff

@ -21,40 +21,41 @@
* 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
* 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 "field_overlay_source.hh"
#include "ansi_scrubber.hh"
#include "base/humanize.time.hh"
#include "config.h"
#include "lnav_util.hh"
#include "ansi_scrubber.hh"
#include "vtab_module.hh"
#include "relative_time.hh"
#include "field_overlay_source.hh"
#include "readline_highlighters.hh"
#include "vtab_module_json.hh"
#include "log_format_ext.hh"
#include "log_vtab_impl.hh"
#include "readline_highlighters.hh"
#include "relative_time.hh"
#include "vtab_module.hh"
#include "vtab_module_json.hh"
using namespace std;
json_string extract(const char *str);
json_string extract(const char* str);
void field_overlay_source::build_summary_lines(const listview_curses &lv)
void
field_overlay_source::build_summary_lines(const listview_curses& lv)
{
auto& tc = dynamic_cast<const textview_curses &>(lv);
textfile_sub_source &tss = this->fos_tss;
logfile_sub_source &lss = this->fos_lss;
auto& tc = dynamic_cast<const textview_curses&>(lv);
textfile_sub_source& tss = this->fos_tss;
logfile_sub_source& lss = this->fos_lss;
this->fos_summary_lines.clear();
{
vis_line_t filled_rows = lv.rows_available(
lv.get_top(), listview_curses::RD_DOWN);
vis_line_t filled_rows
= lv.rows_available(lv.get_top(), listview_curses::RD_DOWN);
vis_line_t height, free_rows;
unsigned long width;
long rate_len = 0;
@ -63,69 +64,72 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
free_rows = height - filled_rows - vis_line_t(this->fos_lines.size());
if (free_rows < 2 || !this->fos_show_status) {
this->fos_summary_lines.clear();
}
else {
} else {
string time_span;
double error_rate = 0.0;
if (lv.get_inner_height() == 0) {
time_span = "None";
}
else {
} else {
logline *first_line, *last_line;
time_t now = time(nullptr);
first_line = lss.find_line(lss.at(vis_line_t(0)));
last_line = lss.find_line(lss.at(lv.get_bottom()));
time_span = humanize::time::duration::from_tv(
last_line->get_timeval() - first_line->get_timeval())
.to_string();
time_span
= humanize::time::duration::from_tv(
last_line->get_timeval() - first_line->get_timeval())
.to_string();
time_t local_now = convert_log_time_to_local(now);
time_t five_minutes_ago = local_now - (5 * 60 * 60);
time_t ten_secs_ago = local_now - 10;
auto from_five_min_ago_opt = lss.find_from_time(five_minutes_ago);
auto from_five_min_ago_opt
= lss.find_from_time(five_minutes_ago);
auto from_ten_secs_ago_opt = lss.find_from_time(ten_secs_ago);
auto &bm = tc.get_bookmarks();
auto& bm = tc.get_bookmarks();
auto error_bm_iter = bm.find(&logfile_sub_source::BM_ERRORS);
if (now > last_line->get_time() && from_five_min_ago_opt &&
error_bm_iter != bm.end()) {
if (now > last_line->get_time() && from_five_min_ago_opt
&& error_bm_iter != bm.end())
{
auto& error_bookmarks = error_bm_iter->second;
auto five_min_lower =
lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_five_min_ago_opt.value());
auto five_min_lower
= lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_five_min_ago_opt.value());
if (five_min_lower != error_bookmarks.end()) {
double error_count = distance(
five_min_lower, error_bookmarks.end());
double error_count
= distance(five_min_lower, error_bookmarks.end());
double time_diff = 5.0;
if (first_line->get_time() > five_minutes_ago) {
time_diff = (double) (local_now - first_line->get_time()) /
60.0;
time_diff
= (double) (local_now - first_line->get_time())
/ 60.0;
}
error_rate = error_count / time_diff;
if (from_ten_secs_ago_opt) {
auto ten_sec_lower =
lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_ten_secs_ago_opt.value());
auto ten_sec_lower
= lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
from_ten_secs_ago_opt.value());
if (ten_sec_lower != error_bookmarks.end()) {
double recent_error_count = distance(
ten_sec_lower, error_bookmarks.end());
double recent_error_rate =
recent_error_count / 10.0;
double long_error_rate =
error_count / (time_diff * 60.0 / 10.0);
double recent_error_rate
= recent_error_count / 10.0;
double long_error_rate
= error_count / (time_diff * 60.0 / 10.0);
if (long_error_rate == 0.0) {
long_error_rate = 1.0;
}
long computed_rate_len = lrint(ceil(
(recent_error_rate * 40.0) / long_error_rate));
long computed_rate_len
= lrint(ceil((recent_error_rate * 40.0)
/ long_error_rate));
rate_len = min(10L, computed_rate_len);
}
}
@ -134,7 +138,7 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
}
this->fos_summary_lines.emplace_back();
attr_line_t &sum_line = this->fos_summary_lines.back();
attr_line_t& sum_line = this->fos_summary_lines.back();
if (tss.empty()) {
sum_line.with_ansi_string(
" "
@ -160,44 +164,35 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
error_rate,
time_span.c_str());
}
string &sum_msg = sum_line.get_string();
sum_line.with_attr(string_attr(
string& sum_msg = sum_line.get_string();
sum_line
.with_attr(string_attr(
line_range(sum_msg.find("Error rate"),
sum_msg.find("Error rate") + rate_len),
&view_curses::VC_STYLE,
A_REVERSE
))
A_REVERSE))
.with_attr(string_attr(
line_range(1, 2),
&view_curses::VC_GRAPHIC,
ACS_ULCORNER
))
line_range(1, 2), &view_curses::VC_GRAPHIC, ACS_ULCORNER))
.with_attr(string_attr(
line_range(2, 6),
&view_curses::VC_GRAPHIC,
ACS_HLINE
))
line_range(2, 6), &view_curses::VC_GRAPHIC, ACS_HLINE))
.with_attr(string_attr(
line_range(sum_msg.length() + 1,
sum_msg.length() + 5),
line_range(sum_msg.length() + 1, sum_msg.length() + 5),
&view_curses::VC_GRAPHIC,
ACS_HLINE
))
ACS_HLINE))
.with_attr(string_attr(
line_range(sum_msg.length() + 5,
sum_msg.length() + 6),
line_range(sum_msg.length() + 5, sum_msg.length() + 6),
&view_curses::VC_GRAPHIC,
ACS_URCORNER
))
ACS_URCORNER))
.right_justify(width - 2);
}
}
}
void field_overlay_source::build_field_lines(const listview_curses &lv)
void
field_overlay_source::build_field_lines(const listview_curses& lv)
{
logfile_sub_source &lss = this->fos_lss;
view_colors &vc = view_colors::singleton();
logfile_sub_source& lss = this->fos_lss;
view_colors& vc = view_colors::singleton();
this->fos_lines.clear();
@ -213,8 +208,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
auto format = file->get_format();
bool display = false;
if (ll->is_time_skewed() ||
ll->get_msg_level() == log_level_t::LEVEL_INVALID) {
if (ll->is_time_skewed()
|| ll->get_msg_level() == log_level_t::LEVEL_INVALID) {
display = true;
}
if (!this->fos_contexts.empty()) {
@ -238,25 +233,26 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
}
auto emsg = fmt::format(" Invalid log message: {}",
(const char *) sattr.sa_value.sav_ptr);
(const char*) sattr.sa_value.sav_ptr);
auto al = attr_line_t(emsg)
.with_attr(string_attr(line_range{1, 2},
&view_curses::VC_GRAPHIC,
ACS_LLCORNER))
.with_attr(string_attr(line_range{0, 22},
&view_curses::VC_ROLE,
view_colors::VCR_INVALID_MSG));
.with_attr(string_attr(line_range{1, 2},
&view_curses::VC_GRAPHIC,
ACS_LLCORNER))
.with_attr(string_attr(line_range{0, 22},
&view_curses::VC_ROLE,
view_colors::VCR_INVALID_MSG));
this->fos_lines.emplace_back(al);
}
}
char old_timestamp[64], curr_timestamp[64], orig_timestamp[64];
struct timeval curr_tv, offset_tv, orig_tv, diff_tv = { 0, 0 };
struct timeval curr_tv, offset_tv, orig_tv, diff_tv = {0, 0};
attr_line_t time_line;
string &time_str = time_line.get_string();
string& time_str = time_line.get_string();
struct line_range time_lr;
sql_strftime(curr_timestamp, sizeof(curr_timestamp),
sql_strftime(curr_timestamp,
sizeof(curr_timestamp),
ll->get_time(),
ll->get_millis(),
'T');
@ -264,13 +260,13 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
if (ll->is_time_skewed()) {
time_lr.lr_start = 1;
time_lr.lr_end = 2;
time_line.with_attr(string_attr(time_lr, &view_curses::VC_GRAPHIC,
ACS_LLCORNER));
time_line.with_attr(
string_attr(time_lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER));
time_str.append(" Out-Of-Time-Order Message");
time_lr.lr_start = 3;
time_lr.lr_end = time_str.length();
time_line.with_attr(string_attr(time_lr, &view_curses::VC_ROLE,
view_colors::VCR_SKEWED_TIME));
time_line.with_attr(string_attr(
time_lr, &view_curses::VC_ROLE, view_colors::VCR_SKEWED_TIME));
time_str.append(" --");
}
@ -292,62 +288,65 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
curr_tv = this->fos_log_helper.ldh_line->get_timeval();
if (ll->is_time_skewed() && time_range.lr_end != -1) {
const char *time_src = this->fos_log_helper.ldh_msg.get_data() +
time_range.lr_start;
const char* time_src
= this->fos_log_helper.ldh_msg.get_data() + time_range.lr_start;
struct timeval actual_tv;
date_time_scanner dts;
struct exttm tm;
dts.set_base_time(format->lf_date_time.dts_base_time);
if (format->lf_date_time.scan(time_src, time_range.length(),
if (format->lf_date_time.scan(time_src,
time_range.length(),
format->get_timestamp_formats(),
&tm, actual_tv,
false) ||
dts.scan(time_src, time_range.length(),
nullptr,
&tm, actual_tv,
false)) {
sql_strftime(orig_timestamp, sizeof(orig_timestamp), actual_tv, 'T');
&tm,
actual_tv,
false)
|| dts.scan(
time_src, time_range.length(), nullptr, &tm, actual_tv, false))
{
sql_strftime(
orig_timestamp, sizeof(orig_timestamp), actual_tv, 'T');
time_str.append("; Actual Time: ");
time_lr.lr_start = time_str.length();
time_str.append(orig_timestamp);
time_lr.lr_end = time_str.length();
time_line.with_attr(string_attr(
time_lr,
&view_curses::VC_ROLE,
view_colors::VCR_SKEWED_TIME));
time_lr, &view_curses::VC_ROLE, view_colors::VCR_SKEWED_TIME));
timersub(&curr_tv, &actual_tv, &diff_tv);
time_str.append("; Diff: ");
time_lr.lr_start = time_str.length();
time_str.append(humanize::time::duration::from_tv(diff_tv)
.to_string());
time_str.append(
humanize::time::duration::from_tv(diff_tv).to_string());
time_lr.lr_end = time_str.length();
time_line.with_attr(string_attr(
time_lr,
&view_curses::VC_STYLE,
A_BOLD));
time_line.with_attr(
string_attr(time_lr, &view_curses::VC_STYLE, A_BOLD));
}
}
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
timersub(&curr_tv, &offset_tv, &orig_tv);
sql_strftime(old_timestamp, sizeof(old_timestamp),
orig_tv.tv_sec, orig_tv.tv_usec / 1000,
sql_strftime(old_timestamp,
sizeof(old_timestamp),
orig_tv.tv_sec,
orig_tv.tv_usec / 1000,
'T');
if (offset_tv.tv_sec || offset_tv.tv_usec) {
char offset_str[32];
time_str.append(" Pre-adjust Time: ");
time_str.append(old_timestamp);
snprintf(offset_str, sizeof(offset_str),
snprintf(offset_str,
sizeof(offset_str),
" Offset: %+d.%03d",
(int)offset_tv.tv_sec, (int)(offset_tv.tv_usec / 1000));
(int) offset_tv.tv_sec,
(int) (offset_tv.tv_usec / 1000));
time_str.append(offset_str);
}
if ((!this->fos_contexts.empty() && this->fos_contexts.top().c_show) ||
diff_tv.tv_sec > 0) {
if ((!this->fos_contexts.empty() && this->fos_contexts.top().c_show)
|| diff_tv.tv_sec > 0)
{
this->fos_lines.emplace_back(time_line);
}
@ -358,7 +357,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
this->fos_known_key_size = LOG_BODY.length();
this->fos_unknown_key_size = 0;
for (auto & ldh_line_value : this->fos_log_helper.ldh_line_values) {
for (auto& ldh_line_value : this->fos_log_helper.ldh_line_values) {
auto& meta = ldh_line_value.lv_meta;
int this_key_size = meta.lvm_name.size();
@ -376,19 +375,21 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
for (auto iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
iter != this->fos_log_helper.ldh_parser->dp_pairs.end();
++iter) {
std::string colname = this->fos_log_helper.ldh_parser->get_element_string(
++iter)
{
std::string colname
= this->fos_log_helper.ldh_parser->get_element_string(
iter->e_sub_elements->front());
colname = this->fos_log_helper.ldh_namer->add_column(colname);
this->fos_unknown_key_size = max(
this->fos_unknown_key_size, (int)colname.length());
this->fos_unknown_key_size
= max(this->fos_unknown_key_size, (int) colname.length());
}
auto lf = this->fos_log_helper.ldh_file->get_format();
if (!lf->get_pattern_regex(cl).empty()) {
attr_line_t pattern_al;
std::string &pattern_str = pattern_al.get_string();
std::string& pattern_str = pattern_al.get_string();
pattern_str = " Pattern: " + lf->get_pattern_name(cl) + " = ";
int skip = pattern_str.length();
pattern_str += lf->get_pattern_regex(cl);
@ -396,32 +397,30 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
this->fos_lines.emplace_back(pattern_al);
}
if (this->fos_log_helper.ldh_line_values.empty()) {
this->fos_lines.emplace_back(" No known message fields");
}
const log_format *last_format = nullptr;
const log_format* last_format = nullptr;
for (auto & lv : this->fos_log_helper.ldh_line_values) {
for (auto& lv : this->fos_log_helper.ldh_line_values) {
if (!lv.lv_meta.lvm_format) {
continue;
}
auto curr_format = lv.lv_meta.lvm_format.value();
auto curr_elf = dynamic_cast<external_log_format *>(curr_format);
auto curr_elf = dynamic_cast<external_log_format*>(curr_format);
string format_name = curr_format->get_name().to_string();
attr_line_t al;
string str, value_str = lv.to_string();
if (curr_format != last_format) {
this->fos_lines.emplace_back(" Known message fields for table " +
format_name +
":");
this->fos_lines.back().with_attr(string_attr(
line_range(32, 32 + format_name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(format_name) | A_BOLD));
this->fos_lines.emplace_back(" Known message fields for table "
+ format_name + ":");
this->fos_lines.back().with_attr(
string_attr(line_range(32, 32 + format_name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(format_name) | A_BOLD));
last_format = curr_format;
}
@ -429,7 +428,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
if (lv.lv_meta.lvm_struct_name.empty()) {
if (curr_elf && curr_elf->elf_body_field == lv.lv_meta.lvm_name) {
field_name = LOG_BODY;
} else if (curr_elf && curr_elf->lf_timestamp_field == lv.lv_meta.lvm_name) {
} else if (curr_elf
&& curr_elf->lf_timestamp_field == lv.lv_meta.lvm_name) {
field_name = LOG_TIME;
} else {
field_name = lv.lv_meta.lvm_name.to_string();
@ -471,21 +471,23 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
json_string js = extract(value_str.c_str());
al.clear()
.append(" extract(")
.append(lv.lv_meta.lvm_name.get(),
&view_curses::VC_STYLE,
vc.attrs_for_ident(lv.lv_meta.lvm_name))
.append(")")
.append(this->fos_known_key_size - lv.lv_meta.lvm_name.size() - 9 + 3, ' ')
.append(" = ")
.append((const char *) js.js_content.in(), js.js_len);
.append(" extract(")
.append(lv.lv_meta.lvm_name.get(),
&view_curses::VC_STYLE,
vc.attrs_for_ident(lv.lv_meta.lvm_name))
.append(")")
.append(this->fos_known_key_size - lv.lv_meta.lvm_name.size()
- 9 + 3,
' ')
.append(" = ")
.append((const char*) js.js_content.in(), js.js_len);
this->fos_lines.emplace_back(al);
this->add_key_line_attrs(this->fos_known_key_size);
}
}
std::map<const intern_string_t, json_ptr_walk::walk_list_t>::iterator json_iter;
std::map<const intern_string_t, json_ptr_walk::walk_list_t>::iterator
json_iter;
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
this->fos_lines.emplace_back(" JSON fields:");
@ -493,14 +495,15 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
for (json_iter = this->fos_log_helper.ldh_json_pairs.begin();
json_iter != this->fos_log_helper.ldh_json_pairs.end();
++json_iter) {
json_ptr_walk::walk_list_t &jpairs = json_iter->second;
++json_iter)
{
json_ptr_walk::walk_list_t& jpairs = json_iter->second;
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
this->fos_lines.emplace_back(
" " +
this->fos_log_helper.format_json_getter(json_iter->first, lpc) + " = " +
jpairs[lpc].wt_value);
" "
+ this->fos_log_helper.format_json_getter(json_iter->first, lpc)
+ " = " + jpairs[lpc].wt_value);
this->add_key_line_attrs(0);
}
}
@ -514,101 +517,94 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
auto_mem<char, sqlite3_free> xp_call;
qname = sql_quote_ident(xml_pair.first.first.get());
xp_call = sqlite3_mprintf("xpath(%Q, %s)",
xml_pair.first.second.c_str(),
qname.in());
this->fos_lines.emplace_back(fmt::format(
" {} = {}", xp_call, xml_pair.second));
xp_call = sqlite3_mprintf(
"xpath(%Q, %s)", xml_pair.first.second.c_str(), qname.in());
this->fos_lines.emplace_back(
fmt::format(" {} = {}", xp_call, xml_pair.second));
this->add_key_line_attrs(0);
}
if (!this->fos_contexts.empty() &&
!this->fos_contexts.top().c_show_discovered) {
if (!this->fos_contexts.empty()
&& !this->fos_contexts.top().c_show_discovered) {
return;
}
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
this->fos_lines.emplace_back(" No discovered message fields");
}
else {
this->fos_lines.emplace_back(" Discovered fields for logline table from message format: ");
this->fos_lines.back().with_attr(string_attr(
line_range(23, 23 + 7),
&view_curses::VC_STYLE,
vc.attrs_for_ident("logline")
));
auto &al = this->fos_lines.back();
auto &disc_str = al.get_string();
} else {
this->fos_lines.emplace_back(
" Discovered fields for logline table from message format: ");
this->fos_lines.back().with_attr(
string_attr(line_range(23, 23 + 7),
&view_curses::VC_STYLE,
vc.attrs_for_ident("logline")));
auto& al = this->fos_lines.back();
auto& disc_str = al.get_string();
al.with_attr(string_attr(
line_range(disc_str.length(), -1),
&view_curses::VC_STYLE,
A_BOLD));
line_range(disc_str.length(), -1), &view_curses::VC_STYLE, A_BOLD));
disc_str.append(this->fos_log_helper.ldh_msg_format);
}
auto iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
for (size_t lpc = 0;
lpc < this->fos_log_helper.ldh_parser->dp_pairs.size(); lpc++, ++iter) {
auto &name = this->fos_log_helper.ldh_namer->cn_names[lpc];
for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_parser->dp_pairs.size();
lpc++, ++iter)
{
auto& name = this->fos_log_helper.ldh_namer->cn_names[lpc];
auto val = this->fos_log_helper.ldh_parser->get_element_string(
iter->e_sub_elements->back());
iter->e_sub_elements->back());
attr_line_t al(fmt::format(" {} = {}", name, val));
al.with_attr(string_attr(
line_range(3, 3 + name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(name)));
al.with_attr(string_attr(line_range(3, 3 + name.length()),
&view_curses::VC_STYLE,
vc.attrs_for_ident(name)));
this->fos_lines.emplace_back(al);
this->add_key_line_attrs(this->fos_unknown_key_size,
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
this->add_key_line_attrs(
this->fos_unknown_key_size,
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
}
}
void field_overlay_source::build_meta_line(const listview_curses &lv,
std::vector<attr_line_t> &dst,
vis_line_t row)
void
field_overlay_source::build_meta_line(const listview_curses& lv,
std::vector<attr_line_t>& dst,
vis_line_t row)
{
content_line_t cl = this->fos_lss.at(row);
auto const &bm = this->fos_lss.get_user_bookmark_metadata();
view_colors &vc = view_colors::singleton();
auto const& bm = this->fos_lss.get_user_bookmark_metadata();
view_colors& vc = view_colors::singleton();
auto iter = bm.find(cl);
if (iter != bm.end()) {
const bookmark_metadata &line_meta = iter->second;
const bookmark_metadata& line_meta = iter->second;
size_t filename_width = this->fos_lss.get_filename_offset();
if (!line_meta.bm_comment.empty()) {
attr_line_t al;
al.with_string(" + ")
.with_attr(string_attr(
line_range(1, 2),
&view_curses::VC_GRAPHIC,
line_meta.bm_tags.empty() ? ACS_LLCORNER : ACS_LTEE
))
.append(line_meta.bm_comment);
.with_attr(string_attr(
line_range(1, 2),
&view_curses::VC_GRAPHIC,
line_meta.bm_tags.empty() ? ACS_LLCORNER : ACS_LTEE))
.append(line_meta.bm_comment);
al.insert(0, filename_width, ' ');
dst.emplace_back(al);
}
if (!line_meta.bm_tags.empty()) {
attr_line_t al;
al.with_string(" +")
.with_attr(string_attr(
line_range(1, 2),
&view_curses::VC_GRAPHIC,
ACS_LLCORNER
));
for (const auto &str : line_meta.bm_tags) {
al.append(1, ' ')
.append(str, &view_curses::VC_STYLE, vc.attrs_for_ident(str));
al.with_string(" +").with_attr(string_attr(
line_range(1, 2), &view_curses::VC_GRAPHIC, ACS_LLCORNER));
for (const auto& str : line_meta.bm_tags) {
al.append(1, ' ').append(
str, &view_curses::VC_STYLE, vc.attrs_for_ident(str));
}
const auto *tc = dynamic_cast<const textview_curses *>(&lv);
const auto* tc = dynamic_cast<const textview_curses*>(&lv);
if (tc) {
const auto &hm = tc->get_highlights();
const auto& hm = tc->get_highlights();
auto hl_iter = hm.find({highlight_source_t::PREVIEW, "search"});
if (hl_iter != hm.end()) {

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -40,32 +40,37 @@
class field_overlay_source : public list_overlay_source {
public:
explicit field_overlay_source(logfile_sub_source &lss, textfile_sub_source &tss)
: fos_lss(lss), fos_tss(tss), fos_log_helper(lss) {
explicit field_overlay_source(logfile_sub_source& lss,
textfile_sub_source& tss)
: fos_lss(lss), fos_tss(tss), fos_log_helper(lss){
};
};
void add_key_line_attrs(int key_size, bool last_line = false) {
string_attrs_t &sa = this->fos_lines.back().get_attrs();
void add_key_line_attrs(int key_size, bool last_line = false)
{
string_attrs_t& sa = this->fos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE);
sa.emplace_back(
lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE);
lr.lr_start = 3 + key_size + 3;
lr.lr_end = -1;
lr.lr_end = -1;
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
};
bool list_value_for_overlay(const listview_curses &lv,
int y, int bottom,
bool list_value_for_overlay(const listview_curses& lv,
int y,
int bottom,
vis_line_t row,
attr_line_t &value_out) override {
attr_line_t& value_out) override
{
if (y == 0) {
this->build_field_lines(lv);
this->build_summary_lines(lv);
return false;
}
if (1 <= y && y <= (int)this->fos_lines.size()) {
if (1 <= y && y <= (int) this->fos_lines.size()) {
value_out = this->fos_lines[y - 1];
return true;
}
@ -89,17 +94,18 @@ public:
return false;
};
void build_field_lines(const listview_curses &lv);
void build_summary_lines(const listview_curses &lv);
void build_meta_line(const listview_curses &lv,
std::vector<attr_line_t> &dst,
void build_field_lines(const listview_curses& lv);
void build_summary_lines(const listview_curses& lv);
void build_meta_line(const listview_curses& lv,
std::vector<attr_line_t>& dst,
vis_line_t row);
struct context {
context(std::string prefix, bool show, bool show_discovered)
: c_prefix(std::move(prefix)), c_show(show),
c_show_discovered(show_discovered)
{}
{
}
std::string c_prefix;
bool c_show{false};
@ -108,8 +114,8 @@ public:
bool fos_show_status{true};
std::stack<context> fos_contexts;
logfile_sub_source &fos_lss;
textfile_sub_source &fos_tss;
logfile_sub_source& fos_lss;
textfile_sub_source& fos_tss;
log_data_helper fos_log_helper;
int fos_known_key_size{0};
int fos_unknown_key_size{0};
@ -118,4 +124,4 @@ public:
std::vector<attr_line_t> fos_meta_lines;
};
#endif //LNAV_FIELD_OVERLAY_SOURCE_H
#endif // LNAV_FIELD_OVERLAY_SOURCE_H

@ -21,35 +21,36 @@
* 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
* 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_collection.cc
*/
#include "config.h"
#include <unordered_map>
#include <glob.h>
#include "file_collection.hh"
#include <unordered_map>
#include <glob.h>
#include "base/opt_util.hh"
#include "base/humanize.network.hh"
#include "base/isc.hh"
#include "base/opt_util.hh"
#include "config.h"
#include "lnav_util.hh"
#include "logfile.hh"
#include "file_collection.hh"
#include "pcap_manager.hh"
#include "pcrepp/pcrepp.hh"
#include "tailer/tailer.looper.hh"
#include "service_tags.hh"
#include "lnav_util.hh"
#include "pcap_manager.hh"
#include "tailer/tailer.looper.hh"
static std::mutex REALPATH_CACHE_MUTEX;
static std::unordered_map<std::string, std::string> REALPATH_CACHE;
child_poll_result_t child_poller::poll(file_collection& fc)
child_poll_result_t
child_poller::poll(file_collection& fc)
{
if (!this->cp_child) {
return child_poll_result_t::FINISHED;
@ -58,18 +59,18 @@ child_poll_result_t child_poller::poll(file_collection& fc)
auto poll_res = std::move(this->cp_child.value()).poll();
this->cp_child = nonstd::nullopt;
return poll_res.match(
[this](auto_pid<process_state::RUNNING>& alive) {
[this](auto_pid<process_state::running>& alive) {
this->cp_child = std::move(alive);
return child_poll_result_t::ALIVE;
},
[this, &fc](auto_pid<process_state::FINISHED>& finished) {
[this, &fc](auto_pid<process_state::finished>& finished) {
this->cp_finalizer(fc, finished);
return child_poll_result_t::FINISHED;
}
);
});
}
void file_collection::close_files(const std::vector<std::shared_ptr<logfile>> &files)
void
file_collection::close_files(const std::vector<std::shared_ptr<logfile>>& files)
{
for (const auto& lf : files) {
auto actual_path_opt = lf->get_actual_path();
@ -89,9 +90,7 @@ void file_collection::close_files(const std::vector<std::shared_ptr<logfile>> &f
} else {
this->fc_file_names.erase(lf->get_filename());
}
auto file_iter = find(this->fc_files.begin(),
this->fc_files.end(),
lf);
auto file_iter = find(this->fc_files.begin(), this->fc_files.end(), lf);
if (file_iter != this->fc_files.end()) {
this->fc_files.erase(file_iter);
}
@ -101,32 +100,33 @@ void file_collection::close_files(const std::vector<std::shared_ptr<logfile>> &f
this->regenerate_unique_file_names();
}
void file_collection::regenerate_unique_file_names()
void
file_collection::regenerate_unique_file_names()
{
unique_path_generator upg;
for (const auto &lf : this->fc_files) {
for (const auto& lf : this->fc_files) {
upg.add_source(lf);
}
upg.generate();
this->fc_largest_path_length = 0;
for (const auto &pair : this->fc_name_to_errors) {
for (const auto& pair : this->fc_name_to_errors) {
auto path = ghc::filesystem::path(pair.first).filename().string();
if (path.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = path.length();
}
}
for (const auto &lf : this->fc_files) {
const auto &path = lf->get_unique_path();
for (const auto& lf : this->fc_files) {
const auto& path = lf->get_unique_path();
if (path.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = path.length();
}
}
for (const auto &pair : this->fc_other_files) {
for (const auto& pair : this->fc_other_files) {
switch (pair.second.ofd_format) {
case file_format_t::FF_UNKNOWN:
case file_format_t::FF_ARCHIVE:
@ -148,7 +148,8 @@ void file_collection::regenerate_unique_file_names()
}
}
void file_collection::merge(file_collection &other)
void
file_collection::merge(file_collection& other)
{
this->fc_recursive = this->fc_recursive || other.fc_recursive;
this->fc_rotated = this->fc_rotated || other.fc_rotated;
@ -163,12 +164,11 @@ void file_collection::merge(file_collection &other)
for (const auto& lf : other.fc_files) {
this->fc_name_to_errors.erase(lf->get_filename());
}
this->fc_files.insert(this->fc_files.end(),
other.fc_files.begin(),
other.fc_files.end());
this->fc_files.insert(
this->fc_files.end(), other.fc_files.begin(), other.fc_files.end());
this->fc_files_generation += 1;
}
for (auto &pair : other.fc_renamed_files) {
for (auto& pair : other.fc_renamed_files) {
pair.first->set_filename(pair.second);
}
this->fc_closed_files.insert(other.fc_closed_files.begin(),
@ -188,7 +188,7 @@ void file_collection::merge(file_collection &other)
* Functor used to compare files based on their device and inode number.
*/
struct same_file {
explicit same_file(const struct stat &stat) : sf_stat(stat) {};
explicit same_file(const struct stat& stat) : sf_stat(stat){};
/**
* Compare the given log file against the 'stat' given in the constructor.
@ -196,14 +196,13 @@ struct same_file {
* @return True if the dev/inode values in the stat given in the
* constructor matches the stat in the logfile object.
*/
bool operator()(const std::shared_ptr<logfile> &lf) const
bool operator()(const std::shared_ptr<logfile>& lf) const
{
return !lf->is_closed() &&
this->sf_stat.st_dev == lf->get_stat().st_dev &&
this->sf_stat.st_ino == lf->get_stat().st_ino;
return !lf->is_closed() && this->sf_stat.st_dev == lf->get_stat().st_dev
&& this->sf_stat.st_ino == lf->get_stat().st_ino;
};
const struct stat &sf_stat;
const struct stat& sf_stat;
};
/**
@ -216,8 +215,9 @@ struct same_file {
* @param required Specifies whether or not the file must exist and be valid.
*/
std::future<file_collection>
file_collection::watch_logfile(const std::string &filename,
logfile_open_options &loo, bool required)
file_collection::watch_logfile(const std::string& filename,
logfile_open_options& loo,
bool required)
{
file_collection retval;
struct stat st;
@ -237,8 +237,8 @@ file_collection::watch_logfile(const std::string &filename,
if (S_ISDIR(st.st_mode) && this->fc_recursive) {
std::string wilddir = filename + "/*";
if (this->fc_file_names.find(wilddir) ==
this->fc_file_names.end()) {
if (this->fc_file_names.find(wilddir) == this->fc_file_names.end())
{
retval.fc_file_names.emplace(wilddir, logfile_open_options());
}
return lnav::futures::make_ready_future(std::move(retval));
@ -260,10 +260,11 @@ file_collection::watch_logfile(const std::string &filename,
}
if (rc == -1) {
if (required) {
retval.fc_name_to_errors.emplace(filename, file_error_info{
time(nullptr),
std::string(strerror(errno)),
});
retval.fc_name_to_errors.emplace(filename,
file_error_info{
time(nullptr),
std::string(strerror(errno)),
});
}
return lnav::futures::make_ready_future(std::move(retval));
}
@ -271,8 +272,8 @@ file_collection::watch_logfile(const std::string &filename,
auto stat_iter = find_if(this->fc_new_stats.begin(),
this->fc_new_stats.end(),
[&st](auto& elem) {
return st.st_ino == elem.st_ino &&
st.st_dev == elem.st_dev;
return st.st_ino == elem.st_ino
&& st.st_dev == elem.st_dev;
});
if (stat_iter != this->fc_new_stats.end()) {
// this file is probably a link that we have already scanned in this
@ -281,16 +282,19 @@ file_collection::watch_logfile(const std::string &filename,
}
this->fc_new_stats.emplace_back(st);
auto file_iter = find_if(this->fc_files.begin(),
this->fc_files.end(),
same_file(st));
auto file_iter
= find_if(this->fc_files.begin(), this->fc_files.end(), same_file(st));
if (file_iter == this->fc_files.end()) {
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
return lnav::futures::make_ready_future(std::move(retval));
}
auto func = [filename, st, loo, prog = this->fc_progress, errs = this->fc_name_to_errors]() mutable {
auto func = [filename,
st,
loo,
prog = this->fc_progress,
errs = this->fc_name_to_errors]() mutable {
file_collection retval;
if (errs.find(filename) != errs.end()) {
@ -315,16 +319,27 @@ file_collection::watch_logfile(const std::string &filename,
loo.loo_fd = std::move(convert_res.cr_destination);
retval.fc_child_pollers.emplace_back(child_poller{
std::move(convert_res.cr_child),
[filename, st, error_queue = convert_res.cr_error_queue](auto& fc, auto& child) {
if (child.was_normal_exit() && child.exit_status() == EXIT_SUCCESS) {
log_info("pcap[%d] exited normally", child.in());
[filename,
st,
error_queue = convert_res.cr_error_queue](
auto& fc, auto& child) {
if (child.was_normal_exit()
&& child.exit_status() == EXIT_SUCCESS) {
log_info("pcap[%d] exited normally",
child.in());
return;
}
log_error("pcap[%d] exited with %d", child.in(), child.status());
fc.fc_name_to_errors.emplace(filename, file_error_info{
st.st_mtime,
fmt::format("{}", fmt::join(*error_queue, "\n")),
});
log_error("pcap[%d] exited with %d",
child.in(),
child.status());
fc.fc_name_to_errors.emplace(
filename,
file_error_info{
st.st_mtime,
fmt::format(
"{}",
fmt::join(*error_queue, "\n")),
});
},
});
auto open_res = logfile::open(filename, loo);
@ -332,22 +347,25 @@ file_collection::watch_logfile(const std::string &filename,
retval.fc_files.push_back(open_res.unwrap());
} else {
retval.fc_name_to_errors.emplace(
filename, file_error_info{
filename,
file_error_info{
st.st_mtime,
open_res.unwrapErr(),
});
}
} else {
retval.fc_name_to_errors.emplace(filename, file_error_info{
st.st_mtime,
res.unwrapErr(),
});
retval.fc_name_to_errors.emplace(filename,
file_error_info{
st.st_mtime,
res.unwrapErr(),
});
}
break;
}
case file_format_t::FF_ARCHIVE: {
nonstd::optional<std::list<archive_manager::extract_progress>::iterator>
nonstd::optional<
std::list<archive_manager::extract_progress>::iterator>
prog_iter_opt;
if (loo.loo_source == logfile_name_source::ARCHIVE) {
@ -357,24 +375,21 @@ file_collection::watch_logfile(const std::string &filename,
auto res = archive_manager::walk_archive_files(
filename,
[prog, &prog_iter_opt](
const auto &path,
const auto total) {
[prog, &prog_iter_opt](const auto& path,
const auto total) {
safe::WriteAccess<safe_scan_progress> sp(*prog);
prog_iter_opt | [&sp](auto prog_iter) {
sp->sp_extractions.erase(prog_iter);
};
auto prog_iter = sp->sp_extractions.emplace(
sp->sp_extractions.begin(),
path, total);
sp->sp_extractions.begin(), path, total);
prog_iter_opt = prog_iter;
return &(*prog_iter);
},
[&filename, &retval](
const auto &tmp_path,
const auto &entry) {
[&filename, &retval](const auto& tmp_path,
const auto& entry) {
auto arc_path = ghc::filesystem::relative(
entry.path(), tmp_path);
auto custom_name = filename / arc_path;
@ -400,18 +415,16 @@ file_collection::watch_logfile(const std::string &filename,
log_error("archive extraction failed: %s",
res.unwrapErr().c_str());
retval.clear();
retval.fc_name_to_errors.emplace(
filename,
file_error_info{
st.st_mtime,
res.unwrapErr(),
});
retval.fc_name_to_errors.emplace(filename,
file_error_info{
st.st_mtime,
res.unwrapErr(),
});
} else {
retval.fc_other_files[filename] = ff;
}
{
prog_iter_opt |
[&prog](auto prog_iter) {
prog_iter_opt | [&prog](auto prog_iter) {
prog->writeAccess()->sp_extractions.erase(
prog_iter);
};
@ -425,10 +438,10 @@ file_collection::watch_logfile(const std::string &filename,
auto open_res = logfile::open(filename, loo);
if (open_res.isOk()) {
retval.fc_files.push_back(open_res.unwrap());
}
else {
} else {
retval.fc_name_to_errors.emplace(
filename, file_error_info{
filename,
file_error_info{
st.st_mtime,
open_res.unwrapErr(),
});
@ -460,10 +473,12 @@ file_collection::watch_logfile(const std::string &filename,
* @param path The glob pattern to expand.
* @param required Passed to watch_logfile.
*/
void file_collection::expand_filename(lnav::futures::future_queue<file_collection> &fq,
const std::string &path,
logfile_open_options &loo,
bool required)
void
file_collection::expand_filename(
lnav::futures::future_queue<file_collection>& fq,
const std::string& path,
logfile_open_options& loo,
bool required)
{
static_root_mem<glob_t, globfree> gl;
@ -499,26 +514,25 @@ void file_collection::expand_filename(lnav::futures::future_queue<file_collectio
file_collection retval;
isc::to<tailer::looper &, services::remote_tailer_t>()
.send([=](auto &tlooper) {
tlooper.add_remote(rp, loo);
});
isc::to<tailer::looper&, services::remote_tailer_t>().send(
[=](auto& tlooper) { tlooper.add_remote(rp, loo); });
retval.fc_other_files[path] = file_format_t::FF_REMOTE;
{
this->fc_progress->writeAccess()->
sp_tailers[fmt::format("{}", rp.home())].tp_message =
"Initializing...";
this->fc_progress->writeAccess()
->sp_tailers[fmt::format("{}", rp.home())]
.tp_message
= "Initializing...";
}
fq.push_back(lnav::futures::make_ready_future(std::move(retval)));
fq.push_back(
lnav::futures::make_ready_future(std::move(retval)));
return;
}
required = false;
}
}
if (gl->gl_pathc > 1 ||
strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
if (gl->gl_pathc > 1 || strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
required = false;
}
@ -530,13 +544,15 @@ void file_collection::expand_filename(lnav::futures::future_queue<file_collectio
if (iter == REALPATH_CACHE.end()) {
auto_mem<char> abspath;
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) ==
nullptr) {
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) == nullptr)
{
auto errmsg = strerror(errno);
if (required) {
fprintf(stderr, "Cannot find file: %s -- %s",
gl->gl_pathv[lpc], errmsg);
fprintf(stderr,
"Cannot find file: %s -- %s",
gl->gl_pathv[lpc],
errmsg);
} else if (loo.loo_source != logfile_name_source::REMOTE) {
// XXX The remote code path adds the file name before
// the file exists... not sure checking for that here
@ -544,19 +560,20 @@ void file_collection::expand_filename(lnav::futures::future_queue<file_collectio
file_collection retval;
if (gl->gl_pathc == 1) {
retval.fc_name_to_errors.emplace(
path, file_error_info{
time(nullptr),
errmsg,
});
retval.fc_name_to_errors.emplace(path,
file_error_info{
time(nullptr),
errmsg,
});
} else {
retval.fc_name_to_errors.emplace(
path_str, file_error_info{
time(nullptr),
errmsg,
});
retval.fc_name_to_errors.emplace(path_str,
file_error_info{
time(nullptr),
errmsg,
});
}
fq.push_back(lnav::futures::make_ready_future(std::move(retval)));
fq.push_back(lnav::futures::make_ready_future(
std::move(retval)));
}
continue;
} else {
@ -573,14 +590,14 @@ void file_collection::expand_filename(lnav::futures::future_queue<file_collectio
}
}
file_collection file_collection::rescan_files(bool required)
file_collection
file_collection::rescan_files(bool required)
{
file_collection retval;
lnav::futures::future_queue<file_collection> fq([&retval](auto &fc) {
retval.merge(fc);
});
lnav::futures::future_queue<file_collection> fq(
[&retval](auto& fc) { retval.merge(fc); });
for (auto &pair : this->fc_file_names) {
for (auto& pair : this->fc_file_names) {
if (pair.second.loo_fd == -1) {
this->expand_filename(fq, pair.first, pair.second, required);
if (this->fc_rotated) {

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -32,19 +32,18 @@
#ifndef lnav_file_collection_hh
#define lnav_file_collection_hh
#include <forward_list>
#include <list>
#include <map>
#include <set>
#include <list>
#include <string>
#include <utility>
#include <forward_list>
#include "safe/safe.h"
#include "base/future_util.hh"
#include "logfile_fwd.hh"
#include "archive_manager.hh"
#include "base/future_util.hh"
#include "file_format.hh"
#include "logfile_fwd.hh"
#include "safe/safe.h"
#include "tailer/tailer.looper.hh"
struct tailer_progress {
@ -64,7 +63,9 @@ struct other_file_descriptor {
other_file_descriptor(file_format_t format = file_format_t::FF_UNKNOWN,
std::string description = "")
: ofd_format(format), ofd_description(std::move(description)) {}
: ofd_format(format), ofd_description(std::move(description))
{
}
};
struct file_error_info {
@ -81,16 +82,22 @@ enum class child_poll_result_t {
class child_poller {
public:
explicit child_poller(auto_pid<process_state::RUNNING> child,
std::function<void(file_collection&, auto_pid<process_state::FINISHED>&)> finalizer)
: cp_child(std::move(child)), cp_finalizer(std::move(finalizer)) {
explicit child_poller(
auto_pid<process_state::running> child,
std::function<void(file_collection&,
auto_pid<process_state::finished>&)> finalizer)
: cp_child(std::move(child)), cp_finalizer(std::move(finalizer))
{
}
child_poller(child_poller&& other) noexcept
: cp_child(std::move(other.cp_child)),
cp_finalizer(std::move(other.cp_finalizer)) {}
cp_finalizer(std::move(other.cp_finalizer))
{
}
child_poller& operator=(child_poller&& other) noexcept {
child_poller& operator=(child_poller&& other) noexcept
{
this->cp_child = std::move(other.cp_child);
this->cp_finalizer = std::move(other.cp_finalizer);
@ -100,9 +107,11 @@ public:
~child_poller() noexcept = default;
child_poll_result_t poll(file_collection& fc);
private:
nonstd::optional<auto_pid<process_state::RUNNING>> cp_child;
std::function<void(file_collection&, auto_pid<process_state::FINISHED>&)> cp_finalizer;
nonstd::optional<auto_pid<process_state::running>> cp_child;
std::function<void(file_collection&, auto_pid<process_state::finished>&)>
cp_finalizer;
};
struct file_collection {
@ -127,7 +136,8 @@ struct file_collection {
file_collection()
: fc_progress(std::make_shared<safe::Safe<scan_progress>>())
{}
{
}
void clear()
{
@ -141,22 +151,20 @@ struct file_collection {
file_collection rescan_files(bool required = false);
void
expand_filename(lnav::futures::future_queue<file_collection> &fq,
const std::string &path,
logfile_open_options &loo,
bool required);
void expand_filename(lnav::futures::future_queue<file_collection>& fq,
const std::string& path,
logfile_open_options& loo,
bool required);
std::future<file_collection>
watch_logfile(const std::string &filename, logfile_open_options &loo,
bool required);
std::future<file_collection> watch_logfile(const std::string& filename,
logfile_open_options& loo,
bool required);
void merge(file_collection &other);
void merge(file_collection& other);
void close_files(const std::vector<std::shared_ptr<logfile>> &files);
void close_files(const std::vector<std::shared_ptr<logfile>>& files);
void regenerate_unique_file_names();
};
#endif

@ -21,88 +21,83 @@
* 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
* 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 <unordered_map>
#include "file_format.hh"
#include "archive_manager.hh"
#include "auto_fd.hh"
#include "base/fs_util.hh"
#include "base/intern_string.hh"
#include "base/lnav_log.hh"
#include "auto_fd.hh"
#include "file_format.hh"
#include "archive_manager.hh"
#include "config.h"
static bool is_pcap_header(uint8_t *buffer)
static bool
is_pcap_header(uint8_t* buffer)
{
size_t offset = 0;
if (buffer[0] == 0x0a &&
buffer[1] == 0x0d &&
buffer[2] == 0x0d &&
buffer[3] == 0x0a) {
if (buffer[0] == 0x0a && buffer[1] == 0x0d && buffer[2] == 0x0d
&& buffer[3] == 0x0a)
{
offset += sizeof(uint32_t) * 2;
if (buffer[offset + 0] == 0x1a &&
buffer[offset + 1] == 0x2b &&
buffer[offset + 2] == 0x3c &&
buffer[offset + 3] == 0x4d) {
if (buffer[offset + 0] == 0x1a && buffer[offset + 1] == 0x2b
&& buffer[offset + 2] == 0x3c && buffer[offset + 3] == 0x4d)
{
return true;
}
if (buffer[offset + 0] == 0x4d &&
buffer[offset + 1] == 0x3c &&
buffer[offset + 2] == 0x2b &&
buffer[offset + 3] == 0x1a) {
if (buffer[offset + 0] == 0x4d && buffer[offset + 1] == 0x3c
&& buffer[offset + 2] == 0x2b && buffer[offset + 3] == 0x1a)
{
return true;
}
return false;
}
if (buffer[0] == 0xa1 &&
buffer[1] == 0xb2 &&
buffer[2] == 0xc3 &&
buffer[3] == 0xd4) {
if (buffer[0] == 0xa1 && buffer[1] == 0xb2 && buffer[2] == 0xc3
&& buffer[3] == 0xd4)
{
return true;
}
if (buffer[0] == 0xd4 &&
buffer[1] == 0xc3 &&
buffer[2] == 0xb2 &&
buffer[3] == 0xa1) {
if (buffer[0] == 0xd4 && buffer[1] == 0xc3 && buffer[2] == 0xb2
&& buffer[3] == 0xa1)
{
return true;
}
if (buffer[0] == 0xa1 &&
buffer[1] == 0xb2 &&
buffer[2] == 0x3c &&
buffer[3] == 0x4d) {
if (buffer[0] == 0xa1 && buffer[1] == 0xb2 && buffer[2] == 0x3c
&& buffer[3] == 0x4d)
{
return true;
}
if (buffer[0] == 0x4d &&
buffer[1] == 0x3c &&
buffer[2] == 0xb2 &&
buffer[3] == 0xa1) {
if (buffer[0] == 0x4d && buffer[1] == 0x3c && buffer[2] == 0xb2
&& buffer[3] == 0xa1)
{
return true;
}
return false;
}
file_format_t detect_file_format(const ghc::filesystem::path &filename)
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;
auto_fd fd;
if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) != -1) {
uint8_t buffer[32];

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -49,7 +49,7 @@ namespace fmt {
template<>
struct formatter<file_format_t> : formatter<string_view> {
template<typename FormatContext>
auto format(file_format_t ff, FormatContext &ctx)
auto format(file_format_t ff, FormatContext& ctx)
{
string_view name = "unknown";
switch (ff) {
@ -71,6 +71,6 @@ struct formatter<file_format_t> : formatter<string_view> {
return formatter<string_view>::format(name, ctx);
}
};
}
} // namespace fmt
#endif

@ -21,34 +21,33 @@
* 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
* 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 <unistd.h>
#include <string.h>
#include <unistd.h>
#include "base/injector.bind.hh"
#include "base/lnav.gzip.hh"
#include "base/lnav_log.hh"
#include "config.h"
#include "file_collection.hh"
#include "file_vtab.cfg.hh"
#include "log_format.hh"
#include "logfile.hh"
#include "session_data.hh"
#include "vtab_module.hh"
#include "log_format.hh"
#include "file_vtab.cfg.hh"
using namespace std;
struct lnav_file : public tvt_iterator_cursor<lnav_file> {
using iterator = vector<shared_ptr<logfile>>::iterator;
static constexpr const char *NAME = "lnav_file";
static constexpr const char *CREATE_STMT = R"(
static constexpr const char* NAME = "lnav_file";
static constexpr const char* CREATE_STMT = R"(
-- Access lnav's open file list through this table.
CREATE TABLE lnav_file (
device integer, -- The device the file is stored on.
@ -63,24 +62,26 @@ CREATE TABLE lnav_file (
);
)";
explicit lnav_file(file_collection& fc) : lf_collection(fc) {
}
explicit lnav_file(file_collection& fc) : lf_collection(fc) {}
iterator begin() {
iterator begin()
{
return this->lf_collection.fc_files.begin();
}
iterator end() {
iterator end()
{
return this->lf_collection.fc_files.end();
}
int get_column(const cursor &vc, sqlite3_context *ctx, int col) {
int get_column(const cursor& vc, sqlite3_context* ctx, int col)
{
auto lf = *vc.iter;
const struct stat &st = lf->get_stat();
const string &name = lf->get_filename();
const struct stat& st = lf->get_stat();
const string& name = lf->get_filename();
auto format = lf->get_format();
const char *format_name =
format != nullptr ? format->get_name().get() : nullptr;
const char* format_name = format != nullptr ? format->get_name().get()
: nullptr;
switch (col) {
case 0:
@ -117,35 +118,32 @@ CREATE TABLE lnav_file (
} else {
auto fd = lf->get_fd();
auto_mem<char> buf;
buf = (char *) malloc(lf_stat.st_size);
buf = (char*) malloc(lf_stat.st_size);
auto rc = pread(fd, buf, lf_stat.st_size, 0);
if (rc == -1) {
auto errmsg = fmt::format("unable to read file: {}",
strerror(errno));
sqlite3_result_error(ctx, errmsg.c_str(),
errmsg.length());
sqlite3_result_error(
ctx, errmsg.c_str(), errmsg.length());
} else if (rc != lf_stat.st_size) {
auto errmsg = fmt::format("short read of file: {} < {}",
rc, lf_stat.st_size);
auto errmsg = fmt::format(
"short read of file: {} < {}", rc, lf_stat.st_size);
sqlite3_result_error(ctx, errmsg.c_str(),
errmsg.length());
sqlite3_result_error(
ctx, errmsg.c_str(), errmsg.length());
} else if (lnav::gzip::is_gzipped(buf, rc)) {
lnav::gzip::uncompress(lf->get_unique_path(), buf, rc)
.then([ctx](auto uncomp) {
auto pair = uncomp.release();
sqlite3_result_blob64(ctx,
pair.first,
pair.second,
free);
sqlite3_result_blob64(
ctx, pair.first, pair.second, free);
})
.otherwise([ctx](auto msg) {
sqlite3_result_error(ctx,
msg.c_str(),
msg.size());
sqlite3_result_error(
ctx, msg.c_str(), msg.size());
});
} else {
sqlite3_result_blob64(ctx, buf.release(), rc, free);
@ -161,28 +159,30 @@ CREATE TABLE lnav_file (
return SQLITE_OK;
}
int delete_row(sqlite3_vtab *vt, sqlite3_int64 rowid) {
vt->zErrMsg = sqlite3_mprintf(
"Rows cannot be deleted from this table");
int delete_row(sqlite3_vtab* vt, sqlite3_int64 rowid)
{
vt->zErrMsg = sqlite3_mprintf("Rows cannot be deleted from this table");
return SQLITE_ERROR;
};
int insert_row(sqlite3_vtab *tab, sqlite3_int64 &rowid_out) {
tab->zErrMsg = sqlite3_mprintf(
"Rows cannot be inserted into this table");
int insert_row(sqlite3_vtab* tab, sqlite3_int64& rowid_out)
{
tab->zErrMsg
= sqlite3_mprintf("Rows cannot be inserted into this table");
return SQLITE_ERROR;
};
int update_row(sqlite3_vtab *tab,
sqlite3_int64 &rowid,
int update_row(sqlite3_vtab* tab,
sqlite3_int64& rowid,
int64_t device,
int64_t inode,
std::string path,
const char *text_format,
const char *format,
const char* text_format,
const char* format,
int64_t lines,
int64_t time_offset,
const char *content) {
const char* content)
{
auto lf = this->lf_collection.fc_files[rowid];
struct timeval tv = {
(int) (time_offset / 1000LL),
@ -197,7 +197,8 @@ CREATE TABLE lnav_file (
"real file paths cannot be updated, only symbolic ones");
}
auto iter = this->lf_collection.fc_file_names.find(lf->get_filename());
auto iter
= this->lf_collection.fc_file_names.find(lf->get_filename());
if (iter != this->lf_collection.fc_file_names.end()) {
auto loo = std::move(iter->second);
@ -216,7 +217,7 @@ CREATE TABLE lnav_file (
return SQLITE_OK;
};
file_collection &lf_collection;
file_collection& lf_collection;
};
struct injectable_lnav_file : vtab_module<lnav_file> {
@ -224,5 +225,5 @@ struct injectable_lnav_file : vtab_module<lnav_file> {
using injectable = injectable_lnav_file(file_collection&);
};
static auto file_binder = injector::bind_multiple<vtab_module_base>()
.add<injectable_lnav_file>();
static auto file_binder
= injector::bind_multiple<vtab_module_base>().add<injectable_lnav_file>();

@ -21,8 +21,8 @@
* 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
* 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.
*
@ -38,6 +38,6 @@ struct config {
int64_t fvc_max_content_size{32 * 1024 * 1024};
};
}
} // namespace file_vtab
#endif

@ -21,27 +21,27 @@
* 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
* 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 "files_sub_source.hh"
#include "base/humanize.hh"
#include "base/humanize.network.hh"
#include "base/opt_util.hh"
#include "base/string_util.hh"
#include "mapbox/variant.hpp"
#include "config.h"
#include "lnav.hh"
#include "files_sub_source.hh"
#include "mapbox/variant.hpp"
namespace files_model {
files_list_selection from_selection(vis_line_t sel_vis)
files_list_selection
from_selection(vis_line_t sel_vis)
{
auto &fc = lnav_data.ld_active_files;
auto& fc = lnav_data.ld_active_files;
int sel = (int) sel_vis;
if (sel < fc.fc_name_to_errors.size()) {
@ -71,52 +71,49 @@ files_list_selection from_selection(vis_line_t sel_vis)
return no_selection{};
}
}
} // namespace files_model
files_sub_source::files_sub_source()
{
files_sub_source::files_sub_source() {}
}
bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
bool
files_sub_source::list_input_handle_key(listview_curses& lv, int ch)
{
switch (ch) {
case KEY_ENTER:
case '\r': {
auto sel = files_model::from_selection(lv.get_selection());
sel.match(
[](files_model::no_selection) {},
[](files_model::error_selection) {},
[](files_model::other_selection) {},
[&](files_model::file_selection& fs) {
auto& lss = lnav_data.ld_log_source;
auto lf = *fs.sb_iter;
lss.find_data(lf) | [](auto ld) {
ld->set_visibility(true);
lnav_data.ld_log_source.text_filters_changed();
};
if (lf->get_format() != nullptr) {
auto& log_view = lnav_data.ld_views[LNV_LOG];
lss.row_for_time(lf->front().get_timeval()) | [](auto row) {
lnav_data.ld_views[LNV_LOG].set_top(row);
};
ensure_view(&log_view);
} else {
auto& tv = lnav_data.ld_views[LNV_TEXT];
auto& tss = lnav_data.ld_text_source;
tss.to_front(lf);
tv.reload_data();
ensure_view(&tv);
}
lv.reload_data();
lnav_data.ld_mode = LNM_PAGING;
}
);
sel.match([](files_model::no_selection) {},
[](files_model::error_selection) {},
[](files_model::other_selection) {},
[&](files_model::file_selection& fs) {
auto& lss = lnav_data.ld_log_source;
auto lf = *fs.sb_iter;
lss.find_data(lf) | [](auto ld) {
ld->set_visibility(true);
lnav_data.ld_log_source.text_filters_changed();
};
if (lf->get_format() != nullptr) {
auto& log_view = lnav_data.ld_views[LNV_LOG];
lss.row_for_time(lf->front().get_timeval()) |
[](auto row) {
lnav_data.ld_views[LNV_LOG].set_top(row);
};
ensure_view(&log_view);
} else {
auto& tv = lnav_data.ld_views[LNV_TEXT];
auto& tss = lnav_data.ld_text_source;
tss.to_front(lf);
tv.reload_data();
ensure_view(&tv);
}
lv.reload_data();
lnav_data.ld_mode = LNM_PAGING;
});
return true;
}
@ -124,29 +121,27 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
case ' ': {
auto sel = files_model::from_selection(lv.get_selection());
sel.match(
[](files_model::no_selection) {},
[](files_model::error_selection) {},
[](files_model::other_selection) {},
[&](files_model::file_selection& fs) {
auto& lss = lnav_data.ld_log_source;
auto lf = *fs.sb_iter;
lss.find_data(lf) | [](auto ld) {
ld->set_visibility(!ld->ld_visible);
};
auto top_view = *lnav_data.ld_view_stack.top();
auto tss = top_view->get_sub_source();
if (tss != nullptr) {
tss->text_filters_changed();
top_view->reload_data();
}
lv.reload_data();
}
);
sel.match([](files_model::no_selection) {},
[](files_model::error_selection) {},
[](files_model::other_selection) {},
[&](files_model::file_selection& fs) {
auto& lss = lnav_data.ld_log_source;
auto lf = *fs.sb_iter;
lss.find_data(lf) | [](auto ld) {
ld->set_visibility(!ld->ld_visible);
};
auto top_view = *lnav_data.ld_view_stack.top();
auto tss = top_view->get_sub_source();
if (tss != nullptr) {
tss->text_filters_changed();
top_view->reload_data();
}
lv.reload_data();
});
return true;
}
case 'n': {
@ -158,83 +153,87 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
return true;
}
case '/': {
execute_command(lnav_data.ld_exec_context,
"prompt search-files");
execute_command(lnav_data.ld_exec_context, "prompt search-files");
return true;
}
case 'X': {
auto sel = files_model::from_selection(lv.get_selection());
sel.match(
[](files_model::no_selection) {},
[&](files_model::error_selection& es) {
auto &fc = lnav_data.ld_active_files;
fc.fc_file_names.erase(es.sb_iter->first);
auto name_iter = fc.fc_file_names.begin();
while (name_iter != fc.fc_file_names.end()) {
if (name_iter->first == es.sb_iter->first) {
name_iter = fc.fc_file_names.erase(name_iter);
continue;
}
auto rp_opt = humanize::network::path::from_str(name_iter->first);
if (rp_opt) {
auto rp = *rp_opt;
if (fmt::format("{}", rp.home()) == es.sb_iter->first) {
fc.fc_other_files.erase(name_iter->first);
name_iter = fc.fc_file_names.erase(name_iter);
continue;
}
}
++name_iter;
}
fc.fc_name_to_errors.erase(es.sb_iter);
fc.fc_invalidate_merge = true;
lv.reload_data();
},
[](files_model::other_selection) {},
[](files_model::file_selection) {}
);
sel.match([](files_model::no_selection) {},
[&](files_model::error_selection& es) {
auto& fc = lnav_data.ld_active_files;
fc.fc_file_names.erase(es.sb_iter->first);
auto name_iter = fc.fc_file_names.begin();
while (name_iter != fc.fc_file_names.end()) {
if (name_iter->first == es.sb_iter->first) {
name_iter = fc.fc_file_names.erase(name_iter);
continue;
}
auto rp_opt = humanize::network::path::from_str(
name_iter->first);
if (rp_opt) {
auto rp = *rp_opt;
if (fmt::format("{}", rp.home())
== es.sb_iter->first) {
fc.fc_other_files.erase(name_iter->first);
name_iter
= fc.fc_file_names.erase(name_iter);
continue;
}
}
++name_iter;
}
fc.fc_name_to_errors.erase(es.sb_iter);
fc.fc_invalidate_merge = true;
lv.reload_data();
},
[](files_model::other_selection) {},
[](files_model::file_selection) {});
return true;
}
}
return false;
}
void files_sub_source::list_input_handle_scroll_out(listview_curses &lv)
void
files_sub_source::list_input_handle_scroll_out(listview_curses& lv)
{
lnav_data.ld_mode = LNM_PAGING;
lnav_data.ld_filter_view.reload_data();
}
size_t files_sub_source::text_line_count()
size_t
files_sub_source::text_line_count()
{
const auto &fc = lnav_data.ld_active_files;
const auto& fc = lnav_data.ld_active_files;
return fc.fc_name_to_errors.size() +
fc.fc_other_files.size() +
fc.fc_files.size();
return fc.fc_name_to_errors.size() + fc.fc_other_files.size()
+ fc.fc_files.size();
}
size_t files_sub_source::text_line_width(textview_curses &curses)
size_t
files_sub_source::text_line_width(textview_curses& curses)
{
return 512;
}
void files_sub_source::text_value_for_line(textview_curses &tc, int line,
std::string &value_out,
text_sub_source::line_flags_t flags)
void
files_sub_source::text_value_for_line(textview_curses& tc,
int line,
std::string& value_out,
text_sub_source::line_flags_t flags)
{
const auto dim = tc.get_dimensions();
const auto &fc = lnav_data.ld_active_files;
auto filename_width =
std::min(fc.fc_largest_path_length,
std::max((size_t) 40, (size_t) dim.second - 30));
const auto& fc = lnav_data.ld_active_files;
auto filename_width
= std::min(fc.fc_largest_path_length,
std::max((size_t) 40, (size_t) dim.second - 30));
if (line < fc.fc_name_to_errors.size()) {
auto iter = fc.fc_name_to_errors.begin();
@ -243,9 +242,10 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
auto fn = path.filename().string();
truncate_to(fn, filename_width);
value_out = fmt::format(
FMT_STRING(" {:<{}} {}"),
fn, filename_width, iter->second.fei_description);
value_out = fmt::format(FMT_STRING(" {:<{}} {}"),
fn,
filename_width,
iter->second.fei_description);
return;
}
@ -258,16 +258,17 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
auto fn = path.string();
truncate_to(fn, filename_width);
value_out = fmt::format(
FMT_STRING(" {:<{}} {:14} {}"),
fn, filename_width, iter->second.ofd_format,
iter->second.ofd_description);
value_out = fmt::format(FMT_STRING(" {:<{}} {:14} {}"),
fn,
filename_width,
iter->second.ofd_format,
iter->second.ofd_description);
return;
}
line -= fc.fc_other_files.size();
const auto &lf = fc.fc_files[line];
const auto& lf = fc.fc_files[line];
auto fn = lf->get_unique_path();
char start_time[64] = "", end_time[64] = "";
std::vector<std::string> file_notes;
@ -280,31 +281,34 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
for (const auto& pair : lf->get_notes()) {
file_notes.push_back(pair.second);
}
value_out = fmt::format(
FMT_STRING(" {:<{}} {:>8} {} \u2014 {} {}"),
fn,
filename_width,
humanize::file_size(lf->get_index_size()),
start_time,
end_time,
fmt::join(file_notes, "; "));
this->fss_last_line_len =
filename_width + 23 + strlen(start_time) + strlen(end_time);
value_out = fmt::format(FMT_STRING(" {:<{}} {:>8} {} \u2014 {} {}"),
fn,
filename_width,
humanize::file_size(lf->get_index_size()),
start_time,
end_time,
fmt::join(file_notes, "; "));
this->fss_last_line_len
= filename_width + 23 + strlen(start_time) + strlen(end_time);
}
void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
string_attrs_t &value_out)
void
files_sub_source::text_attrs_for_line(textview_curses& tc,
int line,
string_attrs_t& value_out)
{
bool selected = lnav_data.ld_mode == LNM_FILES && line == tc.get_selection();
const auto &fc = lnav_data.ld_active_files;
auto &vcolors = view_colors::singleton();
bool selected
= lnav_data.ld_mode == LNM_FILES && line == tc.get_selection();
const auto& fc = lnav_data.ld_active_files;
auto& vcolors = view_colors::singleton();
const auto dim = tc.get_dimensions();
auto filename_width =
std::min(fc.fc_largest_path_length,
std::max((size_t) 40, (size_t) dim.second - 30));
auto filename_width
= std::min(fc.fc_largest_path_length,
std::max((size_t) 40, (size_t) dim.second - 30));
if (selected) {
value_out.emplace_back(line_range{0, 1}, &view_curses::VC_GRAPHIC, ACS_RARROW);
value_out.emplace_back(
line_range{0, 1}, &view_curses::VC_GRAPHIC, ACS_RARROW);
}
if (line < fc.fc_name_to_errors.size()) {
@ -328,9 +332,8 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
view_colors::VCR_DISABLED_FOCUSED);
}
if (line == fc.fc_other_files.size() - 1) {
value_out.emplace_back(line_range{0, -1},
&view_curses::VC_STYLE,
A_UNDERLINE);
value_out.emplace_back(
line_range{0, -1}, &view_curses::VC_STYLE, A_UNDERLINE);
}
return;
}
@ -338,13 +341,12 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
line -= fc.fc_other_files.size();
if (selected) {
value_out.emplace_back(line_range{0, -1},
&view_curses::VC_ROLE,
view_colors::VCR_FOCUSED);
value_out.emplace_back(
line_range{0, -1}, &view_curses::VC_ROLE, view_colors::VCR_FOCUSED);
}
auto& lss = lnav_data.ld_log_source;
auto &lf = fc.fc_files[line];
auto& lf = fc.fc_files[line];
auto ld_opt = lss.find_data(lf);
chtype visible = ACS_DIAMOND;
@ -353,7 +355,8 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
}
value_out.emplace_back(line_range{2, 3}, &view_curses::VC_GRAPHIC, visible);
if (visible == ACS_DIAMOND) {
value_out.emplace_back(line_range{2, 3}, &view_curses::VC_FOREGROUND,
value_out.emplace_back(line_range{2, 3},
&view_curses::VC_FOREGROUND,
vcolors.ansi_to_theme_color(COLOR_GREEN));
}
@ -365,45 +368,51 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
lr.lr_start = this->fss_last_line_len;
lr.lr_end = -1;
value_out.emplace_back(lr, &view_curses::VC_FOREGROUND,
value_out.emplace_back(lr,
&view_curses::VC_FOREGROUND,
vcolors.ansi_to_theme_color(COLOR_YELLOW));
}
size_t files_sub_source::text_size_for_line(textview_curses &tc, int line,
text_sub_source::line_flags_t raw)
size_t
files_sub_source::text_size_for_line(textview_curses& tc,
int line,
text_sub_source::line_flags_t raw)
{
return 0;
}
static
auto spinner_index()
static auto
spinner_index()
{
auto now = ui_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count() / 100;
now.time_since_epoch())
.count()
/ 100;
}
bool
files_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
int bottom, vis_line_t line,
attr_line_t &value_out)
files_overlay_source::list_value_for_overlay(const listview_curses& lv,
int y,
int bottom,
vis_line_t line,
attr_line_t& value_out)
{
if (y == 0) {
static const char PROG[] = "-\\|/";
constexpr size_t PROG_SIZE = sizeof(PROG) - 1;
auto &fc = lnav_data.ld_active_files;
auto &fc_prog = fc.fc_progress;
auto& fc = lnav_data.ld_active_files;
auto& fc_prog = fc.fc_progress;
safe::WriteAccess<safe_scan_progress> sp(*fc_prog);
if (!sp->sp_extractions.empty()) {
const auto& prog = sp->sp_extractions.front();
value_out.with_ansi_string(fmt::format(
"{} Extracting "
ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
"... {:>8}/{}",
"{} Extracting " ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
"... {:>8}/{}",
PROG[spinner_index() % PROG_SIZE],
prog.ep_path.filename().string(),
humanize::file_size(prog.ep_out_size),
@ -414,9 +423,8 @@ files_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
auto first_iter = sp->sp_tailers.begin();
value_out.with_ansi_string(fmt::format(
"{} Connecting to "
ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
": {}",
"{} Connecting to " ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
": {}",
PROG[spinner_index() % PROG_SIZE],
first_iter->first,
first_iter->second.tp_message));

@ -21,8 +21,8 @@
* 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
* 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.
*/
@ -30,31 +30,35 @@
#ifndef files_sub_source_hh
#define files_sub_source_hh
#include "textview_curses.hh"
#include "file_collection.hh"
#include "textview_curses.hh"
class files_sub_source
: public text_sub_source, public list_input_delegate {
: public text_sub_source
, public list_input_delegate {
public:
files_sub_source();
bool list_input_handle_key(listview_curses &lv, int ch) override;
bool list_input_handle_key(listview_curses& lv, int ch) override;
void list_input_handle_scroll_out(listview_curses &lv) override;
void list_input_handle_scroll_out(listview_curses& lv) override;
size_t text_line_count() override;
size_t text_line_width(textview_curses &curses) override;
size_t text_line_width(textview_curses& curses) override;
void
text_value_for_line(textview_curses &tc, int line, std::string &value_out,
line_flags_t flags) override;
void text_value_for_line(textview_curses& tc,
int line,
std::string& value_out,
line_flags_t flags) override;
void text_attrs_for_line(textview_curses &tc, int line,
string_attrs_t &value_out) override;
void text_attrs_for_line(textview_curses& tc,
int line,
string_attrs_t& value_out) override;
size_t
text_size_for_line(textview_curses &tc, int line, line_flags_t raw) override;
size_t text_size_for_line(textview_curses& tc,
int line,
line_flags_t raw) override;
bool fss_editing{false};
bool fss_filter_state{false};
@ -62,21 +66,25 @@ public:
};
struct files_overlay_source : public list_overlay_source {
bool list_value_for_overlay(const listview_curses &lv, int y, int bottom,
bool list_value_for_overlay(const listview_curses& lv,
int y,
int bottom,
vis_line_t line,
attr_line_t &value_out) override;
attr_line_t& value_out) override;
};
namespace files_model {
struct no_selection {};
struct no_selection {
};
template<typename C, typename T>
struct selection_base {
int sb_index{0};
T sb_iter;
static C build(int index, T iter) {
static C build(int index, T iter)
{
C retval;
retval.sb_index = index;
@ -86,22 +94,26 @@ struct selection_base {
};
struct error_selection
: public selection_base<error_selection, std::map<std::string, file_error_info>::iterator> {
: public selection_base<error_selection,
std::map<std::string, file_error_info>::iterator> {
};
struct other_selection
: public selection_base<other_selection, std::map<std::string, other_file_descriptor>::iterator> {
: public selection_base<
other_selection,
std::map<std::string, other_file_descriptor>::iterator> {
};
struct file_selection
: public selection_base<file_selection, std::vector<std::shared_ptr<logfile>>::iterator> {
: public selection_base<file_selection,
std::vector<std::shared_ptr<logfile>>::iterator> {
};
using files_list_selection = mapbox::util::variant<
no_selection, error_selection, other_selection, file_selection>;
using files_list_selection = mapbox::util::
variant<no_selection, error_selection, other_selection, file_selection>;
files_list_selection from_selection(vis_line_t sel_vis);
}
} // namespace files_model
#endif

@ -21,22 +21,22 @@
* 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
* 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 "filter_observer.hh"
#include "config.h"
#include "log_format.hh"
#include "filter_observer.hh"
void line_filter_observer::logline_new_lines(const logfile &lf,
logfile::const_iterator ll_begin,
logfile::const_iterator ll_end,
shared_buffer_ref &sbr)
void
line_filter_observer::logline_new_lines(const logfile& lf,
logfile::const_iterator ll_begin,
logfile::const_iterator ll_end,
shared_buffer_ref& sbr)
{
size_t offset = std::distance(lf.begin(), ll_begin);
@ -51,21 +51,23 @@ void line_filter_observer::logline_new_lines(const logfile &lf,
if (lf.get_format() != nullptr) {
lf.get_format()->get_subline(*ll_begin, sbr);
}
for (auto &filter : this->lfo_filter_stack) {
for (auto& filter : this->lfo_filter_stack) {
if (filter->lf_deleted) {
continue;
}
if (offset >=
this->lfo_filter_state.tfs_filter_count[filter->get_index()]) {
if (offset
>= this->lfo_filter_state.tfs_filter_count[filter->get_index()])
{
filter->add_line(this->lfo_filter_state, ll_begin, sbr);
}
}
}
}
void line_filter_observer::logline_eof(const logfile &lf)
void
line_filter_observer::logline_eof(const logfile& lf)
{
for (auto &iter : this->lfo_filter_stack) {
for (auto& iter : this->lfo_filter_stack) {
if (iter->lf_deleted) {
continue;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save