mirror of
https://github.com/tstack/lnav.git
synced 2024-10-05 17:17:37 +03:00
[clang-format] init
This commit is contained in:
parent
d0ba84d9be
commit
66ef5fdae1
@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
# BasedOnStyle: Chromium
|
# BasedOnStyle: Chromium
|
||||||
AccessModifierOffset: -2
|
AccessModifierOffset: -4
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveMacros: false
|
AlignConsecutiveMacros: Consecutive
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: None
|
||||||
AlignConsecutiveBitFields: false
|
AlignConsecutiveBitFields: None
|
||||||
AlignConsecutiveDeclarations: false
|
AlignConsecutiveDeclarations: None
|
||||||
AlignEscapedNewlines: DontAlign
|
AlignEscapedNewlines: DontAlign
|
||||||
AlignOperands: DontAlign
|
AlignOperands: DontAlign
|
||||||
AlignTrailingComments: false
|
AlignTrailingComments: false
|
||||||
@ -20,38 +20,38 @@ AllowShortFunctionsOnASingleLine: Inline
|
|||||||
AllowShortLambdasOnASingleLine: All
|
AllowShortLambdasOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
AllowShortLoopsOnASingleLine: false
|
AllowShortLoopsOnASingleLine: false
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
# AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||||
AlwaysBreakBeforeMultilineStrings: true
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
BinPackParameters: false
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterCaseLabel: false
|
AfterCaseLabel: false
|
||||||
AfterClass: true
|
AfterClass: false
|
||||||
AfterControlStatement: MultiLine
|
AfterControlStatement: MultiLine
|
||||||
AfterEnum: true
|
AfterEnum: false
|
||||||
AfterFunction: true
|
AfterFunction: true
|
||||||
AfterNamespace: true
|
AfterNamespace: false
|
||||||
AfterObjCDeclaration: false
|
AfterObjCDeclaration: false
|
||||||
AfterStruct: true
|
AfterStruct: false
|
||||||
AfterUnion: true
|
AfterUnion: false
|
||||||
AfterExternBlock: true
|
AfterExternBlock: true
|
||||||
BeforeCatch: false
|
BeforeCatch: false
|
||||||
BeforeElse: false
|
BeforeElse: false
|
||||||
BeforeLambdaBody: true
|
BeforeLambdaBody: false
|
||||||
BeforeWhile: false
|
BeforeWhile: false
|
||||||
IndentBraces: false
|
IndentBraces: false
|
||||||
SplitEmptyFunction: true
|
SplitEmptyFunction: true
|
||||||
SplitEmptyRecord: true
|
SplitEmptyRecord: true
|
||||||
SplitEmptyNamespace: true
|
SplitEmptyNamespace: true
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
BreakBeforeBinaryOperators: All
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
# BreakBeforeInheritanceComma: true
|
# BreakBeforeInheritanceComma: true
|
||||||
BreakInheritanceList: BeforeComma
|
BreakInheritanceList: BeforeComma
|
||||||
BreakBeforeTernaryOperators: true
|
BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializersBeforeComma: true
|
# BreakConstructorInitializersBeforeComma: true
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeColon
|
||||||
BreakAfterJavaFieldAnnotations: true
|
BreakAfterJavaFieldAnnotations: true
|
||||||
BreakStringLiterals: true
|
BreakStringLiterals: true
|
||||||
ColumnLimit: 80
|
ColumnLimit: 80
|
||||||
@ -88,7 +88,7 @@ IndentCaseBlocks: false
|
|||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: AfterHash
|
IndentPPDirectives: AfterHash
|
||||||
IndentExternBlock: NoIndent
|
IndentExternBlock: NoIndent
|
||||||
IndentWidth: 2
|
IndentWidth: 4
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
InsertTrailingCommas: Wrapped
|
InsertTrailingCommas: Wrapped
|
||||||
JavaScriptQuotes: Double
|
JavaScriptQuotes: Double
|
||||||
@ -99,11 +99,11 @@ MacroBlockEnd: ''
|
|||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
ObjCBinPackProtocolList: Never
|
ObjCBinPackProtocolList: Never
|
||||||
ObjCBlockIndentWidth: 2
|
ObjCBlockIndentWidth: 4
|
||||||
ObjCBreakBeforeNestedBlockParam: true
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
ObjCSpaceAfterProperty: false
|
ObjCSpaceAfterProperty: false
|
||||||
ObjCSpaceBeforeProtocolList: true
|
ObjCSpaceBeforeProtocolList: true
|
||||||
PenaltyBreakAssignment: 2
|
PenaltyBreakAssignment: 4
|
||||||
PenaltyBreakBeforeFirstCallParameter: 1
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
PenaltyBreakComment: 300
|
PenaltyBreakComment: 300
|
||||||
PenaltyBreakFirstLessLess: 120
|
PenaltyBreakFirstLessLess: 120
|
||||||
@ -143,13 +143,13 @@ RawStringFormats:
|
|||||||
CanonicalDelimiter: ''
|
CanonicalDelimiter: ''
|
||||||
BasedOnStyle: google
|
BasedOnStyle: google
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
SortIncludes: true
|
SortIncludes: CaseInsensitive
|
||||||
SortUsingDeclarations: true
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: true
|
||||||
SpaceAfterLogicalNot: false
|
SpaceAfterLogicalNot: false
|
||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: false
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeCpp11BracedList: true
|
SpaceBeforeCpp11BracedList: false
|
||||||
SpaceBeforeCtorInitializerColon: true
|
SpaceBeforeCtorInitializerColon: true
|
||||||
SpaceBeforeInheritanceColon: true
|
SpaceBeforeInheritanceColon: true
|
||||||
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
||||||
@ -157,7 +157,7 @@ SpaceBeforeRangeBasedForLoopColon: true
|
|||||||
SpaceInEmptyBlock: false
|
SpaceInEmptyBlock: false
|
||||||
SpaceInEmptyParentheses: false
|
SpaceInEmptyParentheses: false
|
||||||
SpacesBeforeTrailingComments: 2
|
SpacesBeforeTrailingComments: 2
|
||||||
SpacesInAngles: false
|
SpacesInAngles: Never
|
||||||
SpacesInConditionalStatement: false
|
SpacesInConditionalStatement: false
|
||||||
SpacesInContainerLiterals: false
|
SpacesInContainerLiterals: false
|
||||||
SpacesInCStyleCastParentheses: false
|
SpacesInCStyleCastParentheses: false
|
||||||
|
@ -35,7 +35,7 @@ set(lnav_LIBS
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(test)
|
# add_subdirectory(test)
|
||||||
|
|
||||||
# ---- Install rules ----
|
# ---- Install rules ----
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ class LnavConan(ConanFile):
|
|||||||
"pcre:with_jit": True,
|
"pcre:with_jit": True,
|
||||||
"sqlite3:enable_json1": True,
|
"sqlite3:enable_json1": True,
|
||||||
"sqlite3:enable_soundex": True,
|
"sqlite3:enable_soundex": True,
|
||||||
|
"readline:with_library": "curses",
|
||||||
}
|
}
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
|
@ -19,6 +19,8 @@ add_subdirectory(pcrepp)
|
|||||||
add_subdirectory(remote)
|
add_subdirectory(remote)
|
||||||
add_subdirectory(tailer)
|
add_subdirectory(tailer)
|
||||||
add_subdirectory(formats/logfmt)
|
add_subdirectory(formats/logfmt)
|
||||||
|
add_subdirectory(yajl)
|
||||||
|
add_subdirectory(yajlpp)
|
||||||
|
|
||||||
add_executable(bin2c bin2c.hh tools/bin2c.c)
|
add_executable(bin2c bin2c.hh tools/bin2c.c)
|
||||||
target_link_libraries(bin2c ZLIB::ZLIB)
|
target_link_libraries(bin2c ZLIB::ZLIB)
|
||||||
@ -26,465 +28,447 @@ target_link_libraries(bin2c ZLIB::ZLIB)
|
|||||||
add_executable(ptimec ptimec.hh ptimec.c)
|
add_executable(ptimec ptimec.hh ptimec.c)
|
||||||
|
|
||||||
set(TIME_FORMATS
|
set(TIME_FORMATS
|
||||||
"@%@"
|
"@%@"
|
||||||
"%Y-%m-%d %H:%M:%S"
|
"%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:%S %z"
|
"%Y-%m-%d %H:%M:%S %z"
|
||||||
"%Y-%m-%d %H:%M"
|
"%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:%S.%f%z"
|
"%y-%m-%dT%H:%M:%S.%f%z"
|
||||||
"%Y-%m-%dT%H:%M:%SZ"
|
"%Y-%m-%dT%H:%M:%SZ"
|
||||||
"%Y-%m-%dT%H:%M:%S%z"
|
"%Y-%m-%dT%H:%M:%S%z"
|
||||||
"%Y-%m-%dT%H:%M:%S"
|
"%Y-%m-%dT%H:%M:%S"
|
||||||
"%Y-%m-%dT%H:%M:%S%z"
|
"%Y-%m-%dT%H:%M:%S%z"
|
||||||
"%Y/%m/%d %H:%M:%S"
|
"%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:%S%z"
|
"%Y/%m/%d %H:%M:%S%z"
|
||||||
"%Y/%m/%d %H:%M"
|
"%Y/%m/%d %H:%M"
|
||||||
"%Y %b %d %a %H:%M:%S.%L"
|
"%Y %b %d %a %H:%M:%S.%L"
|
||||||
"%Y %b %d %H:%M:%S.%L"
|
"%Y %b %d %H:%M:%S.%L"
|
||||||
"%Y %b %d %H:%M:%S"
|
"%Y %b %d %H:%M:%S"
|
||||||
"%a %b %d %H:%M:%S %Y"
|
"%a %b %d %H:%M:%S %Y"
|
||||||
"%a %b %d %H:%M:%S.%f %Y"
|
"%a %b %d %H:%M:%S.%f %Y"
|
||||||
"%a %b %d %H:%M:%S %Z %Y"
|
"%a %b %d %H:%M:%S %Z %Y"
|
||||||
"%a %b %d %H:%M:%S "
|
"%a %b %d %H:%M:%S "
|
||||||
"%a %b %d %H:%M:%S.%L "
|
"%a %b %d %H:%M:%S.%L "
|
||||||
"%d/%b/%Y:%H:%M:%S +0000"
|
"%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 %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"
|
||||||
"%d %b %Y %H:%M:%S.%L"
|
"%d %b %Y %H:%M:%S.%L"
|
||||||
"%d %b %Y %H:%M:%S,%L"
|
"%d %b %Y %H:%M:%S,%L"
|
||||||
"%b %d %H:%M:%S"
|
"%b %d %H:%M:%S"
|
||||||
"%b %d %k:%M:%S"
|
"%b %d %k:%M:%S"
|
||||||
"%b %d %l:%M:%S"
|
"%b %d %l:%M:%S"
|
||||||
"%b %e, %Y %l:%M:%S %p"
|
"%b %e, %Y %l:%M:%S %p"
|
||||||
"%m/%d/%y %H:%M:%S"
|
"%m/%d/%y %H:%M:%S"
|
||||||
"%m/%d/%Y %I:%M:%S:%L %p %Z"
|
"%m/%d/%Y %I:%M:%S:%L %p %Z"
|
||||||
"%m/%d/%Y %I:%M:%S %p %Z"
|
"%m/%d/%Y %I:%M:%S %p %Z"
|
||||||
"%m/%d/%Y %l:%M:%S %p %Z"
|
"%m/%d/%Y %l:%M:%S %p %Z"
|
||||||
"%m/%e/%Y %I:%M:%S %p"
|
"%m/%e/%Y %I:%M:%S %p"
|
||||||
"%m/%e/%Y %l:%M:%S %p"
|
"%m/%e/%Y %l:%M:%S %p"
|
||||||
"%d/%b/%y %H:%M:%S"
|
"%d/%b/%y %H:%M:%S"
|
||||||
"%m%d %H:%M:%S"
|
"%m%d %H:%M:%S"
|
||||||
"%H:%M:%S"
|
"%H:%M:%S"
|
||||||
"%M:%S"
|
"%M:%S"
|
||||||
"%m/%d %H:%M:%S"
|
"%m/%d %H:%M:%S"
|
||||||
"%Y-%m-%d"
|
"%Y-%m-%d"
|
||||||
"%Y-%m"
|
"%Y-%m"
|
||||||
"%Y/%m/%d"
|
"%Y/%m/%d"
|
||||||
"%Y/%m"
|
"%Y/%m"
|
||||||
"%s.%f")
|
"%s.%f")
|
||||||
|
|
||||||
set(GEN_SRCS "")
|
set(GEN_SRCS "")
|
||||||
|
|
||||||
add_custom_command(OUTPUT time_fmts.cc COMMAND ptimec ${TIME_FORMATS} >
|
add_custom_command(OUTPUT time_fmts.cc COMMAND ptimec ${TIME_FORMATS} >
|
||||||
time_fmts.cc)
|
time_fmts.cc)
|
||||||
list(APPEND GEN_SRCS 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)
|
function(bin2c)
|
||||||
cmake_parse_arguments(BIN2C_ "" "VARNAME" "" ${ARGN})
|
cmake_parse_arguments(BIN2C_ "" "VARNAME" "" ${ARGN})
|
||||||
|
|
||||||
list(TRANSFORM BIN2C_UNPARSED_ARGUMENTS "\\." "-")
|
list(TRANSFORM BIN2C_UNPARSED_ARGUMENTS "\\." "-")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
|
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
|
||||||
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
|
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
|
||||||
DEPENDS bin2c "${FILE_TO_LINK}")
|
DEPENDS bin2c "${FILE_TO_LINK}")
|
||||||
endfunction(bin2c)
|
endfunction(bin2c)
|
||||||
|
|
||||||
foreach(FILE_TO_LINK ansi-palette.json xterm-palette.json help.txt init.sql)
|
foreach (FILE_TO_LINK ansi-palette.json xterm-palette.json help.txt init.sql)
|
||||||
string(REPLACE "." "-" DST_FILE "${FILE_TO_LINK}")
|
string(REPLACE "." "-" DST_FILE "${FILE_TO_LINK}")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
|
OUTPUT "${DST_FILE}.h" "${DST_FILE}.cc"
|
||||||
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
|
COMMAND bin2c "${DST_FILE}" "${CMAKE_CURRENT_SOURCE_DIR}/${FILE_TO_LINK}"
|
||||||
DEPENDS bin2c "${FILE_TO_LINK}")
|
DEPENDS bin2c "${FILE_TO_LINK}")
|
||||||
list(APPEND GEN_SRCS "${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.h"
|
list(APPEND GEN_SRCS "${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.h"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.cc")
|
"${CMAKE_CURRENT_BINARY_DIR}/${DST_FILE}.cc")
|
||||||
endforeach(FILE_TO_LINK)
|
endforeach (FILE_TO_LINK)
|
||||||
|
|
||||||
set(FORMAT_FILES
|
set(FORMAT_FILES
|
||||||
formats/access_log.json
|
formats/access_log.json
|
||||||
formats/alb_log.json
|
formats/alb_log.json
|
||||||
formats/autodeploy_log.json
|
formats/autodeploy_log.json
|
||||||
formats/block_log.json
|
formats/block_log.json
|
||||||
formats/candlepin_log.json
|
formats/candlepin_log.json
|
||||||
formats/choose_repo_log.json
|
formats/choose_repo_log.json
|
||||||
formats/cups_log.json
|
formats/cups_log.json
|
||||||
formats/dpkg_log.json
|
formats/dpkg_log.json
|
||||||
formats/elb_log.json
|
formats/elb_log.json
|
||||||
formats/engine_log.json
|
formats/engine_log.json
|
||||||
formats/error_log.json
|
formats/error_log.json
|
||||||
formats/fsck_hfs_log.json
|
formats/fsck_hfs_log.json
|
||||||
formats/glog_log.json
|
formats/glog_log.json
|
||||||
formats/haproxy_log.json
|
formats/haproxy_log.json
|
||||||
formats/java_log.json
|
formats/java_log.json
|
||||||
formats/journald_json_log.json
|
formats/journald_json_log.json
|
||||||
formats/katello_log.json
|
formats/katello_log.json
|
||||||
formats/openam_log.json
|
formats/openam_log.json
|
||||||
formats/openamdb_log.json
|
formats/openamdb_log.json
|
||||||
formats/openstack_log.json
|
formats/openstack_log.json
|
||||||
formats/page_log.json
|
formats/page_log.json
|
||||||
formats/papertrail_log.json
|
formats/papertrail_log.json
|
||||||
formats/snaplogic_log.json
|
formats/snaplogic_log.json
|
||||||
formats/sssd_log.json
|
formats/sssd_log.json
|
||||||
formats/strace_log.json
|
formats/strace_log.json
|
||||||
formats/sudo_log.json
|
formats/sudo_log.json
|
||||||
formats/syslog_log.json
|
formats/syslog_log.json
|
||||||
formats/s3_log.json
|
formats/s3_log.json
|
||||||
formats/tcf_log.json
|
formats/tcf_log.json
|
||||||
formats/tcsh_history.json
|
formats/tcsh_history.json
|
||||||
formats/uwsgi_log.json
|
formats/uwsgi_log.json
|
||||||
formats/vdsm_log.json
|
formats/vdsm_log.json
|
||||||
formats/vmk_log.json
|
formats/vmk_log.json
|
||||||
formats/vmw_log.json
|
formats/vmw_log.json
|
||||||
formats/xmlrpc_log.json)
|
formats/xmlrpc_log.json)
|
||||||
|
|
||||||
set(FORMAT_FILE_PATHS ${FORMAT_FILES})
|
set(FORMAT_FILE_PATHS ${FORMAT_FILES})
|
||||||
|
|
||||||
list(TRANSFORM FORMAT_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
list(TRANSFORM FORMAT_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT default-formats.h default-formats.cc
|
OUTPUT default-formats.h default-formats.cc
|
||||||
COMMAND bin2c -n lnav_format_json default-formats ${FORMAT_FILE_PATHS}
|
COMMAND bin2c -n lnav_format_json default-formats ${FORMAT_FILE_PATHS}
|
||||||
DEPENDS bin2c ${FORMAT_FILES})
|
DEPENDS bin2c ${FORMAT_FILES})
|
||||||
list(APPEND GEN_SRCS default-formats.h default-formats.cc)
|
list(APPEND GEN_SRCS default-formats.h default-formats.cc)
|
||||||
|
|
||||||
set(CONFIG_FILES
|
set(CONFIG_FILES
|
||||||
root-config.json
|
root-config.json
|
||||||
keymaps/de-keymap.json
|
keymaps/de-keymap.json
|
||||||
keymaps/default-keymap.json
|
keymaps/default-keymap.json
|
||||||
keymaps/fr-keymap.json
|
keymaps/fr-keymap.json
|
||||||
keymaps/uk-keymap.json
|
keymaps/uk-keymap.json
|
||||||
keymaps/us-keymap.json
|
keymaps/us-keymap.json
|
||||||
themes/default-theme.json
|
themes/default-theme.json
|
||||||
themes/grayscale.json
|
themes/grayscale.json
|
||||||
themes/eldar.json
|
themes/eldar.json
|
||||||
themes/monocai.json
|
themes/monocai.json
|
||||||
themes/night-owl.json
|
themes/night-owl.json
|
||||||
themes/solarized-dark.json
|
themes/solarized-dark.json
|
||||||
themes/solarized-light.json)
|
themes/solarized-light.json)
|
||||||
|
|
||||||
set(CONFIG_FILE_PATHS ${CONFIG_FILES})
|
set(CONFIG_FILE_PATHS ${CONFIG_FILES})
|
||||||
|
|
||||||
list(TRANSFORM CONFIG_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
list(TRANSFORM CONFIG_FILE_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT default-config.h default-config.cc
|
OUTPUT default-config.h default-config.cc
|
||||||
COMMAND bin2c -n lnav_config_json default-config ${CONFIG_FILE_PATHS}
|
COMMAND bin2c -n lnav_config_json default-config ${CONFIG_FILE_PATHS}
|
||||||
DEPENDS bin2c ${CONFIG_FILES})
|
DEPENDS bin2c ${CONFIG_FILES})
|
||||||
list(APPEND GEN_SRCS default-config.h default-config.cc)
|
list(APPEND GEN_SRCS default-config.h default-config.cc)
|
||||||
|
|
||||||
set(BUILTIN_LNAV_SCRIPTS
|
set(BUILTIN_LNAV_SCRIPTS
|
||||||
scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
|
scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
|
||||||
scripts/partition-by-boot.lnav scripts/rename-stdin.lnav
|
scripts/partition-by-boot.lnav scripts/rename-stdin.lnav
|
||||||
scripts/search-for.lnav)
|
scripts/search-for.lnav)
|
||||||
|
|
||||||
set(BUILTIN_LNAV_SCRIPT_PATHS ${BUILTIN_LNAV_SCRIPTS})
|
set(BUILTIN_LNAV_SCRIPT_PATHS ${BUILTIN_LNAV_SCRIPTS})
|
||||||
|
|
||||||
list(TRANSFORM BUILTIN_LNAV_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
list(TRANSFORM BUILTIN_LNAV_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT builtin-scripts.h builtin-scripts.cc
|
OUTPUT builtin-scripts.h builtin-scripts.cc
|
||||||
COMMAND bin2c -n lnav_scripts builtin-scripts ${BUILTIN_LNAV_SCRIPT_PATHS}
|
COMMAND bin2c -n lnav_scripts builtin-scripts ${BUILTIN_LNAV_SCRIPT_PATHS}
|
||||||
DEPENDS bin2c ${BUILTIN_LNAV_SCRIPTS})
|
DEPENDS bin2c ${BUILTIN_LNAV_SCRIPTS})
|
||||||
list(APPEND GEN_SRCS builtin-scripts.h builtin-scripts.cc)
|
list(APPEND GEN_SRCS builtin-scripts.h builtin-scripts.cc)
|
||||||
|
|
||||||
set(BUILTIN_SH_SCRIPTS scripts/dhclient-summary.lnav scripts/lnav-pop-view.lnav
|
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})
|
set(BUILTIN_SH_SCRIPT_PATHS ${BUILTIN_SH_SCRIPTS})
|
||||||
|
|
||||||
list(TRANSFORM BUILTIN_SH_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
list(TRANSFORM BUILTIN_SH_SCRIPT_PATHS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT builtin-sh-scripts.h builtin-sh-scripts.cc
|
OUTPUT builtin-sh-scripts.h builtin-sh-scripts.cc
|
||||||
COMMAND bin2c -n lnav_sh_scripts builtin-sh-scripts ${BUILTIN_SH_SCRIPT_PATHS}
|
COMMAND bin2c -n lnav_sh_scripts builtin-sh-scripts ${BUILTIN_SH_SCRIPT_PATHS}
|
||||||
DEPENDS bin2c ${BUILTIN_SH_SCRIPTS})
|
DEPENDS bin2c ${BUILTIN_SH_SCRIPTS})
|
||||||
list(APPEND GEN_SRCS builtin-sh-scripts.h builtin-sh-scripts.cc)
|
list(APPEND GEN_SRCS builtin-sh-scripts.h builtin-sh-scripts.cc)
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
cppfmt STATIC
|
cppfmt STATIC
|
||||||
fmtlib/format.cc
|
fmtlib/format.cc
|
||||||
fmtlib/os.cc
|
fmtlib/os.cc
|
||||||
fmtlib/fmt/chrono.h
|
fmtlib/fmt/chrono.h
|
||||||
fmtlib/fmt/color.h
|
fmtlib/fmt/color.h
|
||||||
fmtlib/fmt/compile.h
|
fmtlib/fmt/compile.h
|
||||||
fmtlib/fmt/core.h
|
fmtlib/fmt/core.h
|
||||||
fmtlib/fmt/format-inl.h
|
fmtlib/fmt/format-inl.h
|
||||||
fmtlib/fmt/format.h
|
fmtlib/fmt/format.h
|
||||||
fmtlib/fmt/locale.h
|
fmtlib/fmt/locale.h
|
||||||
fmtlib/fmt/os.h
|
fmtlib/fmt/os.h
|
||||||
fmtlib/fmt/ostream.h
|
fmtlib/fmt/ostream.h
|
||||||
fmtlib/fmt/posix.h
|
fmtlib/fmt/posix.h
|
||||||
fmtlib/fmt/printf.h
|
fmtlib/fmt/printf.h
|
||||||
fmtlib/fmt/ranges.h
|
fmtlib/fmt/ranges.h
|
||||||
fmtlib/fmt/time.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(
|
add_library(
|
||||||
diag STATIC
|
diag STATIC
|
||||||
${GEN_SRCS}
|
${GEN_SRCS}
|
||||||
config.h.in
|
config.h.in
|
||||||
all_logs_vtab.cc
|
all_logs_vtab.cc
|
||||||
ansi_scrubber.cc
|
ansi_scrubber.cc
|
||||||
archive_manager.cc
|
archive_manager.cc
|
||||||
attr_line.cc
|
attr_line.cc
|
||||||
bin2c.hh
|
bin2c.hh
|
||||||
bookmarks.cc
|
bookmarks.cc
|
||||||
bottom_status_source.cc
|
bottom_status_source.cc
|
||||||
collation-functions.cc
|
collation-functions.cc
|
||||||
column_namer.cc
|
column_namer.cc
|
||||||
command_executor.cc
|
command_executor.cc
|
||||||
curl_looper.cc
|
curl_looper.cc
|
||||||
db_sub_source.cc
|
db_sub_source.cc
|
||||||
elem_to_json.cc
|
elem_to_json.cc
|
||||||
environ_vtab.cc
|
environ_vtab.cc
|
||||||
extension-functions.cc
|
extension-functions.cc
|
||||||
field_overlay_source.cc
|
field_overlay_source.cc
|
||||||
file_collection.cc
|
file_collection.cc
|
||||||
file_format.cc
|
file_format.cc
|
||||||
file_vtab.cc
|
file_vtab.cc
|
||||||
files_sub_source.cc
|
files_sub_source.cc
|
||||||
filter_observer.cc
|
filter_observer.cc
|
||||||
filter_status_source.cc
|
filter_status_source.cc
|
||||||
filter_sub_source.cc
|
filter_sub_source.cc
|
||||||
fs-extension-functions.cc
|
fs-extension-functions.cc
|
||||||
fstat_vtab.cc
|
fstat_vtab.cc
|
||||||
fts_fuzzy_match.cc
|
fts_fuzzy_match.cc
|
||||||
grep_proc.cc
|
help_text.cc
|
||||||
help_text.cc
|
help_text_formatter.cc
|
||||||
help_text_formatter.cc
|
highlighter.cc
|
||||||
highlighter.cc
|
hist_source.cc
|
||||||
hist_source.cc
|
hotkeys.cc
|
||||||
hotkeys.cc
|
input_dispatcher.cc
|
||||||
input_dispatcher.cc
|
json-extension-functions.cc
|
||||||
json-extension-functions.cc
|
listview_curses.cc
|
||||||
yajlpp/json_op.cc
|
lnav_commands.cc
|
||||||
yajlpp/json_ptr.cc
|
lnav_config.cc
|
||||||
line_buffer.cc
|
lnav_util.cc
|
||||||
listview_curses.cc
|
log_accel.cc
|
||||||
lnav_commands.cc
|
log_actions.cc
|
||||||
lnav_config.cc
|
log_data_helper.cc
|
||||||
lnav_util.cc
|
log_data_table.cc
|
||||||
log_accel.cc
|
log_format.cc
|
||||||
log_actions.cc
|
log_format_loader.cc
|
||||||
log_data_helper.cc
|
log_level.cc
|
||||||
log_data_table.cc
|
log_search_table.cc
|
||||||
log_format.cc
|
logfile.cc
|
||||||
log_format_loader.cc
|
logfile_sub_source.cc
|
||||||
log_level.cc
|
network-extension-functions.cc
|
||||||
log_search_table.cc
|
data_scanner.cc
|
||||||
logfile.cc
|
data_scanner_re.cc
|
||||||
logfile_sub_source.cc
|
data_parser.cc
|
||||||
network-extension-functions.cc
|
papertrail_proc.cc
|
||||||
data_scanner.cc
|
pcap_manager.cc
|
||||||
data_scanner_re.cc
|
pretty_printer.cc
|
||||||
data_parser.cc
|
pugixml/pugixml.cpp
|
||||||
papertrail_proc.cc
|
readline_callbacks.cc
|
||||||
pcap_manager.cc
|
readline_curses.cc
|
||||||
ptimec_rt.cc
|
readline_highlighters.cc
|
||||||
pretty_printer.cc
|
readline_possibilities.cc
|
||||||
pugixml/pugixml.cpp
|
regexp_vtab.cc
|
||||||
readline_callbacks.cc
|
relative_time.cc
|
||||||
readline_curses.cc
|
session_data.cc
|
||||||
readline_highlighters.cc
|
sequence_matcher.cc
|
||||||
readline_possibilities.cc
|
shlex.cc
|
||||||
regexp_vtab.cc
|
sqlite-extension-func.cc
|
||||||
relative_time.cc
|
statusview_curses.cc
|
||||||
session_data.cc
|
string-extension-functions.cc
|
||||||
sequence_matcher.cc
|
sysclip.cc
|
||||||
shared_buffer.cc
|
piper_proc.cc
|
||||||
shlex.cc
|
spectro_source.cc
|
||||||
sqlite-extension-func.cc
|
sql_commands.cc
|
||||||
statusview_curses.cc
|
sql_util.cc
|
||||||
string-extension-functions.cc
|
state-extension-functions.cc
|
||||||
sysclip.cc
|
styling.cc
|
||||||
piper_proc.cc
|
string_attr_type.cc
|
||||||
spectro_source.cc
|
text_format.cc
|
||||||
sql_commands.cc
|
textfile_highlighters.cc
|
||||||
sql_util.cc
|
textfile_sub_source.cc
|
||||||
state-extension-functions.cc
|
textview_curses.cc
|
||||||
styling.cc
|
top_status_source.cc
|
||||||
string_attr_type.cc
|
time-extension-functions.cc
|
||||||
text_format.cc
|
timer.cc
|
||||||
textfile_highlighters.cc
|
unique_path.cc
|
||||||
textfile_sub_source.cc
|
unique_path.hh
|
||||||
textview_curses.cc
|
view_curses.cc
|
||||||
top_status_source.cc
|
view_helpers.cc
|
||||||
time-extension-functions.cc
|
views_vtab.cc
|
||||||
timer.cc
|
vt52_curses.cc
|
||||||
unique_path.cc
|
vtab_module.cc
|
||||||
unique_path.hh
|
log_vtab_impl.cc
|
||||||
view_curses.cc
|
xml_util.cc
|
||||||
view_helpers.cc
|
xpath_vtab.cc
|
||||||
views_vtab.cc
|
xterm_mouse.cc
|
||||||
vt52_curses.cc
|
spookyhash/SpookyV2.cpp
|
||||||
vtab_module.cc
|
third-party/sqlite/ext/series.c
|
||||||
log_vtab_impl.cc
|
third-party/sqlite/ext/dbdump.c
|
||||||
xml_util.cc
|
all_logs_vtab.hh
|
||||||
xpath_vtab.cc
|
archive_manager.hh
|
||||||
xterm_mouse.cc
|
archive_manager.cfg.hh
|
||||||
yajlpp/yajlpp.cc
|
attr_line.hh
|
||||||
yajl/yajl.c
|
auto_fd.hh
|
||||||
yajl/yajl_alloc.c
|
auto_mem.hh
|
||||||
yajl/yajl_alloc.h
|
big_array.hh
|
||||||
yajl/yajl_buf.c
|
bottom_status_source.hh
|
||||||
yajl/yajl_buf.h
|
bound_tags.hh
|
||||||
yajl/yajl_bytestack.h
|
byte_array.hh
|
||||||
yajl/yajl_encode.c
|
command_executor.hh
|
||||||
yajl/yajl_encode.h
|
column_namer.hh
|
||||||
yajl/yajl_gen.c
|
curl_looper.hh
|
||||||
yajl/yajl_lex.c
|
doc_status_source.hh
|
||||||
yajl/yajl_lex.h
|
elem_to_json.hh
|
||||||
yajl/yajl_parser.c
|
field_overlay_source.hh
|
||||||
yajl/yajl_parser.h
|
file_collection.hh
|
||||||
yajl/yajl_tree.c
|
file_format.hh
|
||||||
yajl/yajl_version.c
|
files_sub_source.hh
|
||||||
spookyhash/SpookyV2.cpp
|
filter_observer.hh
|
||||||
third-party/sqlite/ext/series.c
|
filter_status_source.hh
|
||||||
third-party/sqlite/ext/dbdump.c
|
filter_sub_source.hh
|
||||||
all_logs_vtab.hh
|
fstat_vtab.hh
|
||||||
archive_manager.hh
|
fts_fuzzy_match.hh
|
||||||
archive_manager.cfg.hh
|
grep_highlighter.hh
|
||||||
attr_line.hh
|
help_text.hh
|
||||||
auto_fd.hh
|
help_text_formatter.hh
|
||||||
auto_mem.hh
|
highlighter.hh
|
||||||
big_array.hh
|
hotkeys.hh
|
||||||
bottom_status_source.hh
|
input_dispatcher.hh
|
||||||
bound_tags.hh
|
k_merge_tree.h
|
||||||
byte_array.hh
|
log_actions.hh
|
||||||
command_executor.hh
|
log_data_helper.hh
|
||||||
column_namer.hh
|
log_data_table.hh
|
||||||
curl_looper.hh
|
log_format.hh
|
||||||
doc_status_source.hh
|
log_format_ext.hh
|
||||||
elem_to_json.hh
|
log_format_fwd.hh
|
||||||
field_overlay_source.hh
|
log_format_impls.cc
|
||||||
file_collection.hh
|
log_gutter_source.hh
|
||||||
file_format.hh
|
log_level.hh
|
||||||
files_sub_source.hh
|
log_search_table.hh
|
||||||
filter_observer.hh
|
logfile.hh
|
||||||
filter_status_source.hh
|
logfile_fwd.hh
|
||||||
filter_sub_source.hh
|
logfile_stats.hh
|
||||||
fstat_vtab.hh
|
optional.hpp
|
||||||
fts_fuzzy_match.hh
|
papertrail_proc.hh
|
||||||
grep_highlighter.hh
|
pcap_manager.hh
|
||||||
help_text.hh
|
plain_text_source.hh
|
||||||
help_text_formatter.hh
|
pretty_printer.hh
|
||||||
highlighter.hh
|
preview_status_source.hh
|
||||||
hotkeys.hh
|
pugixml/pugiconfig.hpp
|
||||||
input_dispatcher.hh
|
pugixml/pugixml.hpp
|
||||||
k_merge_tree.h
|
readline_callbacks.hh
|
||||||
log_actions.hh
|
readline_context.hh
|
||||||
log_data_helper.hh
|
readline_possibilities.hh
|
||||||
log_data_table.hh
|
regexp_vtab.hh
|
||||||
log_format.hh
|
relative_time.hh
|
||||||
log_format_ext.hh
|
styling.hh
|
||||||
log_format_fwd.hh
|
ring_span.hh
|
||||||
log_format_impls.cc
|
safe/accessmode.h
|
||||||
log_gutter_source.hh
|
safe/defaulttypes.h
|
||||||
log_level.hh
|
safe/mutableref.h
|
||||||
log_search_table.hh
|
safe/safe.h
|
||||||
logfile.hh
|
sequence_sink.hh
|
||||||
logfile_fwd.hh
|
shlex.hh
|
||||||
logfile_stats.hh
|
shlex.resolver.hh
|
||||||
optional.hpp
|
simdutf8check.h
|
||||||
papertrail_proc.hh
|
spectro_source.hh
|
||||||
pcap_manager.hh
|
sqlitepp.hh
|
||||||
plain_text_source.hh
|
sql_help.hh
|
||||||
pretty_printer.hh
|
sql_util.hh
|
||||||
preview_status_source.hh
|
strong_int.hh
|
||||||
ptimec.hh
|
string_attr_type.hh
|
||||||
pugixml/pugiconfig.hpp
|
sysclip.hh
|
||||||
pugixml/pugixml.hpp
|
sysclip.cfg.hh
|
||||||
readline_callbacks.hh
|
term_extra.hh
|
||||||
readline_context.hh
|
termios_guard.hh
|
||||||
readline_possibilities.hh
|
text_format.hh
|
||||||
regexp_vtab.hh
|
textfile_highlighters.hh
|
||||||
relative_time.hh
|
textfile_sub_source.hh
|
||||||
styling.hh
|
textview_curses.hh
|
||||||
ring_span.hh
|
textview_curses_fwd.hh
|
||||||
safe/accessmode.h
|
time_T.hh
|
||||||
safe/defaulttypes.h
|
timer.hh
|
||||||
safe/mutableref.h
|
top_status_source.hh
|
||||||
safe/safe.h
|
url_loader.hh
|
||||||
sequence_sink.hh
|
view_helpers.hh
|
||||||
shlex.hh
|
view_helpers.examples.hh
|
||||||
shlex.resolver.hh
|
views_vtab.hh
|
||||||
simdutf8check.h
|
vis_line.hh
|
||||||
spectro_source.hh
|
vtab_module.hh
|
||||||
sqlitepp.hh
|
vtab_module_json.hh
|
||||||
sql_help.hh
|
xml_util.hh
|
||||||
sql_util.hh
|
xpath_vtab.hh
|
||||||
strong_int.hh
|
mapbox/recursive_wrapper.hpp
|
||||||
string_attr_type.hh
|
mapbox/variant.hpp
|
||||||
sysclip.hh
|
mapbox/variant_io.hpp
|
||||||
sysclip.cfg.hh
|
mapbox/variant_visitor.hpp
|
||||||
term_extra.hh
|
ghc/filesystem.hpp
|
||||||
termios_guard.hh
|
ghc/fs_fwd.hpp
|
||||||
text_format.hh
|
ghc/fs_impl.hpp
|
||||||
textfile_highlighters.hh
|
ghc/fs_std.hpp
|
||||||
textfile_sub_source.hh
|
ghc/fs_std_fwd.hpp
|
||||||
textview_curses.hh
|
ghc/fs_std_impl.hpp
|
||||||
textview_curses_fwd.hh
|
ww898/cp_utf8.hpp
|
||||||
time_T.hh
|
log_level_re.cc)
|
||||||
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)
|
|
||||||
|
|
||||||
set(lnav_SRCS lnav.cc)
|
set(lnav_SRCS lnav.cc)
|
||||||
|
|
||||||
target_include_directories(diag PUBLIC . fmtlib ${CMAKE_CURRENT_BINARY_DIR}
|
target_include_directories(diag PUBLIC . fmtlib ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
third-party)
|
third-party)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
diag
|
diag
|
||||||
base
|
base
|
||||||
pcrepp
|
lnavdt
|
||||||
tailerservice
|
lnavfileio
|
||||||
tailerpp
|
pcrepp
|
||||||
tailercommon
|
tailerservice
|
||||||
logfmt
|
tailerpp
|
||||||
${lnav_LIBS})
|
tailercommon
|
||||||
|
logfmt
|
||||||
|
yajlpp
|
||||||
|
${lnav_LIBS})
|
||||||
target_compile_definitions(diag PRIVATE SQLITE_OMIT_LOAD_EXTENSION)
|
target_compile_definitions(diag PRIVATE SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
|
||||||
check_library_exists(util openpty "" HAVE_LIBUTIL)
|
check_library_exists(util openpty "" HAVE_LIBUTIL)
|
||||||
|
|
||||||
if(HAVE_LIBUTIL)
|
if (HAVE_LIBUTIL)
|
||||||
target_link_libraries(diag util)
|
target_link_libraries(diag util)
|
||||||
endif()
|
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})
|
|
||||||
|
|
||||||
add_executable(lnav ${lnav_SRCS})
|
add_executable(lnav ${lnav_SRCS})
|
||||||
target_link_libraries(lnav diag)
|
target_link_libraries(lnav diag)
|
||||||
|
@ -21,48 +21,54 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "all_logs_vtab.hh"
|
#include "all_logs_vtab.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "string_attr_type.hh"
|
#include "string_attr_type.hh"
|
||||||
|
|
||||||
static auto intern_lifetime = intern_string::get_table_lifetime();
|
static auto intern_lifetime = intern_string::get_table_lifetime();
|
||||||
|
|
||||||
all_logs_vtab::all_logs_vtab()
|
all_logs_vtab::all_logs_vtab()
|
||||||
: log_vtab_impl(intern_string::lookup("all_logs")),
|
: log_vtab_impl(intern_string::lookup("all_logs")),
|
||||||
alv_value_meta(intern_string::lookup("log_format"),
|
alv_value_meta(
|
||||||
value_kind_t::VALUE_TEXT,
|
intern_string::lookup("log_format"), value_kind_t::VALUE_TEXT, 0),
|
||||||
0),
|
alv_msg_meta(
|
||||||
alv_msg_meta(intern_string::lookup("log_msg_format"),
|
intern_string::lookup("log_msg_format"), value_kind_t::VALUE_TEXT, 1),
|
||||||
value_kind_t::VALUE_TEXT,
|
alv_schema_meta(
|
||||||
1),
|
intern_string::lookup("log_msg_schema"), value_kind_t::VALUE_TEXT, 2)
|
||||||
alv_schema_meta(intern_string::lookup("log_msg_schema"),
|
{
|
||||||
value_kind_t::VALUE_TEXT,
|
|
||||||
2) {
|
|
||||||
this->alv_value_meta.lvm_identifier = true;
|
this->alv_value_meta.lvm_identifier = true;
|
||||||
this->alv_msg_meta.lvm_identifier = true;
|
this->alv_msg_meta.lvm_identifier = true;
|
||||||
this->alv_schema_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())
|
cols.emplace_back(vtab_column(this->alv_value_meta.lvm_name.get())
|
||||||
.with_comment("The name of the log file format"));
|
.with_comment("The name of the log file format"));
|
||||||
cols.emplace_back(vtab_column(this->alv_msg_meta.lvm_name.get())
|
cols.emplace_back(
|
||||||
.with_comment("The message format with variables replaced by hash marks"));
|
vtab_column(this->alv_msg_meta.lvm_name.get())
|
||||||
cols.emplace_back(this->alv_schema_meta.lvm_name.get(), SQLITE3_TEXT, "", true,
|
.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");
|
"The ID for the message schema");
|
||||||
}
|
}
|
||||||
|
|
||||||
void all_logs_vtab::extract(std::shared_ptr<logfile> lf, uint64_t line_number,
|
void
|
||||||
shared_buffer_ref &line,
|
all_logs_vtab::extract(std::shared_ptr<logfile> lf,
|
||||||
std::vector<logline_value> &values)
|
uint64_t line_number,
|
||||||
|
shared_buffer_ref& line,
|
||||||
|
std::vector<logline_value>& values)
|
||||||
{
|
{
|
||||||
auto format = lf->get_format();
|
auto format = lf->get_format();
|
||||||
values.emplace_back(this->alv_value_meta, format->get_name());
|
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);
|
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 cl = lss.at(lc.lc_curr_line);
|
||||||
auto lf = lss.find(cl);
|
auto lf = lss.find(cl);
|
||||||
@ -111,7 +118,8 @@ bool all_logs_vtab::is_valid(log_cursor &lc, logfile_sub_source &lss)
|
|||||||
return true;
|
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_curr_line = lc.lc_curr_line + vis_line_t(1);
|
||||||
lc.lc_sub_index = 0;
|
lc.lc_sub_index = 0;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -32,27 +32,26 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include "log_vtab_impl.hh"
|
|
||||||
#include "data_parser.hh"
|
#include "data_parser.hh"
|
||||||
|
#include "log_vtab_impl.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A virtual table that provides access to all log messages from all formats.
|
* A virtual table that provides access to all log messages from all formats.
|
||||||
*/
|
*/
|
||||||
class all_logs_vtab : public log_vtab_impl {
|
class all_logs_vtab : public log_vtab_impl {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
all_logs_vtab();
|
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,
|
void extract(std::shared_ptr<logfile> lf,
|
||||||
uint64_t line_number,
|
uint64_t line_number,
|
||||||
shared_buffer_ref &line,
|
shared_buffer_ref& line,
|
||||||
std::vector<logline_value> &values) override;
|
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:
|
private:
|
||||||
logline_value_meta alv_value_meta;
|
logline_value_meta alv_value_meta;
|
||||||
@ -62,4 +61,4 @@ private:
|
|||||||
std::array<char, data_parser::schema_id_t::STRING_SIZE> alv_schema_buffer{};
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file ansi_scrubber.cc
|
* @file ansi_scrubber.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "base/opt_util.hh"
|
|
||||||
#include "view_curses.hh"
|
|
||||||
#include "pcrepp/pcrepp.hh"
|
|
||||||
#include "ansi_scrubber.hh"
|
#include "ansi_scrubber.hh"
|
||||||
|
|
||||||
|
#include "base/opt_util.hh"
|
||||||
|
#include "config.h"
|
||||||
|
#include "pcrepp/pcrepp.hh"
|
||||||
|
#include "view_curses.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static pcrepp &ansi_regex()
|
static pcrepp&
|
||||||
|
ansi_regex()
|
||||||
{
|
{
|
||||||
static pcrepp retval("\x1b\\[([\\d=;\\?]*)([a-zA-Z])");
|
static pcrepp retval("\x1b\\[([\\d=;\\?]*)([a-zA-Z])");
|
||||||
|
|
||||||
return retval;
|
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;
|
pcre_context_static<60> context;
|
||||||
pcrepp & regex = ansi_regex();
|
pcrepp& regex = ansi_regex();
|
||||||
pcre_input pi(str);
|
pcre_input pi(str);
|
||||||
|
|
||||||
replace(str.begin(), str.end(), '\0', ' ');
|
replace(str.begin(), str.end(), '\0', ' ');
|
||||||
while (regex.match(context, pi)) {
|
while (regex.match(context, pi)) {
|
||||||
pcre_context::capture_t *caps = context.all();
|
pcre_context::capture_t* caps = context.all();
|
||||||
struct line_range lr;
|
struct line_range lr;
|
||||||
bool has_attrs = false;
|
bool has_attrs = false;
|
||||||
attr_t attrs = 0;
|
attr_t attrs = 0;
|
||||||
auto bg = nonstd::optional<int>();
|
auto bg = nonstd::optional<int>();
|
||||||
auto fg = nonstd::optional<int>();
|
auto fg = nonstd::optional<int>();
|
||||||
auto role = 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]) {
|
switch (pi.get_substr_start(&caps[2])[0]) {
|
||||||
case 'm':
|
case 'm':
|
||||||
for (lpc = caps[1].c_begin;
|
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;
|
int ansi_code = 0;
|
||||||
|
|
||||||
if (sscanf(&(str[lpc]), "%d", &ansi_code) == 1) {
|
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': {
|
case 'C': {
|
||||||
unsigned int spaces = 0;
|
unsigned int spaces = 0;
|
||||||
|
|
||||||
if (sscanf(&(str[caps[1].c_begin]), "%u", &spaces) == 1 &&
|
if (sscanf(&(str[caps[1].c_begin]), "%u", &spaces) == 1
|
||||||
spaces > 0) {
|
&& spaces > 0) {
|
||||||
str.insert((unsigned long) caps[0].c_end, spaces, ' ');
|
str.insert(
|
||||||
|
(std::string::size_type) caps[0].c_end, spaces, ' ');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -120,11 +124,13 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
|||||||
case 'H': {
|
case 'H': {
|
||||||
unsigned int row = 0, spaces = 0;
|
unsigned int row = 0, spaces = 0;
|
||||||
|
|
||||||
if (sscanf(&(str[caps[1].c_begin]), "%u;%u", &row, &spaces) == 2 &&
|
if (sscanf(&(str[caps[1].c_begin]), "%u;%u", &row, &spaces) == 2
|
||||||
spaces > 1) {
|
&& spaces > 1) {
|
||||||
int ispaces = spaces - 1;
|
int ispaces = spaces - 1;
|
||||||
if (ispaces > caps[0].c_begin) {
|
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;
|
break;
|
||||||
@ -142,8 +148,7 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str.erase(str.begin() + caps[0].c_begin,
|
str.erase(str.begin() + caps[0].c_begin, str.begin() + caps[0].c_end);
|
||||||
str.begin() + caps[0].c_end);
|
|
||||||
|
|
||||||
if (has_attrs) {
|
if (has_attrs) {
|
||||||
for (auto rit = sa.rbegin(); rit != sa.rend(); rit++) {
|
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;
|
rit->sa_range.lr_end = caps[0].c_begin;
|
||||||
}
|
}
|
||||||
lr.lr_start = caps[0].c_begin;
|
lr.lr_start = caps[0].c_begin;
|
||||||
lr.lr_end = -1;
|
lr.lr_end = -1;
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
sa.emplace_back(lr, &view_curses::VC_STYLE, 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_csi"] = ANSI_CSI;
|
||||||
vars["ansi_norm"] = ANSI_NORM;
|
vars["ansi_norm"] = ANSI_NORM;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -37,22 +37,22 @@
|
|||||||
|
|
||||||
#include "attr_line.hh"
|
#include "attr_line.hh"
|
||||||
|
|
||||||
#define ANSI_CSI "\x1b["
|
#define ANSI_CSI "\x1b["
|
||||||
#define ANSI_CHAR_ATTR "m"
|
#define ANSI_CHAR_ATTR "m"
|
||||||
#define ANSI_BOLD_PARAM "1"
|
#define ANSI_BOLD_PARAM "1"
|
||||||
#define ANSI_BOLD_START ANSI_CSI ANSI_BOLD_PARAM ANSI_CHAR_ATTR
|
#define ANSI_BOLD_START ANSI_CSI ANSI_BOLD_PARAM ANSI_CHAR_ATTR
|
||||||
#define ANSI_UNDERLINE_START ANSI_CSI "4m"
|
#define ANSI_UNDERLINE_START ANSI_CSI "4m"
|
||||||
#define ANSI_NORM ANSI_CSI "0m"
|
#define ANSI_NORM ANSI_CSI "0m"
|
||||||
#define ANSI_STRIKE_PARAM "9"
|
#define ANSI_STRIKE_PARAM "9"
|
||||||
#define ANSI_STRIKE_START ANSI_CSI ANSI_STRIKE_PARAM ANSI_CHAR_ATTR
|
#define ANSI_STRIKE_START ANSI_CSI ANSI_STRIKE_PARAM ANSI_CHAR_ATTR
|
||||||
|
|
||||||
#define ANSI_BOLD(msg) ANSI_BOLD_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_UNDERLINE(msg) ANSI_UNDERLINE_START msg ANSI_NORM
|
||||||
|
|
||||||
#define ANSI_ROLE(msg) ANSI_CSI "%dO" msg ANSI_NORM
|
#define ANSI_ROLE(msg) ANSI_CSI "%dO" msg ANSI_NORM
|
||||||
#define XANSI_COLOR(col) "3" #col
|
#define XANSI_COLOR(col) "3" #col
|
||||||
#define ANSI_COLOR_PARAM(col) XANSI_COLOR(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
|
* 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 str The string to check for ANSI escape sequences.
|
||||||
* @param sa The container for any style attributes.
|
* @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
|
* Populate a variable map with strings that contain escape sequences that
|
||||||
* might be useful to script writers.
|
* 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
|
#endif
|
||||||
|
@ -21,36 +21,35 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file archive_manager.cc
|
* @file archive_manager.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#if HAVE_ARCHIVE_H
|
#if HAVE_ARCHIVE_H
|
||||||
#include "archive.h"
|
# include "archive.h"
|
||||||
#include "archive_entry.h"
|
# include "archive_entry.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "archive_manager.cfg.hh"
|
||||||
|
#include "archive_manager.hh"
|
||||||
#include "auto_fd.hh"
|
#include "auto_fd.hh"
|
||||||
#include "auto_mem.hh"
|
#include "auto_mem.hh"
|
||||||
#include "fmt/format.h"
|
|
||||||
#include "base/fs_util.hh"
|
#include "base/fs_util.hh"
|
||||||
|
#include "base/humanize.hh"
|
||||||
#include "base/injector.hh"
|
#include "base/injector.hh"
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "base/humanize.hh"
|
|
||||||
#include "base/paths.hh"
|
#include "base/paths.hh"
|
||||||
|
#include "fmt/format.h"
|
||||||
#include "lnav_util.hh"
|
#include "lnav_util.hh"
|
||||||
|
|
||||||
#include "archive_manager.hh"
|
|
||||||
#include "archive_manager.cfg.hh"
|
|
||||||
|
|
||||||
namespace fs = ghc::filesystem;
|
namespace fs = ghc::filesystem;
|
||||||
|
|
||||||
namespace archive_manager {
|
namespace archive_manager {
|
||||||
@ -59,32 +58,37 @@ class archive_lock {
|
|||||||
public:
|
public:
|
||||||
class guard {
|
class guard {
|
||||||
public:
|
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();
|
this->g_lock.lock();
|
||||||
};
|
};
|
||||||
|
|
||||||
~guard() {
|
~guard()
|
||||||
|
{
|
||||||
this->g_lock.unlock();
|
this->g_lock.unlock();
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
archive_lock &g_lock;
|
archive_lock& g_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
void lock() const {
|
void lock() const
|
||||||
|
{
|
||||||
lockf(this->lh_fd, F_LOCK, 0);
|
lockf(this->lh_fd, F_LOCK, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
void unlock() const {
|
void unlock() const
|
||||||
|
{
|
||||||
lockf(this->lh_fd, F_ULOCK, 0);
|
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;
|
auto lock_path = archive_path;
|
||||||
|
|
||||||
lock_path += ".lck";
|
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));
|
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,
|
* Enables a subset of the supported archive formats to speed up detection,
|
||||||
* since some formats, like xar are unlikely to be used.
|
* 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_7zip(arc);
|
||||||
archive_read_support_format_cpio(arc);
|
archive_read_support_format_cpio(arc);
|
||||||
@ -107,7 +112,8 @@ static void enable_desired_archive_formats(archive *arc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_archive(const fs::path& filename)
|
bool
|
||||||
|
is_archive(const fs::path& filename)
|
||||||
{
|
{
|
||||||
#if HAVE_ARCHIVE_H
|
#if HAVE_ARCHIVE_H
|
||||||
auto_mem<archive> arc(archive_read_free);
|
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());
|
log_debug("read open %s", filename.c_str());
|
||||||
auto r = archive_read_open_filename(arc, filename.c_str(), 128 * 1024);
|
auto r = archive_read_open_filename(arc, filename.c_str(), 128 * 1024);
|
||||||
if (r == ARCHIVE_OK) {
|
if (r == ARCHIVE_OK) {
|
||||||
struct archive_entry *entry;
|
struct archive_entry* entry;
|
||||||
|
|
||||||
auto format_name = archive_format_name(arc);
|
auto format_name = archive_format_name(arc);
|
||||||
|
|
||||||
@ -145,8 +151,8 @@ bool is_archive(const fs::path& filename)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log_info("detected archive: %s -- %s",
|
log_info(
|
||||||
filename.c_str(), format_name);
|
"detected archive: %s -- %s", filename.c_str(), format_name);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log_info("archive read header failed: %s -- %s",
|
log_info("archive read header failed: %s -- %s",
|
||||||
@ -163,14 +169,14 @@ bool is_archive(const fs::path& filename)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static fs::path
|
||||||
fs::path archive_cache_path()
|
archive_cache_path()
|
||||||
{
|
{
|
||||||
return lnav::paths::workdir() / "archives";
|
return lnav::paths::workdir() / "archives";
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path
|
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 fn_path = fs::path(filename);
|
||||||
auto basename = fn_path.filename().string();
|
auto basename = fn_path.filename().string();
|
||||||
@ -195,14 +201,14 @@ filename_to_tmp_path(const std::string &filename)
|
|||||||
#if HAVE_ARCHIVE_H
|
#if HAVE_ARCHIVE_H
|
||||||
static walk_result_t
|
static walk_result_t
|
||||||
copy_data(const std::string& filename,
|
copy_data(const std::string& filename,
|
||||||
struct archive *ar,
|
struct archive* ar,
|
||||||
struct archive_entry *entry,
|
struct archive_entry* entry,
|
||||||
struct archive *aw,
|
struct archive* aw,
|
||||||
const fs::path &entry_path,
|
const fs::path& entry_path,
|
||||||
struct extract_progress *ep)
|
struct extract_progress* ep)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
const void *buff;
|
const void* buff;
|
||||||
size_t size, total = 0, next_space_check = 0;
|
size_t size, total = 0, next_space_check = 0;
|
||||||
la_int64_t offset;
|
la_int64_t offset;
|
||||||
|
|
||||||
@ -213,7 +219,9 @@ copy_data(const std::string& filename,
|
|||||||
|
|
||||||
if (tmp_space.available < cfg.amc_min_free_space) {
|
if (tmp_space.available < cfg.amc_min_free_space) {
|
||||||
return Err(fmt::format(
|
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(tmp_space.available),
|
||||||
humanize::file_size(cfg.amc_min_free_space),
|
humanize::file_size(cfg.amc_min_free_space),
|
||||||
entry_path.filename().string(),
|
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
|
static int FLAGS = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM
|
||||||
| ARCHIVE_EXTRACT_PERM
|
| ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;
|
||||||
| ARCHIVE_EXTRACT_ACL
|
|
||||||
| ARCHIVE_EXTRACT_FFLAGS;
|
|
||||||
|
|
||||||
auto tmp_path = filename_to_tmp_path(filename);
|
auto tmp_path = filename_to_tmp_path(filename);
|
||||||
auto arc_lock = archive_lock(tmp_path);
|
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) {
|
if (file_count > 0) {
|
||||||
fs::last_write_time(
|
fs::last_write_time(done_path, std::chrono::system_clock::now());
|
||||||
done_path, std::chrono::system_clock::now());
|
log_info("%s: archive has already been extracted!",
|
||||||
log_info("%s: archive has already been extracted!", done_path.c_str());
|
done_path.c_str());
|
||||||
return Ok();
|
return Ok();
|
||||||
} else {
|
} else {
|
||||||
log_warning("%s: archive cache has been damaged, re-extracting",
|
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();
|
ext = archive_write_disk_new();
|
||||||
archive_write_disk_set_options(ext, FLAGS);
|
archive_write_disk_set_options(ext, FLAGS);
|
||||||
archive_write_disk_set_standard_lookup(ext);
|
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: {} -- {}",
|
return Err(fmt::format("unable to open archive: {} -- {}",
|
||||||
filename,
|
filename,
|
||||||
archive_error_string(arc)));
|
archive_error_string(arc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("extracting %s to %s",
|
log_info("extracting %s to %s", filename.c_str(), tmp_path.c_str());
|
||||||
filename.c_str(),
|
|
||||||
tmp_path.c_str());
|
|
||||||
while (true) {
|
while (true) {
|
||||||
struct archive_entry *entry;
|
struct archive_entry* entry;
|
||||||
auto r = archive_read_next_header(arc, &entry);
|
auto r = archive_read_next_header(arc, &entry);
|
||||||
if (r == ARCHIVE_EOF) {
|
if (r == ARCHIVE_EOF) {
|
||||||
log_info("all done");
|
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();
|
desired_pathname = fs::path(filename).filename();
|
||||||
}
|
}
|
||||||
auto entry_path = tmp_path / desired_pathname;
|
auto entry_path = tmp_path / desired_pathname;
|
||||||
auto prog = cb(entry_path,
|
auto prog = cb(
|
||||||
archive_entry_size_is_set(entry) ?
|
entry_path,
|
||||||
archive_entry_size(entry) : -1);
|
archive_entry_size_is_set(entry) ? archive_entry_size(entry) : -1);
|
||||||
archive_entry_copy_pathname(wentry, entry_path.c_str());
|
archive_entry_copy_pathname(wentry, entry_path.c_str());
|
||||||
auto entry_mode = archive_entry_mode(wentry);
|
auto entry_mode = archive_entry_mode(wentry);
|
||||||
|
|
||||||
archive_entry_set_perm(
|
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);
|
r = archive_write_header(ext, wentry);
|
||||||
if (r < ARCHIVE_OK) {
|
if (r < ARCHIVE_OK) {
|
||||||
return Err(fmt::format("unable to write entry: {} -- {}",
|
return Err(fmt::format("unable to write entry: {} -- {}",
|
||||||
entry_path.string(),
|
entry_path.string(),
|
||||||
archive_error_string(ext)));
|
archive_error_string(ext)));
|
||||||
}
|
} else if (!archive_entry_size_is_set(entry)
|
||||||
else if (!archive_entry_size_is_set(entry) ||
|
|| archive_entry_size(entry) > 0) {
|
||||||
archive_entry_size(entry) > 0) {
|
|
||||||
TRY(copy_data(filename, arc, entry, ext, entry_path, prog));
|
TRY(copy_data(filename, arc, entry, ext, entry_path, prog));
|
||||||
}
|
}
|
||||||
r = archive_write_finish_entry(ext);
|
r = archive_write_finish_entry(ext);
|
||||||
@ -355,12 +360,12 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
walk_result_t walk_archive_files(
|
walk_result_t
|
||||||
const std::string &filename,
|
walk_archive_files(
|
||||||
const extract_cb &cb,
|
const std::string& filename,
|
||||||
const std::function<void(
|
const extract_cb& cb,
|
||||||
const fs::path&,
|
const std::function<void(const fs::path&, const fs::directory_entry&)>&
|
||||||
const fs::directory_entry &)>& callback)
|
callback)
|
||||||
{
|
{
|
||||||
#if HAVE_ARCHIVE_H
|
#if HAVE_ARCHIVE_H
|
||||||
auto tmp_path = filename_to_tmp_path(filename);
|
auto tmp_path = filename_to_tmp_path(filename);
|
||||||
@ -385,7 +390,8 @@ walk_result_t walk_archive_files(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_cache()
|
void
|
||||||
|
cleanup_cache()
|
||||||
{
|
{
|
||||||
(void) std::async(std::launch::async, []() {
|
(void) std::async(std::launch::async, []() {
|
||||||
auto now = std::chrono::system_clock::now();
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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)};
|
std::chrono::seconds amc_cache_ttl{std::chrono::hours(48)};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace archive_manager
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -33,8 +33,8 @@
|
|||||||
#define lnav_archive_manager_hh
|
#define lnav_archive_manager_hh
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/result.h"
|
#include "base/result.h"
|
||||||
@ -43,34 +43,33 @@
|
|||||||
namespace archive_manager {
|
namespace archive_manager {
|
||||||
|
|
||||||
struct extract_progress {
|
struct extract_progress {
|
||||||
extract_progress(ghc::filesystem::path path,
|
extract_progress(ghc::filesystem::path path, ssize_t total)
|
||||||
ssize_t total) : ep_path(std::move(path)),
|
: ep_path(std::move(path)), ep_total_size(total)
|
||||||
ep_total_size(total)
|
{
|
||||||
{}
|
}
|
||||||
|
|
||||||
const ghc::filesystem::path ep_path;
|
const ghc::filesystem::path ep_path;
|
||||||
const ssize_t ep_total_size;
|
const ssize_t ep_total_size;
|
||||||
std::atomic<size_t> ep_out_size{0};
|
std::atomic<size_t> ep_out_size{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
using extract_cb = std::function<extract_progress *(
|
using extract_cb
|
||||||
const ghc::filesystem::path &, ssize_t)>;
|
= std::function<extract_progress*(const ghc::filesystem::path&, ssize_t)>;
|
||||||
|
|
||||||
bool is_archive(const ghc::filesystem::path& filename);
|
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>;
|
using walk_result_t = Result<void, std::string>;
|
||||||
|
|
||||||
walk_result_t walk_archive_files(
|
walk_result_t walk_archive_files(
|
||||||
const std::string &filename,
|
const std::string& filename,
|
||||||
const extract_cb &cb,
|
const extract_cb& cb,
|
||||||
const std::function<void(
|
const std::function<void(const ghc::filesystem::path&,
|
||||||
const ghc::filesystem::path &,
|
const ghc::filesystem::directory_entry&)>&);
|
||||||
const ghc::filesystem::directory_entry &)> &);
|
|
||||||
|
|
||||||
void cleanup_cache();
|
void cleanup_cache();
|
||||||
|
|
||||||
}
|
} // namespace archive_manager
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
112
src/attr_line.cc
112
src/attr_line.cc
@ -21,22 +21,23 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "auto_mem.hh"
|
|
||||||
#include "ansi_scrubber.hh"
|
|
||||||
#include "view_curses.hh"
|
|
||||||
#include "attr_line.hh"
|
#include "attr_line.hh"
|
||||||
|
|
||||||
attr_line_t &attr_line_t::with_ansi_string(const char *str, ...)
|
#include "ansi_scrubber.hh"
|
||||||
|
#include "auto_mem.hh"
|
||||||
|
#include "config.h"
|
||||||
|
#include "view_curses.hh"
|
||||||
|
|
||||||
|
attr_line_t&
|
||||||
|
attr_line_t::with_ansi_string(const char* str, ...)
|
||||||
{
|
{
|
||||||
auto_mem<char> formatted_str;
|
auto_mem<char> formatted_str;
|
||||||
va_list args;
|
va_list args;
|
||||||
@ -53,7 +54,8 @@ attr_line_t &attr_line_t::with_ansi_string(const char *str, ...)
|
|||||||
return *this;
|
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;
|
this->al_string = str;
|
||||||
scrub_ansi_string(this->al_string, this->al_attrs);
|
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;
|
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()) {
|
if (index < this->al_string.length()) {
|
||||||
shift_string_attrs(this->al_attrs, index, al.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);
|
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);
|
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);
|
lr.shift(0, index);
|
||||||
if (lr.lr_end == -1) {
|
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 start_pos = index;
|
||||||
ssize_t line_start = this->al_string.rfind('\n', start_pos);
|
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 line_len = index - line_start;
|
||||||
ssize_t usable_width = tws->tws_width - tws->tws_indent;
|
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) {
|
if (avail == 0) {
|
||||||
avail = INT_MAX;
|
avail = INT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (start_pos < (int)this->al_string.length()) {
|
while (start_pos < (int) this->al_string.length()) {
|
||||||
ssize_t lpc;
|
ssize_t lpc;
|
||||||
|
|
||||||
// Find the end of a word or a breakpoint.
|
// Find the end of a word or a breakpoint.
|
||||||
for (lpc = start_pos;
|
for (lpc = start_pos; lpc < (int) this->al_string.length()
|
||||||
lpc < (int)this->al_string.length() &&
|
&& (isalnum(this->al_string[lpc])
|
||||||
(isalnum(this->al_string[lpc]) ||
|
|| this->al_string[lpc] == ','
|
||||||
this->al_string[lpc] == ',' ||
|
|| this->al_string[lpc] == '_'
|
||||||
this->al_string[lpc] == '_' ||
|
|| this->al_string[lpc] == '.'
|
||||||
this->al_string[lpc] == '.' ||
|
|| this->al_string[lpc] == ';');
|
||||||
this->al_string[lpc] == ';');
|
lpc++)
|
||||||
lpc++) {
|
{
|
||||||
if (this->al_string[lpc] == '-' ||
|
if (this->al_string[lpc] == '-' || this->al_string[lpc] == '.')
|
||||||
this->al_string[lpc] == '.') {
|
{
|
||||||
lpc += 1;
|
lpc += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -126,15 +132,15 @@ attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_
|
|||||||
} else {
|
} else {
|
||||||
// There's still room to add stuff.
|
// There's still room to add stuff.
|
||||||
avail -= (lpc - start_pos);
|
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') {
|
if (this->al_string[lpc] == '\n') {
|
||||||
this->insert(lpc + 1, tws->tws_indent, ' ');
|
this->insert(lpc + 1, tws->tws_indent, ' ');
|
||||||
avail = usable_width;
|
avail = usable_width;
|
||||||
lpc += 1 + tws->tws_indent;
|
lpc += 1 + tws->tws_indent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isalnum(this->al_string[lpc]) ||
|
if (isalnum(this->al_string[lpc])
|
||||||
this->al_string[lpc] == '_') {
|
|| this->al_string[lpc] == '_') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
avail -= 1;
|
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;
|
start_pos += 1 + tws->tws_indent;
|
||||||
avail = usable_width;
|
avail = usable_width;
|
||||||
|
|
||||||
for (lpc = start_pos;
|
for (lpc = start_pos; lpc < (int) this->al_string.length()
|
||||||
lpc < (int)this->al_string.length() &&
|
&& this->al_string[lpc] == ' ';
|
||||||
this->al_string[lpc] == ' ';
|
lpc++)
|
||||||
lpc++) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpc != start_pos) {
|
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;
|
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) {
|
if (len == std::string::npos) {
|
||||||
len = this->al_string.length() - start;
|
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;
|
attr_line_t retval;
|
||||||
|
|
||||||
retval.al_string = this->al_string.substr(start, len);
|
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)) {
|
if (!lr.intersects(sa.sa_range)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval.al_attrs.emplace_back(lr.intersection(sa.sa_range)
|
retval.al_attrs.emplace_back(
|
||||||
.shift(lr.lr_start, -lr.lr_start),
|
lr.intersection(sa.sa_range).shift(lr.lr_start, -lr.lr_start),
|
||||||
sa.sa_type, sa.sa_value);
|
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());
|
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;
|
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;
|
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));
|
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();
|
long padding = width - this->length();
|
||||||
if (padding > 0) {
|
if (padding > 0) {
|
||||||
this->al_string.insert(0, padding, ' ');
|
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) {
|
if (al_attr.sa_range.lr_start > 0) {
|
||||||
al_attr.sa_range.lr_start += padding;
|
al_attr.sa_range.lr_start += padding;
|
||||||
}
|
}
|
||||||
@ -220,7 +230,8 @@ attr_line_t &attr_line_t::right_justify(unsigned long width)
|
|||||||
return *this;
|
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 (x > 0 && x >= (size_t) this->length()) {
|
||||||
if (this->empty()) {
|
if (this->empty()) {
|
||||||
@ -237,18 +248,18 @@ size_t attr_line_t::nearest_text(size_t x) const
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void attr_line_t::apply_hide()
|
void
|
||||||
|
attr_line_t::apply_hide()
|
||||||
{
|
{
|
||||||
auto& sa = this->al_attrs;
|
auto& sa = this->al_attrs;
|
||||||
|
|
||||||
for (auto &sattr : sa) {
|
for (auto& sattr : sa) {
|
||||||
if (sattr.sa_type == &SA_HIDDEN &&
|
if (sattr.sa_type == &SA_HIDDEN && sattr.sa_range.length() > 3) {
|
||||||
sattr.sa_range.length() > 3) {
|
struct line_range& lr = sattr.sa_range;
|
||||||
struct line_range &lr = sattr.sa_range;
|
|
||||||
|
|
||||||
std::for_each(sa.begin(), sa.end(), [&] (string_attr &attr) {
|
std::for_each(sa.begin(), sa.end(), [&](string_attr& attr) {
|
||||||
if (attr.sa_type == &view_curses::VC_STYLE &&
|
if (attr.sa_type == &view_curses::VC_STYLE
|
||||||
lr.contains(attr.sa_range)) {
|
&& lr.contains(attr.sa_range)) {
|
||||||
attr.sa_type = &SA_REMOVED;
|
attr.sa_type = &SA_REMOVED;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -258,7 +269,6 @@ void attr_line_t::apply_hide()
|
|||||||
sattr.sa_type = &view_curses::VC_ROLE;
|
sattr.sa_type = &view_curses::VC_ROLE;
|
||||||
sattr.sa_value.sav_int = view_colors::VCR_HIDDEN;
|
sattr.sa_value.sav_int = view_colors::VCR_HIDDEN;
|
||||||
lr.lr_end = lr.lr_start + 3;
|
lr.lr_end = lr.lr_start + 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
253
src/attr_line.hh
253
src/attr_line.hh
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,14 +32,14 @@
|
|||||||
#ifndef attr_line_hh
|
#ifndef attr_line_hh
|
||||||
#define attr_line_hh
|
#define attr_line_hh
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "base/intern_string.hh"
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "base/string_util.hh"
|
#include "base/string_util.hh"
|
||||||
#include "base/intern_string.hh"
|
|
||||||
#include "string_attr_type.hh"
|
#include "string_attr_type.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,9 +49,11 @@ struct line_range {
|
|||||||
int lr_start;
|
int lr_start;
|
||||||
int lr_end;
|
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;
|
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;
|
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;
|
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;
|
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);
|
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;
|
int actual_end;
|
||||||
|
|
||||||
if (this->lr_end == -1) {
|
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};
|
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) {
|
if (this->lr_start >= start) {
|
||||||
this->lr_start = std::max(0, this->lr_start + amount);
|
this->lr_start = std::max(0, this->lr_start + amount);
|
||||||
}
|
}
|
||||||
@ -99,35 +106,46 @@ struct line_range {
|
|||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ltrim(const char *str) {
|
void ltrim(const char* str)
|
||||||
|
{
|
||||||
while (this->lr_start < this->lr_end && isspace(str[this->lr_start])) {
|
while (this->lr_start < this->lr_end && isspace(str[this->lr_start])) {
|
||||||
this->lr_start += 1;
|
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; }
|
if (this->lr_start < rhs.lr_start) {
|
||||||
else if (this->lr_start > rhs.lr_start) { return false; }
|
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;
|
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);
|
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) {
|
if (this->lr_start == -1) {
|
||||||
return str.c_str();
|
return str.c_str();
|
||||||
}
|
}
|
||||||
return &(str.c_str()[this->lr_start]);
|
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) {
|
if (this->lr_start == -1) {
|
||||||
return str.length();
|
return str.length();
|
||||||
}
|
}
|
||||||
@ -142,53 +160,67 @@ struct line_range {
|
|||||||
* Container for attribute values for a substring.
|
* Container for attribute values for a substring.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
const void *sav_ptr;
|
const void* sav_ptr;
|
||||||
int64_t sav_int;
|
int64_t sav_int;
|
||||||
} string_attr_value_t;
|
} string_attr_value_t;
|
||||||
|
|
||||||
struct string_attr {
|
struct string_attr {
|
||||||
string_attr(const struct line_range &lr, string_attr_type_t type, void *val)
|
string_attr(const struct line_range& lr, string_attr_type_t type, void* val)
|
||||||
: sa_range(lr), sa_type(type) {
|
: sa_range(lr), sa_type(type)
|
||||||
|
{
|
||||||
require(lr.is_valid());
|
require(lr.is_valid());
|
||||||
require(type);
|
require(type);
|
||||||
this->sa_value.sav_ptr = val;
|
this->sa_value.sav_ptr = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
string_attr(const struct line_range &lr, string_attr_type_t type, std::string val)
|
string_attr(const struct line_range& lr,
|
||||||
: sa_range(lr), sa_type(type), sa_str_value(std::move(val)) {
|
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(lr.is_valid());
|
||||||
require(type);
|
require(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
string_attr(const struct line_range &lr, string_attr_type_t type, intern_string_t val)
|
string_attr(const struct line_range& lr,
|
||||||
: sa_range(lr), sa_type(type) {
|
string_attr_type_t type,
|
||||||
|
intern_string_t val)
|
||||||
|
: sa_range(lr), sa_type(type)
|
||||||
|
{
|
||||||
require(lr.is_valid());
|
require(lr.is_valid());
|
||||||
require(type);
|
require(type);
|
||||||
this->sa_value.sav_ptr = val.unwrap();
|
this->sa_value.sav_ptr = val.unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
string_attr(const struct line_range &lr, string_attr_type_t type, int64_t val = 0)
|
string_attr(const struct line_range& lr,
|
||||||
: sa_range(lr), sa_type(type) {
|
string_attr_type_t type,
|
||||||
|
int64_t val = 0)
|
||||||
|
: sa_range(lr), sa_type(type)
|
||||||
|
{
|
||||||
require(lr.is_valid());
|
require(lr.is_valid());
|
||||||
require(type);
|
require(type);
|
||||||
this->sa_value.sav_int = val;
|
this->sa_value.sav_int = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
string_attr(const struct line_range &lr, string_attr_type_t type, string_attr_value_t val)
|
string_attr(const struct line_range& lr,
|
||||||
: sa_range(lr), sa_type(type), sa_value(val) {
|
string_attr_type_t type,
|
||||||
|
string_attr_value_t val)
|
||||||
|
: sa_range(lr), sa_type(type), sa_value(val)
|
||||||
|
{
|
||||||
require(lr.is_valid());
|
require(lr.is_valid());
|
||||||
require(type);
|
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;
|
return this->sa_range < rhs.sa_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
intern_string_t to_string() const {
|
intern_string_t to_string() const
|
||||||
return intern_string_t((const intern_string *) this->sa_value.sav_ptr);
|
{
|
||||||
|
return intern_string_t((const intern_string*) this->sa_value.sav_ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct line_range sa_range;
|
struct line_range sa_range;
|
||||||
@ -201,7 +233,9 @@ struct string_attr {
|
|||||||
typedef std::vector<string_attr> string_attrs_t;
|
typedef std::vector<string_attr> string_attrs_t;
|
||||||
|
|
||||||
inline string_attrs_t::const_iterator
|
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;
|
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*>
|
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);
|
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>
|
template<typename T>
|
||||||
inline string_attrs_t::const_iterator
|
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;
|
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
|
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;
|
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
|
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();
|
string_attrs_t::const_iterator iter, nearest = sa.end();
|
||||||
ssize_t last_diff = INT_MAX;
|
ssize_t last_diff = INT_MAX;
|
||||||
|
|
||||||
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
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)) {
|
if (!lr.is_valid() || !lr.contains(near)) {
|
||||||
continue;
|
continue;
|
||||||
@ -280,13 +318,13 @@ find_string_attr(const string_attrs_t &sa, size_t near)
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline string_attrs_t::const_iterator
|
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();
|
string_attrs_t::const_iterator iter, nearest = sa.end();
|
||||||
ssize_t last_diff = INT_MAX;
|
ssize_t last_diff = INT_MAX;
|
||||||
|
|
||||||
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
||||||
auto &lr = iter->sa_range;
|
auto& lr = iter->sa_range;
|
||||||
|
|
||||||
if (lr.lr_start > near) {
|
if (lr.lr_start > near) {
|
||||||
continue;
|
continue;
|
||||||
@ -307,7 +345,7 @@ rfind_string_attr_if(const string_attrs_t &sa, ssize_t near, T predicate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline struct line_range
|
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);
|
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();
|
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;
|
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();) {
|
for (auto iter = sa.begin(); iter != sa.end();) {
|
||||||
if (iter->sa_type == type) {
|
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);
|
iter.sa_range.shift(start, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct text_wrap_settings {
|
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;
|
this->tws_indent = indent;
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
text_wrap_settings &with_width(int width) {
|
text_wrap_settings& with_width(int width)
|
||||||
|
{
|
||||||
this->tws_width = width;
|
this->tws_width = width;
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
@ -367,62 +410,80 @@ struct text_wrap_settings {
|
|||||||
*/
|
*/
|
||||||
class attr_line_t {
|
class attr_line_t {
|
||||||
public:
|
public:
|
||||||
attr_line_t() {
|
attr_line_t()
|
||||||
|
{
|
||||||
this->al_attrs.reserve(RESERVE_SIZE);
|
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);
|
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);
|
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;
|
attr_line_t retval;
|
||||||
|
|
||||||
return retval.with_ansi_string("%s", str);
|
return retval.with_ansi_string("%s", str);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @return The string itself. */
|
/** @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. */
|
/** @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;
|
this->al_string = str;
|
||||||
return *this;
|
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);
|
this->al_attrs.push_back(sa);
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
attr_line_t &ensure_space() {
|
attr_line_t& ensure_space()
|
||||||
if (!this->al_string.empty() &&
|
{
|
||||||
this->al_string.back() != ' ' &&
|
if (!this->al_string.empty() && this->al_string.back() != ' '
|
||||||
this->al_string.back() != '[') {
|
&& this->al_string.back() != '[')
|
||||||
|
{
|
||||||
this->append(1, ' ');
|
this->append(1, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename S, typename T = void *>
|
template<typename S, typename T = void*>
|
||||||
attr_line_t &append(S str,
|
attr_line_t& append(S str, string_attr_type_t type = nullptr, T val = T())
|
||||||
string_attr_type_t type = nullptr,
|
{
|
||||||
T val = T()) {
|
|
||||||
size_t start_len = this->al_string.length();
|
size_t start_len = this->al_string.length();
|
||||||
|
|
||||||
this->al_string.append(str);
|
this->al_string.append(str);
|
||||||
@ -434,24 +495,31 @@ public:
|
|||||||
return *this;
|
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);
|
this->al_string.append(str, len);
|
||||||
|
|
||||||
return *this;
|
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);
|
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);
|
this->al_string.append(len, c);
|
||||||
return *this;
|
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);
|
this->al_string.insert(index, len, c);
|
||||||
|
|
||||||
shift_string_attrs(this->al_attrs, index, len);
|
shift_string_attrs(this->al_attrs, index, len);
|
||||||
@ -459,7 +527,8 @@ public:
|
|||||||
return *this;
|
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);
|
this->al_string.insert(index, str);
|
||||||
|
|
||||||
shift_string_attrs(this->al_attrs, index, strlen(str));
|
shift_string_attrs(this->al_attrs, index, strlen(str));
|
||||||
@ -467,7 +536,8 @@ public:
|
|||||||
return *this;
|
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);
|
this->al_string.erase(pos, len);
|
||||||
|
|
||||||
shift_string_attrs(this->al_attrs, pos, -((int32_t) len));
|
shift_string_attrs(this->al_attrs, pos, -((int32_t) len));
|
||||||
@ -475,19 +545,21 @@ public:
|
|||||||
return *this;
|
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);
|
auto byte_index = utf8_char_to_byte_index(this->al_string, start);
|
||||||
this->erase(byte_index);
|
this->erase(byte_index);
|
||||||
|
|
||||||
return *this;
|
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();
|
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);
|
retval = std::max(retval, (size_t) al_attr.sa_range.lr_start);
|
||||||
if (al_attr.sa_range.lr_end != -1) {
|
if (al_attr.sa_range.lr_end != -1) {
|
||||||
retval = std::max(retval, (size_t) al_attr.sa_range.lr_end);
|
retval = std::max(retval, (size_t) al_attr.sa_range.lr_end);
|
||||||
@ -497,14 +569,16 @@ public:
|
|||||||
return retval;
|
return retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string get_substring(const line_range &lr) const {
|
std::string get_substring(const line_range& lr) const
|
||||||
|
{
|
||||||
if (!lr.is_valid()) {
|
if (!lr.is_valid()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return this->al_string.substr(lr.lr_start, lr.length());
|
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);
|
near = std::min(near, this->al_string.length() - 1);
|
||||||
|
|
||||||
while (near > 0 && isspace(this->al_string[near])) {
|
while (near > 0 && isspace(this->al_string[near])) {
|
||||||
@ -514,12 +588,13 @@ public:
|
|||||||
return find_string_attr(this->al_attrs, near);
|
return find_string_attr(this->al_attrs, near);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return this->length() == 0;
|
return this->length() == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Clear the string and the attributes for the string. */
|
/** Clear the string and the attributes for the string. */
|
||||||
attr_line_t &clear()
|
attr_line_t& clear()
|
||||||
{
|
{
|
||||||
this->al_string.clear();
|
this->al_string.clear();
|
||||||
this->al_attrs.clear();
|
this->al_attrs.clear();
|
||||||
@ -529,7 +604,7 @@ public:
|
|||||||
|
|
||||||
attr_line_t subline(size_t start, size_t len = std::string::npos) const;
|
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;
|
size_t nearest_text(size_t x) const;
|
||||||
|
|
||||||
@ -538,7 +613,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
const static size_t RESERVE_SIZE = 128;
|
const static size_t RESERVE_SIZE = 128;
|
||||||
|
|
||||||
std::string al_string;
|
std::string al_string;
|
||||||
string_attrs_t al_attrs;
|
string_attrs_t al_attrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
139
src/auto_fd.hh
139
src/auto_fd.hh
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,14 +32,14 @@
|
|||||||
#ifndef auto_fd_hh
|
#ifndef auto_fd_hh
|
||||||
#define auto_fd_hh
|
#define auto_fd_hh
|
||||||
|
|
||||||
#include <errno.h>
|
#include <exception>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <exception>
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "base/result.h"
|
#include "base/result.h"
|
||||||
@ -51,7 +51,6 @@
|
|||||||
*/
|
*/
|
||||||
class auto_fd {
|
class auto_fd {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for the posix pipe(2) function that stores the file descriptor
|
* Wrapper for the posix pipe(2) function that stores the file descriptor
|
||||||
* results in an auto_fd array.
|
* results in an auto_fd array.
|
||||||
@ -60,7 +59,7 @@ public:
|
|||||||
* contains the reader end of the pipe and the second contains the writer.
|
* contains the reader end of the pipe and the second contains the writer.
|
||||||
* @return The result of the pipe(2) function.
|
* @return The result of the pipe(2) function.
|
||||||
*/
|
*/
|
||||||
static int pipe(auto_fd *af)
|
static int pipe(auto_fd* af)
|
||||||
{
|
{
|
||||||
int retval, fd[2];
|
int retval, fd[2];
|
||||||
|
|
||||||
@ -80,7 +79,8 @@ public:
|
|||||||
* @param fd The file descriptor to duplicate.
|
* @param fd The file descriptor to duplicate.
|
||||||
* @return A new auto_fd that contains the duplicated file descriptor.
|
* @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) {
|
if (fd == -1) {
|
||||||
return auto_fd{};
|
return auto_fd{};
|
||||||
}
|
}
|
||||||
@ -99,8 +99,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param fd The file descriptor to be managed.
|
* @param fd The file descriptor to be managed.
|
||||||
*/
|
*/
|
||||||
explicit auto_fd(int fd = -1)
|
explicit auto_fd(int fd = -1) : af_fd(fd)
|
||||||
: af_fd(fd)
|
|
||||||
{
|
{
|
||||||
require(fd >= -1);
|
require(fd >= -1);
|
||||||
};
|
};
|
||||||
@ -112,9 +111,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param af The source of the file descriptor.
|
* @param af The source of the file descriptor.
|
||||||
*/
|
*/
|
||||||
auto_fd(auto_fd && af) noexcept
|
auto_fd(auto_fd&& af) noexcept : af_fd(af.release()){};
|
||||||
: af_fd(af.release()) {
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Const copy constructor. The file descriptor from the source will be
|
* Const copy constructor. The file descriptor from the source will be
|
||||||
@ -122,8 +119,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param af The source of the file descriptor.
|
* @param af The source of the file descriptor.
|
||||||
*/
|
*/
|
||||||
auto_fd(const auto_fd &af)
|
auto_fd(const auto_fd& af) : af_fd(-1)
|
||||||
: af_fd(-1)
|
|
||||||
{
|
{
|
||||||
if (af.af_fd != -1 && (this->af_fd = dup(af.af_fd)) == -1) {
|
if (af.af_fd != -1 && (this->af_fd = dup(af.af_fd)) == -1) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
@ -139,7 +135,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** @return The file descriptor as a plain integer. */
|
/** @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
|
* 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.
|
* @param fd The file descriptor to store in this object.
|
||||||
* @return *this
|
* @return *this
|
||||||
*/
|
*/
|
||||||
auto_fd &operator=(int fd)
|
auto_fd& operator=(int fd)
|
||||||
{
|
{
|
||||||
require(fd >= -1);
|
require(fd >= -1);
|
||||||
|
|
||||||
@ -162,7 +161,8 @@ public:
|
|||||||
* @param af The old manager of the file descriptor.
|
* @param af The old manager of the file descriptor.
|
||||||
* @return *this
|
* @return *this
|
||||||
*/
|
*/
|
||||||
auto_fd &operator=(auto_fd && af) noexcept {
|
auto_fd& operator=(auto_fd&& af) noexcept
|
||||||
|
{
|
||||||
this->reset(af.release());
|
this->reset(af.release());
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
@ -173,7 +173,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A pointer to the internal integer.
|
* @return A pointer to the internal integer.
|
||||||
*/
|
*/
|
||||||
int *out()
|
int* out()
|
||||||
{
|
{
|
||||||
this->reset();
|
this->reset();
|
||||||
return &this->af_fd;
|
return &this->af_fd;
|
||||||
@ -218,7 +218,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void close_on_exec() const {
|
void close_on_exec() const
|
||||||
|
{
|
||||||
if (this->af_fd == -1) {
|
if (this->af_fd == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -226,12 +227,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int af_fd; /*< The managed file descriptor. */
|
int af_fd; /*< The managed file descriptor. */
|
||||||
};
|
};
|
||||||
|
|
||||||
class auto_pipe {
|
class auto_pipe {
|
||||||
public:
|
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);
|
auto_pipe retval(child_fd);
|
||||||
|
|
||||||
if (retval.open() == -1) {
|
if (retval.open() == -1) {
|
||||||
@ -245,70 +247,73 @@ public:
|
|||||||
: ap_child_flags(child_flags), ap_child_fd(child_fd)
|
: ap_child_flags(child_flags), ap_child_fd(child_fd)
|
||||||
{
|
{
|
||||||
switch (child_fd) {
|
switch (child_fd) {
|
||||||
case STDIN_FILENO:
|
case STDIN_FILENO:
|
||||||
this->ap_child_flags = O_RDONLY;
|
this->ap_child_flags = O_RDONLY;
|
||||||
break;
|
break;
|
||||||
case STDOUT_FILENO:
|
case STDOUT_FILENO:
|
||||||
case STDERR_FILENO:
|
case STDERR_FILENO:
|
||||||
this->ap_child_flags = O_WRONLY;
|
this->ap_child_flags = O_WRONLY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int open() {
|
int open()
|
||||||
|
{
|
||||||
return auto_fd::pipe(this->ap_fd);
|
return auto_fd::pipe(this->ap_fd);
|
||||||
};
|
};
|
||||||
|
|
||||||
void close() {
|
void close()
|
||||||
|
{
|
||||||
this->ap_fd[0].reset();
|
this->ap_fd[0].reset();
|
||||||
this->ap_fd[1].reset();
|
this->ap_fd[1].reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto_fd &read_end() {
|
auto_fd& read_end()
|
||||||
|
{
|
||||||
return this->ap_fd[0];
|
return this->ap_fd[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
auto_fd &write_end() {
|
auto_fd& write_end()
|
||||||
|
{
|
||||||
return this->ap_fd[1];
|
return this->ap_fd[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
void after_fork(pid_t child_pid) {
|
void after_fork(pid_t child_pid)
|
||||||
|
{
|
||||||
int new_fd;
|
int new_fd;
|
||||||
|
|
||||||
switch (child_pid) {
|
switch (child_pid) {
|
||||||
case -1:
|
case -1:
|
||||||
this->close();
|
this->close();
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
if (this->ap_child_flags == O_RDONLY) {
|
if (this->ap_child_flags == O_RDONLY) {
|
||||||
this->write_end().reset();
|
this->write_end().reset();
|
||||||
if (this->read_end().get() == -1) {
|
if (this->read_end().get() == -1) {
|
||||||
this->read_end() = ::open("/dev/null", O_RDONLY);
|
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();
|
if (this->ap_child_fd != -1) {
|
||||||
}
|
if (new_fd != this->ap_child_fd) {
|
||||||
else {
|
dup2(new_fd, this->ap_child_fd);
|
||||||
this->read_end().reset();
|
this->close();
|
||||||
if (this->write_end().get() == -1) {
|
}
|
||||||
this->write_end() = ::open("/dev/null", O_WRONLY);
|
|
||||||
}
|
}
|
||||||
new_fd = this->write_end().get();
|
break;
|
||||||
}
|
default:
|
||||||
if (this->ap_child_fd != -1) {
|
if (this->ap_child_flags == O_RDONLY) {
|
||||||
if (new_fd != this->ap_child_fd) {
|
this->read_end().reset();
|
||||||
dup2(new_fd, this->ap_child_fd);
|
} else {
|
||||||
this->close();
|
this->write_end().reset();
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (this->ap_child_flags == O_RDONLY) {
|
|
||||||
this->read_end().reset();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->write_end().reset();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
126
src/auto_mem.hh
126
src/auto_mem.hh
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,15 +32,15 @@
|
|||||||
#ifndef lnav_auto_mem_hh
|
#ifndef lnav_auto_mem_hh
|
||||||
#define lnav_auto_mem_hh
|
#define lnav_auto_mem_hh
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#include "base/result.h"
|
#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.
|
* 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>
|
template<class T, free_func_t default_free = free>
|
||||||
class auto_mem {
|
class auto_mem {
|
||||||
public:
|
public:
|
||||||
explicit auto_mem(T *ptr = nullptr)
|
explicit auto_mem(T* ptr = nullptr)
|
||||||
: am_ptr(ptr), am_free_func(default_free) {
|
: 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>
|
template<typename F>
|
||||||
explicit auto_mem(F free_func) noexcept
|
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
|
auto_mem(auto_mem&& other) noexcept
|
||||||
: am_ptr(other.release()),
|
: am_ptr(other.release()), am_free_func(other.am_free_func){};
|
||||||
am_free_func(other.am_free_func) {
|
|
||||||
};
|
|
||||||
|
|
||||||
~auto_mem() {
|
~auto_mem()
|
||||||
|
{
|
||||||
this->reset();
|
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);
|
this->reset(ptr);
|
||||||
return *this;
|
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->reset(am.release());
|
||||||
this->am_free_func = am.am_free_func;
|
this->am_free_func = am.am_free_func;
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
T *release()
|
T* release()
|
||||||
{
|
{
|
||||||
T *retval = this->am_ptr;
|
T* retval = this->am_ptr;
|
||||||
|
|
||||||
this->am_ptr = nullptr;
|
this->am_ptr = nullptr;
|
||||||
return retval;
|
return retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
T *in() const
|
T* in() const
|
||||||
{
|
{
|
||||||
return this->am_ptr;
|
return this->am_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
T **out()
|
T** out()
|
||||||
{
|
{
|
||||||
this->reset();
|
this->reset();
|
||||||
return &this->am_ptr;
|
return &this->am_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset(T *ptr = nullptr)
|
void reset(T* ptr = nullptr)
|
||||||
{
|
{
|
||||||
if (this->am_ptr != ptr) {
|
if (this->am_ptr != ptr) {
|
||||||
if (this->am_ptr != nullptr) {
|
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;
|
this->am_ptr = ptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T * am_ptr;
|
T* am_ptr;
|
||||||
void (*am_free_func)(void *);
|
void (*am_free_func)(void*);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, void(*free_func) (T *)>
|
template<typename T, void (*free_func)(T*)>
|
||||||
class static_root_mem {
|
class static_root_mem {
|
||||||
public:
|
public:
|
||||||
static_root_mem() {
|
static_root_mem()
|
||||||
|
{
|
||||||
memset(&this->srm_value, 0, sizeof(T));
|
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);
|
free_func(&this->srm_value);
|
||||||
memset(&this->srm_value, 0, sizeof(T));
|
memset(&this->srm_value, 0, sizeof(T));
|
||||||
return &this->srm_value;
|
return &this->srm_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
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;
|
T srm_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class auto_buffer {
|
class auto_buffer {
|
||||||
public:
|
public:
|
||||||
static auto_buffer alloc(size_t size) {
|
static auto_buffer alloc(size_t size)
|
||||||
return auto_buffer{ (char *) malloc(size), size };
|
{
|
||||||
|
return auto_buffer{(char*) malloc(size), size};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_buffer(auto_buffer&& other) noexcept
|
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_buffer = nullptr;
|
||||||
other.ab_size = 0;
|
other.ab_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~auto_buffer() {
|
~auto_buffer()
|
||||||
|
{
|
||||||
free(this->ab_buffer);
|
free(this->ab_buffer);
|
||||||
this->ab_buffer = nullptr;
|
this->ab_buffer = nullptr;
|
||||||
this->ab_size = 0;
|
this->ab_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *in() {
|
char* in()
|
||||||
|
{
|
||||||
return this->ab_buffer;
|
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);
|
auto retval = std::make_pair(this->ab_buffer, this->ab_size);
|
||||||
|
|
||||||
this->ab_buffer = nullptr;
|
this->ab_buffer = nullptr;
|
||||||
@ -178,16 +201,18 @@ public:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const
|
||||||
|
{
|
||||||
return this->ab_size;
|
return this->ab_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expand_by(size_t amount) {
|
void expand_by(size_t amount)
|
||||||
|
{
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto new_size = this->ab_size + amount;
|
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) {
|
if (new_buffer == nullptr) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
@ -197,15 +222,16 @@ public:
|
|||||||
this->ab_size = new_size;
|
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;
|
this->ab_size = new_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
auto_buffer(char *buffer, size_t size) : ab_buffer(buffer), ab_size(size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ab_buffer;
|
private:
|
||||||
|
auto_buffer(char* buffer, size_t size) : ab_buffer(buffer), ab_size(size) {}
|
||||||
|
|
||||||
|
char* ab_buffer;
|
||||||
size_t ab_size;
|
size_t ab_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,23 +21,24 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "auto_pid.hh"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "lnav_log.hh"
|
#include "config.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "auto_pid.hh"
|
#include "lnav_log.hh"
|
||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace pid {
|
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();
|
auto pid = ::fork();
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ Result<auto_pid<process_state::RUNNING>, std::string> from_fork()
|
|||||||
log_debug("started child: %d", pid);
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,50 +32,58 @@
|
|||||||
#ifndef auto_pid_hh
|
#ifndef auto_pid_hh
|
||||||
#define auto_pid_hh
|
#define auto_pid_hh
|
||||||
|
|
||||||
#include <errno.h>
|
#include <cerrno>
|
||||||
#include <signal.h>
|
#include <csignal>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "base/result.h"
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
|
#include "base/result.h"
|
||||||
#include "mapbox/variant.hpp"
|
#include "mapbox/variant.hpp"
|
||||||
|
|
||||||
enum class process_state {
|
enum class process_state {
|
||||||
RUNNING,
|
running,
|
||||||
FINISHED,
|
finished,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<process_state ProcState>
|
template<process_state ProcState>
|
||||||
class auto_pid {
|
class auto_pid {
|
||||||
public:
|
public:
|
||||||
explicit auto_pid(pid_t child, int status = 0) : ap_child(child),
|
explicit auto_pid(pid_t child, int status = 0)
|
||||||
ap_status(status)
|
: 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
|
auto_pid(auto_pid&& other) noexcept
|
||||||
: ap_child(std::move(other).release()),
|
: ap_child(std::move(other).release()), ap_status(other.ap_status)
|
||||||
ap_status(other.ap_status)
|
{
|
||||||
{};
|
}
|
||||||
|
|
||||||
~auto_pid() noexcept
|
~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->reset(std::move(other).release());
|
||||||
this->ap_status = other.ap_status;
|
this->ap_status = other.ap_status;
|
||||||
return *this;
|
return *this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
auto_pid& operator=(const auto_pid& other) = delete;
|
||||||
|
|
||||||
pid_t in() const
|
pid_t in() const
|
||||||
{ return this->ap_child; }
|
{
|
||||||
|
return this->ap_child;
|
||||||
|
}
|
||||||
|
|
||||||
bool in_child() const
|
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");
|
"this method is only available in the RUNNING state");
|
||||||
return this->ap_child == 0;
|
return this->ap_child == 0;
|
||||||
};
|
};
|
||||||
@ -87,31 +95,31 @@ public:
|
|||||||
|
|
||||||
int status() const
|
int status() const
|
||||||
{
|
{
|
||||||
static_assert(ProcState == process_state::FINISHED,
|
static_assert(ProcState == process_state::finished,
|
||||||
"wait_for_child() must be called first");
|
"wait_for_child() must be called first");
|
||||||
return this->ap_status;
|
return this->ap_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool was_normal_exit() const
|
bool was_normal_exit() const
|
||||||
{
|
{
|
||||||
static_assert(ProcState == process_state::FINISHED,
|
static_assert(ProcState == process_state::finished,
|
||||||
"wait_for_child() must be called first");
|
"wait_for_child() must be called first");
|
||||||
return WIFEXITED(this->ap_status);
|
return WIFEXITED(this->ap_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exit_status() const
|
int exit_status() const
|
||||||
{
|
{
|
||||||
static_assert(ProcState == process_state::FINISHED,
|
static_assert(ProcState == process_state::finished,
|
||||||
"wait_for_child() must be called first");
|
"wait_for_child() must be called first");
|
||||||
return WEXITSTATUS(this->ap_status);
|
return WEXITSTATUS(this->ap_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
using poll_result = mapbox::util::variant<
|
using poll_result
|
||||||
auto_pid<process_state::RUNNING>,
|
= mapbox::util::variant<auto_pid<process_state::running>,
|
||||||
auto_pid<process_state::FINISHED>
|
auto_pid<process_state::finished>>;
|
||||||
>;
|
|
||||||
|
|
||||||
poll_result poll() && {
|
poll_result poll() &&
|
||||||
|
{
|
||||||
if (this->ap_child != -1) {
|
if (this->ap_child != -1) {
|
||||||
auto rc = waitpid(this->ap_child, &this->ap_status, WNOHANG);
|
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);
|
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) {
|
if (this->ap_child != -1) {
|
||||||
while ((waitpid(this->ap_child,
|
while ((waitpid(this->ap_child, &this->ap_status, options)) < 0
|
||||||
&this->ap_status,
|
&& (errno == EINTR))
|
||||||
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);
|
std::exchange(this->ap_child, -1), this->ap_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +150,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (this->ap_child != child) {
|
if (this->ap_child != child) {
|
||||||
this->ap_status = 0;
|
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);
|
log_debug("sending SIGTERM to child: %d", this->ap_child);
|
||||||
kill(this->ap_child, SIGTERM);
|
kill(this->ap_child, SIGTERM);
|
||||||
}
|
}
|
||||||
@ -156,8 +165,8 @@ private:
|
|||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace pid {
|
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
|
#endif
|
||||||
|
@ -21,20 +21,21 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file date_time_scanner.cc
|
* @file date_time_scanner.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "date_time_scanner.hh"
|
#include "date_time_scanner.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "ptimec.hh"
|
#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;
|
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;
|
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;
|
bool retval = true;
|
||||||
|
|
||||||
@ -52,40 +54,35 @@ bool next_format(const char * const fmt[], int &index, int &locked_index)
|
|||||||
if (fmt[index] == nullptr) {
|
if (fmt[index] == nullptr) {
|
||||||
retval = false;
|
retval = false;
|
||||||
}
|
}
|
||||||
}
|
} else if (index == locked_index) {
|
||||||
else if (index == locked_index) {
|
|
||||||
retval = false;
|
retval = false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
index = locked_index;
|
index = locked_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *date_time_scanner::scan(const char *time_dest,
|
const char*
|
||||||
size_t time_len,
|
date_time_scanner::scan(const char* time_dest,
|
||||||
const char * const time_fmt[],
|
size_t time_len,
|
||||||
struct exttm *tm_out,
|
const char* const time_fmt[],
|
||||||
struct timeval &tv_out,
|
struct exttm* tm_out,
|
||||||
bool convert_local)
|
struct timeval& tv_out,
|
||||||
|
bool convert_local)
|
||||||
{
|
{
|
||||||
int curr_time_fmt = -1;
|
int curr_time_fmt = -1;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const char *retval = nullptr;
|
const char* retval = nullptr;
|
||||||
|
|
||||||
if (!time_fmt) {
|
if (!time_fmt) {
|
||||||
time_fmt = PTIMEC_FORMAT_STR;
|
time_fmt = PTIMEC_FORMAT_STR;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (next_format(time_fmt,
|
while (next_format(time_fmt, curr_time_fmt, this->dts_fmt_lock)) {
|
||||||
curr_time_fmt,
|
|
||||||
this->dts_fmt_lock)) {
|
|
||||||
*tm_out = this->dts_base_tm;
|
*tm_out = this->dts_base_tm;
|
||||||
tm_out->et_flags = 0;
|
tm_out->et_flags = 0;
|
||||||
if (time_len > 1 &&
|
if (time_len > 1 && time_dest[0] == '+' && isdigit(time_dest[1])) {
|
||||||
time_dest[0] == '+' &&
|
|
||||||
isdigit(time_dest[1])) {
|
|
||||||
char time_cp[time_len + 1];
|
char time_cp[time_len + 1];
|
||||||
int gmt_int, off;
|
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_sec = gmt;
|
||||||
tv_out.tv_usec = 0;
|
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_lock = curr_time_fmt;
|
||||||
this->dts_fmt_len = off;
|
this->dts_fmt_len = off;
|
||||||
@ -113,8 +111,7 @@ const char *date_time_scanner::scan(const char *time_dest,
|
|||||||
found = true;
|
found = true;
|
||||||
break;
|
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;
|
ptime_func func = PTIMEC_FORMATS[curr_time_fmt].pf_func;
|
||||||
off_t off = 0;
|
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) {
|
if (tm_out->et_tm.tm_year < 70) {
|
||||||
tm_out->et_tm.tm_year = 80;
|
tm_out->et_tm.tm_year = 80;
|
||||||
}
|
}
|
||||||
if (convert_local &&
|
if (convert_local
|
||||||
(this->dts_local_time || tm_out->et_flags & ETF_EPOCH_TIME)) {
|
&& (this->dts_local_time
|
||||||
|
|| tm_out->et_flags & ETF_EPOCH_TIME))
|
||||||
|
{
|
||||||
time_t gmt = tm2sec(&tm_out->et_tm);
|
time_t gmt = tm2sec(&tm_out->et_tm);
|
||||||
|
|
||||||
this->to_localtime(gmt, *tm_out);
|
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);
|
secs2wday(tv_out, &tm_out->et_tm);
|
||||||
|
|
||||||
this->dts_fmt_lock = curr_time_fmt;
|
this->dts_fmt_lock = curr_time_fmt;
|
||||||
this->dts_fmt_len = retval - time_dest;
|
this->dts_fmt_len = retval - time_dest;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
off_t off = 0;
|
off_t off = 0;
|
||||||
|
|
||||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
#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;
|
tm_out->et_tm.tm_zone = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ptime_fmt(time_fmt[curr_time_fmt], tm_out, time_dest, off, time_len) &&
|
if (ptime_fmt(
|
||||||
(time_dest[off] == '.' || time_dest[off] == ',' || off == (off_t)time_len)) {
|
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];
|
retval = &time_dest[off];
|
||||||
if (tm_out->et_tm.tm_year < 70) {
|
if (tm_out->et_tm.tm_year < 70) {
|
||||||
tm_out->et_tm.tm_year = 80;
|
tm_out->et_tm.tm_year = 80;
|
||||||
}
|
}
|
||||||
if (convert_local &&
|
if (convert_local
|
||||||
(this->dts_local_time || tm_out->et_flags & ETF_EPOCH_TIME)) {
|
&& (this->dts_local_time
|
||||||
|
|| tm_out->et_flags & ETF_EPOCH_TIME))
|
||||||
|
{
|
||||||
time_t gmt = tm2sec(&tm_out->et_tm);
|
time_t gmt = tm2sec(&tm_out->et_tm);
|
||||||
|
|
||||||
this->to_localtime(gmt, *tm_out);
|
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);
|
secs2wday(tv_out, &tm_out->et_tm);
|
||||||
|
|
||||||
this->dts_fmt_lock = curr_time_fmt;
|
this->dts_fmt_lock = curr_time_fmt;
|
||||||
this->dts_fmt_len = retval - time_dest;
|
this->dts_fmt_len = retval - time_dest;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -197,8 +200,7 @@ const char *date_time_scanner::scan(const char *time_dest,
|
|||||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||||
this->dts_fmt_len += 7;
|
this->dts_fmt_len += 7;
|
||||||
retval += 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;
|
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||||
this->dts_fmt_len += 4;
|
this->dts_fmt_len += 4;
|
||||||
retval += 4;
|
retval += 4;
|
||||||
@ -209,15 +211,16 @@ const char *date_time_scanner::scan(const char *time_dest,
|
|||||||
return retval;
|
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)) {
|
if (t < (24 * 60 * 60)) {
|
||||||
// Don't convert and risk going past the epoch.
|
// Don't convert and risk going past the epoch.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t < this->dts_local_offset_valid ||
|
if (t < this->dts_local_offset_valid || t >= this->dts_local_offset_expiry)
|
||||||
t >= this->dts_local_offset_expiry) {
|
{
|
||||||
time_t new_gmt;
|
time_t new_gmt;
|
||||||
|
|
||||||
localtime_r(&t, &tm_out.et_tm);
|
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_cache = t - new_gmt;
|
||||||
this->dts_local_offset_valid = t;
|
this->dts_local_offset_valid = t;
|
||||||
this->dts_local_offset_expiry = t + (EXPIRE_TIME - 1);
|
this->dts_local_offset_expiry = t + (EXPIRE_TIME - 1);
|
||||||
this->dts_local_offset_expiry -=
|
this->dts_local_offset_expiry
|
||||||
this->dts_local_offset_expiry % EXPIRE_TIME;
|
-= this->dts_local_offset_expiry % EXPIRE_TIME;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
time_t adjust_gmt = t - this->dts_local_offset_cache;
|
time_t adjust_gmt = t - this->dts_local_offset_cache;
|
||||||
gmtime_r(&adjust_gmt, &tm_out.et_tm);
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,11 +32,11 @@
|
|||||||
#ifndef lnav_date_time_scanner_hh
|
#ifndef lnav_date_time_scanner_hh
|
||||||
#define lnav_date_time_scanner_hh
|
#define lnav_date_time_scanner_hh
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "time_util.hh"
|
#include "time_util.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,11 +47,13 @@
|
|||||||
* an exttm struct to a string using the ftime() method.
|
* an exttm struct to a string using the ftime() method.
|
||||||
*/
|
*/
|
||||||
struct date_time_scanner {
|
struct date_time_scanner {
|
||||||
date_time_scanner() {
|
date_time_scanner()
|
||||||
|
{
|
||||||
this->clear();
|
this->clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->dts_base_time = 0;
|
this->dts_base_time = 0;
|
||||||
memset(&this->dts_base_tm, 0, sizeof(this->dts_base_tm));
|
memset(&this->dts_base_tm, 0, sizeof(this->dts_base_tm));
|
||||||
this->dts_fmt_lock = -1;
|
this->dts_fmt_lock = -1;
|
||||||
@ -61,12 +63,14 @@ struct date_time_scanner {
|
|||||||
/**
|
/**
|
||||||
* Unlock this scanner so that the format is rediscovered.
|
* Unlock this scanner so that the format is rediscovered.
|
||||||
*/
|
*/
|
||||||
void unlock() {
|
void unlock()
|
||||||
|
{
|
||||||
this->dts_fmt_lock = -1;
|
this->dts_fmt_lock = -1;
|
||||||
this->dts_fmt_len = -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;
|
this->dts_base_time = base_time;
|
||||||
localtime_r(&base_time, &this->dts_base_tm.et_tm);
|
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
|
* every call, so we cache the result and only call it again if the
|
||||||
* requested time falls outside of a fifteen minute range.
|
* 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_keep_base_tz{false};
|
||||||
bool dts_local_time{false};
|
bool dts_local_time{false};
|
||||||
@ -92,19 +96,20 @@ struct date_time_scanner {
|
|||||||
|
|
||||||
static const int EXPIRE_TIME = 15 * 60;
|
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,
|
size_t time_len,
|
||||||
const char * const time_fmt[],
|
const char* const time_fmt[],
|
||||||
struct exttm *tm_out,
|
struct exttm* tm_out,
|
||||||
struct timeval &tv_out,
|
struct timeval& tv_out,
|
||||||
bool convert_local = true);
|
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,
|
ssize_t time_len,
|
||||||
const char * const time_fmt[],
|
const char* const time_fmt[],
|
||||||
struct timeval &tv_out) {
|
struct timeval& tv_out)
|
||||||
|
{
|
||||||
struct exttm tm;
|
struct exttm tm;
|
||||||
|
|
||||||
if (time_len == -1) {
|
if (time_len == -1) {
|
||||||
@ -116,12 +121,13 @@ struct date_time_scanner {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool convert_to_timeval(const std::string &time_src,
|
bool convert_to_timeval(const std::string& time_src, struct timeval& tv_out)
|
||||||
struct timeval &tv_out) {
|
{
|
||||||
struct exttm tm;
|
struct exttm tm;
|
||||||
|
|
||||||
if (this->scan(time_src.c_str(), time_src.size(),
|
if (this->scan(time_src.c_str(), time_src.size(), nullptr, &tm, tv_out)
|
||||||
nullptr, &tm, tv_out) != nullptr) {
|
!= nullptr)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -35,13 +35,14 @@
|
|||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace enums {
|
namespace enums {
|
||||||
|
|
||||||
template <typename E>
|
template<typename E>
|
||||||
constexpr auto to_underlying(E e) noexcept
|
constexpr auto
|
||||||
|
to_underlying(E e) noexcept
|
||||||
{
|
{
|
||||||
return static_cast<std::underlying_type_t<E>>(e);
|
return static_cast<std::underlying_type_t<E>>(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace enums
|
||||||
}
|
} // namespace lnav
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -43,28 +43,31 @@ public:
|
|||||||
file_off_t fr_offset{0};
|
file_off_t fr_offset{0};
|
||||||
file_ssize_t fr_size{0};
|
file_ssize_t fr_size{0};
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->fr_offset = 0;
|
this->fr_offset = 0;
|
||||||
this->fr_size = 0;
|
this->fr_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t next_offset() const {
|
ssize_t next_offset() const
|
||||||
|
{
|
||||||
return this->fr_offset + this->fr_size;
|
return this->fr_offset + this->fr_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return fr_size == 0;
|
return fr_size == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct source_location {
|
struct source_location {
|
||||||
source_location()
|
source_location()
|
||||||
: sl_source(intern_string::lookup("unknown")),
|
: sl_source(intern_string::lookup("unknown")), sl_line_number(-1)
|
||||||
sl_line_number(-1) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
source_location(intern_string_t source, int line)
|
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;
|
intern_string_t sl_source;
|
||||||
int sl_line_number;
|
int sl_line_number;
|
||||||
|
@ -21,23 +21,23 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "fmt/format.h"
|
|
||||||
#include "fs_util.hh"
|
#include "fs_util.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
#include "opt_util.hh"
|
#include "opt_util.hh"
|
||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace filesystem {
|
namespace filesystem {
|
||||||
|
|
||||||
Result<std::pair<ghc::filesystem::path, int>, std::string>
|
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();
|
auto pattern_str = pattern.string();
|
||||||
char pattern_copy[pattern_str.size() + 1];
|
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());
|
strcpy(pattern_copy, pattern_str.c_str());
|
||||||
if ((fd = mkstemp(pattern_copy)) == -1) {
|
if ((fd = mkstemp(pattern_copy)) == -1) {
|
||||||
return Err(fmt::format("unable to create temporary file: {} -- {}",
|
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));
|
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 {
|
try {
|
||||||
ghc::filesystem::ifstream file_stream(path);
|
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;
|
std::string retval;
|
||||||
|
|
||||||
for (const auto &path : paths) {
|
for (const auto& path : paths) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -90,5 +93,5 @@ std::string build_path(const std::vector<ghc::filesystem::path> &paths)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace filesystem
|
||||||
}
|
} // namespace lnav
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -33,32 +33,38 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "result.h"
|
|
||||||
#include "ghc/filesystem.hpp"
|
#include "ghc/filesystem.hpp"
|
||||||
|
#include "result.h"
|
||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace filesystem {
|
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);
|
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);
|
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);
|
return open(path.c_str(), flags, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::pair<ghc::filesystem::path, int>, std::string>
|
Result<std::pair<ghc::filesystem::path, int>, std::string> open_temp_file(
|
||||||
open_temp_file(const ghc::filesystem::path &pattern);
|
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
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -33,12 +33,11 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
template<typename F, typename FrontArg>
|
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),
|
return [f = std::forward<F>(f),
|
||||||
frontArg = std::forward<FrontArg>(frontArg)]
|
frontArg = std::forward<FrontArg>(frontArg)](auto&&... backArgs) {
|
||||||
(auto&&...backArgs)
|
|
||||||
{
|
|
||||||
return (frontArg->*f)(std::forward<decltype(backArgs)>(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 noop_func {
|
||||||
struct anything {
|
struct anything {
|
||||||
template<class T>
|
template<class T>
|
||||||
operator T(){ return {}; }
|
operator T()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
// optional reference support. Somewhat evil.
|
// optional reference support. Somewhat evil.
|
||||||
template<class T>
|
template<class T>
|
||||||
operator T&()const{ static T t{}; return t; }
|
operator T&() const
|
||||||
|
{
|
||||||
|
static T t{};
|
||||||
|
return t;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
template<class...Args>
|
template<class... Args>
|
||||||
anything operator()(Args&&...)const{return {};}
|
anything operator()(Args&&...) const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -44,7 +44,9 @@ namespace futures {
|
|||||||
* @return The new future.
|
* @return The new future.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
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;
|
std::promise<std::decay_t<T>> pr;
|
||||||
auto r = pr.get_future();
|
auto r = pr.get_future();
|
||||||
pr.set_value(std::forward<T>(t));
|
pr.set_value(std::forward<T>(t));
|
||||||
@ -64,9 +66,10 @@ public:
|
|||||||
* @param processor The function to execute with the result of a future.
|
* @param processor The function to execute with the result of a future.
|
||||||
*/
|
*/
|
||||||
explicit future_queue(std::function<void(T&)> processor)
|
explicit future_queue(std::function<void(T&)> processor)
|
||||||
: fq_processor(processor) {};
|
: fq_processor(processor){};
|
||||||
|
|
||||||
~future_queue() {
|
~future_queue()
|
||||||
|
{
|
||||||
this->pop_to();
|
this->pop_to();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +80,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @param f The future to add to the queue.
|
* @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->fq_deque.emplace_back(std::move(f));
|
||||||
this->pop_to(MAX_QUEUE_SIZE);
|
this->pop_to(MAX_QUEUE_SIZE);
|
||||||
}
|
}
|
||||||
@ -88,7 +92,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @param size The new desired size of the queue.
|
* @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) {
|
while (this->fq_deque.size() > size) {
|
||||||
auto v = this->fq_deque.front().get();
|
auto v = this->fq_deque.front().get();
|
||||||
this->fq_processor(v);
|
this->fq_processor(v);
|
||||||
@ -100,7 +105,7 @@ public:
|
|||||||
std::deque<std::future<T>> fq_deque;
|
std::deque<std::future<T>> fq_deque;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace futures
|
||||||
}
|
} // namespace lnav
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,27 +21,34 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "fmt/format.h"
|
|
||||||
#include "humanize.hh"
|
#include "humanize.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
namespace humanize {
|
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 double LN1024 = log(1024.0);
|
||||||
static const std::vector<const char *> UNITS = {
|
static const std::vector<const char*> UNITS = {
|
||||||
" ", "K", "M", "G", "T", "P", "E",
|
" ",
|
||||||
|
"K",
|
||||||
|
"M",
|
||||||
|
"G",
|
||||||
|
"T",
|
||||||
|
"P",
|
||||||
|
"E",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
@ -52,8 +59,8 @@ std::string file_size(file_ssize_t value)
|
|||||||
return "0.0 B";
|
return "0.0 B";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto exp = floor(std::min(log(value) / LN1024,
|
auto exp
|
||||||
(double) (UNITS.size() - 1)));
|
= floor(std::min(log(value) / LN1024, (double) (UNITS.size() - 1)));
|
||||||
auto divisor = pow(1024, exp);
|
auto divisor = pow(1024, exp);
|
||||||
|
|
||||||
return fmt::format(FMT_STRING("{:.1f}{}B"),
|
return fmt::format(FMT_STRING("{:.1f}{}B"),
|
||||||
@ -61,7 +68,8 @@ std::string file_size(file_ssize_t value)
|
|||||||
UNITS[exp]);
|
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 ZERO = " ";
|
||||||
static const std::string BARS[] = {
|
static const std::string BARS[] = {
|
||||||
@ -91,4 +99,4 @@ const std::string& sparkline(double value, nonstd::optional<double> upper_opt)
|
|||||||
return BARS[index];
|
return BARS[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace humanize
|
||||||
|
@ -21,21 +21,21 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "doctest/doctest.h"
|
|
||||||
|
|
||||||
#include "base/humanize.hh"
|
#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(0) == "0.0 B");
|
||||||
CHECK(humanize::file_size(1) == "1.0 B");
|
CHECK(humanize::file_size(1) == "1.0 B");
|
||||||
CHECK(humanize::file_size(1024) == "1.0KB");
|
CHECK(humanize::file_size(1024) == "1.0KB");
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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);
|
const std::string& sparkline(double value, nonstd::optional<double> upper);
|
||||||
|
|
||||||
}
|
} // namespace humanize
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,22 +21,23 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "humanize.network.hh"
|
#include "humanize.network.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "pcrepp/pcrepp.hh"
|
#include "pcrepp/pcrepp.hh"
|
||||||
|
|
||||||
namespace humanize {
|
namespace humanize {
|
||||||
namespace network {
|
namespace network {
|
||||||
namespace path {
|
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(
|
static const pcrepp REMOTE_PATTERN(
|
||||||
"(?:(?<username>[\\w\\._\\-]+)@)?"
|
"(?:(?<username>[\\w\\._\\-]+)@)?"
|
||||||
@ -60,11 +61,11 @@ nonstd::optional<::network::path> from_str(const char *str)
|
|||||||
path = ".";
|
path = ".";
|
||||||
}
|
}
|
||||||
return ::network::path{
|
return ::network::path{
|
||||||
{ username, locality_hostname, nonstd::nullopt },
|
{username, locality_hostname, nonstd::nullopt},
|
||||||
path,
|
path,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace path
|
||||||
}
|
} // namespace network
|
||||||
}
|
} // namespace humanize
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -32,15 +32,16 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "optional.hpp"
|
|
||||||
#include "network.tcp.hh"
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
#include "network.tcp.hh"
|
||||||
|
#include "optional.hpp"
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct formatter<network::locality> {
|
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();
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
|
|
||||||
// Check if reached the end of the range:
|
// Check if reached the end of the range:
|
||||||
@ -51,24 +52,25 @@ struct formatter<network::locality> {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const network::locality& l, FormatContext& ctx) {
|
auto format(const network::locality& l, FormatContext& ctx)
|
||||||
|
{
|
||||||
bool is_ipv6 = l.l_hostname.find(':') != std::string::npos;
|
bool is_ipv6 = l.l_hostname.find(':') != std::string::npos;
|
||||||
|
|
||||||
return format_to(
|
return format_to(ctx.out(),
|
||||||
ctx.out(),
|
"{}{}{}{}{}",
|
||||||
"{}{}{}{}{}",
|
l.l_username.value_or(std::string()),
|
||||||
l.l_username.value_or(std::string()),
|
l.l_username ? "@" : "",
|
||||||
l.l_username ? "@" : "",
|
is_ipv6 ? "[" : "",
|
||||||
is_ipv6 ? "[" : "",
|
l.l_hostname,
|
||||||
l.l_hostname,
|
is_ipv6 ? "]" : "");
|
||||||
is_ipv6 ? "]" : "");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct formatter<network::path> {
|
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();
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
|
|
||||||
// Check if reached the end of the range:
|
// Check if reached the end of the range:
|
||||||
@ -79,32 +81,30 @@ struct formatter<network::path> {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const network::path& p, FormatContext& ctx) {
|
auto format(const network::path& p, FormatContext& ctx)
|
||||||
|
{
|
||||||
return format_to(
|
return format_to(
|
||||||
ctx.out(),
|
ctx.out(), "{}:{}", p.p_locality, p.p_path == "." ? "" : p.p_path);
|
||||||
"{}:{}",
|
|
||||||
p.p_locality,
|
|
||||||
p.p_path == "." ? "" : p.p_path);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace fmt
|
||||||
|
|
||||||
namespace humanize {
|
namespace humanize {
|
||||||
namespace network {
|
namespace network {
|
||||||
namespace path {
|
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());
|
return from_str(str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace path
|
||||||
}
|
} // namespace network
|
||||||
}
|
} // namespace humanize
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,21 +21,20 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "base/humanize.network.hh"
|
||||||
|
#include "config.h"
|
||||||
#include "doctest/doctest.h"
|
#include "doctest/doctest.h"
|
||||||
|
|
||||||
#include "base/humanize.network.hh"
|
TEST_CASE("humanize::network::path")
|
||||||
|
{
|
||||||
TEST_CASE("humanize::network::path") {
|
|
||||||
{
|
{
|
||||||
auto rp_opt = humanize::network::path::from_str("foobar");
|
auto rp_opt = humanize::network::path::from_str("foobar");
|
||||||
CHECK(!rp_opt);
|
CHECK(!rp_opt);
|
||||||
@ -70,8 +69,8 @@ TEST_CASE("humanize::network::path") {
|
|||||||
CHECK(!rp.p_locality.l_service.has_value());
|
CHECK(!rp.p_locality.l_service.has_value());
|
||||||
CHECK(rp.p_path == "/var/log");
|
CHECK(rp.p_path == "/var/log");
|
||||||
|
|
||||||
CHECK(fmt::format("{}", rp.p_locality) ==
|
CHECK(fmt::format("{}", rp.p_locality)
|
||||||
"dean@[fe80::184f:c67:baf1:fe02%en0]");
|
== "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_locality.l_service.has_value());
|
||||||
CHECK(rp.p_path == "/var/log");
|
CHECK(rp.p_path == "/var/log");
|
||||||
|
|
||||||
CHECK(fmt::format("{}", rp.p_locality) ==
|
CHECK(fmt::format("{}", rp.p_locality)
|
||||||
"[fe80::184f:c67:baf1:fe02%en0]");
|
== "[fe80::184f:c67:baf1:fe02%en0]");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto rp_opt = humanize::network::path::from_str(
|
auto rp_opt
|
||||||
"host1.example.com:/var/log");
|
= humanize::network::path::from_str("host1.example.com:/var/log");
|
||||||
CHECK(rp_opt.has_value());
|
CHECK(rp_opt.has_value());
|
||||||
|
|
||||||
auto rp = *rp_opt;
|
auto rp = *rp_opt;
|
||||||
|
@ -21,35 +21,37 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "humanize.time.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "time_util.hh"
|
#include "time_util.hh"
|
||||||
#include "humanize.time.hh"
|
|
||||||
|
|
||||||
namespace humanize {
|
namespace humanize {
|
||||||
namespace time {
|
namespace time {
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
point point::from_tv(const timeval &tv)
|
point
|
||||||
|
point::from_tv(const timeval& tv)
|
||||||
{
|
{
|
||||||
return point(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
|
struct timeval current_time
|
||||||
.value_or(current_timeval());
|
= this->p_recent_point.value_or(current_timeval());
|
||||||
const char *fmt;
|
const char* fmt;
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
int amount;
|
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);
|
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) {
|
if (delta < 0s) {
|
||||||
return "in the future";
|
return "in the future";
|
||||||
} else if (delta < 1min) {
|
} else if (delta < 1min) {
|
||||||
@ -66,7 +69,8 @@ std::string point::as_time_ago() const
|
|||||||
return "one minute ago";
|
return "one minute ago";
|
||||||
} else if (delta < 1h) {
|
} else if (delta < 1h) {
|
||||||
fmt = "%d minutes ago";
|
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) {
|
} else if (delta < 2h) {
|
||||||
return "one hour ago";
|
return "one hour ago";
|
||||||
} else if (delta < 24h) {
|
} else if (delta < 24h) {
|
||||||
@ -89,7 +93,8 @@ std::string point::as_time_ago() const
|
|||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string point::as_precise_time_ago() const
|
std::string
|
||||||
|
point::as_precise_time_ago() const
|
||||||
{
|
{
|
||||||
struct timeval now, diff;
|
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};
|
return duration{tv};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string duration::to_string() const
|
std::string
|
||||||
|
duration::to_string() const
|
||||||
{
|
{
|
||||||
/* 24h22m33s111 */
|
/* 24h22m33s111 */
|
||||||
|
|
||||||
static const struct rel_interval {
|
static const struct rel_interval {
|
||||||
uint64_t length;
|
uint64_t length;
|
||||||
const char *format;
|
const char* format;
|
||||||
const char *symbol;
|
const char* symbol;
|
||||||
} intervals[] = {
|
} intervals[] = {
|
||||||
{ 1000, "%03lld%s", "" },
|
{1000, "%03lld%s", ""},
|
||||||
{ 60, "%lld%s", "s" },
|
{60, "%lld%s", "s"},
|
||||||
{ 60, "%lld%s", "m" },
|
{60, "%lld%s", "m"},
|
||||||
{ 24, "%lld%s", "h" },
|
{24, "%lld%s", "h"},
|
||||||
{ 0, "%lld%s", "d" },
|
{0, "%lld%s", "d"},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto *curr_interval = intervals;
|
auto* curr_interval = intervals;
|
||||||
auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(
|
auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
std::chrono::seconds(this->d_timeval.tv_sec)) +
|
std::chrono::seconds(this->d_timeval.tv_sec))
|
||||||
std::chrono::microseconds(this->d_timeval.tv_usec);
|
+ std::chrono::microseconds(this->d_timeval.tv_usec);
|
||||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(usecs);
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(usecs);
|
||||||
std::string retval;
|
std::string retval;
|
||||||
bool neg = false;
|
bool neg = false;
|
||||||
@ -157,8 +164,8 @@ std::string duration::to_string() const
|
|||||||
|
|
||||||
uint64_t remaining;
|
uint64_t remaining;
|
||||||
if (millis >= 10min) {
|
if (millis >= 10min) {
|
||||||
remaining = std::chrono::duration_cast<std::chrono::seconds>(millis)
|
remaining
|
||||||
.count();
|
= std::chrono::duration_cast<std::chrono::seconds>(millis).count();
|
||||||
curr_interval += 1;
|
curr_interval += 1;
|
||||||
} else {
|
} else {
|
||||||
remaining = millis.count();
|
remaining = millis.count();
|
||||||
@ -171,8 +178,7 @@ std::string duration::to_string() const
|
|||||||
if (curr_interval->length) {
|
if (curr_interval->length) {
|
||||||
amount = remaining % curr_interval->length;
|
amount = remaining % curr_interval->length;
|
||||||
remaining = remaining / curr_interval->length;
|
remaining = remaining / curr_interval->length;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
amount = remaining;
|
amount = remaining;
|
||||||
remaining = 0;
|
remaining = 0;
|
||||||
}
|
}
|
||||||
@ -181,7 +187,10 @@ std::string duration::to_string() const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(segment, sizeof(segment), curr_interval->format, amount,
|
snprintf(segment,
|
||||||
|
sizeof(segment),
|
||||||
|
curr_interval->format,
|
||||||
|
amount,
|
||||||
curr_interval->symbol);
|
curr_interval->symbol);
|
||||||
retval.insert(0, segment);
|
retval.insert(0, segment);
|
||||||
}
|
}
|
||||||
@ -193,5 +202,5 @@ std::string duration::to_string() const
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace time
|
||||||
}
|
} // namespace humanize
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,10 +30,10 @@
|
|||||||
#ifndef lnav_humanize_time_hh
|
#ifndef lnav_humanize_time_hh
|
||||||
#define lnav_humanize_time_hh
|
#define lnav_humanize_time_hh
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "optional.hpp"
|
#include "optional.hpp"
|
||||||
|
|
||||||
namespace humanize {
|
namespace humanize {
|
||||||
@ -41,15 +41,15 @@ namespace time {
|
|||||||
|
|
||||||
class point {
|
class point {
|
||||||
public:
|
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;
|
this->p_recent_point = tv;
|
||||||
return *this;
|
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;
|
this->p_convert_to_local = convert_to_local;
|
||||||
return *this;
|
return *this;
|
||||||
@ -60,9 +60,10 @@ public:
|
|||||||
std::string as_precise_time_ago() const;
|
std::string as_precise_time_ago() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit point(const struct timeval &tv) : p_past_point{tv.tv_sec,
|
explicit point(const struct timeval& tv)
|
||||||
tv.tv_usec}
|
: p_past_point{tv.tv_sec, tv.tv_usec}
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
struct timeval p_past_point;
|
struct timeval p_past_point;
|
||||||
nonstd::optional<struct timeval> p_recent_point;
|
nonstd::optional<struct timeval> p_recent_point;
|
||||||
@ -74,13 +75,14 @@ public:
|
|||||||
static duration from_tv(const struct timeval& tv);
|
static duration from_tv(const struct timeval& tv);
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit duration(const struct timeval& tv) : d_timeval(tv) {}
|
explicit duration(const struct timeval& tv) : d_timeval(tv) {}
|
||||||
|
|
||||||
struct timeval d_timeval;
|
struct timeval d_timeval;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace time
|
||||||
}
|
} // namespace humanize
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,18 +21,17 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "doctest/doctest.h"
|
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "doctest/doctest.h"
|
||||||
#include "humanize.time.hh"
|
#include "humanize.time.hh"
|
||||||
|
|
||||||
TEST_CASE("time ago")
|
TEST_CASE("time ago")
|
||||||
@ -42,87 +41,82 @@ TEST_CASE("time ago")
|
|||||||
time_t t1 = 1610000000;
|
time_t t1 = 1610000000;
|
||||||
auto t1_chrono = std::chrono::seconds(t1);
|
auto t1_chrono = std::chrono::seconds(t1);
|
||||||
|
|
||||||
auto p1 = humanize::time::point::from_tv({t1, 0})
|
auto p1 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) t1 + 5, 0});
|
{(time_t) t1 + 5, 0});
|
||||||
|
|
||||||
CHECK(p1.as_time_ago() == "just now");
|
CHECK(p1.as_time_ago() == "just now");
|
||||||
CHECK(p1.as_precise_time_ago() == " 5 seconds ago");
|
CHECK(p1.as_precise_time_ago() == " 5 seconds ago");
|
||||||
|
|
||||||
auto p2 = humanize::time::point::from_tv({t1, 0})
|
auto p2 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) t1 + 65, 0});
|
{(time_t) t1 + 65, 0});
|
||||||
|
|
||||||
CHECK(p2.as_time_ago() == "one minute ago");
|
CHECK(p2.as_time_ago() == "one minute ago");
|
||||||
CHECK(p2.as_precise_time_ago() == " 1 minute and 5 seconds ago");
|
CHECK(p2.as_precise_time_ago() == " 1 minute and 5 seconds ago");
|
||||||
|
|
||||||
auto p3 = humanize::time::point::from_tv({t1, 0})
|
auto p3 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) t1 + (3 * 60 + 5), 0});
|
{(time_t) t1 + (3 * 60 + 5), 0});
|
||||||
|
|
||||||
CHECK(p3.as_time_ago() == "3 minutes ago");
|
CHECK(p3.as_time_ago() == "3 minutes ago");
|
||||||
CHECK(p3.as_precise_time_ago() == " 3 minutes and 5 seconds ago");
|
CHECK(p3.as_precise_time_ago() == " 3 minutes and 5 seconds ago");
|
||||||
|
|
||||||
auto p4 = humanize::time::point::from_tv({t1, 0})
|
auto p4 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 65min).count(), 0});
|
{(time_t) (t1_chrono + 65min).count(), 0});
|
||||||
|
|
||||||
CHECK(p4.as_time_ago() == "one hour ago");
|
CHECK(p4.as_time_ago() == "one hour ago");
|
||||||
CHECK(p4.as_precise_time_ago() == "one hour ago");
|
CHECK(p4.as_precise_time_ago() == "one hour ago");
|
||||||
|
|
||||||
auto p5 = humanize::time::point::from_tv({t1, 0})
|
auto p5 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 3h).count(), 0});
|
{(time_t) (t1_chrono + 3h).count(), 0});
|
||||||
|
|
||||||
CHECK(p5.as_time_ago() == "3 hours ago");
|
CHECK(p5.as_time_ago() == "3 hours ago");
|
||||||
CHECK(p5.as_precise_time_ago() == "3 hours ago");
|
CHECK(p5.as_precise_time_ago() == "3 hours ago");
|
||||||
|
|
||||||
auto p6 = humanize::time::point::from_tv({t1, 0})
|
auto p6 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 25h).count(), 0});
|
{(time_t) (t1_chrono + 25h).count(), 0});
|
||||||
|
|
||||||
CHECK(p6.as_time_ago() == "one day ago");
|
CHECK(p6.as_time_ago() == "one day ago");
|
||||||
CHECK(p6.as_precise_time_ago() == "one day ago");
|
CHECK(p6.as_precise_time_ago() == "one day ago");
|
||||||
|
|
||||||
auto p7 = humanize::time::point::from_tv({t1, 0})
|
auto p7 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 50h).count(), 0});
|
{(time_t) (t1_chrono + 50h).count(), 0});
|
||||||
|
|
||||||
CHECK(p7.as_time_ago() == "2 days ago");
|
CHECK(p7.as_time_ago() == "2 days ago");
|
||||||
CHECK(p7.as_precise_time_ago() == "2 days ago");
|
CHECK(p7.as_precise_time_ago() == "2 days ago");
|
||||||
|
|
||||||
auto p8 = humanize::time::point::from_tv({t1, 0})
|
auto p8 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 370 * 24h).count(), 0});
|
{(time_t) (t1_chrono + 370 * 24h).count(), 0});
|
||||||
|
|
||||||
CHECK(p8.as_time_ago() == "over a year ago");
|
CHECK(p8.as_time_ago() == "over a year ago");
|
||||||
CHECK(p8.as_precise_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})
|
auto p9 = humanize::time::point::from_tv({t1, 0}).with_recent_point(
|
||||||
.with_recent_point({(time_t) (t1_chrono + 800 * 24h).count(), 0});
|
{(time_t) (t1_chrono + 800 * 24h).count(), 0});
|
||||||
|
|
||||||
CHECK(p9.as_time_ago() == "over 2 years ago");
|
CHECK(p9.as_time_ago() == "over 2 years ago");
|
||||||
CHECK(p9.as_precise_time_ago() == "over 2 years ago");
|
CHECK(p9.as_precise_time_ago() == "over 2 years ago");
|
||||||
|
|
||||||
CHECK(humanize::time::point::from_tv({1610000000, 0})
|
CHECK(humanize::time::point::from_tv({1610000000, 0})
|
||||||
.with_recent_point({(time_t) 1612000000, 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;
|
std::string val;
|
||||||
|
|
||||||
val = humanize::time::duration::from_tv({25 * 60 * 60, 123000})
|
val = humanize::time::duration::from_tv({25 * 60 * 60, 123000}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "1d1h0m0s");
|
CHECK(val == "1d1h0m0s");
|
||||||
val = humanize::time::duration::from_tv({10, 123000})
|
val = humanize::time::duration::from_tv({10, 123000}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "10s123");
|
CHECK(val == "10s123");
|
||||||
val = humanize::time::duration::from_tv({10, 0})
|
val = humanize::time::duration::from_tv({10, 0}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "10s000");
|
CHECK(val == "10s000");
|
||||||
val = humanize::time::duration::from_tv({0, 100000})
|
val = humanize::time::duration::from_tv({0, 100000}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "100");
|
CHECK(val == "100");
|
||||||
val = humanize::time::duration::from_tv({0, 0})
|
val = humanize::time::duration::from_tv({0, 0}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "");
|
CHECK(val == "");
|
||||||
val = humanize::time::duration::from_tv({0, -10000})
|
val = humanize::time::duration::from_tv({0, -10000}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "-010");
|
CHECK(val == "-010");
|
||||||
val = humanize::time::duration::from_tv({-10, 0})
|
val = humanize::time::duration::from_tv({-10, 0}).to_string();
|
||||||
.to_string();
|
|
||||||
CHECK(val == "-10s000");
|
CHECK(val == "-10s000");
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -38,55 +38,60 @@ namespace injector {
|
|||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template<typename I, typename R, typename ...Args>
|
template<typename I, typename R, typename... Args>
|
||||||
std::function<std::shared_ptr<I>()> create_factory(R (*)(Args...)) {
|
std::function<std::shared_ptr<I>()>
|
||||||
return []() {
|
create_factory(R (*)(Args...))
|
||||||
return std::make_shared<I>(::injector::get<Args>()...);
|
{
|
||||||
};
|
return []() { return std::make_shared<I>(::injector::get<Args>()...); };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I,
|
template<typename I, std::enable_if_t<has_injectable<I>::value, bool> = true>
|
||||||
std::enable_if_t<has_injectable<I>::value, bool> = true>
|
std::function<std::shared_ptr<I>()>
|
||||||
std::function<std::shared_ptr<I>()> create_factory() {
|
create_factory()
|
||||||
typename I::injectable *i = nullptr;
|
{
|
||||||
|
typename I::injectable* i = nullptr;
|
||||||
|
|
||||||
return create_factory<I>(i);
|
return create_factory<I>(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I,
|
template<typename I, std::enable_if_t<!has_injectable<I>::value, bool> = true>
|
||||||
std::enable_if_t<!has_injectable<I>::value, bool> = true>
|
std::function<std::shared_ptr<I>()>
|
||||||
std::function<std::shared_ptr<I>()> create_factory() noexcept {
|
create_factory() noexcept
|
||||||
return []() {
|
{
|
||||||
return std::make_shared<I>();
|
return []() { return std::make_shared<I>(); };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace details
|
||||||
|
|
||||||
template<typename T, typename...Annotations>
|
template<typename T, typename... Annotations>
|
||||||
struct bind : singleton_storage<T, Annotations...> {
|
struct bind : singleton_storage<T, Annotations...> {
|
||||||
static bool to_singleton() noexcept {
|
static bool to_singleton() noexcept
|
||||||
|
{
|
||||||
static T storage;
|
static T storage;
|
||||||
|
|
||||||
singleton_storage<T, Annotations...>::ss_data = &storage;
|
singleton_storage<T, Annotations...>::ss_data = &storage;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename...Args>
|
template<typename... Args>
|
||||||
static bool to_instance(T* (*f)(Args...)) noexcept {
|
static bool to_instance(T* (*f)(Args...)) noexcept
|
||||||
singleton_storage<T, Annotations...>::ss_data = f(::injector::get<Args>()...);
|
{
|
||||||
|
singleton_storage<T, Annotations...>::ss_data
|
||||||
|
= f(::injector::get<Args>()...);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool to_instance(T* data) noexcept {
|
static bool to_instance(T* data) noexcept
|
||||||
|
{
|
||||||
singleton_storage<T, Annotations...>::ss_data = data;
|
singleton_storage<T, Annotations...>::ss_data = data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I>
|
template<typename I>
|
||||||
static bool to() noexcept {
|
static bool to() noexcept
|
||||||
singleton_storage<T, Annotations...>::ss_factory =
|
{
|
||||||
details::create_factory<I>();
|
singleton_storage<T, Annotations...>::ss_factory
|
||||||
|
= details::create_factory<I>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -96,15 +101,17 @@ struct bind_multiple : multiple_storage<T> {
|
|||||||
bind_multiple() noexcept = default;
|
bind_multiple() noexcept = default;
|
||||||
|
|
||||||
template<typename I>
|
template<typename I>
|
||||||
bind_multiple& add() noexcept {
|
bind_multiple& add() noexcept
|
||||||
multiple_storage<T>::get_factories()[typeid(I).name()] =
|
{
|
||||||
details::create_factory<I>();
|
multiple_storage<T>::get_factories()[typeid(I).name()]
|
||||||
|
= details::create_factory<I>();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I, typename...Annotations>
|
template<typename I, typename... Annotations>
|
||||||
bind_multiple& add_singleton() noexcept {
|
bind_multiple& add_singleton() noexcept
|
||||||
|
{
|
||||||
auto factory = details::create_factory<I>();
|
auto factory = details::create_factory<I>();
|
||||||
auto single = factory();
|
auto single = factory();
|
||||||
|
|
||||||
@ -112,14 +119,13 @@ struct bind_multiple : multiple_storage<T> {
|
|||||||
bind<T, Annotations...>::to_instance(single.get());
|
bind<T, Annotations...>::to_instance(single.get());
|
||||||
}
|
}
|
||||||
bind<I, Annotations...>::to_instance(single.get());
|
bind<I, Annotations...>::to_instance(single.get());
|
||||||
multiple_storage<T>::get_factories()[typeid(I).name()] = [single]() {
|
multiple_storage<T>::get_factories()[typeid(I).name()]
|
||||||
return single;
|
= [single]() { return single; };
|
||||||
};
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace injector
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,12 +32,12 @@
|
|||||||
#ifndef lnav_injector_hh
|
#ifndef lnav_injector_hh
|
||||||
#define lnav_injector_hh
|
#define lnav_injector_hh
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
|
|
||||||
@ -46,40 +46,45 @@ namespace injector {
|
|||||||
template<typename Annotation>
|
template<typename Annotation>
|
||||||
void force_linking(Annotation anno);
|
void force_linking(Annotation anno);
|
||||||
|
|
||||||
template<class ...>
|
template<class...>
|
||||||
using void_t = void;
|
using void_t = void;
|
||||||
|
|
||||||
template <class, class = void>
|
template<class, class = void>
|
||||||
struct has_injectable : std::false_type {};
|
struct has_injectable : std::false_type {
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
struct has_injectable<T, void_t<typename T::injectable>> : std::true_type
|
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 {
|
struct singleton_storage {
|
||||||
static T *get() {
|
static T* get()
|
||||||
|
{
|
||||||
static int _[] = {0, (force_linking(Annotations{}), 0)...};
|
static int _[] = {0, (force_linking(Annotations{}), 0)...};
|
||||||
(void)_;
|
(void) _;
|
||||||
assert(ss_data != nullptr);
|
assert(ss_data != nullptr);
|
||||||
return ss_data;
|
return ss_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<T> create() {
|
static std::shared_ptr<T> create()
|
||||||
|
{
|
||||||
static int _[] = {0, (force_linking(Annotations{}), 0)...};
|
static int _[] = {0, (force_linking(Annotations{}), 0)...};
|
||||||
(void)_;
|
(void) _;
|
||||||
return ss_factory();
|
return ss_factory();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static T *ss_data;
|
static T* ss_data;
|
||||||
static std::function<std::shared_ptr<T>()> ss_factory;
|
static std::function<std::shared_ptr<T>()> ss_factory;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename...Annotations>
|
template<typename T, typename... Annotations>
|
||||||
T *singleton_storage<T, Annotations...>::ss_data = nullptr;
|
T* singleton_storage<T, Annotations...>::ss_data = nullptr;
|
||||||
|
|
||||||
template<typename T, typename...Annotations>
|
template<typename T, typename... Annotations>
|
||||||
std::function<std::shared_ptr<T>()> singleton_storage<T, Annotations...>::ss_factory;
|
std::function<std::shared_ptr<T>()>
|
||||||
|
singleton_storage<T, Annotations...>::ss_factory;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Impl {
|
struct Impl {
|
||||||
@ -88,7 +93,8 @@ struct Impl {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct multiple_storage {
|
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;
|
std::vector<std::shared_ptr<T>> retval;
|
||||||
|
|
||||||
for (const auto& pair : get_factories()) {
|
for (const auto& pair : get_factories()) {
|
||||||
@ -96,28 +102,35 @@ struct multiple_storage {
|
|||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
protected:
|
|
||||||
using factory_map_t = std::map<std::string, std::function<std::shared_ptr<T>()>>;
|
|
||||||
|
|
||||||
static factory_map_t& get_factories() {
|
protected:
|
||||||
|
using factory_map_t
|
||||||
|
= std::map<std::string, std::function<std::shared_ptr<T>()>>;
|
||||||
|
|
||||||
|
static factory_map_t& get_factories()
|
||||||
|
{
|
||||||
static factory_map_t retval;
|
static factory_map_t retval;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename...Annotations,
|
template<typename T,
|
||||||
std::enable_if_t<std::is_reference<T>::value, bool> = true>
|
typename... Annotations,
|
||||||
T get()
|
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>>;
|
using plain_t = std::remove_const_t<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
return *singleton_storage<plain_t, Annotations...>::get();
|
return *singleton_storage<plain_t, Annotations...>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename...Annotations,
|
template<typename T,
|
||||||
std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
typename... Annotations,
|
||||||
T get()
|
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>>;
|
using plain_t = std::remove_const_t<std::remove_pointer_t<T>>;
|
||||||
|
|
||||||
@ -125,31 +138,38 @@ T get()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_shared_ptr : std::false_type {};
|
struct is_shared_ptr : std::false_type {
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
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>
|
template<class T>
|
||||||
struct is_vector : std::false_type {};
|
struct is_vector : std::false_type {
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
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()
|
|
||||||
{
|
|
||||||
return singleton_storage<typename T::element_type, Annotations...>::create();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T,
|
template<typename T,
|
||||||
std::enable_if_t<is_vector<T>::value, bool> = true>
|
typename... Annotations,
|
||||||
T get()
|
std::enable_if_t<is_shared_ptr<T>::value, bool> = true>
|
||||||
|
T
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
return singleton_storage<typename T::element_type,
|
||||||
|
Annotations...>::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
return multiple_storage<typename T::value_type::element_type>::create();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace injector
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,26 +21,27 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file intern_string.cc
|
* @file intern_string.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "intern_string.hh"
|
#include "intern_string.hh"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
const static int TABLE_SIZE = 4095;
|
const static int TABLE_SIZE = 4095;
|
||||||
|
|
||||||
struct intern_string::intern_table {
|
struct intern_string::intern_table {
|
||||||
~intern_table() {
|
~intern_table()
|
||||||
|
{
|
||||||
for (auto is : this->it_table) {
|
for (auto is : this->it_table) {
|
||||||
auto curr = is;
|
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>();
|
static intern_table_lifetime retval = std::make_shared<intern_table>();
|
||||||
|
|
||||||
@ -64,22 +66,23 @@ intern_table_lifetime intern_string::get_table_lifetime()
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
unsigned long
|
||||||
hash_str(const char *str, size_t len)
|
hash_str(const char* str, size_t len)
|
||||||
{
|
{
|
||||||
unsigned long retval = 5381;
|
unsigned long retval = 5381;
|
||||||
|
|
||||||
for (size_t lpc = 0; lpc < len; lpc++) {
|
for (size_t lpc = 0; lpc < len; lpc++) {
|
||||||
/* retval * 33 + c */
|
/* retval * 33 + c */
|
||||||
retval = ((retval << 5) + retval) + (unsigned char)str[lpc];
|
retval = ((retval << 5) + retval) + (unsigned char) str[lpc];
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
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;
|
unsigned long h;
|
||||||
intern_string *curr;
|
intern_string* curr;
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
len = strlen(str);
|
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];
|
curr = tab->it_table[h];
|
||||||
while (curr != nullptr) {
|
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;
|
return curr;
|
||||||
}
|
}
|
||||||
curr = curr->is_next;
|
curr = curr->is_next;
|
||||||
@ -106,22 +110,24 @@ const intern_string *intern_string::lookup(const char *str, ssize_t len) noexcep
|
|||||||
|
|
||||||
return curr;
|
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());
|
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());
|
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) {
|
while (*prefix != '\0' && *prefix == *curr) {
|
||||||
prefix += 1;
|
prefix += 1;
|
||||||
@ -131,7 +137,8 @@ bool intern_string::startswith(const char *prefix) const
|
|||||||
return *prefix == '\0';
|
return *prefix == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_fragment::trim(const char *tokens)
|
void
|
||||||
|
string_fragment::trim(const char* tokens)
|
||||||
{
|
{
|
||||||
while (this->sf_begin < this->sf_end) {
|
while (this->sf_begin < this->sf_end) {
|
||||||
bool found = false;
|
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()) {
|
if (amount > this->length()) {
|
||||||
return nonstd::nullopt;
|
return nonstd::nullopt;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,72 +32,81 @@
|
|||||||
#ifndef intern_string_hh
|
#ifndef intern_string_hh
|
||||||
#define intern_string_hh
|
#define intern_string_hh
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <string>
|
#include "fmt/format.h"
|
||||||
|
|
||||||
#include "optional.hpp"
|
#include "optional.hpp"
|
||||||
#include "strnatcmp.h"
|
#include "strnatcmp.h"
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
struct string_fragment {
|
struct string_fragment {
|
||||||
using iterator = const char *;
|
using iterator = const char*;
|
||||||
|
|
||||||
explicit string_fragment(const char *str = "", int begin = 0, int end = -1)
|
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) {
|
: sf_string(str), sf_begin(begin),
|
||||||
};
|
sf_end(end == -1 ? strlen(str) : end){};
|
||||||
|
|
||||||
explicit string_fragment(const unsigned char *str, int begin = 0, int end = -1)
|
explicit string_fragment(const unsigned char* str,
|
||||||
: sf_string((const char *) str),
|
int begin = 0,
|
||||||
sf_begin(begin),
|
int end = -1)
|
||||||
sf_end(end == -1 ? strlen((const char *) str) : end) {
|
: 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()) {
|
|
||||||
|
|
||||||
|
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;
|
return this->sf_begin != -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
int length() const {
|
int length() const
|
||||||
|
{
|
||||||
return this->sf_end - this->sf_begin;
|
return this->sf_end - this->sf_begin;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *data() const {
|
const char* data() const
|
||||||
|
{
|
||||||
return &this->sf_string[this->sf_begin];
|
return &this->sf_string[this->sf_begin];
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin() const {
|
iterator begin() const
|
||||||
|
{
|
||||||
return &this->sf_string[this->sf_begin];
|
return &this->sf_string[this->sf_begin];
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() const {
|
iterator end() const
|
||||||
|
{
|
||||||
return &this->sf_string[this->sf_end];
|
return &this->sf_string[this->sf_end];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return !this->is_valid() || length() == 0;
|
return !this->is_valid() || length() == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
char operator[](int index) const {
|
char operator[](int index) const
|
||||||
|
{
|
||||||
return this->sf_string[sf_begin + index];
|
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()) {
|
if (this->length() != (int) str.length()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return memcmp(&this->sf_string[this->sf_begin],
|
return memcmp(
|
||||||
str.c_str(),
|
&this->sf_string[this->sf_begin], str.c_str(), str.length())
|
||||||
str.length()) == 0;
|
== 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const string_fragment &sf) const {
|
bool operator==(const string_fragment& sf) const
|
||||||
|
{
|
||||||
if (this->length() != sf.length()) {
|
if (this->length() != sf.length()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -105,27 +114,32 @@ struct string_fragment {
|
|||||||
return memcmp(this->data(), sf.data(), sf.length()) == 0;
|
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()) {
|
if (this->length() != sf.length()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return strnatcasecmp(this->length(), this->data(),
|
return strnatcasecmp(
|
||||||
sf.length(), sf.data()) == 0;
|
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);
|
size_t len = strlen(str);
|
||||||
|
|
||||||
return len == (size_t) this->length() &&
|
return len == (size_t) this->length()
|
||||||
strncmp(this->data(), str, this->length()) == 0;
|
&& strncmp(this->data(), str, this->length()) == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator!=(const char *str) const {
|
bool operator!=(const char* str) const
|
||||||
|
{
|
||||||
return !(*this == str);
|
return !(*this == str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startswith(const char *prefix) const {
|
bool startswith(const char* prefix) const
|
||||||
|
{
|
||||||
auto iter = this->begin();
|
auto iter = this->begin();
|
||||||
|
|
||||||
while (*prefix != '\0' && *prefix == *iter && iter < this->end()) {
|
while (*prefix != '\0' && *prefix == *iter && iter < this->end()) {
|
||||||
@ -136,15 +150,14 @@ struct string_fragment {
|
|||||||
return *prefix == '\0';
|
return *prefix == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
string_fragment substr(int begin) const {
|
string_fragment substr(int begin) const
|
||||||
|
{
|
||||||
return string_fragment{
|
return string_fragment{
|
||||||
this->sf_string,
|
this->sf_string, this->sf_begin + begin, this->sf_end};
|
||||||
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++) {
|
for (int lpc = this->sf_begin; lpc < this->sf_end; lpc++) {
|
||||||
if (this->sf_string[lpc] == ch) {
|
if (this->sf_string[lpc] == ch) {
|
||||||
return lpc;
|
return lpc;
|
||||||
@ -155,7 +168,8 @@ struct string_fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
nonstd::optional<string_fragment> consume(P predicate) const {
|
nonstd::optional<string_fragment> consume(P predicate) const
|
||||||
|
{
|
||||||
int consumed = 0;
|
int consumed = 0;
|
||||||
while (consumed < this->length()) {
|
while (consumed < this->length()) {
|
||||||
if (!predicate(this->data()[consumed])) {
|
if (!predicate(this->data()[consumed])) {
|
||||||
@ -179,7 +193,8 @@ struct string_fragment {
|
|||||||
nonstd::optional<string_fragment> consume_n(int amount) const;
|
nonstd::optional<string_fragment> consume_n(int amount) const;
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
string_fragment skip(P predicate) const {
|
string_fragment skip(P predicate) const
|
||||||
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while (offset < this->length() && predicate(this->data()[offset])) {
|
while (offset < this->length() && predicate(this->data()[offset])) {
|
||||||
offset += 1;
|
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>
|
template<typename P>
|
||||||
split_result split_while(P& predicate) const {
|
split_result split_while(P& predicate) const
|
||||||
|
{
|
||||||
int consumed = 0;
|
int consumed = 0;
|
||||||
while (consumed < this->length()) {
|
while (consumed < this->length()) {
|
||||||
if (!predicate(this->data()[consumed])) {
|
if (!predicate(this->data()[consumed])) {
|
||||||
@ -219,14 +236,14 @@ struct string_fragment {
|
|||||||
this->sf_string,
|
this->sf_string,
|
||||||
this->sf_begin + consumed,
|
this->sf_begin + consumed,
|
||||||
this->sf_end,
|
this->sf_end,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tag1 {
|
struct tag1 {
|
||||||
const char t_value;
|
const char t_value;
|
||||||
|
|
||||||
bool operator()(char ch) const {
|
bool operator()(char ch) const
|
||||||
|
{
|
||||||
return this->t_value == ch;
|
return this->t_value == ch;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -234,7 +251,8 @@ struct string_fragment {
|
|||||||
struct quoted_string_body {
|
struct quoted_string_body {
|
||||||
bool qs_in_escape{false};
|
bool qs_in_escape{false};
|
||||||
|
|
||||||
bool operator()(char ch) {
|
bool operator()(char ch)
|
||||||
|
{
|
||||||
if (this->qs_in_escape) {
|
if (this->qs_in_escape) {
|
||||||
this->qs_in_escape = false;
|
this->qs_in_escape = false;
|
||||||
return true;
|
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());
|
memcpy(buf, this->data(), this->length());
|
||||||
buf[this->length()] = '\0';
|
buf[this->length()] = '\0';
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string to_string() const
|
||||||
|
{
|
||||||
return {this->data(), (size_t) this->length()};
|
return {this->data(), (size_t) this->length()};
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->sf_begin = 0;
|
this->sf_begin = 0;
|
||||||
this->sf_end = 0;
|
this->sf_end = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void invalidate() {
|
void invalidate()
|
||||||
|
{
|
||||||
this->sf_begin = -1;
|
this->sf_begin = -1;
|
||||||
this->sf_end = -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_begin;
|
||||||
int sf_end;
|
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());
|
int rc = strncmp(left, right.data(), right.length());
|
||||||
return rc < 0;
|
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;
|
return strncmp(left.data(), right, left.length()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class intern_string {
|
class intern_string {
|
||||||
|
|
||||||
public:
|
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();
|
return this->is_str.c_str();
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const
|
||||||
|
{
|
||||||
return this->is_str.size();
|
return this->is_str.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string to_string() const
|
||||||
|
{
|
||||||
return this->is_str;
|
return this->is_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_fragment to_string_fragment() const {
|
string_fragment to_string_fragment() const
|
||||||
|
{
|
||||||
return string_fragment{this->is_str};
|
return string_fragment{this->is_str};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startswith(const char *prefix) const;
|
bool startswith(const char* prefix) const;
|
||||||
|
|
||||||
struct intern_table;
|
struct intern_table;
|
||||||
static std::shared_ptr<intern_table> get_table_lifetime();
|
static std::shared_ptr<intern_table> get_table_lifetime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend intern_table;
|
friend intern_table;
|
||||||
|
|
||||||
intern_string(const char *str, ssize_t len)
|
intern_string(const char* str, ssize_t len)
|
||||||
: is_next(nullptr), is_str(str, (size_t) len) {
|
: is_next(nullptr), is_str(str, (size_t) len)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
intern_string *is_next;
|
intern_string* is_next;
|
||||||
std::string is_str;
|
std::string is_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -330,97 +361,112 @@ using intern_table_lifetime = std::shared_ptr<intern_string::intern_table>;
|
|||||||
|
|
||||||
class intern_string_t {
|
class intern_string_t {
|
||||||
public:
|
public:
|
||||||
using iterator = const char *;
|
using iterator = const char*;
|
||||||
|
|
||||||
intern_string_t(const intern_string *is = nullptr) : ist_interned_string(is) {
|
|
||||||
|
|
||||||
|
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;
|
return this->ist_interned_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->ist_interned_string = nullptr;
|
this->ist_interned_string = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return this->ist_interned_string == nullptr;
|
return this->ist_interned_string == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *get() const {
|
const char* get() const
|
||||||
|
{
|
||||||
if (this->empty()) {
|
if (this->empty()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return this->ist_interned_string->get();
|
return this->ist_interned_string->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin() const {
|
iterator begin() const
|
||||||
|
{
|
||||||
return this->get();
|
return this->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() const {
|
iterator end() const
|
||||||
|
{
|
||||||
return this->get() + this->size();
|
return this->get() + this->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const
|
||||||
|
{
|
||||||
if (this->ist_interned_string == nullptr) {
|
if (this->ist_interned_string == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return this->ist_interned_string->size();
|
return this->ist_interned_string->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash() const {
|
size_t hash() const
|
||||||
|
{
|
||||||
auto ptr = (uintptr_t) this->ist_interned_string;
|
auto ptr = (uintptr_t) this->ist_interned_string;
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string to_string() const
|
||||||
|
{
|
||||||
if (this->ist_interned_string == nullptr) {
|
if (this->ist_interned_string == nullptr) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return this->ist_interned_string->to_string();
|
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) {
|
if (this->ist_interned_string == nullptr) {
|
||||||
return string_fragment{"", 0, 0};
|
return string_fragment{"", 0, 0};
|
||||||
}
|
}
|
||||||
return this->ist_interned_string->to_string_fragment();
|
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;
|
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;
|
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);
|
return !(*this == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const char *rhs) const {
|
bool operator==(const char* rhs) const
|
||||||
|
{
|
||||||
return strcmp(this->get(), rhs) == 0;
|
return strcmp(this->get(), rhs) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const char *rhs) const {
|
bool operator!=(const char* rhs) const
|
||||||
|
{
|
||||||
return strcmp(this->get(), rhs) != 0;
|
return strcmp(this->get(), rhs) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 {
|
namespace fmt {
|
||||||
template<>
|
template<>
|
||||||
struct formatter<string_fragment> : formatter<string_view> {
|
struct formatter<string_fragment> : formatter<string_view> {
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const string_fragment &sf, FormatContext &ctx)
|
auto format(const string_fragment& sf, FormatContext& ctx)
|
||||||
{
|
{
|
||||||
return formatter<string_view>::format(
|
return formatter<string_view>::format(
|
||||||
string_view{sf.data(), (size_t) sf.length()}, ctx);
|
string_view{sf.data(), (size_t) sf.length()}, ctx);
|
||||||
@ -430,61 +476,80 @@ struct formatter<string_fragment> : formatter<string_view> {
|
|||||||
template<>
|
template<>
|
||||||
struct formatter<intern_string_t> : formatter<string_view> {
|
struct formatter<intern_string_t> : formatter<string_view> {
|
||||||
template<typename FormatContext>
|
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(
|
return formatter<string_view>::format(
|
||||||
string_view{is.get(), (size_t) is.size()}, ctx);
|
string_view{is.get(), (size_t) is.size()}, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace fmt
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template <>
|
template<>
|
||||||
struct hash<const intern_string_t> {
|
struct hash<const intern_string_t> {
|
||||||
std::size_t operator()(const intern_string_t &ist) const {
|
std::size_t operator()(const intern_string_t& ist) const
|
||||||
return ist.hash();
|
{
|
||||||
}
|
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());
|
int rc = strncmp(left, right.get(), right.size());
|
||||||
return rc < 0;
|
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;
|
return strncmp(left.get(), right, left.size()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const intern_string_t &left, const string_fragment &sf) {
|
inline bool
|
||||||
return ((int) left.size() == sf.length()) &&
|
operator==(const intern_string_t& left, const string_fragment& sf)
|
||||||
(memcmp(left.get(), sf.data(), left.size()) == 0);
|
{
|
||||||
|
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) {
|
inline bool
|
||||||
return (left.length() == (int) right.size()) &&
|
operator==(const string_fragment& left, const intern_string_t& right)
|
||||||
(memcmp(left.data(), right.get(), left.length()) == 0);
|
{
|
||||||
|
return (left.length() == (int) right.size())
|
||||||
|
&& (memcmp(left.data(), right.get(), left.length()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
inline string to_string(const string_fragment &s) {
|
inline string
|
||||||
return {s.data(), (size_t) s.length()};
|
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_fragment to_string_fragment(const string_fragment &s) {
|
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)
|
||||||
|
{
|
||||||
return 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());
|
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());
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "doctest/doctest.h"
|
|
||||||
|
|
||||||
#include "intern_string.hh"
|
#include "intern_string.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "doctest/doctest.h"
|
||||||
|
|
||||||
TEST_CASE("consume")
|
TEST_CASE("consume")
|
||||||
{
|
{
|
||||||
auto is_eq = string_fragment::tag1{'='};
|
auto is_eq = string_fragment::tag1{'='};
|
||||||
auto is_dq = string_fragment::tag1{'"'};
|
auto is_dq = string_fragment::tag1{'"'};
|
||||||
auto is_colon = 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 sf = string_fragment(pair);
|
||||||
|
|
||||||
auto split_sf = sf.split_while(isalnum);
|
auto split_sf = sf.split_while(isalnum);
|
||||||
@ -64,7 +63,7 @@ TEST_CASE("consume")
|
|||||||
auto no_value = sf.consume(is_colon);
|
auto no_value = sf.consume(is_colon);
|
||||||
CHECK(!no_value.has_value());
|
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_sf = string_fragment{qs};
|
||||||
|
|
||||||
auto qs_body = qs_sf.consume(is_dq);
|
auto qs_body = qs_sf.consume(is_dq);
|
||||||
|
@ -25,10 +25,10 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "is_utf8.hh"
|
#include "is_utf8.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if the given unsigned char * is a valid utf-8 sequence.
|
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
|
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;
|
size_t i = 0;
|
||||||
|
|
||||||
*message = nullptr;
|
*message = nullptr;
|
||||||
*faulty_bytes = 0;
|
*faulty_bytes = 0;
|
||||||
while (i < len)
|
while (i < len) {
|
||||||
{
|
|
||||||
if (str[i] == '\n') {
|
if (str[i] == '\n') {
|
||||||
*message = nullptr;
|
*message = nullptr;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str[i] <= 0x7F) /* 00..7F */
|
if (str[i] <= 0x7F) /* 00..7F */ {
|
||||||
{
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
} else if (str[i] >= 0xC2 && str[i] <= 0xDF) /* C2..DF 80..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) {
|
||||||
if (i + 1 < len) /* Expect a 2nd byte */
|
*message
|
||||||
{
|
= "After a first byte between C2 and DF, expecting a "
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
|
"2nd byte between 80 and BF";
|
||||||
{
|
|
||||||
*message = "After a first byte between C2 and DF, expecting a 2nd byte between 80 and BF";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte between C2 and DF, expecting a 2nd "
|
||||||
*message = "After a first byte between C2 and DF, expecting a 2nd byte.";
|
"byte.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
} else if (str[i] == 0xE0) /* E0 A0..BF 80..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) {
|
||||||
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
|
*message
|
||||||
{
|
= "After a first byte of E0, expecting a 2nd byte "
|
||||||
if (str[i + 1] < 0xA0 || str[i + 1] > 0xBF)
|
"between A0 and BF.";
|
||||||
{
|
|
||||||
*message = "After a first byte of E0, expecting a 2nd byte between A0 and BF.";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of E0, expecting a 3nd byte between 80 and BF.";
|
= "After a first byte of E0, expecting a 3nd byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte of E0, expecting two following "
|
||||||
*message = "After a first byte of E0, expecting two following bytes.";
|
"bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 3;
|
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 (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
|
||||||
{
|
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
|
*message
|
||||||
{
|
= "After a first byte between E1 and EC, expecting the "
|
||||||
*message = "After a first byte between E1 and EC, expecting the 2nd byte between 80 and BF.";
|
"2nd byte between 80 and BF.";
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte between E1 and EC, expecting the 3rd byte between 80 and BF.";
|
= "After a first byte between E1 and EC, expecting the "
|
||||||
|
"3rd byte between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte between E1 and EC, expecting two "
|
||||||
*message = "After a first byte between E1 and EC, expecting two following bytes.";
|
"following bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 3;
|
i += 3;
|
||||||
}
|
} else if (str[i] == 0xED) /* ED 80..9F 80..BF */ {
|
||||||
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) {
|
||||||
if (i + 2 < len) /* Expect a 2nd and 3rd byte */
|
*message
|
||||||
{
|
= "After a first byte of ED, expecting 2nd byte "
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0x9F)
|
"between 80 and 9F.";
|
||||||
{
|
|
||||||
*message = "After a first byte of ED, expecting 2nd byte between 80 and 9F.";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of ED, expecting 3rd byte between 80 and BF.";
|
= "After a first byte of ED, expecting 3rd byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte of ED, expecting two following "
|
||||||
*message = "After a first byte of ED, expecting two following bytes.";
|
"bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 3;
|
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 (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
|
||||||
{
|
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
|
*message
|
||||||
{
|
= "After a first byte between EE and EF, expecting 2nd "
|
||||||
*message = "After a first byte between EE and EF, expecting 2nd byte between 80 and BF.";
|
"byte between 80 and BF.";
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte between EE and EF, expecting 3rd byte between 80 and BF.";
|
= "After a first byte between EE and EF, expecting 3rd "
|
||||||
|
"byte between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte between EE and EF, two following "
|
||||||
*message = "After a first byte between EE and EF, two following bytes.";
|
"bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 3;
|
i += 3;
|
||||||
}
|
} else if (str[i] == 0xF0) /* F0 90..BF 80..BF 80..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) {
|
||||||
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
|
*message
|
||||||
{
|
= "After a first byte of F0, expecting 2nd byte "
|
||||||
if (str[i + 1] < 0x90 || str[i + 1] > 0xBF)
|
"between 90 and BF.";
|
||||||
{
|
|
||||||
*message = "After a first byte of F0, expecting 2nd byte between 90 and BF.";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F0, expecting 3rd byte between 80 and BF.";
|
= "After a first byte of F0, expecting 3rd byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
|
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F0, expecting 4th byte between 80 and BF.";
|
= "After a first byte of F0, expecting 4th byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 4;
|
*faulty_bytes = 4;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte of F0, expecting three following "
|
||||||
*message = "After a first byte of F0, expecting three following bytes.";
|
"bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
} else if (str[i] >= 0xF1
|
||||||
else if (str[i] >= 0xF1 && str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */
|
&& str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */ {
|
||||||
{
|
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
|
||||||
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
|
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
|
||||||
{
|
*message
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF)
|
= "After a first byte of F1, F2, or F3, expecting a "
|
||||||
{
|
"2nd byte between 80 and BF.";
|
||||||
*message = "After a first byte of F1, F2, or F3, expecting a 2nd byte between 80 and BF.";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F1, F2, or F3, expecting a 3rd byte between 80 and BF.";
|
= "After a first byte of F1, F2, or F3, expecting a "
|
||||||
|
"3rd byte between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
|
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F1, F2, or F3, expecting a 4th byte between 80 and BF.";
|
= "After a first byte of F1, F2, or F3, expecting a "
|
||||||
|
"4th byte between 80 and BF.";
|
||||||
*faulty_bytes = 4;
|
*faulty_bytes = 4;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte of F1, F2, or F3, expecting three "
|
||||||
*message = "After a first byte of F1, F2, or F3, expecting three following bytes.";
|
"following bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
} else if (str[i] == 0xF4) /* F4 80..8F 80..BF 80..BF */ {
|
||||||
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) {
|
||||||
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */
|
*message
|
||||||
{
|
= "After a first byte of F4, expecting 2nd byte "
|
||||||
if (str[i + 1] < 0x80 || str[i + 1] > 0x8F)
|
"between 80 and 8F.";
|
||||||
{
|
|
||||||
*message = "After a first byte of F4, expecting 2nd byte between 80 and 8F.";
|
|
||||||
*faulty_bytes = 2;
|
*faulty_bytes = 2;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF)
|
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F4, expecting 3rd byte between 80 and BF.";
|
= "After a first byte of F4, expecting 3rd byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 3;
|
*faulty_bytes = 3;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF)
|
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
|
||||||
{
|
*message
|
||||||
*message = "After a first byte of F4, expecting 4th byte between 80 and BF.";
|
= "After a first byte of F4, expecting 4th byte "
|
||||||
|
"between 80 and BF.";
|
||||||
*faulty_bytes = 4;
|
*faulty_bytes = 4;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "After a first byte of F4, expecting three following "
|
||||||
*message = "After a first byte of F4, expecting three following bytes.";
|
"bytes.";
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
} else {
|
||||||
else
|
*message
|
||||||
{
|
= "Expecting bytes in the following ranges: 00..7F C2..F4.";
|
||||||
*message = "Expecting bytes in the following ranges: 00..7F C2..F4.";
|
|
||||||
*faulty_bytes = 1;
|
*faulty_bytes = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,12 @@
|
|||||||
#ifndef _IS_UTF8_H
|
#ifndef _IS_UTF8_H
|
||||||
#define _IS_UTF8_H
|
#define _IS_UTF8_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.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 */
|
#endif /* _IS_UTF8_H */
|
||||||
|
@ -21,30 +21,32 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file isc.cc
|
* @file isc.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "isc.hh"
|
#include "isc.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
|
|
||||||
void service_base::start()
|
void
|
||||||
|
service_base::start()
|
||||||
{
|
{
|
||||||
log_debug("starting service thread for: %s", this->s_name.c_str());
|
log_debug("starting service thread for: %s", this->s_name.c_str());
|
||||||
this->s_thread = std::thread(&service_base::run, this);
|
this->s_thread = std::thread(&service_base::run, this);
|
||||||
this->s_started = true;
|
this->s_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *service_base::run()
|
void*
|
||||||
|
service_base::run()
|
||||||
{
|
{
|
||||||
log_info("BEGIN isc thread: %s", this->s_name.c_str());
|
log_info("BEGIN isc thread: %s", this->s_name.c_str());
|
||||||
while (this->s_looping) {
|
while (this->s_looping) {
|
||||||
@ -66,7 +68,8 @@ void *service_base::run()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_base::stop()
|
void
|
||||||
|
service_base::stop()
|
||||||
{
|
{
|
||||||
if (this->s_started) {
|
if (this->s_started) {
|
||||||
log_debug("stopping service thread: %s", this->s_name.c_str());
|
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)
|
supervisor::supervisor(service_list servs, service_base* parent)
|
||||||
: s_service_list(std::move(servs)), s_parent(parent) {
|
: s_service_list(std::move(servs)), s_parent(parent)
|
||||||
|
{
|
||||||
for (auto& serv : this->s_service_list) {
|
for (auto& serv : this->s_service_list) {
|
||||||
serv->start();
|
serv->start();
|
||||||
}
|
}
|
||||||
@ -93,7 +97,8 @@ supervisor::~supervisor()
|
|||||||
this->stop_children();
|
this->stop_children();
|
||||||
}
|
}
|
||||||
|
|
||||||
void supervisor::stop_children()
|
void
|
||||||
|
supervisor::stop_children()
|
||||||
{
|
{
|
||||||
for (auto& serv : this->s_service_list) {
|
for (auto& serv : this->s_service_list) {
|
||||||
serv->stop();
|
serv->stop();
|
||||||
@ -101,29 +106,31 @@ void supervisor::stop_children()
|
|||||||
this->cleanup_children();
|
this->cleanup_children();
|
||||||
}
|
}
|
||||||
|
|
||||||
void supervisor::cleanup_children()
|
void
|
||||||
|
supervisor::cleanup_children()
|
||||||
{
|
{
|
||||||
this->s_service_list.erase(
|
this->s_service_list.erase(
|
||||||
std::remove_if(
|
std::remove_if(this->s_service_list.begin(),
|
||||||
this->s_service_list.begin(), this->s_service_list.end(),
|
this->s_service_list.end(),
|
||||||
[this](auto &child) {
|
[this](auto& child) {
|
||||||
if (child->is_looping()) {
|
if (child->is_looping()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
child->stop();
|
child->stop();
|
||||||
if (this->s_parent != nullptr) {
|
if (this->s_parent != nullptr) {
|
||||||
this->s_parent->child_finished(child);
|
this->s_parent->child_finished(child);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
this->s_service_list.end());
|
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);
|
this->s_service_list.emplace_back(new_service);
|
||||||
new_service->start();
|
new_service->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace isc
|
||||||
|
103
src/base/isc.hh
103
src/base/isc.hh
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -30,19 +30,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <condition_variable>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "injector.hh"
|
#include "injector.hh"
|
||||||
#include "time_util.hh"
|
|
||||||
#include "safe/safe.h"
|
#include "safe/safe.h"
|
||||||
|
#include "time_util.hh"
|
||||||
|
|
||||||
#ifndef lnav_isc_hh
|
#ifndef lnav_isc_hh
|
||||||
#define lnav_isc_hh
|
# define lnav_isc_hh
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
|
|
||||||
@ -50,28 +50,33 @@ struct msg {
|
|||||||
std::function<void()> m_callback;
|
std::function<void()> m_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline msg empty_msg() {
|
inline msg
|
||||||
return { []() { } };
|
empty_msg()
|
||||||
|
{
|
||||||
|
return {[]() {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
class msg_port {
|
class msg_port {
|
||||||
public:
|
public:
|
||||||
msg_port() = default;
|
msg_port() = default;
|
||||||
|
|
||||||
void send(msg&& m) {
|
void send(msg&& m)
|
||||||
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);
|
||||||
|
|
||||||
writable_msgs->emplace_back(m);
|
writable_msgs->emplace_back(m);
|
||||||
this->sp_cond.notify_all();
|
this->sp_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Rep, class Period>
|
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;
|
std::deque<msg> tmp_msgs;
|
||||||
|
|
||||||
{
|
{
|
||||||
safe::WriteAccess<safe_message_list, std::unique_lock> writable_msgs(
|
safe::WriteAccess<safe_message_list, std::unique_lock>
|
||||||
this->mp_messages);
|
writable_msgs(this->mp_messages);
|
||||||
|
|
||||||
if (writable_msgs->empty()) {
|
if (writable_msgs->empty()) {
|
||||||
this->sp_cond.template wait_for(writable_msgs.lock, rel_time);
|
this->sp_cond.template wait_for(writable_msgs.lock, rel_time);
|
||||||
@ -80,12 +85,13 @@ public:
|
|||||||
tmp_msgs.swap(*writable_msgs);
|
tmp_msgs.swap(*writable_msgs);
|
||||||
}
|
}
|
||||||
while (!tmp_msgs.empty()) {
|
while (!tmp_msgs.empty()) {
|
||||||
auto &m = tmp_msgs.front();
|
auto& m = tmp_msgs.front();
|
||||||
|
|
||||||
m.m_callback();
|
m.m_callback();
|
||||||
tmp_msgs.pop_front();
|
tmp_msgs.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using message_list = std::deque<msg>;
|
using message_list = std::deque<msg>;
|
||||||
using safe_message_list = safe::Safe<message_list>;
|
using safe_message_list = safe::Safe<message_list>;
|
||||||
@ -99,11 +105,12 @@ using service_list = std::vector<std::shared_ptr<service_base>>;
|
|||||||
|
|
||||||
struct supervisor {
|
struct supervisor {
|
||||||
explicit supervisor(service_list servs = {},
|
explicit supervisor(service_list servs = {},
|
||||||
service_base *parent = nullptr);
|
service_base* parent = nullptr);
|
||||||
|
|
||||||
~supervisor();
|
~supervisor();
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return this->s_service_list.empty();
|
return this->s_service_list.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,39 +119,46 @@ struct supervisor {
|
|||||||
void stop_children();
|
void stop_children();
|
||||||
|
|
||||||
void cleanup_children();
|
void cleanup_children();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
service_list s_service_list;
|
service_list s_service_list;
|
||||||
service_base *s_parent;
|
service_base* s_parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
class service_base : public std::enable_shared_from_this<service_base> {
|
class service_base : public std::enable_shared_from_this<service_base> {
|
||||||
public:
|
public:
|
||||||
explicit service_base(std::string name)
|
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;
|
virtual ~service_base() = default;
|
||||||
|
|
||||||
bool is_looping() const {
|
bool is_looping() const
|
||||||
|
{
|
||||||
return this->s_looping;
|
return this->s_looping;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_port& get_port() {
|
msg_port& get_port()
|
||||||
|
{
|
||||||
return this->s_port;
|
return this->s_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend supervisor;
|
friend supervisor;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void *run();
|
virtual void* run();
|
||||||
virtual void loop_body() {};
|
virtual void loop_body(){};
|
||||||
virtual void child_finished(std::shared_ptr<service_base> child) {};
|
virtual void child_finished(std::shared_ptr<service_base> child){};
|
||||||
virtual void stopped() {};
|
virtual void stopped(){};
|
||||||
virtual std::chrono::milliseconds compute_timeout(mstime_t current_time) const {
|
virtual std::chrono::milliseconds compute_timeout(
|
||||||
|
mstime_t current_time) const
|
||||||
|
{
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
return 1s;
|
return 1s;
|
||||||
@ -162,36 +176,37 @@ template<typename T>
|
|||||||
class service : public service_base {
|
class service : public service_base {
|
||||||
public:
|
public:
|
||||||
explicit service(std::string sub_name = "")
|
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>
|
template<typename F>
|
||||||
void send(F msg) {
|
void send(F msg)
|
||||||
this->s_port.send({
|
{
|
||||||
[lifetime = this->shared_from_this(), this, msg]() {
|
this->s_port.send({[lifetime = this->shared_from_this(), this, msg]() {
|
||||||
msg(*(static_cast<T *>(this)));
|
msg(*(static_cast<T*>(this)));
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, class Rep, class Period>
|
template<typename F, class Rep, class Period>
|
||||||
void send_and_wait(F msg,
|
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;
|
msg_port reply_port;
|
||||||
|
|
||||||
this->s_port.send({
|
this->s_port.send(
|
||||||
[lifetime = this->shared_from_this(), this, &reply_port, msg]() {
|
{[lifetime = this->shared_from_this(), this, &reply_port, msg]() {
|
||||||
msg(*(static_cast<T *>(this)));
|
msg(*(static_cast<T*>(this)));
|
||||||
reply_port.send(empty_msg());
|
reply_port.send(empty_msg());
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
reply_port.template process_for(rel_time);
|
reply_port.template process_for(rel_time);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Service, typename...Annotations>
|
template<typename T, typename Service, typename... Annotations>
|
||||||
struct to {
|
struct to {
|
||||||
void send(std::function<void(T&)> cb) {
|
void send(std::function<void(T&)> cb)
|
||||||
|
{
|
||||||
auto& service = injector::get<T&, Service>();
|
auto& service = injector::get<T&, Service>();
|
||||||
|
|
||||||
service.send(cb);
|
service.send(cb);
|
||||||
@ -199,19 +214,21 @@ struct to {
|
|||||||
|
|
||||||
template<class Rep, class Period>
|
template<class Rep, class Period>
|
||||||
void send_and_wait(std::function<void(T)> cb,
|
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>();
|
auto& service = injector::get<T&, Service>();
|
||||||
|
|
||||||
service.send_and_wait(cb, rel_time);
|
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;
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
this->send_and_wait(cb, 48h);
|
this->send_and_wait(cb, 48h);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace isc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,30 +21,32 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file lnav.gzip.cc
|
* @file lnav.gzip.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "lnav.gzip.hh"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "lnav.gzip.hh"
|
|
||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace gzip {
|
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';
|
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);
|
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.zalloc = Z_NULL;
|
||||||
zs.zfree = Z_NULL;
|
zs.zfree = Z_NULL;
|
||||||
zs.opaque = Z_NULL;
|
zs.opaque = Z_NULL;
|
||||||
zs.avail_in = (uInt)len;
|
zs.avail_in = (uInt) len;
|
||||||
zs.next_in = (Bytef *)input;
|
zs.next_in = (Bytef*) input;
|
||||||
zs.avail_out = (uInt)retval.size();
|
zs.avail_out = (uInt) retval.size();
|
||||||
zs.next_out = (Bytef *)retval.in();
|
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) {
|
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);
|
rc = deflate(&zs, Z_FINISH);
|
||||||
if (rc != Z_STREAM_END) {
|
if (rc != Z_STREAM_END) {
|
||||||
@ -67,20 +71,20 @@ Result<auto_buffer, std::string> compress(const void* input, size_t len)
|
|||||||
}
|
}
|
||||||
rc = deflateEnd(&zs);
|
rc = deflateEnd(&zs);
|
||||||
if (rc != Z_OK) {
|
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)));
|
return Ok(std::move(retval.shrink_to(zs.total_out)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<auto_buffer, std::string> uncompress(const std::string& src,
|
Result<auto_buffer, std::string>
|
||||||
const void *buffer,
|
uncompress(const std::string& src, const void* buffer, size_t size)
|
||||||
size_t size)
|
|
||||||
{
|
{
|
||||||
auto uncomp = auto_buffer::alloc(size * 2);
|
auto uncomp = auto_buffer::alloc(size * 2);
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
strm.next_in = (Bytef *) buffer;
|
strm.next_in = (Bytef*) buffer;
|
||||||
strm.avail_in = size;
|
strm.avail_in = size;
|
||||||
strm.total_out = 0;
|
strm.total_out = 0;
|
||||||
strm.zalloc = Z_NULL;
|
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) {
|
if ((err = inflateInit2(&strm, (16 + MAX_WBITS))) != Z_OK) {
|
||||||
return Err(fmt::format("invalid gzip data: {} -- {}",
|
return Err(fmt::format("invalid gzip data: {} -- {}",
|
||||||
src, strm.msg ? strm.msg : zError(err)));
|
src,
|
||||||
|
strm.msg ? strm.msg : zError(err)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
@ -98,7 +103,7 @@ Result<auto_buffer, std::string> uncompress(const std::string& src,
|
|||||||
uncomp.expand_by(size / 2);
|
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;
|
strm.avail_out = uncomp.size() - strm.total_out;
|
||||||
|
|
||||||
// Inflate another chunk.
|
// Inflate another chunk.
|
||||||
@ -108,17 +113,19 @@ Result<auto_buffer, std::string> uncompress(const std::string& src,
|
|||||||
} else if (err != Z_OK) {
|
} else if (err != Z_OK) {
|
||||||
inflateEnd(&strm);
|
inflateEnd(&strm);
|
||||||
return Err(fmt::format("unable to uncompress: {} -- {}",
|
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) {
|
if (inflateEnd(&strm) != Z_OK) {
|
||||||
return Err(fmt::format("unable to uncompress: {} -- {}",
|
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)));
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -40,15 +40,15 @@
|
|||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace gzip {
|
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,
|
Result<auto_buffer, std::string> uncompress(const std::string& src,
|
||||||
const void *buffer,
|
const void* buffer,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
}
|
} // namespace gzip
|
||||||
}
|
} // namespace lnav
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,35 +21,35 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <zlib.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "doctest/doctest.h"
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "base/lnav.gzip.hh"
|
#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);
|
auto u_res = lnav::gzip::uncompress("empty", nullptr, 0);
|
||||||
|
|
||||||
CHECK(u_res.isErr());
|
CHECK(u_res.isErr());
|
||||||
CHECK(u_res.unwrapErr() ==
|
CHECK(u_res.unwrapErr()
|
||||||
"unable to uncompress: empty -- buffer error");
|
== "unable to uncompress: empty -- buffer error");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto u_res = lnav::gzip::uncompress("garbage", "abc", 3);
|
auto u_res = lnav::gzip::uncompress("garbage", "abc", 3);
|
||||||
|
|
||||||
CHECK(u_res.isErr());
|
CHECK(u_res.isErr());
|
||||||
CHECK(u_res.unwrapErr() ==
|
CHECK(u_res.unwrapErr()
|
||||||
"unable to uncompress: garbage -- incorrect header check");
|
== "unable to uncompress: garbage -- incorrect header check");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,101 +21,104 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file lnav_log.cc
|
* @file lnav_log.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include <assert.h>
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <signal.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef HAVE_EXECINFO_H
|
#ifdef HAVE_EXECINFO_H
|
||||||
#include <execinfo.h>
|
# include <execinfo.h>
|
||||||
#endif
|
#endif
|
||||||
#if BACKWARD_HAS_DW == 1
|
#if BACKWARD_HAS_DW == 1
|
||||||
#include "backward-cpp/backward.hpp"
|
# include "backward-cpp/backward.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <algorithm>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/utsname.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#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
|
#ifdef HAVE_PCRE_H
|
||||||
#include <pcre.h>
|
# include <pcre.h>
|
||||||
#elif HAVE_PCRE_PCRE_H
|
#elif HAVE_PCRE_PCRE_H
|
||||||
#include <pcre/pcre.h>
|
# include <pcre/pcre.h>
|
||||||
#else
|
#else
|
||||||
#error "pcre.h not found?"
|
# error "pcre.h not found?"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined HAVE_NCURSESW_CURSES_H
|
#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
|
#elif defined HAVE_NCURSESW_H
|
||||||
# include <termcap.h>
|
# include <ncursesw.h>
|
||||||
# include <ncursesw.h>
|
# include <termcap.h>
|
||||||
#elif defined HAVE_NCURSES_CURSES_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
|
#elif defined HAVE_NCURSES_H
|
||||||
# include <termcap.h>
|
# include <ncurses.h>
|
||||||
# include <ncurses.h>
|
# include <termcap.h>
|
||||||
#elif defined HAVE_CURSES_H
|
#elif defined HAVE_CURSES_H
|
||||||
# include <termcap.h>
|
# include <curses.h>
|
||||||
# include <curses.h>
|
# include <termcap.h>
|
||||||
#else
|
#else
|
||||||
# error "SysV or X/Open-compatible Curses header file required"
|
# error "SysV or X/Open-compatible Curses header file required"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "opt_util.hh"
|
|
||||||
#include "lnav_log.hh"
|
|
||||||
#include "enum_util.hh"
|
|
||||||
#include "auto_mem.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 BUFFER_SIZE = 256 * 1024;
|
||||||
static const size_t MAX_LOG_LINE_SIZE = 2048;
|
static const size_t MAX_LOG_LINE_SIZE = 2048;
|
||||||
|
|
||||||
static const char *CRASH_MSG =
|
static const char* CRASH_MSG
|
||||||
"\n"
|
= "\n"
|
||||||
"\n"
|
"\n"
|
||||||
"==== GURU MEDITATION ====\n"
|
"==== GURU MEDITATION ====\n"
|
||||||
"Unfortunately, lnav has crashed, sorry for the inconvenience.\n"
|
"Unfortunately, lnav has crashed, sorry for the inconvenience.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"You can help improve lnav by sending the following file to " PACKAGE_BUGREPORT " :\n"
|
"You can help improve lnav by sending the following file "
|
||||||
" %s\n"
|
"to " PACKAGE_BUGREPORT
|
||||||
"=========================\n";
|
" :\n"
|
||||||
|
" %s\n"
|
||||||
|
"=========================\n";
|
||||||
|
|
||||||
nonstd::optional<FILE *> lnav_log_file;
|
nonstd::optional<FILE*> lnav_log_file;
|
||||||
lnav_log_level_t lnav_log_level = lnav_log_level_t::DEBUG;
|
lnav_log_level_t lnav_log_level = lnav_log_level_t::DEBUG;
|
||||||
const char *lnav_log_crash_dir;
|
const char* lnav_log_crash_dir;
|
||||||
nonstd::optional<const struct termios *> lnav_log_orig_termios;
|
nonstd::optional<const struct termios*> lnav_log_orig_termios;
|
||||||
// NOTE: This mutex is leaked so that it is not destroyed during exit.
|
// NOTE: This mutex is leaked so that it is not destroyed during exit.
|
||||||
// Otherwise, any attempts to log will fail.
|
// 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;
|
static std::vector<log_state_dumper*> retval;
|
||||||
|
|
||||||
@ -141,14 +144,9 @@ static struct {
|
|||||||
off_t lr_frag_start;
|
off_t lr_frag_start;
|
||||||
off_t lr_frag_end;
|
off_t lr_frag_end;
|
||||||
char lr_data[BUFFER_SIZE];
|
char lr_data[BUFFER_SIZE];
|
||||||
} log_ring = {
|
} log_ring = {0, BUFFER_SIZE, 0, {}};
|
||||||
0,
|
|
||||||
BUFFER_SIZE,
|
|
||||||
0,
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *LEVEL_NAMES[] = {
|
static const char* LEVEL_NAMES[] = {
|
||||||
"T",
|
"T",
|
||||||
"D",
|
"D",
|
||||||
"I",
|
"I",
|
||||||
@ -156,38 +154,40 @@ static const char *LEVEL_NAMES[] = {
|
|||||||
"E",
|
"E",
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *log_alloc()
|
static char*
|
||||||
|
log_alloc()
|
||||||
{
|
{
|
||||||
off_t data_end = log_ring.lr_length + MAX_LOG_LINE_SIZE;
|
off_t data_end = log_ring.lr_length + MAX_LOG_LINE_SIZE;
|
||||||
|
|
||||||
if (data_end >= (off_t)BUFFER_SIZE) {
|
if (data_end >= (off_t) BUFFER_SIZE) {
|
||||||
const char *new_start = &log_ring.lr_data[MAX_LOG_LINE_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);
|
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_start = new_start - log_ring.lr_data;
|
||||||
log_ring.lr_frag_end = log_ring.lr_length;
|
log_ring.lr_frag_end = log_ring.lr_length;
|
||||||
log_ring.lr_length = 0;
|
log_ring.lr_length = 0;
|
||||||
|
|
||||||
assert(log_ring.lr_frag_start >= 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) {
|
} 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);
|
new_start, '\n', log_ring.lr_frag_end - log_ring.lr_frag_start);
|
||||||
assert(new_start != nullptr);
|
assert(new_start != nullptr);
|
||||||
log_ring.lr_frag_start = new_start - log_ring.lr_data;
|
log_ring.lr_frag_start = new_start - log_ring.lr_data;
|
||||||
assert(log_ring.lr_frag_start >= 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return &log_ring.lr_data[log_ring.lr_length];
|
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) {
|
if (log_path != nullptr) {
|
||||||
lnav_log_file = make_optional_from_nullable(fopen(log_path, "a"));
|
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);
|
// thread_log_prefix = std::move(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_host_info()
|
void
|
||||||
|
log_host_info()
|
||||||
{
|
{
|
||||||
char cwd[MAXPATHLEN];
|
char cwd[MAXPATHLEN];
|
||||||
const char *jittarget;
|
const char* jittarget;
|
||||||
struct utsname un;
|
struct utsname un;
|
||||||
struct rusage ru;
|
struct rusage ru;
|
||||||
int pcre_jit;
|
int pcre_jit;
|
||||||
@ -242,8 +244,7 @@ void log_host_info()
|
|||||||
log_info(" egid=%d", getegid());
|
log_info(" egid=%d", getegid());
|
||||||
if (getcwd(cwd, sizeof(cwd)) == nullptr) {
|
if (getcwd(cwd, sizeof(cwd)) == nullptr) {
|
||||||
log_info(" ERROR: getcwd failed");
|
log_info(" ERROR: getcwd failed");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
log_info(" cwd=%s", cwd);
|
log_info(" cwd=%s", cwd);
|
||||||
}
|
}
|
||||||
log_info("Executable:");
|
log_info("Executable:");
|
||||||
@ -253,13 +254,25 @@ void log_host_info()
|
|||||||
log_rusage(lnav_log_level_t::INFO, ru);
|
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, "rusage:");
|
||||||
log_msg(level, src_file, line_number, " utime=%d.%06d",
|
log_msg(level,
|
||||||
ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
|
src_file,
|
||||||
log_msg(level, src_file, line_number, " stime=%d.%06d",
|
line_number,
|
||||||
ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
|
" 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, " maxrss=%ld", ru.ru_maxrss);
|
||||||
log_msg(level, src_file, line_number, " ixrss=%ld", ru.ru_ixrss);
|
log_msg(level, src_file, line_number, " ixrss=%ld", ru.ru_ixrss);
|
||||||
log_msg(level, src_file, line_number, " idrss=%ld", ru.ru_idrss);
|
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);
|
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,
|
void
|
||||||
const char *fmt, ...)
|
log_msg(lnav_log_level_t level,
|
||||||
|
const char* src_file,
|
||||||
|
int line_number,
|
||||||
|
const char* fmt,
|
||||||
|
...)
|
||||||
{
|
{
|
||||||
struct timeval curr_time;
|
struct timeval curr_time;
|
||||||
struct tm localtm;
|
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
|
// get the base name of the file. NB: can't use basename() since it
|
||||||
// can modify its argument
|
// can modify its argument
|
||||||
const char *last_slash = src_file;
|
const char* last_slash = src_file;
|
||||||
|
|
||||||
for (int lpc = 0; src_file[lpc]; lpc++) {
|
for (int lpc = 0; src_file[lpc]; lpc++) {
|
||||||
if (src_file[lpc] == '/' || src_file[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);
|
gettimeofday(&curr_time, nullptr);
|
||||||
localtime_r(&curr_time.tv_sec, &localtm);
|
localtime_r(&curr_time.tv_sec, &localtm);
|
||||||
auto line = log_alloc();
|
auto line = log_alloc();
|
||||||
prefix_size = snprintf(
|
prefix_size = snprintf(line,
|
||||||
line, MAX_LOG_LINE_SIZE,
|
MAX_LOG_LINE_SIZE,
|
||||||
"%4d-%02d-%02dT%02d:%02d:%02d.%03d %s t%u %s:%d ",
|
"%4d-%02d-%02dT%02d:%02d:%02d.%03d %s t%u %s:%d ",
|
||||||
localtm.tm_year + 1900,
|
localtm.tm_year + 1900,
|
||||||
localtm.tm_mon + 1,
|
localtm.tm_mon + 1,
|
||||||
localtm.tm_mday,
|
localtm.tm_mday,
|
||||||
localtm.tm_hour,
|
localtm.tm_hour,
|
||||||
localtm.tm_min,
|
localtm.tm_min,
|
||||||
localtm.tm_sec,
|
localtm.tm_sec,
|
||||||
(int)(curr_time.tv_usec / 1000),
|
(int) (curr_time.tv_usec / 1000),
|
||||||
LEVEL_NAMES[lnav::enums::to_underlying(level)],
|
LEVEL_NAMES[lnav::enums::to_underlying(level)],
|
||||||
current_thid.t_id,
|
current_thid.t_id,
|
||||||
src_file,
|
src_file,
|
||||||
line_number);
|
line_number);
|
||||||
#if 0
|
#if 0
|
||||||
if (!thread_log_prefix.empty()) {
|
if (!thread_log_prefix.empty()) {
|
||||||
prefix_size += snprintf(
|
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());
|
thread_log_prefix.c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
rc = vsnprintf(&line[prefix_size], MAX_LOG_LINE_SIZE - prefix_size,
|
rc = vsnprintf(
|
||||||
fmt, args);
|
&line[prefix_size], MAX_LOG_LINE_SIZE - prefix_size, fmt, args);
|
||||||
if (rc >= (ssize_t)(MAX_LOG_LINE_SIZE - prefix_size)) {
|
if (rc >= (ssize_t) (MAX_LOG_LINE_SIZE - prefix_size)) {
|
||||||
rc = MAX_LOG_LINE_SIZE - prefix_size - 1;
|
rc = MAX_LOG_LINE_SIZE - prefix_size - 1;
|
||||||
}
|
}
|
||||||
line[prefix_size + rc] = '\n';
|
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);
|
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);
|
std::lock_guard<std::mutex> mg(*lnav_log_mutex);
|
||||||
va_list args;
|
va_list args;
|
||||||
@ -361,7 +379,8 @@ void log_msg_extra(const char *fmt, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_msg_extra_complete()
|
void
|
||||||
|
log_msg_extra_complete()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> mg(*lnav_log_mutex);
|
std::lock_guard<std::mutex> mg(*lnav_log_mutex);
|
||||||
auto line = log_alloc();
|
auto line = log_alloc();
|
||||||
@ -375,13 +394,14 @@ void log_msg_extra_complete()
|
|||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
#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];
|
char crash_path[1024], latest_crash_path[1024];
|
||||||
int fd;
|
int fd;
|
||||||
#ifdef HAVE_EXECINFO_H
|
#ifdef HAVE_EXECINFO_H
|
||||||
int frame_count;
|
int frame_count;
|
||||||
void *frames[128];
|
void* frames[128];
|
||||||
#endif
|
#endif
|
||||||
struct tm localtm;
|
struct tm localtm;
|
||||||
time_t curr_time;
|
time_t curr_time;
|
||||||
@ -398,45 +418,53 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
|
|||||||
#endif
|
#endif
|
||||||
curr_time = time(nullptr);
|
curr_time = time(nullptr);
|
||||||
localtime_r(&curr_time, &localtm);
|
localtime_r(&curr_time, &localtm);
|
||||||
snprintf(crash_path, sizeof(crash_path),
|
snprintf(crash_path,
|
||||||
"%s/crash-%4d-%02d-%02d-%02d-%02d-%02d.%d.log",
|
sizeof(crash_path),
|
||||||
lnav_log_crash_dir,
|
"%s/crash-%4d-%02d-%02d-%02d-%02d-%02d.%d.log",
|
||||||
localtm.tm_year + 1900,
|
lnav_log_crash_dir,
|
||||||
localtm.tm_mon + 1,
|
localtm.tm_year + 1900,
|
||||||
localtm.tm_mday,
|
localtm.tm_mon + 1,
|
||||||
localtm.tm_hour,
|
localtm.tm_mday,
|
||||||
localtm.tm_min,
|
localtm.tm_hour,
|
||||||
localtm.tm_sec,
|
localtm.tm_min,
|
||||||
getpid());
|
localtm.tm_sec,
|
||||||
snprintf(latest_crash_path, sizeof(latest_crash_path),
|
getpid());
|
||||||
"%s/latest-crash.log", lnav_log_crash_dir);
|
snprintf(latest_crash_path,
|
||||||
if ((fd = open(crash_path, O_CREAT|O_TRUNC|O_RDWR, 0600)) != -1) {
|
sizeof(latest_crash_path),
|
||||||
if (log_ring.lr_frag_start < (off_t)BUFFER_SIZE) {
|
"%s/latest-crash.log",
|
||||||
(void)write(fd, &log_ring.lr_data[log_ring.lr_frag_start],
|
lnav_log_crash_dir);
|
||||||
log_ring.lr_frag_end - log_ring.lr_frag_start);
|
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
|
#ifdef HAVE_EXECINFO_H
|
||||||
backtrace_symbols_fd(frames, frame_count, fd);
|
backtrace_symbols_fd(frames, frame_count, fd);
|
||||||
#endif
|
#endif
|
||||||
#if BACKWARD_HAS_DW == 1
|
#if BACKWARD_HAS_DW == 1
|
||||||
{
|
{
|
||||||
ucontext_t *uctx = static_cast<ucontext_t *>(ctx);
|
ucontext_t* uctx = static_cast<ucontext_t*>(ctx);
|
||||||
void *error_addr = nullptr;
|
void* error_addr = nullptr;
|
||||||
|
|
||||||
#ifdef REG_RIP // x86_64
|
# ifdef REG_RIP // x86_64
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_RIP]);
|
error_addr
|
||||||
#elif defined(REG_EIP) // x86_32
|
= reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_EIP]);
|
# elif defined(REG_EIP) // x86_32
|
||||||
#endif
|
error_addr
|
||||||
|
= reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
|
||||||
|
# endif
|
||||||
|
|
||||||
backward::StackTrace st;
|
backward::StackTrace st;
|
||||||
|
|
||||||
if (error_addr) {
|
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);
|
info->si_addr);
|
||||||
} else {
|
} 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;
|
backward::TraceResolver tr;
|
||||||
|
|
||||||
@ -445,7 +473,8 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
|
|||||||
auto trace = tr.resolve(st[lpc]);
|
auto trace = tr.resolve(st[lpc]);
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf,
|
||||||
|
sizeof(buf),
|
||||||
"Frame %lu:%s:%s (%s:%d)\n",
|
"Frame %lu:%s:%s (%s:%d)\n",
|
||||||
lpc,
|
lpc,
|
||||||
trace.object_filename.c_str(),
|
trace.object_filename.c_str(),
|
||||||
@ -466,9 +495,10 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
|
|||||||
lsd->log_state();
|
lsd->log_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_ring.lr_frag_start < (off_t)BUFFER_SIZE) {
|
if (log_ring.lr_frag_start < (off_t) BUFFER_SIZE) {
|
||||||
write(fd, &log_ring.lr_data[log_ring.lr_frag_start],
|
write(fd,
|
||||||
log_ring.lr_frag_end - log_ring.lr_frag_start);
|
&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);
|
write(fd, log_ring.lr_data, log_ring.lr_length);
|
||||||
if (getenv("DUMP_CRASH") != nullptr) {
|
if (getenv("DUMP_CRASH") != nullptr) {
|
||||||
@ -530,7 +560,6 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
while (wait(&status) < 0) {
|
while (wait(&status) < 0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -543,7 +572,8 @@ static void sigabrt(int sig, siginfo_t *info, void *ctx)
|
|||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
void log_install_handlers()
|
void
|
||||||
|
log_install_handlers()
|
||||||
{
|
{
|
||||||
const size_t stack_size = 8 * 1024 * 1024;
|
const size_t stack_size = 8 * 1024 * 1024;
|
||||||
const int sigs[] = {
|
const int sigs[] = {
|
||||||
@ -575,15 +605,17 @@ void log_install_handlers()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_abort()
|
void
|
||||||
|
log_abort()
|
||||||
{
|
{
|
||||||
raise(SIGABRT);
|
raise(SIGABRT);
|
||||||
_exit(1);
|
_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];
|
char buffer[1024];
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
@ -596,8 +628,7 @@ void log_pipe_err(int fd)
|
|||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
while (buffer[rc - 1] == '\n' ||
|
while (buffer[rc - 1] == '\n' || buffer[rc - 1] == '\r') {
|
||||||
buffer[rc - 1] == '\r') {
|
|
||||||
rc -= 1;
|
rc -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,13 +32,14 @@
|
|||||||
#ifndef lnav_log_hh
|
#ifndef lnav_log_hh
|
||||||
#define lnav_log_hh
|
#define lnav_log_hh
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifndef lnav_dead2
|
#ifndef lnav_dead2
|
||||||
#define lnav_dead2 __attribute__((noreturn))
|
# define lnav_dead2 __attribute__((noreturn))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "optional.hpp"
|
#include "optional.hpp"
|
||||||
@ -53,12 +54,18 @@ enum class lnav_log_level_t : uint32_t {
|
|||||||
ERROR,
|
ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
void log_argv(int argc, char *argv[]);
|
void log_argv(int argc, char* argv[]);
|
||||||
void log_host_info();
|
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_rusage_raw(enum lnav_log_level_t level,
|
||||||
void log_msg(enum lnav_log_level_t level, const char *src_file, int line_number,
|
const char* src_file,
|
||||||
const char *fmt, ...);
|
int line_number,
|
||||||
void log_msg_extra(const char *fmt, ...);
|
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_msg_extra_complete();
|
||||||
void log_install_handlers();
|
void log_install_handlers();
|
||||||
void log_abort() lnav_dead2;
|
void log_abort() lnav_dead2;
|
||||||
@ -71,7 +78,7 @@ public:
|
|||||||
|
|
||||||
virtual ~log_state_dumper();
|
virtual ~log_state_dumper();
|
||||||
|
|
||||||
virtual void log_state() {
|
virtual void log_state(){
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,9 +95,9 @@ public:
|
|||||||
virtual void log_crash_recover() = 0;
|
virtual void log_crash_recover() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern nonstd::optional<FILE *> lnav_log_file;
|
extern nonstd::optional<FILE*> lnav_log_file;
|
||||||
extern const char *lnav_log_crash_dir;
|
extern const char* lnav_log_crash_dir;
|
||||||
extern nonstd::optional<const struct termios *> lnav_log_orig_termios;
|
extern nonstd::optional<const struct termios*> lnav_log_orig_termios;
|
||||||
extern enum lnav_log_level_t lnav_log_level;
|
extern enum lnav_log_level_t lnav_log_level;
|
||||||
|
|
||||||
#define log_msg_wrapper(level, fmt...) \
|
#define log_msg_wrapper(level, fmt...) \
|
||||||
@ -98,40 +105,43 @@ extern enum lnav_log_level_t lnav_log_level;
|
|||||||
if (lnav_log_level <= level) { \
|
if (lnav_log_level <= level) { \
|
||||||
log_msg(level, __FILE__, __LINE__, fmt); \
|
log_msg(level, __FILE__, __LINE__, fmt); \
|
||||||
} \
|
} \
|
||||||
} \
|
} while (false)
|
||||||
while (false)
|
|
||||||
|
|
||||||
#define log_rusage(level, ru) \
|
#define log_rusage(level, ru) log_rusage_raw(level, __FILE__, __LINE__, ru);
|
||||||
log_rusage_raw(level, __FILE__, __LINE__, ru);
|
|
||||||
|
|
||||||
#define log_error(fmt...) \
|
#define log_error(fmt...) log_msg_wrapper(lnav_log_level_t::ERROR, fmt);
|
||||||
log_msg_wrapper(lnav_log_level_t::ERROR, fmt);
|
|
||||||
|
|
||||||
#define log_warning(fmt...) \
|
#define log_warning(fmt...) log_msg_wrapper(lnav_log_level_t::WARNING, fmt);
|
||||||
log_msg_wrapper(lnav_log_level_t::WARNING, fmt);
|
|
||||||
|
|
||||||
#define log_info(fmt...) \
|
#define log_info(fmt...) log_msg_wrapper(lnav_log_level_t::INFO, fmt);
|
||||||
log_msg_wrapper(lnav_log_level_t::INFO, fmt);
|
|
||||||
|
|
||||||
#define log_debug(fmt...) \
|
#define log_debug(fmt...) log_msg_wrapper(lnav_log_level_t::DEBUG, fmt);
|
||||||
log_msg_wrapper(lnav_log_level_t::DEBUG, fmt);
|
|
||||||
|
|
||||||
#define log_trace(fmt...) \
|
#define log_trace(fmt...) log_msg_wrapper(lnav_log_level_t::TRACE, fmt);
|
||||||
log_msg_wrapper(lnav_log_level_t::TRACE, fmt);
|
|
||||||
|
|
||||||
#define require(e) \
|
#define require(e) ((void) ((e) ? 0 : lnav_require(#e, __FILE__, __LINE__)))
|
||||||
((void) ((e) ? 0 : lnav_require (#e, __FILE__, __LINE__)))
|
|
||||||
#define 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) \
|
#define ensure(e) ((void) ((e) ? 0 : lnav_ensure(#e, __FILE__, __LINE__)))
|
||||||
((void) ((e) ? 0 : lnav_ensure (#e, __FILE__, __LINE__)))
|
|
||||||
#define 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) \
|
#define log_perror(e) \
|
||||||
((void) ((e != -1) ? 0 : lnav_log_perror (#e, __FILE__, __LINE__)))
|
((void) ((e != -1) ? 0 : lnav_log_perror(#e, __FILE__, __LINE__)))
|
||||||
#define 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
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -41,17 +41,20 @@
|
|||||||
* @param step The granularity.
|
* @param step The granularity.
|
||||||
*/
|
*/
|
||||||
template<typename Size, typename Step>
|
template<typename Size, typename Step>
|
||||||
inline int rounddown(Size size, Step step)
|
inline int
|
||||||
|
rounddown(Size size, Step step)
|
||||||
{
|
{
|
||||||
return size - (size % 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);
|
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;
|
size_t retval = size + step;
|
||||||
|
|
||||||
|
@ -21,27 +21,26 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
#include "network.tcp.hh"
|
#include "network.tcp.hh"
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
namespace network {
|
namespace network {
|
||||||
namespace tcp {
|
namespace tcp {
|
||||||
|
|
||||||
Result<auto_fd, std::string> connect(const char *hostname,
|
Result<auto_fd, std::string>
|
||||||
const char *servname)
|
connect(const char* hostname, const char* servname)
|
||||||
{
|
{
|
||||||
struct addrinfo hints, *ai;
|
struct addrinfo hints, *ai;
|
||||||
|
|
||||||
@ -52,7 +51,9 @@ Result<auto_fd, std::string> connect(const char *hostname,
|
|||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return Err(fmt::format("unable to resolve {}:{} -- {}",
|
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));
|
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);
|
rc = ::connect(retval, ai->ai_addr, ai->ai_addrlen);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return Err(fmt::format("unable to connect to {}:{} -- {}",
|
return Err(fmt::format("unable to connect to {}:{} -- {}",
|
||||||
hostname, servname, strerror(rc)));
|
hostname,
|
||||||
|
servname,
|
||||||
|
strerror(rc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(retval);
|
return Ok(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace tcp
|
||||||
}
|
} // namespace network
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -40,11 +40,11 @@ namespace network {
|
|||||||
struct locality {
|
struct locality {
|
||||||
locality(nonstd::optional<std::string> username,
|
locality(nonstd::optional<std::string> username,
|
||||||
std::string hostname,
|
std::string hostname,
|
||||||
nonstd::optional<std::string> service) :
|
nonstd::optional<std::string> service)
|
||||||
l_username(std::move(username)),
|
: l_username(std::move(username)), l_hostname(std::move(hostname)),
|
||||||
l_hostname(std::move(hostname)),
|
l_service(std::move(service))
|
||||||
l_service(std::move(service))
|
{
|
||||||
{}
|
}
|
||||||
|
|
||||||
nonstd::optional<std::string> l_username;
|
nonstd::optional<std::string> l_username;
|
||||||
std::string l_hostname;
|
std::string l_hostname;
|
||||||
@ -55,11 +55,13 @@ struct path {
|
|||||||
locality p_locality;
|
locality p_locality;
|
||||||
std::string p_path;
|
std::string p_path;
|
||||||
|
|
||||||
path(locality l, std::string path) : p_locality(std::move(l)),
|
path(locality l, std::string path)
|
||||||
p_path(std::move(path))
|
: p_locality(std::move(l)), p_path(std::move(path))
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
path home() const {
|
path home() const
|
||||||
|
{
|
||||||
return {
|
return {
|
||||||
this->p_locality,
|
this->p_locality,
|
||||||
".",
|
".",
|
||||||
@ -69,10 +71,10 @@ struct path {
|
|||||||
|
|
||||||
namespace tcp {
|
namespace tcp {
|
||||||
|
|
||||||
Result<auto_fd, std::string> connect(const char *hostname,
|
Result<auto_fd, std::string> connect(const char* hostname,
|
||||||
const char *servname);
|
const char* servname);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
} // namespace network
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,21 +21,19 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "doctest/doctest.h"
|
#include "doctest/doctest.h"
|
||||||
|
|
||||||
#include "network.tcp.hh"
|
#include "network.tcp.hh"
|
||||||
|
|
||||||
TEST_CASE ("bad hostname")
|
TEST_CASE("bad hostname")
|
||||||
{
|
{
|
||||||
auto connect_res = network::tcp::connect("foobar.bazzer", "http");
|
auto connect_res = network::tcp::connect("foobar.bazzer", "http");
|
||||||
CHECK(connect_res.unwrapErr() ==
|
CHECK(connect_res.unwrapErr() ==
|
||||||
@ -43,7 +41,7 @@ TEST_CASE ("bad hostname")
|
|||||||
"provided, or not known");
|
"provided, or not known");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE ("bad servname")
|
TEST_CASE("bad servname")
|
||||||
{
|
{
|
||||||
auto connect_res = network::tcp::connect("www.cnn.com", "non-existent");
|
auto connect_res = network::tcp::connect("www.cnn.com", "non-existent");
|
||||||
CHECK(connect_res.unwrapErr() ==
|
CHECK(connect_res.unwrapErr() ==
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -37,36 +37,47 @@
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
typename std::enable_if<std::is_void<T>::value, T>::type
|
typename std::enable_if<std::is_void<T>::value, T>::type
|
||||||
void_or_nullopt()
|
void_or_nullopt()
|
||||||
{
|
{
|
||||||
return;
|
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>
|
|
||||||
struct is_optional : std::false_type {};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct is_optional<nonstd::optional<T>> : std::true_type {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class F, std::enable_if_t<detail::is_optional<std::decay_t<T>>::value, int> = 0>
|
template<class T>
|
||||||
auto operator|(T&& t, F f) -> decltype(detail::void_or_nullopt<decltype(f(std::forward<T>(t).operator*()))>()) {
|
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<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*()))>())
|
||||||
|
{
|
||||||
using return_type = 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*());
|
if (t)
|
||||||
else return detail::void_or_nullopt<return_type>();
|
return f(std::forward<T>(t).operator*());
|
||||||
|
else
|
||||||
|
return detail::void_or_nullopt<return_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class T >
|
template<class T>
|
||||||
optional_constexpr nonstd::optional< typename std::decay<T>::type > make_optional_from_nullable( T && v )
|
optional_constexpr nonstd::optional<typename std::decay<T>::type>
|
||||||
|
make_optional_from_nullable(T&& v)
|
||||||
{
|
{
|
||||||
if (v != nullptr) {
|
if (v != nullptr) {
|
||||||
return nonstd::optional<typename std::decay<T>::type>(
|
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;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<template <typename, typename...> class C, typename T>
|
template<template<typename, typename...> class C, typename T>
|
||||||
nonstd::optional<T> cget(const C<T> &container, size_t index)
|
nonstd::optional<T>
|
||||||
|
cget(const C<T>& container, size_t index)
|
||||||
{
|
{
|
||||||
if (index < container.size()) {
|
if (index < container.size()) {
|
||||||
return container[index];
|
return container[index];
|
||||||
@ -85,7 +97,9 @@ nonstd::optional<T> cget(const C<T> &container, size_t index)
|
|||||||
return nonstd::nullopt;
|
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));
|
return make_optional_from_nullable(getenv(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,32 +30,38 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
#include <sstream>
|
# include <iostream>
|
||||||
#include <iostream>
|
# include <sstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "paths.hh"
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
#include "paths.hh"
|
||||||
|
|
||||||
namespace lnav {
|
namespace lnav {
|
||||||
namespace paths {
|
namespace paths {
|
||||||
|
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
char* windows_to_unix_file_path(char* input) {
|
char*
|
||||||
|
windows_to_unix_file_path(char* input)
|
||||||
|
{
|
||||||
if (input == nullptr) {
|
if (input == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::string file_path;
|
std::string file_path;
|
||||||
file_path.assign(input);
|
file_path.assign(input);
|
||||||
|
|
||||||
// Replace the slashes
|
// 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
|
// Convert the drive letter to lowercase
|
||||||
std::transform(file_path.begin(), file_path.begin() + 1, file_path.begin(),
|
std::transform(
|
||||||
[](unsigned char character) {
|
file_path.begin(),
|
||||||
return std::tolower(character);
|
file_path.begin() + 1,
|
||||||
});
|
file_path.begin(),
|
||||||
|
[](unsigned char character) { return std::tolower(character); });
|
||||||
|
|
||||||
// Remove the colon
|
// Remove the colon
|
||||||
const auto drive_letter = file_path.substr(0, 1);
|
const auto drive_letter = file_path.substr(0, 1);
|
||||||
@ -70,7 +76,8 @@ char* windows_to_unix_file_path(char* input) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ghc::filesystem::path dotlnav()
|
ghc::filesystem::path
|
||||||
|
dotlnav()
|
||||||
{
|
{
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
auto home_env = windows_to_unix_file_path(getenv("APPDATA"));
|
auto home_env = windows_to_unix_file_path(getenv("APPDATA"));
|
||||||
@ -110,7 +117,8 @@ ghc::filesystem::path dotlnav()
|
|||||||
return ghc::filesystem::current_path();
|
return ghc::filesystem::current_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
ghc::filesystem::path workdir()
|
ghc::filesystem::path
|
||||||
|
workdir()
|
||||||
{
|
{
|
||||||
auto subdir_name = fmt::format("lnav-user-{}-work", getuid());
|
auto subdir_name = fmt::format("lnav-user-{}-work", getuid());
|
||||||
auto tmp_path = ghc::filesystem::temp_directory_path();
|
auto tmp_path = ghc::filesystem::temp_directory_path();
|
||||||
@ -118,5 +126,5 @@ ghc::filesystem::path workdir()
|
|||||||
return tmp_path / ghc::filesystem::path(subdir_name);
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -52,7 +52,7 @@ ghc::filesystem::path dotlnav();
|
|||||||
|
|
||||||
ghc::filesystem::path workdir();
|
ghc::filesystem::path workdir();
|
||||||
|
|
||||||
}
|
} // namespace paths
|
||||||
}
|
} // namespace lnav
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,30 +21,31 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "lnav_log.hh"
|
|
||||||
#include "is_utf8.hh"
|
|
||||||
#include "string_util.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;
|
int faulty_bytes;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ssize_t utf8_end = is_utf8(
|
ssize_t utf8_end
|
||||||
(unsigned char *) buffer, length, &msg, &faulty_bytes);
|
= is_utf8((unsigned char*) buffer, length, &msg, &faulty_bytes);
|
||||||
|
|
||||||
if (msg == nullptr) {
|
if (msg == nullptr) {
|
||||||
break;
|
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') {
|
if (str[0] == 'r' || str[0] == 'u') {
|
||||||
str += 1;
|
str += 1;
|
||||||
@ -70,8 +72,7 @@ size_t unquote(char *dst, const char *str, size_t len)
|
|||||||
dst[index] = str[lpc];
|
dst[index] = str[lpc];
|
||||||
if (str[lpc] == quote_char) {
|
if (str[lpc] == quote_char) {
|
||||||
lpc += 1;
|
lpc += 1;
|
||||||
}
|
} else if (str[lpc] == '\\' && (lpc + 1) < len) {
|
||||||
else if (str[lpc] == '\\' && (lpc + 1) < len) {
|
|
||||||
switch (str[lpc + 1]) {
|
switch (str[lpc + 1]) {
|
||||||
case 'n':
|
case 'n':
|
||||||
dst[index] = '\n';
|
dst[index] = '\n';
|
||||||
@ -94,7 +95,8 @@ size_t unquote(char *dst, const char *str, size_t len)
|
|||||||
return index;
|
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;
|
size_t index = 0;
|
||||||
|
|
||||||
@ -111,7 +113,8 @@ size_t unquote_w3c(char *dst, const char *str, size_t len)
|
|||||||
return index;
|
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";
|
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 chars_to_remove = (str_char_len - max_char_len) + 1;
|
||||||
auto midpoint = str_char_len / 2;
|
auto midpoint = str_char_len / 2;
|
||||||
auto chars_to_keep_at_front = midpoint - (chars_to_remove / 2);
|
auto chars_to_keep_at_front = midpoint - (chars_to_remove / 2);
|
||||||
auto bytes_to_keep_at_front =
|
auto bytes_to_keep_at_front
|
||||||
utf8_char_to_byte_index(str, chars_to_keep_at_front);
|
= utf8_char_to_byte_index(str, chars_to_keep_at_front);
|
||||||
auto remove_up_to_bytes =
|
auto remove_up_to_bytes = utf8_char_to_byte_index(
|
||||||
utf8_char_to_byte_index(str, chars_to_keep_at_front + chars_to_remove);
|
str, chars_to_keep_at_front + chars_to_remove);
|
||||||
auto bytes_to_remove = remove_up_to_bytes - bytes_to_keep_at_front;
|
auto bytes_to_remove = remove_up_to_bytes - bytes_to_keep_at_front;
|
||||||
str.erase(bytes_to_keep_at_front, bytes_to_remove);
|
str.erase(bytes_to_keep_at_front, bytes_to_remove);
|
||||||
str.insert(bytes_to_keep_at_front, ELLIPSIS);
|
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):.*");
|
static const auto url_re = std::regex("^(file|https?|ftps?|scp|sftp):.*");
|
||||||
|
|
||||||
return std::regex_match(fn, url_re);
|
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;
|
size_t last_start = 1;
|
||||||
|
|
||||||
@ -184,7 +189,8 @@ size_t abbreviate_str(char *str, size_t len, size_t max_len)
|
|||||||
return 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::stringstream ss(str);
|
||||||
std::string buf;
|
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::ostringstream os;
|
||||||
std::fill_n(std::ostream_iterator<std::string>(os), num, input);
|
std::fill_n(std::ostream_iterator<std::string>(os), num, input);
|
||||||
return os.str();
|
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;
|
std::string retval = subject;
|
||||||
|
|
||||||
@ -219,18 +227,23 @@ std::string center_str(const std::string &subject, size_t width)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
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;
|
size_t retval = 0;
|
||||||
T sign = 1;
|
T sign = 1;
|
||||||
|
|
||||||
num_out = 0;
|
num_out = 0;
|
||||||
|
|
||||||
for (; retval < len && isspace(string[retval]); retval++);
|
for (; retval < len && isspace(string[retval]); retval++) {
|
||||||
|
;
|
||||||
|
}
|
||||||
for (; retval < len && string[retval] == '-'; retval++) {
|
for (; retval < len && string[retval] == '-'; retval++) {
|
||||||
sign *= -1;
|
sign *= -1;
|
||||||
}
|
}
|
||||||
for (; retval < len && string[retval] == '+'; retval++);
|
for (; retval < len && string[retval] == '+'; retval++) {
|
||||||
|
;
|
||||||
|
}
|
||||||
for (; retval < len && isdigit(string[retval]); retval++) {
|
for (; retval < len && isdigit(string[retval]); retval++) {
|
||||||
num_out *= 10;
|
num_out *= 10;
|
||||||
num_out += string[retval] - '0';
|
num_out += string[retval] - '0';
|
||||||
@ -240,11 +253,10 @@ size_t strtonum(T &num_out, const char *string, size_t len)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
template
|
template size_t strtonum<long long>(long long& num_out,
|
||||||
size_t strtonum<long long>(long long &num_out, const char *string, size_t len);
|
const char* string,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
template
|
template size_t strtonum<long>(long& num_out, const char* string, size_t len);
|
||||||
size_t strtonum<long>(long &num_out, const char *string, size_t len);
|
|
||||||
|
|
||||||
template
|
template size_t strtonum<int>(int& num_out, const char* string, size_t len);
|
||||||
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,38 +30,45 @@
|
|||||||
#ifndef lnav_string_util_hh
|
#ifndef lnav_string_util_hh
|
||||||
#define lnav_string_util_hh
|
#define lnav_string_util_hh
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "ww898/cp_utf8.hpp"
|
#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';
|
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;
|
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);
|
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());
|
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);
|
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>
|
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()) {
|
if (N - 1 > str.length()) {
|
||||||
return false;
|
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;
|
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;
|
std::string::size_type start, end;
|
||||||
|
|
||||||
for (start = 0; start < str.size() && isspace(str[start]); start++);
|
for (start = 0; start < str.size() && isspace(str[start]); start++)
|
||||||
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--);
|
;
|
||||||
|
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--)
|
||||||
|
;
|
||||||
|
|
||||||
return str.substr(start, end - start);
|
return str.substr(start, end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string tolower(const char *str)
|
inline std::string
|
||||||
|
tolower(const char* str)
|
||||||
{
|
{
|
||||||
std::string retval;
|
std::string retval;
|
||||||
|
|
||||||
@ -105,12 +117,14 @@ inline std::string tolower(const char *str)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string tolower(const std::string &str)
|
inline std::string
|
||||||
|
tolower(const std::string& str)
|
||||||
{
|
{
|
||||||
return tolower(str.c_str());
|
return tolower(str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string toupper(const char *str)
|
inline std::string
|
||||||
|
toupper(const char* str)
|
||||||
{
|
{
|
||||||
std::string retval;
|
std::string retval;
|
||||||
|
|
||||||
@ -121,19 +135,22 @@ inline std::string toupper(const char *str)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string toupper(const std::string &str)
|
inline std::string
|
||||||
|
toupper(const std::string& str)
|
||||||
{
|
{
|
||||||
return toupper(str.c_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;
|
ssize_t retval = 0;
|
||||||
|
|
||||||
while (ch_index > 0) {
|
while (ch_index > 0) {
|
||||||
auto ch_len = ww898::utf::utf8::char_size([&str, retval]() {
|
auto ch_len
|
||||||
return std::make_pair(str[retval], str.length() - retval - 1);
|
= ww898::utf::utf8::char_size([&str, retval]() {
|
||||||
}).unwrapOr(1);
|
return std::make_pair(str[retval], str.length() - retval - 1);
|
||||||
|
}).unwrapOr(1);
|
||||||
|
|
||||||
retval += ch_len;
|
retval += ch_len;
|
||||||
ch_index -= 1;
|
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;
|
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;
|
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;) {
|
for (ssize_t byte_index = 0; byte_index < len;) {
|
||||||
auto ch_size = TRY(ww898::utf::utf8::char_size([str, len, byte_index]() {
|
auto ch_size
|
||||||
return std::make_pair(str[byte_index], len - byte_index);
|
= TRY(ww898::utf::utf8::char_size([str, len, byte_index]() {
|
||||||
}));
|
return std::make_pair(str[byte_index], len - byte_index);
|
||||||
|
}));
|
||||||
byte_index += ch_size;
|
byte_index += ch_size;
|
||||||
retval += 1;
|
retval += 1;
|
||||||
}
|
}
|
||||||
@ -161,22 +180,23 @@ inline Result<size_t, const char *> utf8_string_length(const char *str, ssize_t
|
|||||||
return Ok(retval);
|
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());
|
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 repeat(const std::string& input, size_t num);
|
||||||
|
|
||||||
std::string center_str(const std::string& subject, size_t width);
|
std::string center_str(const std::string& subject, size_t width);
|
||||||
|
|
||||||
template<typename T>
|
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
|
#endif
|
||||||
|
@ -21,22 +21,21 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "doctest/doctest.h"
|
|
||||||
|
|
||||||
#include "base/strnatcmp.h"
|
|
||||||
#include "base/string_util.hh"
|
#include "base/string_util.hh"
|
||||||
|
|
||||||
TEST_CASE ("endswith")
|
#include "base/strnatcmp.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "doctest/doctest.h"
|
||||||
|
|
||||||
|
TEST_CASE("endswith")
|
||||||
{
|
{
|
||||||
std::string hw("hello");
|
std::string hw("hello");
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ TEST_CASE ("endswith")
|
|||||||
CHECK(endswith(hw, "lo") == true);
|
CHECK(endswith(hw, "lo") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE ("truncate_to")
|
TEST_CASE("truncate_to")
|
||||||
{
|
{
|
||||||
const std::string orig = "0123456789abcdefghijklmnopqrstuvwxyz";
|
const std::string orig = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
std::string str;
|
std::string str;
|
||||||
@ -74,16 +73,17 @@ TEST_CASE ("truncate_to")
|
|||||||
CHECK(str == "01\u22efyz");
|
CHECK(str == "01\u22efyz");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("strnatcmp") {
|
TEST_CASE("strnatcmp")
|
||||||
|
{
|
||||||
{
|
{
|
||||||
constexpr const char *n1 = "010";
|
constexpr const char* n1 = "010";
|
||||||
constexpr const char *n2 = "020";
|
constexpr const char* n2 = "020";
|
||||||
|
|
||||||
CHECK(strnatcmp(strlen(n1), n1, strlen(n2), n2) < 0);
|
CHECK(strnatcmp(strlen(n1), n1, strlen(n2), n2) < 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
constexpr const char *n1 = "2";
|
constexpr const char* n1 = "2";
|
||||||
constexpr const char *n2 = "10";
|
constexpr const char* n2 = "10";
|
||||||
|
|
||||||
CHECK(strnatcmp(strlen(n1), n1, strlen(n2), n2) < 0);
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file time_util.cc
|
* @file time_util.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "time_util.hh"
|
#include "time_util.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
static time_t BAD_DATE = -1;
|
static time_t BAD_DATE = -1;
|
||||||
|
|
||||||
time_t tm2sec(const struct tm *t)
|
time_t
|
||||||
|
tm2sec(const struct tm* t)
|
||||||
{
|
{
|
||||||
int year;
|
int year;
|
||||||
time_t days, secs;
|
time_t days, secs;
|
||||||
const int dayoffset[12] =
|
const int dayoffset[12]
|
||||||
{ 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 };
|
= {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
|
||||||
|
|
||||||
year = t->tm_year;
|
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). */
|
/* 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 += dayoffset[t->tm_mon] + t->tm_mday - 1;
|
||||||
days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
|
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) {
|
if (secs < 0) {
|
||||||
return BAD_DATE;
|
return BAD_DATE;
|
||||||
} /* must have overflowed */
|
} /* must have overflowed */
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
#ifdef HAVE_STRUCT_TM_TM_ZONE
|
||||||
if (t->tm_zone) {
|
if (t->tm_zone) {
|
||||||
secs -= t->tm_gmtoff;
|
secs -= t->tm_gmtoff;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return secs;
|
return secs;
|
||||||
} /* must be a valid time */
|
} /* must be a valid time */
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int SECSPERMIN = 60;
|
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)
|
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
|
||||||
|
|
||||||
static const int year_lengths[2] = {
|
static const int year_lengths[2] = {365, 366};
|
||||||
365,
|
|
||||||
366
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned short int mon_yday[2][13] = {
|
const unsigned short int mon_yday[2][13] = {
|
||||||
/* Normal years. */
|
/* 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. */
|
/* 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;
|
long days, rem;
|
||||||
time_t lcltime;
|
time_t lcltime;
|
||||||
@ -118,21 +118,21 @@ void secs2wday(const struct timeval &tv, struct tm *res)
|
|||||||
res->tm_wday += DAYSPERWEEK;
|
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;
|
long days, rem;
|
||||||
lnav::time64_t lcltime;
|
lnav::time64_t lcltime;
|
||||||
int y;
|
int y;
|
||||||
int yleap;
|
int yleap;
|
||||||
const unsigned short int *ip;
|
const unsigned short int* ip;
|
||||||
|
|
||||||
/* base decision about std/dst time on current time */
|
/* base decision about std/dst time on current time */
|
||||||
lcltime = tim;
|
lcltime = tim;
|
||||||
|
|
||||||
days = ((long)lcltime) / SECSPERDAY;
|
days = ((long) lcltime) / SECSPERDAY;
|
||||||
rem = ((long)lcltime) % SECSPERDAY;
|
rem = ((long) lcltime) % SECSPERDAY;
|
||||||
while (rem < 0)
|
while (rem < 0) {
|
||||||
{
|
|
||||||
rem += SECSPERDAY;
|
rem += SECSPERDAY;
|
||||||
--days;
|
--days;
|
||||||
}
|
}
|
||||||
@ -149,21 +149,16 @@ struct tm *secs2tm(lnav::time64_t tim, struct tm *res)
|
|||||||
|
|
||||||
/* compute year & day of year */
|
/* compute year & day of year */
|
||||||
y = EPOCH_YEAR;
|
y = EPOCH_YEAR;
|
||||||
if (days >= 0)
|
if (days >= 0) {
|
||||||
{
|
for (;;) {
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
yleap = isleap(y);
|
yleap = isleap(y);
|
||||||
if (days < year_lengths[yleap])
|
if (days < year_lengths[yleap])
|
||||||
break;
|
break;
|
||||||
y++;
|
y++;
|
||||||
days -= year_lengths[yleap];
|
days -= year_lengths[yleap];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
do {
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
--y;
|
--y;
|
||||||
yleap = isleap(y);
|
yleap = isleap(y);
|
||||||
days += year_lengths[yleap];
|
days += year_lengths[yleap];
|
||||||
@ -184,14 +179,15 @@ struct tm *secs2tm(lnav::time64_t tim, struct tm *res)
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval exttm::to_timeval() const
|
struct timeval
|
||||||
|
exttm::to_timeval() const
|
||||||
{
|
{
|
||||||
struct timeval retval;
|
struct timeval retval;
|
||||||
|
|
||||||
retval.tv_sec = tm2sec(&this->et_tm);
|
retval.tv_sec = tm2sec(&this->et_tm);
|
||||||
retval.tv_usec =
|
retval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(
|
std::chrono::nanoseconds(this->et_nsec))
|
||||||
std::chrono::nanoseconds(this->et_nsec)).count();
|
.count();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,11 +30,13 @@
|
|||||||
#ifndef lnav_time_util_hh
|
#ifndef lnav_time_util_hh
|
||||||
#define lnav_time_util_hh
|
#define lnav_time_util_hh
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
namespace lnav {
|
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.
|
* Convert the time stored in a 'tm' struct into epoch time.
|
||||||
*
|
*
|
||||||
* @param t The 'tm' structure to convert to epoch time.
|
* @param t The 'tm' structure to convert to epoch time.
|
||||||
* @return The given time in seconds since the epoch.
|
* @return The given time in seconds since the epoch.
|
||||||
*/
|
*/
|
||||||
time_t tm2sec(const struct tm *t);
|
time_t tm2sec(const struct tm* t);
|
||||||
void secs2wday(const struct timeval &tv, struct tm *res);
|
void secs2wday(const struct timeval& tv, struct tm* res);
|
||||||
|
|
||||||
inline
|
inline time_t
|
||||||
time_t convert_log_time_to_local(time_t value) {
|
convert_log_time_to_local(time_t value)
|
||||||
|
{
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
localtime_r(&value, &tm);
|
localtime_r(&value, &tm);
|
||||||
@ -88,37 +91,41 @@ struct exttm {
|
|||||||
unsigned int et_flags;
|
unsigned int et_flags;
|
||||||
long et_gmtoff;
|
long et_gmtoff;
|
||||||
|
|
||||||
bool operator==(const exttm &other) const {
|
bool operator==(const exttm& other) const
|
||||||
|
{
|
||||||
return memcmp(this, &other, sizeof(exttm)) == 0;
|
return memcmp(this, &other, sizeof(exttm)) == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct timeval to_timeval() const;
|
struct timeval to_timeval() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline bool
|
||||||
bool operator<(const struct timeval &left, time_t right) {
|
operator<(const struct timeval& left, time_t right)
|
||||||
|
{
|
||||||
return left.tv_sec < right;
|
return left.tv_sec < right;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline bool
|
||||||
bool operator<(time_t left, const struct timeval &right) {
|
operator<(time_t left, const struct timeval& right)
|
||||||
|
{
|
||||||
return left < right.tv_sec;
|
return left < right.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline bool
|
||||||
bool operator<(const struct timeval &left, const struct timeval &right) {
|
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));
|
return left.tv_sec < right.tv_sec
|
||||||
|
|| ((left.tv_sec == right.tv_sec) && (left.tv_usec < right.tv_usec));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline bool
|
||||||
bool operator!=(const struct timeval &left, const struct timeval &right) {
|
operator!=(const struct timeval& left, const struct timeval& right)
|
||||||
return left.tv_sec != right.tv_sec ||
|
{
|
||||||
left.tv_usec != right.tv_usec;
|
return left.tv_sec != right.tv_sec || left.tv_usec != right.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline struct timeval
|
||||||
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
|
operator-(const struct timeval& lhs, const struct timeval& rhs)
|
||||||
{
|
{
|
||||||
struct timeval diff;
|
struct timeval diff;
|
||||||
|
|
||||||
@ -128,7 +135,9 @@ struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
|
|||||||
|
|
||||||
typedef int64_t mstime_t;
|
typedef int64_t mstime_t;
|
||||||
|
|
||||||
inline mstime_t getmstime() {
|
inline mstime_t
|
||||||
|
getmstime()
|
||||||
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
gettimeofday(&tv, nullptr);
|
gettimeofday(&tv, nullptr);
|
||||||
@ -136,7 +145,9 @@ inline mstime_t getmstime() {
|
|||||||
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
|
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline struct timeval current_timeval() {
|
inline struct timeval
|
||||||
|
current_timeval()
|
||||||
|
{
|
||||||
struct timeval retval;
|
struct timeval retval;
|
||||||
|
|
||||||
gettimeofday(&retval, nullptr);
|
gettimeofday(&retval, nullptr);
|
||||||
@ -144,7 +155,9 @@ inline struct timeval current_timeval() {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline struct timespec current_timespec() {
|
inline struct timespec
|
||||||
|
current_timespec()
|
||||||
|
{
|
||||||
struct timespec retval;
|
struct timespec retval;
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &retval);
|
clock_gettime(CLOCK_REALTIME, &retval);
|
||||||
@ -152,12 +165,14 @@ inline struct timespec current_timespec() {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline time_t day_num(time_t ti)
|
inline time_t
|
||||||
|
day_num(time_t ti)
|
||||||
{
|
{
|
||||||
return ti / (24 * 60 * 60);
|
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);
|
return ti / (60 * 60);
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -33,6 +33,7 @@
|
|||||||
#define lnav_big_array_hh
|
#define lnav_big_array_hh
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "base/math_util.hh"
|
#include "base/math_util.hh"
|
||||||
|
|
||||||
@ -40,11 +41,13 @@ template<typename T>
|
|||||||
struct big_array {
|
struct big_array {
|
||||||
static const size_t DEFAULT_INCREMENT = 100 * 1000;
|
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) {
|
if (size < this->ba_capacity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -55,67 +58,77 @@ struct big_array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->ba_capacity = size + DEFAULT_INCREMENT;
|
this->ba_capacity = size + DEFAULT_INCREMENT;
|
||||||
void *result = mmap(nullptr,
|
void* result
|
||||||
roundup_size(this->ba_capacity * sizeof(T),
|
= mmap(nullptr,
|
||||||
getpagesize()),
|
roundup_size(this->ba_capacity * sizeof(T), getpagesize()),
|
||||||
PROT_READ|PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_ANONYMOUS|MAP_PRIVATE,
|
MAP_ANONYMOUS | MAP_PRIVATE,
|
||||||
-1,
|
-1,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
ensure(result != MAP_FAILED);
|
ensure(result != MAP_FAILED);
|
||||||
|
|
||||||
this->ba_ptr = (T *) result;
|
this->ba_ptr = (T*) result;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->ba_size = 0;
|
this->ba_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const
|
||||||
|
{
|
||||||
return this->ba_size;
|
return this->ba_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
void shrink_to(size_t new_size) {
|
void shrink_to(size_t new_size)
|
||||||
|
{
|
||||||
require(new_size <= this->ba_size);
|
require(new_size <= this->ba_size);
|
||||||
|
|
||||||
this->ba_size = new_size;
|
this->ba_size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
|
{
|
||||||
return this->ba_size == 0;
|
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_ptr[this->ba_size] = val;
|
||||||
this->ba_size += 1;
|
this->ba_size += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
T &operator[](size_t index) {
|
T& operator[](size_t index)
|
||||||
|
{
|
||||||
return this->ba_ptr[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];
|
return this->ba_ptr[index];
|
||||||
};
|
};
|
||||||
|
|
||||||
T &back() {
|
T& back()
|
||||||
|
{
|
||||||
return this->ba_ptr[this->ba_size - 1];
|
return this->ba_ptr[this->ba_size - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef T *iterator;
|
typedef T* iterator;
|
||||||
|
|
||||||
iterator begin() {
|
iterator begin()
|
||||||
|
{
|
||||||
return this->ba_ptr;
|
return this->ba_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
iterator end() {
|
iterator end()
|
||||||
|
{
|
||||||
return this->ba_ptr + this->ba_size;
|
return this->ba_ptr + this->ba_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
T *ba_ptr;
|
T* ba_ptr;
|
||||||
size_t ba_size;
|
size_t ba_size;
|
||||||
size_t ba_capacity;
|
size_t ba_capacity;
|
||||||
};
|
};
|
||||||
|
23
src/bin2c.hh
23
src/bin2c.hh
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,21 +32,24 @@
|
|||||||
#ifndef lnav_bin2c_hh
|
#ifndef lnav_bin2c_hh
|
||||||
#define lnav_bin2c_hh
|
#define lnav_bin2c_hh
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <memory>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <zlib.h>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "base/intern_string.hh"
|
#include "base/intern_string.hh"
|
||||||
|
|
||||||
struct bin_src_file {
|
struct bin_src_file {
|
||||||
bin_src_file(const char *name, const unsigned char *data,
|
bin_src_file(const char* name,
|
||||||
size_t compressed_size, size_t size)
|
const unsigned char* data,
|
||||||
|
size_t compressed_size,
|
||||||
|
size_t size)
|
||||||
: bsf_name(name), bsf_data(new unsigned char[size + 1]), bsf_size(size)
|
: bsf_name(name), bsf_data(new unsigned char[size + 1]), bsf_size(size)
|
||||||
{
|
{
|
||||||
uLongf zsize = 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(rc == Z_OK);
|
||||||
assert(zsize == size);
|
assert(zsize == size);
|
||||||
this->bsf_data[size] = '\0';
|
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};
|
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;
|
return this->bsf_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *bsf_name;
|
const char* bsf_name;
|
||||||
std::unique_ptr<unsigned char[]> bsf_data;
|
std::unique_ptr<unsigned char[]> bsf_data;
|
||||||
ssize_t bsf_size;
|
ssize_t bsf_size;
|
||||||
};
|
};
|
||||||
|
@ -21,18 +21,18 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file bookmarks.cc
|
* @file bookmarks.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "bookmarks.hh"
|
#include "bookmarks.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
set<string> bookmark_metadata::KNOWN_TAGS;
|
set<string> bookmark_metadata::KNOWN_TAGS;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,11 +32,11 @@
|
|||||||
#ifndef bookmarks_hh
|
#ifndef bookmarks_hh
|
||||||
#define bookmarks_hh
|
#define bookmarks_hh
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
|
|
||||||
@ -47,18 +47,18 @@ struct bookmark_metadata {
|
|||||||
std::string bm_comment;
|
std::string bm_comment;
|
||||||
std::vector<std::string> bm_tags;
|
std::vector<std::string> bm_tags;
|
||||||
|
|
||||||
void add_tag(const std::string &tag) {
|
void add_tag(const std::string& tag)
|
||||||
if (std::find(this->bm_tags.begin(),
|
{
|
||||||
this->bm_tags.end(),
|
if (std::find(this->bm_tags.begin(), this->bm_tags.end(), tag)
|
||||||
tag) == this->bm_tags.end()) {
|
== this->bm_tags.end())
|
||||||
|
{
|
||||||
this->bm_tags.push_back(tag);
|
this->bm_tags.push_back(tag);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool remove_tag(const std::string &tag) {
|
bool remove_tag(const std::string& tag)
|
||||||
auto iter = std::find(this->bm_tags.begin(),
|
{
|
||||||
this->bm_tags.end(),
|
auto iter = std::find(this->bm_tags.begin(), this->bm_tags.end(), tag);
|
||||||
tag);
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
if (iter != this->bm_tags.end()) {
|
if (iter != this->bm_tags.end()) {
|
||||||
@ -68,13 +68,14 @@ struct bookmark_metadata {
|
|||||||
return retval;
|
return retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const
|
||||||
return this->bm_name.empty() &&
|
{
|
||||||
this->bm_comment.empty() &&
|
return this->bm_name.empty() && this->bm_comment.empty()
|
||||||
this->bm_tags.empty();
|
&& this->bm_tags.empty();
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear() {
|
void clear()
|
||||||
|
{
|
||||||
this->bm_comment.clear();
|
this->bm_comment.clear();
|
||||||
this->bm_tags.clear();
|
this->bm_tags.clear();
|
||||||
};
|
};
|
||||||
@ -98,9 +99,9 @@ class bookmark_vector : public std::vector<LineType> {
|
|||||||
typedef std::vector<LineType> base_vector;
|
typedef std::vector<LineType> base_vector;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename base_vector::size_type size_type;
|
typedef typename base_vector::size_type size_type;
|
||||||
typedef typename base_vector::iterator iterator;
|
typedef typename base_vector::iterator iterator;
|
||||||
typedef typename base_vector::const_iterator const_iterator;
|
typedef typename base_vector::const_iterator const_iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a bookmark into this vector, but only if it is not already in the
|
* 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) {
|
if (lb == this->end() || *lb != vl) {
|
||||||
this->insert(lb, vl);
|
this->insert(lb, vl);
|
||||||
retval = this->end();
|
retval = this->end();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
retval = lb;
|
retval = lb;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
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);
|
auto lb = std::lower_bound(this->begin(), this->end(), start);
|
||||||
|
|
||||||
if (stop == LineType(-1)) {
|
if (stop == LineType(-1)) {
|
||||||
@ -163,19 +164,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
class bookmark_type_t {
|
class bookmark_type_t {
|
||||||
public:
|
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();
|
return get_all_types().begin();
|
||||||
};
|
};
|
||||||
|
|
||||||
static type_iterator type_end() {
|
static type_iterator type_end()
|
||||||
|
{
|
||||||
return get_all_types().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));
|
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()) {
|
if (iter != type_end()) {
|
||||||
retval = (*iter);
|
retval = (*iter);
|
||||||
@ -183,36 +187,41 @@ public:
|
|||||||
return retval;
|
return retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<bookmark_type_t *> &get_all_types() {
|
static std::vector<bookmark_type_t*>& get_all_types()
|
||||||
static std::vector<bookmark_type_t *> all_types;
|
{
|
||||||
|
static std::vector<bookmark_type_t*> all_types;
|
||||||
|
|
||||||
return 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);
|
get_all_types().push_back(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string &get_name() const {
|
const std::string& get_name() const
|
||||||
|
{
|
||||||
return this->bt_name;
|
return this->bt_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct mark_eq {
|
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;
|
return bt->bt_name == this->me_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string &me_name;
|
const std::string& me_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string bt_name;
|
const std::string bt_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename LineType>
|
template<typename LineType>
|
||||||
LineType bookmark_vector<LineType>::next(LineType start) const
|
LineType
|
||||||
|
bookmark_vector<LineType>::next(LineType start) const
|
||||||
{
|
{
|
||||||
LineType retval(-1);
|
LineType retval(-1);
|
||||||
|
|
||||||
@ -229,7 +238,8 @@ LineType bookmark_vector<LineType>::next(LineType start) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename LineType>
|
template<typename LineType>
|
||||||
LineType bookmark_vector<LineType>::prev(LineType start) const
|
LineType
|
||||||
|
bookmark_vector<LineType>::prev(LineType start) const
|
||||||
{
|
{
|
||||||
LineType retval(-1);
|
LineType retval(-1);
|
||||||
|
|
||||||
@ -237,7 +247,7 @@ LineType bookmark_vector<LineType>::prev(LineType start) const
|
|||||||
|
|
||||||
auto lb = lower_bound(this->cbegin(), this->cend(), start);
|
auto lb = lower_bound(this->cbegin(), this->cend(), start);
|
||||||
if (lb != this->cbegin()) {
|
if (lb != this->cbegin()) {
|
||||||
lb -= 1;
|
lb -= 1;
|
||||||
retval = *lb;
|
retval = *lb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +261,7 @@ LineType bookmark_vector<LineType>::prev(LineType start) const
|
|||||||
*/
|
*/
|
||||||
template<typename LineType>
|
template<typename LineType>
|
||||||
struct bookmarks {
|
struct bookmarks {
|
||||||
typedef std::map<bookmark_type_t *, bookmark_vector<LineType> > type;
|
typedef std::map<const bookmark_type_t*, bookmark_vector<LineType> > type;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,16 +21,15 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "bottom_status_source.hh"
|
#include "bottom_status_source.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
bottom_status_source::bottom_status_source()
|
bottom_status_source::bottom_status_source()
|
||||||
{
|
{
|
||||||
@ -59,22 +58,22 @@ bottom_status_source::bottom_status_source()
|
|||||||
this->bss_line_error.set_share(1);
|
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) {
|
if (lc->get_inner_height() == 0) {
|
||||||
sf.set_value(" L0");
|
sf.set_value(" L0");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
sf.set_value(" L%'d", (int) lc->get_top());
|
sf.set_value(" L%'d", (int) lc->get_top());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lc->get_inner_height() > 0) {
|
if (lc->get_inner_height() > 0) {
|
||||||
std::vector<attr_line_t> rows(1);
|
std::vector<attr_line_t> rows(1);
|
||||||
|
|
||||||
lc->get_data_source()->
|
lc->get_data_source()->listview_value_for_rows(
|
||||||
listview_value_for_rows(*lc, lc->get_top(), rows);
|
*lc, lc->get_top(), rows);
|
||||||
auto& sa = rows[0].get_attrs();
|
auto& sa = rows[0].get_attrs();
|
||||||
auto iter = find_string_attr(sa, &SA_ERROR);
|
auto iter = find_string_attr(sa, &SA_ERROR);
|
||||||
if (iter != sa.end()) {
|
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();
|
auto search_term = tc.get_current_search();
|
||||||
|
|
||||||
if (search_term.empty()) {
|
if (search_term.empty()) {
|
||||||
@ -102,74 +102,73 @@ void bottom_status_source::update_search_term(textview_curses &tc)
|
|||||||
this->update_loading(0, 0);
|
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];
|
status_field& sf = this->bss_fields[BSF_PERCENT];
|
||||||
vis_line_t top = lc->get_top();
|
vis_line_t top = lc->get_top();
|
||||||
vis_line_t bottom, height;
|
vis_line_t bottom, height;
|
||||||
unsigned long width;
|
unsigned long width;
|
||||||
double percent;
|
double percent;
|
||||||
|
|
||||||
lc->get_dimensions(height, width);
|
lc->get_dimensions(height, width);
|
||||||
|
|
||||||
if (lc->get_inner_height() > 0) {
|
if (lc->get_inner_height() > 0) {
|
||||||
bottom = std::min(top + height - vis_line_t(1),
|
bottom = std::min(top + height - vis_line_t(1),
|
||||||
vis_line_t(lc->get_inner_height() - 1));
|
vis_line_t(lc->get_inner_height() - 1));
|
||||||
percent = (double)(bottom + 1);
|
percent = (double) (bottom + 1);
|
||||||
percent /= (double)lc->get_inner_height();
|
percent /= (double) lc->get_inner_height();
|
||||||
percent *= 100.0;
|
percent *= 100.0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
percent = 0.0;
|
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);
|
auto* tc = static_cast<textview_curses*>(lc);
|
||||||
vis_bookmarks &bm = tc->get_bookmarks();
|
vis_bookmarks& bm = tc->get_bookmarks();
|
||||||
status_field &sf = this->bss_fields[BSF_HITS];
|
status_field& sf = this->bss_fields[BSF_HITS];
|
||||||
|
|
||||||
if (bm.find(&textview_curses::BM_SEARCH) != bm.end()) {
|
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()) {
|
if (!bv.empty() || !tc->get_current_search().empty()) {
|
||||||
bookmark_vector<vis_line_t>::iterator lb;
|
bookmark_vector<vis_line_t>::iterator lb;
|
||||||
|
|
||||||
lb = std::lower_bound(bv.begin(), bv.end(), tc->get_top());
|
lb = std::lower_bound(bv.begin(), bv.end(), tc->get_top());
|
||||||
if (lb != bv.end() && *lb == tc->get_top()) {
|
if (lb != bv.end() && *lb == tc->get_top()) {
|
||||||
sf.set_value(
|
sf.set_value(" Hit %'d of %'d for ",
|
||||||
" Hit %'d of %'d for ",
|
std::distance(bv.begin(), lb) + 1,
|
||||||
std::distance(bv.begin(), lb) + 1, tc->get_match_count());
|
tc->get_match_count());
|
||||||
} else {
|
} else {
|
||||||
sf.set_value(" %'d hits for ", tc->get_match_count());
|
sf.set_value(" %'d hits for ", tc->get_match_count());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sf.clear();
|
sf.clear();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
sf.clear();
|
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;
|
view_colors::role_t new_role;
|
||||||
|
|
||||||
if (tc->is_searching()) {
|
if (tc->is_searching()) {
|
||||||
this->bss_hit_spinner += 1;
|
this->bss_hit_spinner += 1;
|
||||||
if (this->bss_hit_spinner % 2) {
|
if (this->bss_hit_spinner % 2) {
|
||||||
new_role = view_colors::VCR_ACTIVE_STATUS;
|
new_role = view_colors::VCR_ACTIVE_STATUS;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
new_role = view_colors::VCR_ACTIVE_STATUS2;
|
new_role = view_colors::VCR_ACTIVE_STATUS2;
|
||||||
}
|
}
|
||||||
sf.set_cylon(true);
|
sf.set_cylon(true);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
new_role = view_colors::VCR_STATUS;
|
new_role = view_colors::VCR_STATUS;
|
||||||
sf.set_cylon(false);
|
sf.set_cylon(false);
|
||||||
}
|
}
|
||||||
@ -178,13 +177,14 @@ void bottom_status_source::update_hits(textview_curses *tc)
|
|||||||
this->update_marks(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);
|
require(off >= 0);
|
||||||
|
|
||||||
if (total == 0 || (size_t)off == total) {
|
if (total == 0 || (size_t) off == total) {
|
||||||
sf.set_cylon(false);
|
sf.set_cylon(false);
|
||||||
sf.set_role(view_colors::VCR_STATUS);
|
sf.set_role(view_colors::VCR_STATUS);
|
||||||
if (this->bss_paused) {
|
if (this->bss_paused) {
|
||||||
@ -192,9 +192,8 @@ void bottom_status_source::update_loading(file_off_t off, file_size_t total)
|
|||||||
} else {
|
} else {
|
||||||
sf.clear();
|
sf.clear();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
int pct = (int) (((double) off / (double) total) * 100.0);
|
||||||
int pct = (int)(((double)off / (double)total) * 100.0);
|
|
||||||
|
|
||||||
if (this->bss_load_percent != pct) {
|
if (this->bss_load_percent != pct) {
|
||||||
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;
|
size_t retval;
|
||||||
|
|
||||||
if (this->bss_prompt.empty() &&
|
if (this->bss_prompt.empty() && this->bss_error.empty()
|
||||||
this->bss_error.empty() &&
|
&& this->bss_line_error.empty())
|
||||||
this->bss_line_error.empty()) {
|
{
|
||||||
retval = BSF__MAX;
|
retval = BSF__MAX;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
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()) {
|
if (!this->bss_error.empty()) {
|
||||||
return this->bss_error;
|
return this->bss_error;
|
||||||
}
|
} else if (!this->bss_prompt.empty()) {
|
||||||
else if (!this->bss_prompt.empty()) {
|
|
||||||
return this->bss_prompt;
|
return this->bss_prompt;
|
||||||
}
|
} else if (!this->bss_line_error.empty()) {
|
||||||
else if (!this->bss_line_error.empty()) {
|
|
||||||
return this->bss_line_error;
|
return this->bss_line_error;
|
||||||
}
|
} else {
|
||||||
else {
|
return this->get_field((field_t) field);
|
||||||
return this->get_field((field_t)field);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -33,12 +33,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "grep_proc.hh"
|
#include "grep_proc.hh"
|
||||||
#include "textview_curses.hh"
|
|
||||||
#include "statusview_curses.hh"
|
#include "statusview_curses.hh"
|
||||||
|
#include "textview_curses.hh"
|
||||||
|
|
||||||
class bottom_status_source
|
class bottom_status_source
|
||||||
: public status_data_source,
|
: public status_data_source
|
||||||
public grep_proc_control {
|
, public grep_proc_control {
|
||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BSF_LINE_NUMBER,
|
BSF_LINE_NUMBER,
|
||||||
@ -53,9 +53,12 @@ public:
|
|||||||
|
|
||||||
bottom_status_source();
|
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);
|
this->bss_prompt.set_value(prompt);
|
||||||
};
|
};
|
||||||
@ -67,17 +70,17 @@ public:
|
|||||||
|
|
||||||
size_t statusview_fields() override;
|
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);
|
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_error{1024, view_colors::VCR_ALERT_STATUS};
|
||||||
status_field bss_line_error{1024, view_colors::VCR_ALERT_STATUS};
|
status_field bss_line_error{1024, view_colors::VCR_ALERT_STATUS};
|
||||||
status_field bss_fields[BSF__MAX];
|
status_field bss_fields[BSF__MAX];
|
||||||
int bss_hit_spinner{0};
|
int bss_hit_spinner{0};
|
||||||
int bss_load_percent{0};
|
int bss_load_percent{0};
|
||||||
bool bss_paused{false};
|
bool bss_paused{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,10 +32,13 @@
|
|||||||
#ifndef lnav_bound_tags_hh
|
#ifndef lnav_bound_tags_hh
|
||||||
#define 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
|
#endif
|
||||||
|
@ -21,21 +21,21 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#ifndef byte_array_hh
|
#ifndef byte_array_hh
|
||||||
#define byte_array_hh
|
#define byte_array_hh
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
|
|
||||||
template<size_t COUNT, typename T = unsigned char>
|
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 BYTE_COUNT = COUNT * sizeof(T);
|
||||||
static constexpr size_t STRING_SIZE = BYTE_COUNT * 2 + 1;
|
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);
|
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;
|
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;
|
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;
|
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);
|
memset(this->ba_data, 0, BYTE_COUNT);
|
||||||
};
|
};
|
||||||
|
|
||||||
void to_string(char *buffer) const
|
void to_string(char* buffer) const
|
||||||
{
|
{
|
||||||
require(buffer != nullptr);
|
require(buffer != nullptr);
|
||||||
|
|
||||||
@ -87,10 +87,14 @@ struct byte_array {
|
|||||||
return std::string(buffer);
|
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* out(int offset = 0)
|
||||||
T *ptr = (T *)this->ba_data;
|
{
|
||||||
|
T* ptr = (T*) this->ba_data;
|
||||||
|
|
||||||
return &ptr[offset];
|
return &ptr[offset];
|
||||||
};
|
};
|
||||||
@ -99,7 +103,8 @@ struct byte_array {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<size_t COUNT, typename T = unsigned char>
|
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();
|
os << ba.to_string();
|
||||||
return os;
|
return os;
|
||||||
|
@ -21,34 +21,33 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file logfile_sub_source.hh
|
* @file logfile_sub_source.hh
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "log_level.hh"
|
|
||||||
#include "base/strnatcmp.h"
|
#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];
|
char buf[MAX_ADDR_LEN + 1];
|
||||||
int retval = AF_MAX;
|
int retval = AF_MAX;
|
||||||
|
|
||||||
strncpy(buf, p, p_len);
|
strncpy(buf, p, p_len);
|
||||||
buf[p_len] = '\0';
|
buf[p_len] = '\0';
|
||||||
@ -62,13 +61,14 @@ static int try_inet_pton(int p_len, const char *p, char *n)
|
|||||||
return retval;
|
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 &&
|
if (family == AF_INET6
|
||||||
(IN6_IS_ADDR_V4COMPAT(ia) ||
|
&& (IN6_IS_ADDR_V4COMPAT(ia) || IN6_IS_ADDR_V4MAPPED(ia)))
|
||||||
IN6_IS_ADDR_V4MAPPED(ia))) {
|
{
|
||||||
family = AF_INET;
|
family = AF_INET;
|
||||||
memmove(n, n + 12, sizeof(struct in_addr));
|
memmove(n, n + 12, sizeof(struct in_addr));
|
||||||
}
|
}
|
||||||
@ -76,15 +76,12 @@ static int convert_v6_to_v4(int family, char *n)
|
|||||||
return family;
|
return family;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int ipaddress(void *ptr,
|
ipaddress(void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
|
||||||
int a_len, const void *a_in,
|
|
||||||
int b_len, const void *b_in)
|
|
||||||
{
|
{
|
||||||
char a_addr[sizeof(struct in6_addr)],
|
char a_addr[sizeof(struct in6_addr)], b_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;
|
||||||
const char *a_str = (const char *)a_in, *b_str = (const char *)b_in;
|
int a_family, b_family, retval;
|
||||||
int a_family, b_family, retval;
|
|
||||||
|
|
||||||
if ((a_len > MAX_ADDR_LEN) || (b_len > MAX_ADDR_LEN)) {
|
if ((a_len > MAX_ADDR_LEN) || (b_len > MAX_ADDR_LEN)) {
|
||||||
return strnatcasecmp(a_len, a_str, b_len, b_str);
|
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) {
|
if (a_family == AF_MAX && b_family == AF_MAX) {
|
||||||
return strnatcasecmp(a_len, a_str, b_len, b_str);
|
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;
|
retval = -1;
|
||||||
}
|
} else if (a_family != AF_MAX && b_family == AF_MAX) {
|
||||||
else if (a_family != AF_MAX && b_family == AF_MAX) {
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
a_family = convert_v6_to_v4(a_family, a_addr);
|
a_family = convert_v6_to_v4(a_family, a_addr);
|
||||||
b_family = convert_v6_to_v4(b_family, b_addr);
|
b_family = convert_v6_to_v4(b_family, b_addr);
|
||||||
if (a_family == b_family) {
|
if (a_family == b_family) {
|
||||||
retval = memcmp(a_addr, b_addr,
|
retval = memcmp(a_addr,
|
||||||
a_family == AF_INET ?
|
b_addr,
|
||||||
sizeof(struct in_addr) :
|
a_family == AF_INET ? sizeof(struct in_addr)
|
||||||
sizeof(struct in6_addr));
|
: sizeof(struct in6_addr));
|
||||||
}
|
} else if (a_family == AF_INET) {
|
||||||
else if (a_family == AF_INET) {
|
|
||||||
retval = -1;
|
retval = -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,40 +119,37 @@ int ipaddress(void *ptr,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int sql_strnatcmp(void *ptr,
|
sql_strnatcmp(
|
||||||
int a_len, const void *a_in,
|
void* ptr, int a_len, const void* a_in, int b_len, const void* b_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
|
static int
|
||||||
int sql_strnatcasecmp(void *ptr,
|
sql_strnatcasecmp(
|
||||||
int a_len, const void *a_in,
|
void* ptr, int a_len, const void* a_in, int b_len, const void* b_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
|
static int
|
||||||
int sql_loglevelcmp(void *ptr,
|
sql_loglevelcmp(
|
||||||
int a_len, const void *a_in,
|
void* ptr, int a_len, const void* a_in, int b_len, const void* b_in)
|
||||||
int b_len, const void *b_in)
|
|
||||||
{
|
{
|
||||||
return levelcmp((const char *)a_in, a_len,
|
return levelcmp((const char*) a_in, a_len, (const char*) b_in, b_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, "ipaddress", SQLITE_UTF8, nullptr, ipaddress);
|
||||||
sqlite3_create_collation(db, "naturalcase", SQLITE_UTF8, nullptr,
|
sqlite3_create_collation(
|
||||||
sql_strnatcmp);
|
db, "naturalcase", SQLITE_UTF8, nullptr, sql_strnatcmp);
|
||||||
sqlite3_create_collation(db, "naturalnocase", SQLITE_UTF8, nullptr,
|
sqlite3_create_collation(
|
||||||
sql_strnatcasecmp);
|
db, "naturalnocase", SQLITE_UTF8, nullptr, sql_strnatcasecmp);
|
||||||
sqlite3_create_collation(db, "loglevel", SQLITE_UTF8, nullptr,
|
sqlite3_create_collation(
|
||||||
sql_loglevelcmp);
|
db, "loglevel", SQLITE_UTF8, nullptr, sql_loglevelcmp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -21,52 +21,55 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file column_namer.cc
|
* @file column_namer.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "base/string_util.hh"
|
|
||||||
#include "sql_util.hh"
|
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
|
||||||
#include "column_namer.hh"
|
#include "column_namer.hh"
|
||||||
|
|
||||||
bool column_namer::existing_name(const std::string &in_name) const
|
#include "base/lnav_log.hh"
|
||||||
|
#include "base/string_util.hh"
|
||||||
|
#include "config.h"
|
||||||
|
#include "sql_util.hh"
|
||||||
|
|
||||||
|
bool
|
||||||
|
column_namer::existing_name(const std::string& in_name) const
|
||||||
{
|
{
|
||||||
if (std::binary_search(std::begin(sql_keywords),
|
if (std::binary_search(
|
||||||
std::end(sql_keywords),
|
std::begin(sql_keywords), std::end(sql_keywords), toupper(in_name)))
|
||||||
toupper(in_name))) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find(this->cn_builtin_names.begin(),
|
if (std::find(this->cn_builtin_names.begin(),
|
||||||
this->cn_builtin_names.end(),
|
this->cn_builtin_names.end(),
|
||||||
in_name) != this->cn_builtin_names.end()) {
|
in_name)
|
||||||
|
!= this->cn_builtin_names.end())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find(this->cn_names.begin(),
|
if (std::find(this->cn_names.begin(), this->cn_names.end(), in_name)
|
||||||
this->cn_names.end(),
|
!= this->cn_names.end())
|
||||||
in_name) != this->cn_names.end()) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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;
|
std::string base_name = in_name, retval;
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
buf_size = in_name.length() + 64;
|
buf_size = in_name.length() + 64;
|
||||||
char buffer[buf_size];
|
char buffer[buf_size];
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -33,16 +33,16 @@
|
|||||||
#define lnav_column_namer_hh
|
#define lnav_column_namer_hh
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class column_namer {
|
class column_namer {
|
||||||
public:
|
public:
|
||||||
column_namer() : cn_builtin_names({"col"}) {}
|
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_builtin_names;
|
||||||
std::vector<std::string> cn_names;
|
std::vector<std::string> cn_names;
|
||||||
|
@ -21,32 +21,31 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/fs_util.hh"
|
|
||||||
#include "base/string_util.hh"
|
|
||||||
#include "base/injector.hh"
|
|
||||||
#include "yajlpp/json_ptr.hh"
|
|
||||||
#include "lnav.hh"
|
|
||||||
#include "log_format_loader.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 "command_executor.hh"
|
||||||
|
|
||||||
|
#include "base/fs_util.hh"
|
||||||
|
#include "base/injector.hh"
|
||||||
|
#include "base/string_util.hh"
|
||||||
|
#include "bound_tags.hh"
|
||||||
|
#include "config.h"
|
||||||
#include "db_sub_source.hh"
|
#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 "papertrail_proc.hh"
|
||||||
|
#include "service_tags.hh"
|
||||||
|
#include "shlex.hh"
|
||||||
|
#include "sql_util.hh"
|
||||||
|
#include "yajlpp/json_ptr.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -59,12 +58,13 @@ SELECT count(*) AS total, min(log_line) AS log_line, log_msg_format
|
|||||||
ORDER BY total DESC
|
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;
|
static sig_atomic_t sql_counter = 0;
|
||||||
|
|
||||||
size_t total = lnav_data.ld_log_source.text_line_count();
|
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) {
|
if (off < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -89,7 +89,8 @@ int sql_progress(const struct log_cursor &lc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sql_progress_finished()
|
void
|
||||||
|
sql_progress_finished()
|
||||||
{
|
{
|
||||||
if (lnav_data.ld_window == nullptr) {
|
if (lnav_data.ld_window == nullptr) {
|
||||||
return;
|
return;
|
||||||
@ -102,9 +103,14 @@ void sql_progress_finished()
|
|||||||
lnav_data.ld_views[LNV_DB].redo_search();
|
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;
|
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()) {
|
if ((iter = lnav_commands.find(args[0])) == lnav_commands.end()) {
|
||||||
return ec.make_error("unknown command - {}", args[0]);
|
return ec.make_error("unknown command - {}", args[0]);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return iter->second->c_func(ec, cmdline, args);
|
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");
|
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);
|
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
|
||||||
struct timeval start_tv, end_tv;
|
struct timeval start_tv, end_tv;
|
||||||
string stmt_str = trim(sql);
|
string stmt_str = trim(sql);
|
||||||
@ -143,8 +149,8 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
|
|||||||
vector<string> args;
|
vector<string> args;
|
||||||
split_ws(stmt_str, args);
|
split_ws(stmt_str, args);
|
||||||
|
|
||||||
auto sql_cmd_map = injector::get<
|
auto sql_cmd_map = injector::get<readline_context::command_map_t*,
|
||||||
readline_context::command_map_t *, sql_cmd_map_tag>();
|
sql_cmd_map_tag>();
|
||||||
auto cmd_iter = sql_cmd_map->find(args[0]);
|
auto cmd_iter = sql_cmd_map->find(args[0]);
|
||||||
|
|
||||||
if (cmd_iter != sql_cmd_map->end()) {
|
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();
|
ec.ec_accumulator->clear();
|
||||||
|
|
||||||
pair<string, int> source = ec.ec_source.top();
|
pair<string, int> source = ec.ec_source.top();
|
||||||
sql_progress_guard progress_guard(sql_progress,
|
sql_progress_guard progress_guard(
|
||||||
sql_progress_finished,
|
sql_progress, sql_progress_finished, source.first, source.second);
|
||||||
source.first,
|
|
||||||
source.second);
|
|
||||||
gettimeofday(&start_tv, nullptr);
|
gettimeofday(&start_tv, nullptr);
|
||||||
retcode = sqlite3_prepare_v2(lnav_data.ld_db.in(),
|
retcode = sqlite3_prepare_v2(
|
||||||
stmt_str.c_str(),
|
lnav_data.ld_db.in(), stmt_str.c_str(), -1, stmt.out(), nullptr);
|
||||||
-1,
|
|
||||||
stmt.out(),
|
|
||||||
nullptr);
|
|
||||||
if (retcode != SQLITE_OK) {
|
if (retcode != SQLITE_OK) {
|
||||||
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
const char* errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
||||||
|
|
||||||
alt_msg = "";
|
alt_msg = "";
|
||||||
return ec.make_error("{}", errmsg);
|
return ec.make_error("{}", errmsg);
|
||||||
}
|
} else if (stmt == nullptr) {
|
||||||
else if (stmt == nullptr) {
|
|
||||||
alt_msg = "";
|
alt_msg = "";
|
||||||
return ec.make_error("No statement given");
|
return ec.make_error("No statement given");
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SQLITE3_STMT_READONLY
|
#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(
|
return ec.make_error(
|
||||||
"modifying statements are not allowed in this context: {}", sql);
|
"modifying statements are not allowed in this context: {}", sql);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
bool done = false;
|
bool done = false;
|
||||||
int param_count;
|
int param_count;
|
||||||
|
|
||||||
param_count = sqlite3_bind_parameter_count(stmt.in());
|
param_count = sqlite3_bind_parameter_count(stmt.in());
|
||||||
for (int lpc = 0; lpc < param_count; lpc++) {
|
for (int lpc = 0; lpc < param_count; lpc++) {
|
||||||
map<string, string>::iterator ov_iter;
|
map<string, string>::iterator ov_iter;
|
||||||
const char *name;
|
const char* name;
|
||||||
|
|
||||||
name = sqlite3_bind_parameter_name(stmt.in(), lpc + 1);
|
name = sqlite3_bind_parameter_name(stmt.in(), lpc + 1);
|
||||||
ov_iter = ec.ec_override.find(name);
|
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.c_str(),
|
||||||
ov_iter->second.length(),
|
ov_iter->second.length(),
|
||||||
SQLITE_TRANSIENT);
|
SQLITE_TRANSIENT);
|
||||||
}
|
} else if (name[0] == '$') {
|
||||||
else if (name[0] == '$') {
|
const auto& lvars = ec.ec_local_vars.top();
|
||||||
const auto &lvars = ec.ec_local_vars.top();
|
const auto& gvars = ec.ec_global_vars;
|
||||||
const auto &gvars = ec.ec_global_vars;
|
|
||||||
map<string, string>::const_iterator local_var, global_var;
|
map<string, string>::const_iterator local_var, global_var;
|
||||||
const char *env_value;
|
const char* env_value;
|
||||||
|
|
||||||
if (lnav_data.ld_window) {
|
if (lnav_data.ld_window) {
|
||||||
char buf[32];
|
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);
|
getmaxyx(lnav_data.ld_window, lines, cols);
|
||||||
if (strcmp(name, "$LINES") == 0) {
|
if (strcmp(name, "$LINES") == 0) {
|
||||||
snprintf(buf, sizeof(buf), "%d", lines);
|
snprintf(buf, sizeof(buf), "%d", lines);
|
||||||
sqlite3_bind_text(stmt.in(), lpc + 1,
|
sqlite3_bind_text(
|
||||||
buf, -1,
|
stmt.in(), lpc + 1, buf, -1, SQLITE_TRANSIENT);
|
||||||
SQLITE_TRANSIENT);
|
|
||||||
} else if (strcmp(name, "$COLS") == 0) {
|
} else if (strcmp(name, "$COLS") == 0) {
|
||||||
snprintf(buf, sizeof(buf), "%d", cols);
|
snprintf(buf, sizeof(buf), "%d", cols);
|
||||||
sqlite3_bind_text(stmt.in(), lpc + 1,
|
sqlite3_bind_text(
|
||||||
buf, -1,
|
stmt.in(), lpc + 1, buf, -1, SQLITE_TRANSIENT);
|
||||||
SQLITE_TRANSIENT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((local_var = lvars.find(&name[1])) != lvars.end()) {
|
if ((local_var = lvars.find(&name[1])) != lvars.end()) {
|
||||||
sqlite3_bind_text(stmt.in(), lpc + 1,
|
sqlite3_bind_text(stmt.in(),
|
||||||
local_var->second.c_str(), -1,
|
lpc + 1,
|
||||||
|
local_var->second.c_str(),
|
||||||
|
-1,
|
||||||
SQLITE_TRANSIENT);
|
SQLITE_TRANSIENT);
|
||||||
}
|
} else if ((global_var = gvars.find(&name[1])) != gvars.end()) {
|
||||||
else if ((global_var = gvars.find(&name[1])) != gvars.end()) {
|
sqlite3_bind_text(stmt.in(),
|
||||||
sqlite3_bind_text(stmt.in(), lpc + 1,
|
lpc + 1,
|
||||||
global_var->second.c_str(), -1,
|
global_var->second.c_str(),
|
||||||
|
-1,
|
||||||
SQLITE_TRANSIENT);
|
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) {
|
} else if (name[0] == ':' && ec.ec_line_values != nullptr) {
|
||||||
sqlite3_bind_text(stmt.in(), lpc + 1, env_value, -1, SQLITE_STATIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name[0] == ':' && ec.ec_line_values != nullptr) {
|
|
||||||
for (auto& lv : *ec.ec_line_values) {
|
for (auto& lv : *ec.ec_line_values) {
|
||||||
if (lv.lv_meta.lvm_name != &name[1]) {
|
if (lv.lv_meta.lvm_name != &name[1]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (lv.lv_meta.lvm_kind) {
|
switch (lv.lv_meta.lvm_kind) {
|
||||||
case value_kind_t::VALUE_BOOLEAN:
|
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;
|
break;
|
||||||
case value_kind_t::VALUE_FLOAT:
|
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;
|
break;
|
||||||
case value_kind_t::VALUE_INTEGER:
|
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;
|
break;
|
||||||
case value_kind_t::VALUE_NULL:
|
case value_kind_t::VALUE_NULL:
|
||||||
sqlite3_bind_null(stmt.in(), lpc + 1);
|
sqlite3_bind_null(stmt.in(), lpc + 1);
|
||||||
@ -268,8 +272,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
sqlite3_bind_null(stmt.in(), lpc + 1);
|
sqlite3_bind_null(stmt.in(), lpc + 1);
|
||||||
log_warning("Could not bind variable: %s", name);
|
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;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
const char *errmsg;
|
const char* errmsg;
|
||||||
|
|
||||||
log_error("sqlite3_step error code: %d", retcode);
|
log_error("sqlite3_step error code: %d", retcode);
|
||||||
errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
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() &&
|
if (!dls.dls_rows.empty() && !ec.ec_local_vars.empty()
|
||||||
!ec.ec_dry_run) {
|
&& !ec.ec_dry_run) {
|
||||||
auto &vars = ec.ec_local_vars.top();
|
auto& vars = ec.ec_local_vars.top();
|
||||||
|
|
||||||
for (unsigned int lpc = 0; lpc < dls.dls_headers.size(); lpc++) {
|
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())) {
|
if (sql_ident_needs_quote(column_name.c_str())) {
|
||||||
continue;
|
continue;
|
||||||
@ -342,8 +345,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
|
|||||||
|
|
||||||
if (!ec.ec_accumulator->empty()) {
|
if (!ec.ec_accumulator->empty()) {
|
||||||
retval = ec.ec_accumulator->get_string();
|
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 (lnav_data.ld_flags & LNF_HEADLESS) {
|
||||||
if (ec.ec_local_vars.size() == 1) {
|
if (ec.ec_local_vars.size() == 1) {
|
||||||
ensure_view(&lnav_data.ld_views[LNV_DB]);
|
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 = "";
|
retval = "";
|
||||||
alt_msg = "";
|
alt_msg = "";
|
||||||
}
|
} else if (dls.dls_rows.size() == 1) {
|
||||||
else if (dls.dls_rows.size() == 1) {
|
auto& row = dls.dls_rows[0];
|
||||||
auto &row = dls.dls_rows[0];
|
|
||||||
|
|
||||||
if (dls.dls_headers.size() == 1) {
|
if (dls.dls_headers.size() == 1) {
|
||||||
retval = row[0];
|
retval = row[0];
|
||||||
} else {
|
} 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) {
|
if (lpc > 0) {
|
||||||
retval.append("; ");
|
retval.append("; ");
|
||||||
}
|
}
|
||||||
@ -367,29 +369,31 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
|
|||||||
retval.append(row[lpc]);
|
retval.append(row[lpc]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int row_count = dls.dls_rows.size();
|
int row_count = dls.dls_rows.size();
|
||||||
char row_count_buf[128];
|
char row_count_buf[128];
|
||||||
struct timeval diff_tv;
|
struct timeval diff_tv;
|
||||||
|
|
||||||
timersub(&end_tv, &start_tv, &diff_tv);
|
timersub(&end_tv, &start_tv, &diff_tv);
|
||||||
snprintf(row_count_buf, sizeof(row_count_buf),
|
snprintf(row_count_buf,
|
||||||
ANSI_BOLD("%'d") " row%s matched in "
|
sizeof(row_count_buf),
|
||||||
ANSI_BOLD("%ld.%03ld") " seconds",
|
ANSI_BOLD("%'d") " row%s matched in " ANSI_BOLD(
|
||||||
|
"%ld.%03ld") " seconds",
|
||||||
row_count,
|
row_count,
|
||||||
row_count == 1 ? "" : "s",
|
row_count == 1 ? "" : "s",
|
||||||
diff_tv.tv_sec,
|
diff_tv.tv_sec,
|
||||||
std::max((long) diff_tv.tv_usec / 1000, 1L));
|
std::max((long) diff_tv.tv_usec / 1000, 1L));
|
||||||
retval = row_count_buf;
|
retval = row_count_buf;
|
||||||
alt_msg = HELP_MSG_2(
|
alt_msg = HELP_MSG_2(
|
||||||
y, Y,
|
y,
|
||||||
|
Y,
|
||||||
"to move forward/backward through query results "
|
"to move forward/backward through query results "
|
||||||
"in the log view");
|
"in the log view");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SQLITE3_STMT_READONLY
|
#ifdef HAVE_SQLITE3_STMT_READONLY
|
||||||
else if (sqlite3_stmt_readonly(stmt.in())) {
|
else if (sqlite3_stmt_readonly(stmt.in()))
|
||||||
|
{
|
||||||
retval = "info: No rows matched";
|
retval = "info: No rows matched";
|
||||||
alt_msg = "";
|
alt_msg = "";
|
||||||
|
|
||||||
@ -405,25 +409,27 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
|
|||||||
return Ok(retval);
|
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 stdin_path("-");
|
||||||
static ghc::filesystem::path dev_stdin_path("/dev/stdin");
|
static ghc::filesystem::path dev_stdin_path("/dev/stdin");
|
||||||
|
|
||||||
string retval;
|
string retval;
|
||||||
FILE *file;
|
FILE* file;
|
||||||
|
|
||||||
if (path == stdin_path || path == dev_stdin_path) {
|
if (path == stdin_path || path == dev_stdin_path) {
|
||||||
if (isatty(STDIN_FILENO)) {
|
if (isatty(STDIN_FILENO)) {
|
||||||
return ec.make_error("stdin has already been consumed");
|
return ec.make_error("stdin has already been consumed");
|
||||||
}
|
}
|
||||||
file = stdin;
|
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");
|
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;
|
auto_mem<char> line;
|
||||||
size_t line_max_size;
|
size_t line_max_size;
|
||||||
ssize_t line_size;
|
ssize_t line_size;
|
||||||
@ -448,7 +454,8 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
|
|||||||
case ';':
|
case ';':
|
||||||
case '|':
|
case '|':
|
||||||
if (mode) {
|
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;
|
starting_line_number = line_number;
|
||||||
@ -458,17 +465,17 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
|
|||||||
default:
|
default:
|
||||||
if (multiline) {
|
if (multiline) {
|
||||||
cmdline += line;
|
cmdline += line;
|
||||||
}
|
} else {
|
||||||
else {
|
retval = TRY(execute_from_file(
|
||||||
retval = TRY(execute_from_file(ec, path, line_number, ':', line.in()));
|
ec, path, line_number, ':', line.in()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode) {
|
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) {
|
if (file == stdin) {
|
||||||
@ -483,7 +490,8 @@ static Result<string, string> execute_file_contents(exec_context &ec, const ghc:
|
|||||||
return Ok(retval);
|
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;
|
available_scripts scripts;
|
||||||
vector<string> split_args;
|
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);
|
add_ansi_vars(vars);
|
||||||
|
|
||||||
snprintf(env_arg_name, sizeof(env_arg_name), "%d",
|
snprintf(
|
||||||
(int) split_args.size() - 1);
|
env_arg_name, sizeof(env_arg_name), "%d", (int) split_args.size() - 1);
|
||||||
|
|
||||||
vars["#"] = env_arg_name;
|
vars["#"] = env_arg_name;
|
||||||
for (size_t lpc = 0; lpc < split_args.size(); lpc++) {
|
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()) {
|
if (!paths_to_exec.empty()) {
|
||||||
for (auto &path_iter : paths_to_exec) {
|
for (auto& path_iter : paths_to_exec) {
|
||||||
retval = TRY(
|
retval
|
||||||
execute_file_contents(ec, path_iter.sm_path, multiline));
|
= TRY(execute_file_contents(ec, path_iter.sm_path, multiline));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ec.ec_local_vars.pop();
|
ec.ec_local_vars.pop();
|
||||||
|
|
||||||
if (paths_to_exec.empty()) {
|
if (paths_to_exec.empty()) {
|
||||||
return ec.make_error("unknown script -- {} -- {}",
|
return ec.make_error(
|
||||||
script_name, open_error);
|
"unknown script -- {} -- {}", script_name, open_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(retval);
|
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;
|
string retval, alt_msg;
|
||||||
auto _sg = ec.enter_source(path.string(), line_number);
|
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));
|
retval = TRY(execute_command(ec, cmdline));
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
lnav_data.ld_view_stack.top() | [cmdline] (auto tc) {
|
lnav_data.ld_view_stack.top() |
|
||||||
tc->execute_search(cmdline.substr(1));
|
[cmdline](auto tc) { tc->execute_search(cmdline.substr(1)); };
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
setup_logline_table(ec);
|
setup_logline_table(ec);
|
||||||
@ -609,15 +621,16 @@ Result<string, string> execute_from_file(exec_context &ec, const ghc::filesystem
|
|||||||
return Ok(retval);
|
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);
|
string retval, alt_msg, cmdline = cmdline_with_mode.substr(1);
|
||||||
auto _cleanup = finally([&ec] {
|
auto _cleanup = finally([&ec] {
|
||||||
if (ec.is_read_write() &&
|
if (ec.is_read_write() &&
|
||||||
// only rebuild in a script or non-interactive mode so we don't
|
// only rebuild in a script or non-interactive mode so we don't
|
||||||
// block the UI.
|
// block the UI.
|
||||||
(lnav_data.ld_flags & LNF_HEADLESS ||
|
(lnav_data.ld_flags & LNF_HEADLESS || ec.ec_path_stack.size() > 1))
|
||||||
ec.ec_path_stack.size() > 1)) {
|
{
|
||||||
rescan_files();
|
rescan_files();
|
||||||
rebuild_indexes_repeatedly();
|
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));
|
retval = TRY(execute_command(ec, cmdline));
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
lnav_data.ld_view_stack.top() | [cmdline] (auto tc) {
|
lnav_data.ld_view_stack.top() |
|
||||||
tc->execute_search(cmdline.substr(1));
|
[cmdline](auto tc) { tc->execute_search(cmdline.substr(1)); };
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
setup_logline_table(ec);
|
setup_logline_table(ec);
|
||||||
@ -648,38 +660,40 @@ Result<string, string> execute_any(exec_context &ec, const string &cmdline_with_
|
|||||||
return Ok(retval);
|
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) {
|
if (lnav_data.ld_cmd_init_done) {
|
||||||
return;
|
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;
|
int option_index = 1;
|
||||||
|
|
||||||
log_info("Executing initial commands");
|
log_info("Executing initial commands");
|
||||||
for (auto &cmd : lnav_data.ld_commands) {
|
for (auto& cmd : lnav_data.ld_commands) {
|
||||||
string alt_msg;
|
string alt_msg;
|
||||||
|
|
||||||
wait_for_children();
|
wait_for_children();
|
||||||
|
|
||||||
ec.ec_source.emplace("command-option", option_index++);
|
ec.ec_source.emplace("command-option", option_index++);
|
||||||
switch (cmd.at(0)) {
|
switch (cmd.at(0)) {
|
||||||
case ':':
|
case ':':
|
||||||
msgs.emplace_back(execute_command(ec, cmd.substr(1)), alt_msg);
|
msgs.emplace_back(execute_command(ec, cmd.substr(1)), alt_msg);
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
lnav_data.ld_view_stack.top() | [cmd] (auto tc) {
|
lnav_data.ld_view_stack.top() |
|
||||||
tc->execute_search(cmd.substr(1));
|
[cmd](auto tc) { tc->execute_search(cmd.substr(1)); };
|
||||||
};
|
break;
|
||||||
break;
|
case ';':
|
||||||
case ';':
|
setup_logline_table(ec);
|
||||||
setup_logline_table(ec);
|
msgs.emplace_back(execute_sql(ec, cmd.substr(1), alt_msg),
|
||||||
msgs.emplace_back(execute_sql(ec, cmd.substr(1), alt_msg), alt_msg);
|
alt_msg);
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
msgs.emplace_back(execute_file(ec, cmd.substr(1)), alt_msg);
|
msgs.emplace_back(execute_file(ec, cmd.substr(1)), alt_msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rescan_files();
|
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()) {
|
if (!lnav_data.ld_pt_search.empty()) {
|
||||||
#ifdef HAVE_LIBCURL
|
#ifdef HAVE_LIBCURL
|
||||||
auto pt = make_shared<papertrail_proc>(
|
auto pt = make_shared<papertrail_proc>(lnav_data.ld_pt_search.substr(3),
|
||||||
lnav_data.ld_pt_search.substr(3),
|
lnav_data.ld_pt_min_time,
|
||||||
lnav_data.ld_pt_min_time,
|
lnav_data.ld_pt_max_time);
|
||||||
lnav_data.ld_pt_max_time);
|
lnav_data.ld_active_files.fc_file_names[lnav_data.ld_pt_search].with_fd(
|
||||||
lnav_data.ld_active_files.fc_file_names[lnav_data.ld_pt_search]
|
pt->copy_fd());
|
||||||
.with_fd(pt->copy_fd());
|
isc::to<curl_looper&, services::curl_streamer_t>().send(
|
||||||
isc::to<curl_looper&, services::curl_streamer_t>()
|
[pt](auto& clooper) { clooper.add_request(pt); });
|
||||||
.send([pt](auto& clooper) {
|
|
||||||
clooper.add_request(pt);
|
|
||||||
});
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,9 +722,10 @@ void execute_init_commands(exec_context &ec, vector<pair<Result<string, string>,
|
|||||||
lnav_data.ld_cmd_init_done = true;
|
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)) {
|
if (!sqlite3_stmt_busy(stmt)) {
|
||||||
dls.clear();
|
dls.clear();
|
||||||
@ -721,8 +733,8 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stacked_bar_chart<std::string> &chart = dls.dls_chart;
|
stacked_bar_chart<std::string>& chart = dls.dls_chart;
|
||||||
view_colors &vc = view_colors::singleton();
|
view_colors& vc = view_colors::singleton();
|
||||||
int ncols = sqlite3_column_count(stmt);
|
int ncols = sqlite3_column_count(stmt);
|
||||||
int row_number;
|
int row_number;
|
||||||
int lpc, retval = 0;
|
int lpc, retval = 0;
|
||||||
@ -731,14 +743,14 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
|
|||||||
dls.dls_rows.resize(row_number + 1);
|
dls.dls_rows.resize(row_number + 1);
|
||||||
if (dls.dls_headers.empty()) {
|
if (dls.dls_headers.empty()) {
|
||||||
for (lpc = 0; lpc < ncols; lpc++) {
|
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);
|
string colname = sqlite3_column_name(stmt, lpc);
|
||||||
bool graphable;
|
bool graphable;
|
||||||
|
|
||||||
graphable = ((type == SQLITE_INTEGER || type == SQLITE_FLOAT) &&
|
graphable = ((type == SQLITE_INTEGER || type == SQLITE_FLOAT)
|
||||||
!binary_search(lnav_data.ld_db_key_names.begin(),
|
&& !binary_search(lnav_data.ld_db_key_names.begin(),
|
||||||
lnav_data.ld_db_key_names.end(),
|
lnav_data.ld_db_key_names.end(),
|
||||||
colname));
|
colname));
|
||||||
|
|
||||||
dls.push_header(colname, type, graphable);
|
dls.push_header(colname, type, graphable);
|
||||||
if (graphable) {
|
if (graphable) {
|
||||||
@ -748,13 +760,15 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (lpc = 0; lpc < ncols; lpc++) {
|
for (lpc = 0; lpc < ncols; lpc++) {
|
||||||
const char *value = (const char *)sqlite3_column_text(stmt, lpc);
|
const char* value = (const char*) sqlite3_column_text(stmt, lpc);
|
||||||
db_label_source::header_meta &hm = dls.dls_headers[lpc];
|
db_label_source::header_meta& hm = dls.dls_headers[lpc];
|
||||||
|
|
||||||
dls.push_column(value);
|
dls.push_column(value);
|
||||||
if ((hm.hm_column_type == SQLITE_TEXT ||
|
if ((hm.hm_column_type == SQLITE_TEXT
|
||||||
hm.hm_column_type == SQLITE_NULL) && hm.hm_sub_type == 0) {
|
|| hm.hm_column_type == SQLITE_NULL)
|
||||||
sqlite3_value *raw_value = sqlite3_column_value(stmt, lpc);
|
&& hm.hm_sub_type == 0)
|
||||||
|
{
|
||||||
|
sqlite3_value* raw_value = sqlite3_column_value(stmt, lpc);
|
||||||
|
|
||||||
switch (sqlite3_value_type(raw_value)) {
|
switch (sqlite3_value_type(raw_value)) {
|
||||||
case SQLITE_TEXT:
|
case SQLITE_TEXT:
|
||||||
@ -768,12 +782,13 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
|
|||||||
return retval;
|
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();
|
auto out = ec.get_output();
|
||||||
|
|
||||||
if (out) {
|
if (out) {
|
||||||
FILE *file = *out;
|
FILE* file = *out;
|
||||||
|
|
||||||
return std::async(std::launch::async, [&fd, file]() {
|
return std::async(std::launch::async, [&fd, file]() {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
@ -791,8 +806,10 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto pp = make_shared<piper_proc>(
|
auto pp = make_shared<piper_proc>(
|
||||||
fd, false, lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
|
fd,
|
||||||
"lnav.out.XXXXXX")
|
false,
|
||||||
|
lnav::filesystem::open_temp_file(
|
||||||
|
ghc::filesystem::temp_directory_path() / "lnav.out.XXXXXX")
|
||||||
.map([](auto pair) {
|
.map([](auto pair) {
|
||||||
ghc::filesystem::remove(pair.first);
|
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);
|
lnav_data.ld_pipers.push_back(pp);
|
||||||
snprintf(desc,
|
snprintf(desc,
|
||||||
sizeof(desc), "[%d] Output of %s",
|
sizeof(desc),
|
||||||
|
"[%d] Output of %s",
|
||||||
exec_count++,
|
exec_count++,
|
||||||
cmdline.c_str());
|
cmdline.c_str());
|
||||||
lnav_data.ld_active_files.fc_file_names[desc]
|
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);
|
shlex subber(iter.second);
|
||||||
string str;
|
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) {
|
if (this->ec_source.size() <= 1) {
|
||||||
return "error: ";
|
return "error: ";
|
||||||
@ -849,7 +869,8 @@ std::string exec_context::get_error_prefix()
|
|||||||
return fmt::format("{}:{}: error: ", source.first, source.second);
|
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());
|
log_info("redirecting command output to: %s", name.c_str());
|
||||||
this->ec_output_stack.back().second | [](auto out) {
|
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);
|
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");
|
log_info("redirecting command output to screen");
|
||||||
this->ec_output_stack.back().second | [](auto out) {
|
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);
|
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,
|
sql_callback_t sql_callback,
|
||||||
pipe_callback_t pipe_callback)
|
pipe_callback_t pipe_callback)
|
||||||
: ec_line_values(line_values),
|
: ec_line_values(line_values),
|
||||||
ec_accumulator(std::make_unique<attr_line_t>()),
|
ec_accumulator(std::make_unique<attr_line_t>()),
|
||||||
ec_sql_callback(sql_callback),
|
ec_sql_callback(sql_callback), ec_pipe_callback(pipe_callback)
|
||||||
ec_pipe_callback(pipe_callback) {
|
{
|
||||||
this->ec_local_vars.push(std::map<std::string, std::string>());
|
this->ec_local_vars.push(std::map<std::string, std::string>());
|
||||||
this->ec_path_stack.emplace_back(".");
|
this->ec_path_stack.emplace_back(".");
|
||||||
this->ec_source.emplace("command", 1);
|
this->ec_source.emplace("command", 1);
|
||||||
this->ec_output_stack.emplace_back("screen", nonstd::nullopt);
|
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,
|
std::string name,
|
||||||
const nonstd::optional<output_t> &file)
|
const nonstd::optional<output_t>& file)
|
||||||
: sg_context(context) {
|
: sg_context(context)
|
||||||
|
{
|
||||||
if (file) {
|
if (file) {
|
||||||
log_info("redirecting command output to: %s", name.c_str());
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,26 +30,30 @@
|
|||||||
#ifndef LNAV_COMMAND_EXECUTOR_H
|
#ifndef LNAV_COMMAND_EXECUTOR_H
|
||||||
#define LNAV_COMMAND_EXECUTOR_H
|
#define LNAV_COMMAND_EXECUTOR_H
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include <sqlite3.h>
|
||||||
#include "optional.hpp"
|
|
||||||
#include "auto_fd.hh"
|
#include "auto_fd.hh"
|
||||||
#include "bookmarks.hh"
|
#include "bookmarks.hh"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "ghc/filesystem.hpp"
|
||||||
|
#include "optional.hpp"
|
||||||
#include "shlex.resolver.hh"
|
#include "shlex.resolver.hh"
|
||||||
|
#include "vis_line.hh"
|
||||||
|
|
||||||
struct exec_context;
|
struct exec_context;
|
||||||
class attr_line_t;
|
class attr_line_t;
|
||||||
class logline_value;
|
class logline_value;
|
||||||
|
|
||||||
typedef int (*sql_callback_t)(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);
|
int sql_callback(exec_context& ec, sqlite3_stmt* stmt);
|
||||||
|
|
||||||
typedef std::future<std::string> (*pipe_callback_t)(
|
typedef std::future<std::string> (*pipe_callback_t)(exec_context& ec,
|
||||||
exec_context &ec, const std::string &cmdline, auto_fd &fd);
|
const std::string& cmdline,
|
||||||
|
auto_fd& fd);
|
||||||
|
|
||||||
struct exec_context {
|
struct exec_context {
|
||||||
enum class perm_t {
|
enum class perm_t {
|
||||||
@ -57,38 +61,44 @@ struct exec_context {
|
|||||||
READ_ONLY,
|
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,
|
sql_callback_t sql_callback = ::sql_callback,
|
||||||
pipe_callback_t pipe_callback = nullptr);
|
pipe_callback_t pipe_callback = nullptr);
|
||||||
|
|
||||||
bool is_read_write() const {
|
bool is_read_write() const
|
||||||
|
{
|
||||||
return this->ec_perms == perm_t::READ_WRITE;
|
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;
|
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;
|
this->ec_perms = perms;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_error_prefix();
|
std::string get_error_prefix();
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename... Args>
|
||||||
Result<std::string, std::string> make_error(
|
Result<std::string, std::string> make_error(fmt::string_view format_str,
|
||||||
fmt::string_view format_str, const Args& ...args) {
|
const Args&... args)
|
||||||
return Err(this->get_error_prefix() +
|
{
|
||||||
fmt::vformat(format_str, fmt::make_format_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();
|
for (auto iter = this->ec_output_stack.rbegin();
|
||||||
iter != this->ec_output_stack.rend();
|
iter != this->ec_output_stack.rend();
|
||||||
++iter) {
|
++iter)
|
||||||
|
{
|
||||||
if (iter->second && (*iter->second).first) {
|
if (iter->second && (*iter->second).first) {
|
||||||
return (*iter->second).first;
|
return (*iter->second).first;
|
||||||
}
|
}
|
||||||
@ -97,38 +107,40 @@ struct exec_context {
|
|||||||
return nonstd::nullopt;
|
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();
|
void clear_output();
|
||||||
|
|
||||||
struct source_guard {
|
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();
|
this->sg_context.ec_source.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_context &sg_context;
|
exec_context& sg_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_guard {
|
struct output_guard {
|
||||||
explicit output_guard(exec_context &context,
|
explicit output_guard(exec_context& context,
|
||||||
std::string name = "default",
|
std::string name = "default",
|
||||||
const nonstd::optional<output_t>& file = nonstd::nullopt);
|
const nonstd::optional<output_t>& file
|
||||||
|
= nonstd::nullopt);
|
||||||
|
|
||||||
~output_guard();
|
~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);
|
this->ec_source.emplace(path, line_number);
|
||||||
return {*this};
|
return {*this};
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_resolver create_resolver() {
|
scoped_resolver create_resolver()
|
||||||
|
{
|
||||||
return {
|
return {
|
||||||
&this->ec_local_vars.top(),
|
&this->ec_local_vars.top(),
|
||||||
&this->ec_global_vars,
|
&this->ec_global_vars,
|
||||||
@ -140,13 +152,14 @@ struct exec_context {
|
|||||||
perm_t ec_perms{perm_t::READ_WRITE};
|
perm_t ec_perms{perm_t::READ_WRITE};
|
||||||
|
|
||||||
std::map<std::string, std::string> ec_override;
|
std::map<std::string, std::string> ec_override;
|
||||||
std::vector<logline_value> *ec_line_values;
|
std::vector<logline_value>* ec_line_values;
|
||||||
std::stack<std::map<std::string, std::string> > ec_local_vars;
|
std::stack<std::map<std::string, std::string>> ec_local_vars;
|
||||||
std::map<std::string, std::string> ec_global_vars;
|
std::map<std::string, std::string> ec_global_vars;
|
||||||
std::vector<ghc::filesystem::path> ec_path_stack;
|
std::vector<ghc::filesystem::path> ec_path_stack;
|
||||||
std::stack<std::pair<std::string, int>> ec_source;
|
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;
|
std::unique_ptr<attr_line_t> ec_accumulator;
|
||||||
|
|
||||||
@ -154,19 +167,29 @@ struct exec_context {
|
|||||||
pipe_callback_t ec_pipe_callback;
|
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_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_sql(exec_context& ec,
|
||||||
Result<std::string, std::string> execute_file(exec_context &ec, const std::string &path_and_args, bool multiline = true);
|
const std::string& sql,
|
||||||
Result<std::string, std::string> execute_any(exec_context &ec, const std::string &cmdline);
|
std::string& alt_msg);
|
||||||
void execute_init_commands(exec_context &ec, std::vector<std::pair<Result<std::string, std::string>, std::string> > &msgs);
|
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(
|
std::future<std::string> pipe_callback(exec_context& ec,
|
||||||
exec_context &ec, const std::string &cmdline, auto_fd &fd);
|
const std::string& cmdline,
|
||||||
|
auto_fd& fd);
|
||||||
|
|
||||||
int sql_progress(const struct log_cursor &lc);
|
int sql_progress(const struct log_cursor& lc);
|
||||||
void sql_progress_finished();
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file curl_looper.cc
|
* @file curl_looper.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#if defined(HAVE_LIBCURL)
|
#include "config.h"
|
||||||
#include <curl/multi.h>
|
|
||||||
|
|
||||||
#include "curl_looper.hh"
|
#if defined(HAVE_LIBCURL)
|
||||||
|
# include <curl/multi.h>
|
||||||
|
|
||||||
|
# include "curl_looper.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct curl_request_eq {
|
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();
|
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();
|
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,
|
int
|
||||||
curl_infotype type,
|
curl_request::debug_cb(
|
||||||
char *data,
|
CURL* handle, curl_infotype type, char* data, size_t size, void* userp)
|
||||||
size_t size,
|
{
|
||||||
void *userp) {
|
curl_request* cr = (curl_request*) userp;
|
||||||
curl_request *cr = (curl_request *) userp;
|
|
||||||
bool write_to_log;
|
bool write_to_log;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -71,8 +72,7 @@ int curl_request::debug_cb(CURL *handle,
|
|||||||
case CURLINFO_HEADER_OUT:
|
case CURLINFO_HEADER_OUT:
|
||||||
if (lnav_log_level == lnav_log_level_t::TRACE) {
|
if (lnav_log_level == lnav_log_level_t::TRACE) {
|
||||||
write_to_log = true;
|
write_to_log = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
write_to_log = false;
|
write_to_log = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -91,7 +91,8 @@ int curl_request::debug_cb(CURL *handle,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void curl_looper::loop_body()
|
void
|
||||||
|
curl_looper::loop_body()
|
||||||
{
|
{
|
||||||
mstime_t current_time = getmstime();
|
mstime_t current_time = getmstime();
|
||||||
|
|
||||||
@ -104,7 +105,8 @@ void curl_looper::loop_body()
|
|||||||
this->requeue_requests(current_time + 5);
|
this->requeue_requests(current_time + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void curl_looper::perform_io()
|
void
|
||||||
|
curl_looper::perform_io()
|
||||||
{
|
{
|
||||||
if (this->cl_handle_to_request.empty()) {
|
if (this->cl_handle_to_request.empty()) {
|
||||||
return;
|
return;
|
||||||
@ -114,57 +116,54 @@ void curl_looper::perform_io()
|
|||||||
auto timeout = this->compute_timeout(current_time);
|
auto timeout = this->compute_timeout(current_time);
|
||||||
int running_handles;
|
int running_handles;
|
||||||
|
|
||||||
curl_multi_wait(this->cl_curl_multi,
|
curl_multi_wait(this->cl_curl_multi, nullptr, 0, timeout.count(), nullptr);
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
timeout.count(),
|
|
||||||
nullptr);
|
|
||||||
curl_multi_perform(this->cl_curl_multi, &running_handles);
|
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() &&
|
while (!this->cl_poll_queue.empty()
|
||||||
this->cl_poll_queue.front().first <= up_to_time) {
|
&& this->cl_poll_queue.front().first <= up_to_time)
|
||||||
|
{
|
||||||
auto cr = this->cl_poll_queue.front().second;
|
auto cr = this->cl_poll_queue.front().second;
|
||||||
|
|
||||||
log_debug("%s:polling request is ready again -- %p",
|
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;
|
this->cl_handle_to_request[cr->get_handle()] = cr;
|
||||||
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
|
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
|
||||||
this->cl_poll_queue.erase(this->cl_poll_queue.begin());
|
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()) {
|
while (!this->cl_new_requests.empty()) {
|
||||||
auto cr = this->cl_new_requests.back();
|
auto cr = this->cl_new_requests.back();
|
||||||
|
|
||||||
log_info("%s:new curl request %p",
|
log_info("%s:new curl request %p", cr->get_name().c_str(), cr.get());
|
||||||
cr->get_name().c_str(),
|
|
||||||
cr.get());
|
|
||||||
this->cl_handle_to_request[cr->get_handle()] = cr;
|
this->cl_handle_to_request[cr->get_handle()] = cr;
|
||||||
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
|
curl_multi_add_handle(this->cl_curl_multi, cr->get_handle());
|
||||||
this->cl_new_requests.pop_back();
|
this->cl_new_requests.pop_back();
|
||||||
}
|
}
|
||||||
while (!this->cl_close_requests.empty()) {
|
while (!this->cl_close_requests.empty()) {
|
||||||
const std::string &name = this->cl_close_requests.back();
|
const std::string& name = this->cl_close_requests.back();
|
||||||
auto all_iter = find_if(
|
auto all_iter = find_if(this->cl_all_requests.begin(),
|
||||||
this->cl_all_requests.begin(),
|
this->cl_all_requests.end(),
|
||||||
this->cl_all_requests.end(),
|
curl_request_eq(name));
|
||||||
curl_request_eq(name));
|
|
||||||
|
|
||||||
log_info("attempting to close request -- %s", name.c_str());
|
log_info("attempting to close request -- %s", name.c_str());
|
||||||
if (all_iter != this->cl_all_requests.end()) {
|
if (all_iter != this->cl_all_requests.end()) {
|
||||||
auto cr = *all_iter;
|
auto cr = *all_iter;
|
||||||
|
|
||||||
log_info("%s:closing request -- %p",
|
log_info(
|
||||||
cr->get_name().c_str(), cr.get());
|
"%s:closing request -- %p", cr->get_name().c_str(), cr.get());
|
||||||
(*all_iter)->close();
|
(*all_iter)->close();
|
||||||
auto act_iter = this->cl_handle_to_request.find(cr->get_handle());
|
auto act_iter = this->cl_handle_to_request.find(cr->get_handle());
|
||||||
if (act_iter != this->cl_handle_to_request.end()) {
|
if (act_iter != this->cl_handle_to_request.end()) {
|
||||||
curl_multi_remove_handle(this->cl_curl_multi,
|
curl_multi_remove_handle(this->cl_curl_multi, cr->get_handle());
|
||||||
cr->get_handle());
|
|
||||||
this->cl_handle_to_request.erase(act_iter);
|
this->cl_handle_to_request.erase(act_iter);
|
||||||
}
|
}
|
||||||
auto poll_iter = find_if(this->cl_poll_queue.begin(),
|
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_poll_queue.erase(poll_iter);
|
||||||
}
|
}
|
||||||
this->cl_all_requests.erase(all_iter);
|
this->cl_all_requests.erase(all_iter);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
log_error("Unable to find request with the name -- %s",
|
log_error("Unable to find request with the name -- %s",
|
||||||
name.c_str());
|
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;
|
int msgs_left;
|
||||||
|
|
||||||
while ((msg = curl_multi_info_read(this->cl_curl_multi, &msgs_left)) !=
|
while ((msg = curl_multi_info_read(this->cl_curl_multi, &msgs_left))
|
||||||
nullptr) {
|
!= nullptr) {
|
||||||
if (msg->msg != CURLMSG_DONE) {
|
if (msg->msg != CURLMSG_DONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL *easy = msg->easy_handle;
|
CURL* easy = msg->easy_handle;
|
||||||
auto iter = this->cl_handle_to_request.find(easy);
|
auto iter = this->cl_handle_to_request.find(easy);
|
||||||
|
|
||||||
curl_multi_remove_handle(this->cl_curl_multi, 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);
|
delay_ms = cr->complete(msg->data.result);
|
||||||
if (delay_ms < 0) {
|
if (delay_ms < 0) {
|
||||||
log_info("%s:curl_request %p finished, deleting...",
|
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(),
|
auto all_iter = find(this->cl_all_requests.begin(),
|
||||||
this->cl_all_requests.end(),
|
this->cl_all_requests.end(),
|
||||||
cr);
|
cr);
|
||||||
if (all_iter != this->cl_all_requests.end()) {
|
if (all_iter != this->cl_all_requests.end()) {
|
||||||
this->cl_all_requests.erase(all_iter);
|
this->cl_all_requests.erase(all_iter);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
log_debug("%s:curl_request %p is polling, requeueing in %d",
|
log_debug("%s:curl_request %p is polling, requeueing in %d",
|
||||||
cr->get_name().c_str(),
|
cr->get_name().c_str(),
|
||||||
cr.get(),
|
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;
|
std::chrono::milliseconds retval = 1s;
|
||||||
|
|
||||||
if (!this->cl_handle_to_request.empty()) {
|
if (!this->cl_handle_to_request.empty()) {
|
||||||
retval = 1ms;
|
retval = 1ms;
|
||||||
} else if (!this->cl_poll_queue.empty()) {
|
} else if (!this->cl_poll_queue.empty()) {
|
||||||
retval = std::max(
|
retval
|
||||||
1ms,
|
= std::max(1ms,
|
||||||
std::chrono::milliseconds(this->cl_poll_queue.front().first - current_time));
|
std::chrono::milliseconds(
|
||||||
|
this->cl_poll_queue.front().first - current_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(retval.count() > 0);
|
ensure(retval.count() > 0);
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,6 +32,8 @@
|
|||||||
#ifndef curl_looper_hh
|
#ifndef curl_looper_hh
|
||||||
#define curl_looper_hh
|
#define curl_looper_hh
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -46,95 +48,100 @@ typedef int CURLcode;
|
|||||||
|
|
||||||
class curl_request {
|
class curl_request {
|
||||||
public:
|
public:
|
||||||
curl_request(const std::string &name) {
|
curl_request(const std::string& name){};
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class curl_looper : public isc::service<curl_looper> {
|
class curl_looper : public isc::service<curl_looper> {
|
||||||
public:
|
public:
|
||||||
void start() { };
|
void start(){};
|
||||||
void stop() { };
|
void stop(){};
|
||||||
void add_request(std::shared_ptr<curl_request> cr) { };
|
void add_request(std::shared_ptr<curl_request> cr){};
|
||||||
void close_request(const std::string &name) { };
|
void close_request(const std::string& name){};
|
||||||
void process_all() { };
|
void process_all(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <mutex>
|
# include <condition_variable>
|
||||||
#include <thread>
|
# include <mutex>
|
||||||
#include <condition_variable>
|
# include <thread>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
# include <curl/curl.h>
|
||||||
|
|
||||||
#include "auto_mem.hh"
|
# include "auto_mem.hh"
|
||||||
#include "base/lnav_log.hh"
|
# include "base/lnav_log.hh"
|
||||||
#include "base/time_util.hh"
|
# include "base/time_util.hh"
|
||||||
|
|
||||||
class curl_request {
|
class curl_request {
|
||||||
public:
|
public:
|
||||||
curl_request(std::string name)
|
curl_request(std::string name)
|
||||||
: cr_name(std::move(name)),
|
: cr_name(std::move(name)), cr_open(true), cr_handle(curl_easy_cleanup),
|
||||||
cr_open(true),
|
cr_completions(0)
|
||||||
cr_handle(curl_easy_cleanup),
|
{
|
||||||
cr_completions(0) {
|
|
||||||
this->cr_handle.reset(curl_easy_init());
|
this->cr_handle.reset(curl_easy_init());
|
||||||
curl_easy_setopt(this->cr_handle, CURLOPT_NOSIGNAL, 1);
|
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_DEBUGFUNCTION, debug_cb);
|
||||||
curl_easy_setopt(this->cr_handle, CURLOPT_DEBUGDATA, this);
|
curl_easy_setopt(this->cr_handle, CURLOPT_DEBUGDATA, this);
|
||||||
curl_easy_setopt(this->cr_handle, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(this->cr_handle, CURLOPT_VERBOSE, 1);
|
||||||
if (getenv("SSH_AUTH_SOCK") != nullptr) {
|
if (getenv("SSH_AUTH_SOCK") != nullptr) {
|
||||||
curl_easy_setopt(this->cr_handle, CURLOPT_SSH_AUTH_TYPES,
|
curl_easy_setopt(this->cr_handle,
|
||||||
#ifdef CURLSSH_AUTH_AGENT
|
CURLOPT_SSH_AUTH_TYPES,
|
||||||
CURLSSH_AUTH_AGENT|
|
# ifdef CURLSSH_AUTH_AGENT
|
||||||
#endif
|
CURLSSH_AUTH_AGENT |
|
||||||
CURLSSH_AUTH_PASSWORD);
|
# endif
|
||||||
|
CURLSSH_AUTH_PASSWORD);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~curl_request() = default;
|
virtual ~curl_request() = default;
|
||||||
|
|
||||||
const std::string &get_name() const {
|
const std::string& get_name() const
|
||||||
|
{
|
||||||
return this->cr_name;
|
return this->cr_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void close() {
|
virtual void close()
|
||||||
|
{
|
||||||
this->cr_open = false;
|
this->cr_open = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_open() const {
|
bool is_open() const
|
||||||
|
{
|
||||||
return this->cr_open;
|
return this->cr_open;
|
||||||
};
|
};
|
||||||
|
|
||||||
CURL *get_handle() const {
|
CURL* get_handle() const
|
||||||
|
{
|
||||||
return this->cr_handle;
|
return this->cr_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
int get_completions() const {
|
int get_completions() const
|
||||||
|
{
|
||||||
return this->cr_completions;
|
return this->cr_completions;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual long complete(CURLcode result) {
|
virtual long complete(CURLcode result)
|
||||||
|
{
|
||||||
double total_time = 0, download_size = 0, download_speed = 0;
|
double total_time = 0, download_size = 0, download_speed = 0;
|
||||||
|
|
||||||
this->cr_completions += 1;
|
this->cr_completions += 1;
|
||||||
curl_easy_getinfo(this->cr_handle, CURLINFO_TOTAL_TIME, &total_time);
|
curl_easy_getinfo(this->cr_handle, CURLINFO_TOTAL_TIME, &total_time);
|
||||||
log_debug("%s: total_time=%f", this->cr_name.c_str(), 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);
|
log_debug("%s: download_size=%f", this->cr_name.c_str(), download_size);
|
||||||
curl_easy_getinfo(this->cr_handle, CURLINFO_SPEED_DOWNLOAD, &download_speed);
|
curl_easy_getinfo(
|
||||||
log_debug("%s: download_speed=%f", this->cr_name.c_str(), download_speed);
|
this->cr_handle, CURLINFO_SPEED_DOWNLOAD, &download_speed);
|
||||||
|
log_debug(
|
||||||
|
"%s: download_speed=%f", this->cr_name.c_str(), download_speed);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static int debug_cb(
|
||||||
static int debug_cb(CURL *handle,
|
CURL* handle, curl_infotype type, char* data, size_t size, void* userp);
|
||||||
curl_infotype type,
|
|
||||||
char *data,
|
|
||||||
size_t size,
|
|
||||||
void *userp);
|
|
||||||
|
|
||||||
const std::string cr_name;
|
const std::string cr_name;
|
||||||
bool cr_open;
|
bool cr_open;
|
||||||
@ -145,12 +152,13 @@ protected:
|
|||||||
|
|
||||||
class curl_looper : public isc::service<curl_looper> {
|
class curl_looper : public isc::service<curl_looper> {
|
||||||
public:
|
public:
|
||||||
curl_looper()
|
curl_looper() : cl_curl_multi(curl_multi_cleanup)
|
||||||
: cl_curl_multi(curl_multi_cleanup) {
|
{
|
||||||
this->cl_curl_multi.reset(curl_multi_init());
|
this->cl_curl_multi.reset(curl_multi_init());
|
||||||
};
|
};
|
||||||
|
|
||||||
void process_all() {
|
void process_all()
|
||||||
|
{
|
||||||
this->check_for_new_requests();
|
this->check_for_new_requests();
|
||||||
|
|
||||||
this->requeue_requests(LONG_MAX);
|
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);
|
require(cr != nullptr);
|
||||||
|
|
||||||
this->cl_all_requests.emplace_back(cr);
|
this->cl_all_requests.emplace_back(cr);
|
||||||
this->cl_new_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);
|
this->cl_close_requests.emplace_back(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,14 +191,16 @@ private:
|
|||||||
void check_for_new_requests();
|
void check_for_new_requests();
|
||||||
void check_for_finished_requests();
|
void check_for_finished_requests();
|
||||||
void requeue_requests(mstime_t up_to_time);
|
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;
|
auto_mem<CURLM> cl_curl_multi;
|
||||||
std::vector<std::shared_ptr<curl_request>> cl_all_requests;
|
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_new_requests;
|
||||||
std::vector<std::string> cl_close_requests;
|
std::vector<std::string> cl_close_requests;
|
||||||
std::map<CURL *, std::shared_ptr<curl_request>> cl_handle_to_request;
|
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::vector<std::pair<mstime_t, std::shared_ptr<curl_request> > >
|
||||||
|
cl_poll_queue;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -21,44 +21,44 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "spookyhash/SpookyV2.h"
|
|
||||||
#include "data_parser.hh"
|
#include "data_parser.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "spookyhash/SpookyV2.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
data_format data_parser::FORMAT_SEMI("semi", DT_COMMA, DT_SEMI);
|
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_COMMA("comma", DT_INVALID, DT_COMMA);
|
||||||
data_format data_parser::FORMAT_PLAIN("plain", DT_INVALID, DT_INVALID);
|
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_errors("dp_errors", __FILE__, __LINE__),
|
||||||
dp_pairs("dp_pairs", __FILE__, __LINE__),
|
dp_pairs("dp_pairs", __FILE__, __LINE__), dp_msg_format(nullptr),
|
||||||
dp_msg_format(nullptr),
|
dp_msg_format_begin(ds->get_input().pi_offset), dp_scanner(ds)
|
||||||
dp_msg_format_begin(ds->get_input().pi_offset),
|
|
||||||
dp_scanner(ds)
|
|
||||||
{
|
{
|
||||||
if (TRACE_FILE != nullptr) {
|
if (TRACE_FILE != nullptr) {
|
||||||
fprintf(TRACE_FILE, "input %s\n", ds->get_input().get_string());
|
fprintf(TRACE_FILE, "input %s\n", ds->get_input().get_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void data_parser::pairup(data_parser::schema_id_t *schema,
|
void
|
||||||
data_parser::element_list_t &pairs_out,
|
data_parser::pairup(data_parser::schema_id_t* schema,
|
||||||
data_parser::element_list_t &in_list, int group_depth)
|
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 ELEMENT_LIST_T(el_stack), ELEMENT_LIST_T(free_row),
|
||||||
ELEMENT_LIST_T(key_comps), ELEMENT_LIST_T(value),
|
ELEMENT_LIST_T(key_comps), ELEMENT_LIST_T(value),
|
||||||
ELEMENT_LIST_T(prefix);
|
ELEMENT_LIST_T(prefix);
|
||||||
SpookyHash context;
|
SpookyHash context;
|
||||||
|
|
||||||
require(in_list.el_format.df_name != nullptr);
|
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);
|
FORMAT_TRACE(in_list);
|
||||||
|
|
||||||
for (auto iter = in_list.begin();
|
for (auto iter = in_list.begin(); iter != in_list.end(); ++iter) {
|
||||||
iter != in_list.end();
|
|
||||||
++iter) {
|
|
||||||
if (iter->e_token == DNT_GROUP) {
|
if (iter->e_token == DNT_GROUP) {
|
||||||
element_list_t ELEMENT_LIST_T(group_pairs);
|
element_list_t ELEMENT_LIST_T(group_pairs);
|
||||||
|
|
||||||
this->pairup(nullptr, group_pairs, *iter->e_sub_elements,
|
this->pairup(
|
||||||
group_depth + 1);
|
nullptr, group_pairs, *iter->e_sub_elements, group_depth + 1);
|
||||||
if (!group_pairs.empty()) {
|
if (!group_pairs.empty()) {
|
||||||
iter->assign_elements(group_pairs);
|
iter->assign_elements(group_pairs);
|
||||||
}
|
}
|
||||||
@ -87,15 +85,13 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
|
|||||||
el_stack.PUSH_BACK(*iter);
|
el_stack.PUSH_BACK(*iter);
|
||||||
}
|
}
|
||||||
} else if (iter->e_token == in_list.el_format.df_terminator) {
|
} else if (iter->e_token == in_list.el_format.df_terminator) {
|
||||||
this->end_of_value(el_stack, key_comps, value, in_list,
|
this->end_of_value(
|
||||||
group_depth);
|
el_stack, key_comps, value, in_list, group_depth);
|
||||||
|
|
||||||
key_comps.PUSH_BACK(*iter);
|
key_comps.PUSH_BACK(*iter);
|
||||||
} else if (iter->e_token == in_list.el_format.df_qualifier) {
|
} else if (iter->e_token == in_list.el_format.df_qualifier) {
|
||||||
value.SPLICE(value.end(),
|
value.SPLICE(
|
||||||
key_comps,
|
value.end(), key_comps, key_comps.begin(), key_comps.end());
|
||||||
key_comps.begin(),
|
|
||||||
key_comps.end());
|
|
||||||
strip(value, element_if(DT_WHITE));
|
strip(value, element_if(DT_WHITE));
|
||||||
if (!value.empty()) {
|
if (!value.empty()) {
|
||||||
el_stack.PUSH_BACK(element(value, DNT_VALUE));
|
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()) {
|
if (!key_comps.empty()) {
|
||||||
do {
|
do {
|
||||||
--key_iter;
|
--key_iter;
|
||||||
if (key_iter->e_token ==
|
if (key_iter->e_token == in_list.el_format.df_appender) {
|
||||||
in_list.el_format.df_appender) {
|
|
||||||
++key_iter;
|
++key_iter;
|
||||||
value.SPLICE(value.end(),
|
value.SPLICE(value.end(),
|
||||||
key_comps,
|
key_comps,
|
||||||
@ -116,8 +111,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
|
|||||||
key_iter);
|
key_iter);
|
||||||
key_comps.POP_FRONT();
|
key_comps.POP_FRONT();
|
||||||
found = true;
|
found = true;
|
||||||
} else if (key_iter->e_token ==
|
} else if (key_iter->e_token
|
||||||
in_list.el_format.df_terminator) {
|
== in_list.el_format.df_terminator) {
|
||||||
std::vector<element> key_copy;
|
std::vector<element> key_copy;
|
||||||
|
|
||||||
value.SPLICE(value.end(),
|
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()) {
|
if (!found && !el_stack.empty() && !key_comps.empty()) {
|
||||||
element_list_t::iterator value_iter;
|
element_list_t::iterator value_iter;
|
||||||
|
|
||||||
if (el_stack.size() > 1 &&
|
if (el_stack.size() > 1
|
||||||
in_list.el_format.df_appender != DT_INVALID &&
|
&& in_list.el_format.df_appender != DT_INVALID
|
||||||
in_list.el_format.df_terminator != DT_INVALID) {
|
&& in_list.el_format.df_terminator != DT_INVALID)
|
||||||
|
{
|
||||||
/* If we're expecting a terminator and haven't found it */
|
/* If we're expecting a terminator and haven't found it */
|
||||||
/* then this is part of the value. */
|
/* then this is part of the value. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
value.SPLICE(value.end(),
|
value.SPLICE(
|
||||||
key_comps,
|
value.end(), key_comps, key_comps.begin(), key_comps.end());
|
||||||
key_comps.begin(),
|
|
||||||
key_comps.end());
|
|
||||||
value_iter = value.end();
|
value_iter = value.end();
|
||||||
std::advance(value_iter, -1);
|
std::advance(value_iter, -1);
|
||||||
key_comps.SPLICE(key_comps.begin(),
|
key_comps.SPLICE(
|
||||||
value,
|
key_comps.begin(), value, value_iter, value.end());
|
||||||
value_iter,
|
|
||||||
value.end());
|
|
||||||
key_comps.resize(1);
|
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
|
// Only perform the free-row logic at the top level, if we're in a group
|
||||||
// assume it is a list.
|
// assume it is a list.
|
||||||
if (group_depth < 1 && el_stack.empty()) {
|
if (group_depth < 1 && el_stack.empty()) {
|
||||||
free_row.SPLICE(free_row.begin(),
|
free_row.SPLICE(
|
||||||
key_comps, key_comps.begin(), key_comps.end());
|
free_row.begin(), key_comps, key_comps.begin(), key_comps.end());
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -216,9 +208,8 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
|
|||||||
element_list_t ELEMENT_LIST_T(free_pair_subs);
|
element_list_t ELEMENT_LIST_T(free_pair_subs);
|
||||||
struct element blank;
|
struct element blank;
|
||||||
|
|
||||||
blank.e_capture.c_begin = blank.e_capture.c_end =
|
blank.e_capture.c_begin = blank.e_capture.c_end
|
||||||
el_stack.front().e_capture.
|
= el_stack.front().e_capture.c_begin;
|
||||||
c_begin;
|
|
||||||
blank.e_token = DNT_KEY;
|
blank.e_token = DNT_KEY;
|
||||||
free_pair_subs.PUSH_BACK(blank);
|
free_pair_subs.PUSH_BACK(blank);
|
||||||
free_pair_subs.PUSH_BACK(el_stack.front());
|
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) {
|
if (schema != nullptr) {
|
||||||
size_t key_len;
|
size_t key_len;
|
||||||
const char *key_val =
|
const char* key_val
|
||||||
this->get_element_string(el_stack.front(), key_len);
|
= this->get_element_string(el_stack.front(), key_len);
|
||||||
context.Update(key_val, 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);
|
element_list_t ELEMENT_LIST_T(free_pair_subs);
|
||||||
struct element blank;
|
struct element blank;
|
||||||
|
|
||||||
blank.e_capture.c_begin = blank.e_capture.c_end =
|
blank.e_capture.c_begin = blank.e_capture.c_end
|
||||||
free_row.front().e_capture.
|
= free_row.front().e_capture.c_begin;
|
||||||
c_begin;
|
|
||||||
blank.e_token = DNT_KEY;
|
blank.e_token = DNT_KEY;
|
||||||
free_pair_subs.PUSH_BACK(blank);
|
free_pair_subs.PUSH_BACK(blank);
|
||||||
free_pair_subs.PUSH_BACK(free_row.front());
|
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;
|
has_value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pair_subs.SPLICE(pair_subs.begin(),
|
pair_subs.SPLICE(
|
||||||
el_stack,
|
pair_subs.begin(), el_stack, el_stack.begin(), kv_iter);
|
||||||
el_stack.begin(),
|
|
||||||
kv_iter);
|
|
||||||
|
|
||||||
if (!has_value) {
|
if (!has_value) {
|
||||||
element_list_t ELEMENT_LIST_T(blank_value);
|
element_list_t ELEMENT_LIST_T(blank_value);
|
||||||
pcre_input &pi = this->dp_scanner->get_input();
|
pcre_input& pi = this->dp_scanner->get_input();
|
||||||
const char *str = pi.get_string();
|
const char* str = pi.get_string();
|
||||||
struct element blank;
|
struct element blank;
|
||||||
|
|
||||||
blank.e_token = DT_QUOTED_STRING;
|
blank.e_token = DT_QUOTED_STRING;
|
||||||
blank.e_capture.c_begin = blank.e_capture.c_end =
|
blank.e_capture.c_begin = blank.e_capture.c_end
|
||||||
pair_subs.front().e_capture.c_end;
|
= pair_subs.front().e_capture.c_end;
|
||||||
if ((blank.e_capture.c_begin >= 0) &&
|
if ((blank.e_capture.c_begin >= 0)
|
||||||
((size_t) blank.e_capture.c_begin < pi.pi_length)) {
|
&& ((size_t) blank.e_capture.c_begin < pi.pi_length))
|
||||||
|
{
|
||||||
switch (str[blank.e_capture.c_begin]) {
|
switch (str[blank.e_capture.c_begin]) {
|
||||||
case '=':
|
case '=':
|
||||||
case ':':
|
case ':':
|
||||||
@ -298,12 +287,12 @@ void data_parser::pairup(data_parser::schema_id_t *schema,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pairs_out.size() == 1) {
|
if (pairs_out.size() == 1) {
|
||||||
element &pair = pairs_out.front();
|
element& pair = pairs_out.front();
|
||||||
element &evalue = pair.e_sub_elements->back();
|
element& evalue = pair.e_sub_elements->back();
|
||||||
|
|
||||||
if (evalue.e_token == DNT_VALUE &&
|
if (evalue.e_token == DNT_VALUE && evalue.e_sub_elements != nullptr
|
||||||
evalue.e_sub_elements != nullptr &&
|
&& evalue.e_sub_elements->size() > 1)
|
||||||
evalue.e_sub_elements->size() > 1) {
|
{
|
||||||
element_list_t::iterator next_sub;
|
element_list_t::iterator next_sub;
|
||||||
|
|
||||||
next_sub = pair.e_sub_elements->begin();
|
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);
|
element_list_t ELEMENT_LIST_T(pair_subs);
|
||||||
struct element blank;
|
struct element blank;
|
||||||
|
|
||||||
blank.e_capture.c_begin = blank.e_capture.c_end =
|
blank.e_capture.c_begin = blank.e_capture.c_end
|
||||||
free_row.front().e_capture.c_begin;
|
= free_row.front().e_capture.c_begin;
|
||||||
blank.e_token = DNT_KEY;
|
blank.e_token = DNT_KEY;
|
||||||
pair_subs.PUSH_BACK(blank);
|
pair_subs.PUSH_BACK(blank);
|
||||||
pair_subs.PUSH_BACK(free_row.front());
|
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
|
// use the token ID since some columns values might vary
|
||||||
// between rows.
|
// between rows.
|
||||||
context.Update(" ", 1);
|
context.Update(" ", 1);
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
size_t key_len;
|
size_t key_len;
|
||||||
const char *key_val = this->get_element_string(
|
const char* key_val
|
||||||
free_row.front(), key_len);
|
= this->get_element_string(free_row.front(), key_len);
|
||||||
|
|
||||||
context.Update(key_val, key_len);
|
context.Update(key_val, key_len);
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free_row.POP_FRONT();
|
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);
|
element_list_t ELEMENT_LIST_T(pair_subs);
|
||||||
struct element blank;
|
struct element blank;
|
||||||
|
|
||||||
blank.e_capture.c_begin = blank.e_capture.c_end =
|
blank.e_capture.c_begin = blank.e_capture.c_end
|
||||||
prefix.front().e_capture.c_begin;
|
= prefix.front().e_capture.c_begin;
|
||||||
blank.e_token = DNT_KEY;
|
blank.e_token = DNT_KEY;
|
||||||
pair_subs.PUSH_BACK(blank);
|
pair_subs.PUSH_BACK(blank);
|
||||||
pair_subs.PUSH_BACK(prefix.front());
|
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) {
|
if (schema != nullptr && this->dp_msg_format != nullptr) {
|
||||||
pcre_input &pi = this->dp_scanner->get_input();
|
pcre_input& pi = this->dp_scanner->get_input();
|
||||||
for (auto &fiter : pairs_out) {
|
for (auto& fiter : pairs_out) {
|
||||||
*(this->dp_msg_format) += this->get_string_up_to_value(fiter);
|
*(this->dp_msg_format) += this->get_string_up_to_value(fiter);
|
||||||
this->dp_msg_format->append("#");
|
this->dp_msg_format->append("#");
|
||||||
}
|
}
|
||||||
if ((size_t) this->dp_msg_format_begin < pi.pi_length) {
|
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,
|
pcre_context::capture_t last(this->dp_msg_format_begin,
|
||||||
pi.pi_length);
|
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;
|
pcre_context_static<30> pc;
|
||||||
std::stack<discover_format_state> state_stack;
|
std::stack<discover_format_state> state_stack;
|
||||||
@ -459,7 +447,7 @@ void data_parser::discover_format()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DT_EMPTY_CONTAINER: {
|
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__);
|
auto empty_list = element_list_t("_anon_", __FILE__, __LINE__);
|
||||||
discover_format_state dfs;
|
discover_format_state dfs;
|
||||||
|
|
||||||
@ -468,7 +456,7 @@ void data_parser::discover_format()
|
|||||||
empty_list.el_format = dfs.dfs_format;
|
empty_list.el_format = dfs.dfs_format;
|
||||||
curr_group.PUSH_BACK(element());
|
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_begin = elem.e_capture.c_begin + 1;
|
||||||
empty.e_capture.c_end = elem.e_capture.c_begin + 1;
|
empty.e_capture.c_end = elem.e_capture.c_begin + 1;
|
||||||
empty.e_token = DNT_GROUP;
|
empty.e_token = DNT_GROUP;
|
||||||
@ -486,15 +474,16 @@ void data_parser::discover_format()
|
|||||||
auto riter = this->dp_group_stack.rbegin();
|
auto riter = this->dp_group_stack.rbegin();
|
||||||
++riter;
|
++riter;
|
||||||
state_stack.top().finalize();
|
state_stack.top().finalize();
|
||||||
this->dp_group_stack.back().el_format =
|
this->dp_group_stack.back().el_format
|
||||||
state_stack.top().dfs_format;
|
= state_stack.top().dfs_format;
|
||||||
state_stack.pop();
|
state_stack.pop();
|
||||||
if (!this->dp_group_stack.back().empty()) {
|
if (!this->dp_group_stack.back().empty()) {
|
||||||
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
|
(*riter).PUSH_BACK(
|
||||||
DNT_GROUP));
|
element(this->dp_group_stack.back(), DNT_GROUP));
|
||||||
} else {
|
} else {
|
||||||
(*riter).PUSH_BACK(element());
|
(*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_capture.c_end = elem.e_capture.c_begin;
|
||||||
riter->back().e_token = DNT_GROUP;
|
riter->back().e_token = DNT_GROUP;
|
||||||
riter->back().assign_elements(
|
riter->back().assign_elements(
|
||||||
@ -519,10 +508,10 @@ void data_parser::discover_format()
|
|||||||
++riter;
|
++riter;
|
||||||
if (!this->dp_group_stack.back().empty()) {
|
if (!this->dp_group_stack.back().empty()) {
|
||||||
state_stack.top().finalize();
|
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();
|
state_stack.pop();
|
||||||
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
|
(*riter).PUSH_BACK(element(this->dp_group_stack.back(), DNT_GROUP));
|
||||||
DNT_GROUP));
|
|
||||||
}
|
}
|
||||||
this->dp_group_stack.pop_back();
|
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;
|
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,
|
void
|
||||||
data_parser::element_list_t &key_comps,
|
data_parser::end_of_value(data_parser::element_list_t& el_stack,
|
||||||
data_parser::element_list_t &value,
|
data_parser::element_list_t& key_comps,
|
||||||
const data_parser::element_list_t &in_list,
|
data_parser::element_list_t& value,
|
||||||
int group_depth)
|
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(in_list.el_format.df_terminator));
|
||||||
key_comps.remove_if(element_if(DT_COMMA));
|
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));
|
value.remove_if(element_if(DT_COMMA));
|
||||||
strip(key_comps, element_if(DT_WHITE));
|
strip(key_comps, element_if(DT_WHITE));
|
||||||
strip(value, element_if(DT_WHITE));
|
strip(value, element_if(DT_WHITE));
|
||||||
if ((el_stack.empty() || el_stack.back().e_token != DNT_KEY) &&
|
if ((el_stack.empty() || el_stack.back().e_token != DNT_KEY)
|
||||||
value.empty() && key_comps.size() > 1 &&
|
&& value.empty() && key_comps.size() > 1
|
||||||
(key_comps.front().e_token == DT_WORD ||
|
&& (key_comps.front().e_token == DT_WORD
|
||||||
key_comps.front().e_token == DT_SYMBOL)) {
|
|| key_comps.front().e_token == DT_SYMBOL))
|
||||||
|
{
|
||||||
element_list_t::iterator key_iter, key_end;
|
element_list_t::iterator key_iter, key_end;
|
||||||
bool found_value = false;
|
bool found_value = false;
|
||||||
int word_count = 0;
|
int word_count = 0;
|
||||||
key_iter = key_comps.begin();
|
key_iter = key_comps.begin();
|
||||||
key_end = key_comps.begin();
|
key_end = key_comps.begin();
|
||||||
for (; key_iter != key_comps.end(); ++key_iter) {
|
for (; key_iter != key_comps.end(); ++key_iter) {
|
||||||
if (key_iter->e_token == DT_WORD ||
|
if (key_iter->e_token == DT_WORD || key_iter->e_token == DT_SYMBOL)
|
||||||
key_iter->e_token == DT_SYMBOL) {
|
{
|
||||||
word_count += 1;
|
word_count += 1;
|
||||||
if (found_value) {
|
if (found_value) {
|
||||||
key_end = key_comps.begin();
|
key_end = key_comps.begin();
|
||||||
}
|
}
|
||||||
} else if (key_iter->e_token == DT_WHITE) {
|
} else if (key_iter->e_token == DT_WHITE) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!found_value) {
|
if (!found_value) {
|
||||||
key_end = key_iter;
|
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) {
|
if (word_count != 1) {
|
||||||
key_end = key_comps.begin();
|
key_end = key_comps.begin();
|
||||||
}
|
}
|
||||||
value.SPLICE(value.end(),
|
value.SPLICE(value.end(), key_comps, key_end, key_comps.end());
|
||||||
key_comps,
|
|
||||||
key_end,
|
|
||||||
key_comps.end());
|
|
||||||
strip(key_comps, element_if(DT_WHITE));
|
strip(key_comps, element_if(DT_WHITE));
|
||||||
if (!key_comps.empty()) {
|
if (!key_comps.empty()) {
|
||||||
el_stack.PUSH_BACK(element(key_comps, DNT_KEY, false));
|
el_stack.PUSH_BACK(element(key_comps, DNT_KEY, false));
|
||||||
}
|
}
|
||||||
key_comps.CLEAR();
|
key_comps.CLEAR();
|
||||||
} else {
|
} else {
|
||||||
value.SPLICE(value.end(),
|
value.SPLICE(
|
||||||
key_comps,
|
value.end(), key_comps, key_comps.begin(), key_comps.end());
|
||||||
key_comps.begin(),
|
|
||||||
key_comps.end());
|
|
||||||
}
|
}
|
||||||
strip(value, element_if(DT_WHITE));
|
strip(value, element_if(DT_WHITE));
|
||||||
strip(value, element_if(DT_COLON));
|
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();
|
value.CLEAR();
|
||||||
}
|
}
|
||||||
|
|
||||||
void data_parser::parse()
|
void
|
||||||
|
data_parser::parse()
|
||||||
{
|
{
|
||||||
this->discover_format();
|
this->discover_format();
|
||||||
|
|
||||||
this->pairup(&this->dp_schema_id,
|
this->pairup(
|
||||||
this->dp_pairs,
|
&this->dp_schema_id, this->dp_pairs, this->dp_group_stack.front());
|
||||||
this->dp_group_stack.front());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
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);
|
return pi.get_substr(&elem.e_capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
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();
|
pcre_input& pi = this->dp_scanner->get_input();
|
||||||
const element &val_elem = elem.e_token == DNT_PAIR ?
|
const element& val_elem
|
||||||
elem.e_sub_elements->back() : elem;
|
= elem.e_token == DNT_PAIR ? elem.e_sub_elements->back() : elem;
|
||||||
|
|
||||||
if (this->dp_msg_format_begin <= val_elem.e_capture.c_begin) {
|
if (this->dp_msg_format_begin <= val_elem.e_capture.c_begin) {
|
||||||
pcre_context::capture_t leading_and_key = pcre_context::capture_t(
|
pcre_context::capture_t leading_and_key = pcre_context::capture_t(
|
||||||
this->dp_msg_format_begin, val_elem.e_capture.c_begin);
|
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) {
|
if (leading_and_key.length() >= 2) {
|
||||||
switch (str[leading_and_key.c_end - 1]) {
|
switch (str[leading_and_key.c_end - 1]) {
|
||||||
case '\'':
|
case '\'':
|
||||||
@ -658,28 +643,30 @@ data_parser::get_string_up_to_value(const data_parser::element &elem)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *data_parser::get_element_string(const data_parser::element &elem,
|
const char*
|
||||||
size_t &len_out)
|
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();
|
len_out = elem.e_capture.length();
|
||||||
return pi.get_substr_start(&elem.e_capture);
|
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",
|
fprintf(
|
||||||
this->dp_scanner->get_input().get_string());
|
out, " %s\n", this->dp_scanner->get_input().get_string());
|
||||||
for (auto &iter : el) {
|
for (auto& iter : el) {
|
||||||
iter.print(out, this->dp_scanner->get_input());
|
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_format_state_t
|
||||||
data_token_t next_token)
|
dfs_prefix_next(data_format_state_t state, data_token_t next_token)
|
||||||
{
|
{
|
||||||
data_format_state_t retval = state;
|
data_format_state_t retval = state;
|
||||||
|
|
||||||
@ -722,8 +709,8 @@ data_format_state_t dfs_prefix_next(data_format_state_t state,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_format_state_t dfs_semi_next(data_format_state_t state,
|
data_format_state_t
|
||||||
data_token_t next_token)
|
dfs_semi_next(data_format_state_t state, data_token_t next_token)
|
||||||
{
|
{
|
||||||
data_format_state_t retval = state;
|
data_format_state_t retval = state;
|
||||||
|
|
||||||
@ -777,8 +764,8 @@ data_format_state_t dfs_semi_next(data_format_state_t state,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_format_state_t dfs_comma_next(data_format_state_t state,
|
data_format_state_t
|
||||||
data_token_t next_token)
|
dfs_comma_next(data_format_state_t state, data_token_t next_token)
|
||||||
{
|
{
|
||||||
data_format_state_t retval = state;
|
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()
|
data_parser::element::element()
|
||||||
: e_capture(-1, -1),
|
: e_capture(-1, -1), e_token(DT_INVALID), e_sub_elements(nullptr)
|
||||||
e_token(DT_INVALID),
|
|
||||||
e_sub_elements(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
data_parser::element::element(data_parser::element_list_t &subs,
|
data_parser::element::element(data_parser::element_list_t& subs,
|
||||||
data_token_t token, bool assign_subs_elements)
|
data_token_t token,
|
||||||
: e_capture(subs.front().e_capture.c_begin,
|
bool assign_subs_elements)
|
||||||
subs.back().e_capture.c_end),
|
: e_capture(subs.front().e_capture.c_begin, subs.back().e_capture.c_end),
|
||||||
e_token(token),
|
e_token(token), e_sub_elements(nullptr)
|
||||||
e_sub_elements(nullptr)
|
|
||||||
{
|
{
|
||||||
if (assign_subs_elements) {
|
if (assign_subs_elements) {
|
||||||
this->assign_elements(subs);
|
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); */
|
/* require(other.e_sub_elements == nullptr); */
|
||||||
|
|
||||||
@ -908,8 +892,8 @@ data_parser::element::~element()
|
|||||||
this->e_sub_elements = nullptr;
|
this->e_sub_elements = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_parser::element &
|
data_parser::element&
|
||||||
data_parser::element::operator=(const data_parser::element &other)
|
data_parser::element::operator=(const data_parser::element& other)
|
||||||
{
|
{
|
||||||
this->e_capture = other.e_capture;
|
this->e_capture = other.e_capture;
|
||||||
this->e_token = other.e_token;
|
this->e_token = other.e_token;
|
||||||
@ -920,41 +904,43 @@ data_parser::element::operator=(const data_parser::element &other)
|
|||||||
return *this;
|
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) {
|
if (this->e_sub_elements == nullptr) {
|
||||||
this->e_sub_elements = new element_list_t("_sub_", __FILE__,
|
this->e_sub_elements = new element_list_t("_sub_", __FILE__, __LINE__);
|
||||||
__LINE__);
|
|
||||||
this->e_sub_elements->el_format = subs.el_format;
|
this->e_sub_elements->el_format = subs.el_format;
|
||||||
}
|
}
|
||||||
this->e_sub_elements->SWAP(subs);
|
this->e_sub_elements->SWAP(subs);
|
||||||
this->update_capture();
|
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()) {
|
if (this->e_sub_elements != nullptr && !this->e_sub_elements->empty()) {
|
||||||
this->e_capture.c_begin =
|
this->e_capture.c_begin
|
||||||
this->e_sub_elements->front().e_capture.c_begin;
|
= this->e_sub_elements->front().e_capture.c_begin;
|
||||||
this->e_capture.c_end =
|
this->e_capture.c_end = this->e_sub_elements->back().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);
|
require(this->e_token == DNT_PAIR);
|
||||||
|
|
||||||
return this->e_sub_elements->back();
|
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;
|
data_token_t retval = DT_INVALID;
|
||||||
|
|
||||||
if (this->e_token == DNT_VALUE) {
|
if (this->e_token == DNT_VALUE) {
|
||||||
if (this->e_sub_elements != nullptr &&
|
if (this->e_sub_elements != nullptr
|
||||||
this->e_sub_elements->size() == 1) {
|
&& this->e_sub_elements->size() == 1) {
|
||||||
retval = this->e_sub_elements->front().e_token;
|
retval = this->e_sub_elements->front().e_token;
|
||||||
} else {
|
} else {
|
||||||
retval = DT_SYMBOL;
|
retval = DT_SYMBOL;
|
||||||
@ -965,18 +951,20 @@ data_token_t data_parser::element::value_token() const
|
|||||||
return retval;
|
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_token == DNT_VALUE) {
|
||||||
if (this->e_sub_elements != nullptr &&
|
if (this->e_sub_elements != nullptr
|
||||||
this->e_sub_elements->size() == 1) {
|
&& this->e_sub_elements->size() == 1) {
|
||||||
return this->e_sub_elements->front();
|
return this->e_sub_elements->front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
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) {
|
if (this->e_token == DNT_VALUE) {
|
||||||
return this->e_sub_elements->front();
|
return this->e_sub_elements->front();
|
||||||
@ -984,17 +972,19 @@ const data_parser::element &data_parser::element::get_pair_elem() const
|
|||||||
return *this;
|
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;
|
int lpc;
|
||||||
|
|
||||||
if (this->e_sub_elements != nullptr) {
|
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);
|
e_sub_element.print(out, pi, offset + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(out, "%4s %3d:%-3d ",
|
fprintf(out,
|
||||||
|
"%4s %3d:%-3d ",
|
||||||
data_scanner::token2name(this->e_token),
|
data_scanner::token2name(this->e_token),
|
||||||
this->e_capture.c_begin,
|
this->e_capture.c_begin,
|
||||||
this->e_capture.c_end);
|
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()
|
data_parser::discover_format_state::discover_format_state()
|
||||||
: dfs_prefix_state(DFS_INIT),
|
: dfs_prefix_state(DFS_INIT), dfs_semi_state(DFS_INIT),
|
||||||
dfs_semi_state(DFS_INIT),
|
|
||||||
dfs_comma_state(DFS_INIT)
|
dfs_comma_state(DFS_INIT)
|
||||||
{
|
{
|
||||||
memset(this->dfs_hist, 0, sizeof(this->dfs_hist));
|
memset(this->dfs_hist, 0, sizeof(this->dfs_hist));
|
||||||
}
|
}
|
||||||
|
|
||||||
void data_parser::discover_format_state::update_for_element(
|
void
|
||||||
const data_parser::element &elem)
|
data_parser::discover_format_state::update_for_element(
|
||||||
|
const data_parser::element& elem)
|
||||||
{
|
{
|
||||||
this->dfs_prefix_state = dfs_prefix_next(this->dfs_prefix_state,
|
this->dfs_prefix_state
|
||||||
elem.e_token);
|
= 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_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);
|
this->dfs_comma_state = dfs_comma_next(this->dfs_comma_state, elem.e_token);
|
||||||
if (this->dfs_prefix_state != DFS_ERROR) {
|
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;
|
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 qualifier = this->dfs_format.df_qualifier;
|
||||||
data_token_t separator = this->dfs_format.df_separator;
|
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) {
|
} else if (this->dfs_comma_state != DFS_ERROR) {
|
||||||
this->dfs_format = FORMAT_COMMA;
|
this->dfs_format = FORMAT_COMMA;
|
||||||
if (separator == DT_COLON && this->dfs_hist[DT_COMMA] > 0) {
|
if (separator == DT_COLON && this->dfs_hist[DT_COMMA] > 0) {
|
||||||
if (!((this->dfs_hist[DT_COLON] == 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_COLON] - 1)
|
||||||
this->dfs_hist[DT_COMMA]))) {
|
== this->dfs_hist[DT_COMMA])))
|
||||||
|
{
|
||||||
separator = DT_INVALID;
|
separator = DT_INVALID;
|
||||||
if (this->dfs_hist[DT_COLON] == 1) {
|
if (this->dfs_hist[DT_COLON] == 1) {
|
||||||
prefix_term = DT_COLON;
|
prefix_term = DT_COLON;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,30 +30,31 @@
|
|||||||
#ifndef data_parser_hh
|
#ifndef data_parser_hh
|
||||||
#define data_parser_hh
|
#define data_parser_hh
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <iterator>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iterator>
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "pcrepp/pcrepp.hh"
|
|
||||||
#include "byte_array.hh"
|
#include "byte_array.hh"
|
||||||
#include "data_scanner.hh"
|
#include "data_scanner.hh"
|
||||||
|
#include "pcrepp/pcrepp.hh"
|
||||||
|
|
||||||
#define ELEMENT_LIST_T(var) var("" #var, __FILE__, __LINE__, group_depth)
|
#define ELEMENT_LIST_T(var) var("" #var, __FILE__, __LINE__, group_depth)
|
||||||
#define PUSH_FRONT(elem) push_front(elem, __FILE__, __LINE__)
|
#define PUSH_FRONT(elem) push_front(elem, __FILE__, __LINE__)
|
||||||
#define PUSH_BACK(elem) push_back(elem, __FILE__, __LINE__)
|
#define PUSH_BACK(elem) push_back(elem, __FILE__, __LINE__)
|
||||||
#define POP_FRONT(elem) pop_front(__FILE__, __LINE__)
|
#define POP_FRONT(elem) pop_front(__FILE__, __LINE__)
|
||||||
#define POP_BACK(elem) pop_back(__FILE__, __LINE__)
|
#define POP_BACK(elem) pop_back(__FILE__, __LINE__)
|
||||||
#define CLEAR(elem) clear2(__FILE__, __LINE__)
|
#define CLEAR(elem) clear2(__FILE__, __LINE__)
|
||||||
#define SWAP(other) swap(other, __FILE__, __LINE__)
|
#define SWAP(other) swap(other, __FILE__, __LINE__)
|
||||||
#define SPLICE(pos, other, first, last) splice(pos, other, first, last, \
|
#define SPLICE(pos, other, first, last) \
|
||||||
__FILE__, __LINE__)
|
splice(pos, other, first, last, __FILE__, __LINE__)
|
||||||
|
|
||||||
template<class Container, class UnaryPredicate>
|
template<class Container, class UnaryPredicate>
|
||||||
void strip(Container &container, UnaryPredicate p)
|
void
|
||||||
|
strip(Container& container, UnaryPredicate p)
|
||||||
{
|
{
|
||||||
while (!container.empty() && p(container.front())) {
|
while (!container.empty() && p(container.front())) {
|
||||||
container.POP_FRONT();
|
container.POP_FRONT();
|
||||||
@ -72,18 +73,14 @@ enum data_format_state_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct data_format {
|
struct data_format {
|
||||||
data_format(const char *name = nullptr,
|
data_format(const char* name = nullptr,
|
||||||
data_token_t appender = DT_INVALID,
|
data_token_t appender = DT_INVALID,
|
||||||
data_token_t terminator = DT_INVALID) noexcept
|
data_token_t terminator = DT_INVALID) noexcept
|
||||||
: df_name(name),
|
: df_name(name), df_appender(appender), df_terminator(terminator),
|
||||||
df_appender(appender),
|
df_qualifier(DT_INVALID), df_separator(DT_COLON),
|
||||||
df_terminator(terminator),
|
df_prefix_terminator(DT_INVALID){};
|
||||||
df_qualifier(DT_INVALID),
|
|
||||||
df_separator(DT_COLON),
|
|
||||||
df_prefix_terminator(DT_INVALID)
|
|
||||||
{};
|
|
||||||
|
|
||||||
const char * df_name;
|
const char* df_name;
|
||||||
data_token_t df_appender;
|
data_token_t df_appender;
|
||||||
data_token_t df_terminator;
|
data_token_t df_terminator;
|
||||||
data_token_t df_qualifier;
|
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_format_state_t dfs_comma_next(data_format_state_t state,
|
||||||
data_token_t next_token);
|
data_token_t next_token);
|
||||||
|
|
||||||
#define LIST_INIT_TRACE \
|
#define LIST_INIT_TRACE \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d %s %s %d\n", \
|
"%p %s:%d %s %s %d\n", \
|
||||||
this, \
|
this, \
|
||||||
fn, line, \
|
fn, \
|
||||||
__func__, \
|
line, \
|
||||||
varname, \
|
__func__, \
|
||||||
group_depth); \
|
varname, \
|
||||||
} \
|
group_depth); \
|
||||||
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define LIST_DEINIT_TRACE \
|
#define LIST_DEINIT_TRACE \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, "%p %s:%d %s\n", this, fn, line, __func__); \
|
||||||
"%p %s:%d %s\n", \
|
} \
|
||||||
this, \
|
|
||||||
fn, line, \
|
|
||||||
__func__); \
|
|
||||||
} \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define ELEMENT_TRACE \
|
#define ELEMENT_TRACE \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d %s %s %d:%d\n", \
|
"%p %s:%d %s %s %d:%d\n", \
|
||||||
this, \
|
this, \
|
||||||
fn, line, \
|
fn, \
|
||||||
__func__, \
|
line, \
|
||||||
|
__func__, \
|
||||||
data_scanner::token2name(elem.e_token), \
|
data_scanner::token2name(elem.e_token), \
|
||||||
elem.e_capture.c_begin, \
|
elem.e_capture.c_begin, \
|
||||||
elem.e_capture.c_end); \
|
elem.e_capture.c_end); \
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define LIST_TRACE \
|
#define LIST_TRACE \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, "%p %s:%d %s\n", this, fn, line, __func__); \
|
||||||
"%p %s:%d %s\n", \
|
} \
|
||||||
this, \
|
|
||||||
fn, line, \
|
|
||||||
__func__); \
|
|
||||||
} \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define SPLICE_TRACE \
|
#define SPLICE_TRACE \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d %s %d %p %d:%d\n", \
|
"%p %s:%d %s %d %p %d:%d\n", \
|
||||||
this, \
|
this, \
|
||||||
fn, line, \
|
fn, \
|
||||||
__func__, \
|
line, \
|
||||||
(int)std::distance(this->begin(), pos), \
|
__func__, \
|
||||||
&other, \
|
(int) std::distance(this->begin(), pos), \
|
||||||
(int)std::distance(other.begin(), first), \
|
&other, \
|
||||||
(int)std::distance(last, other.end())); \
|
(int) std::distance(other.begin(), first), \
|
||||||
} \
|
(int) std::distance(last, other.end())); \
|
||||||
|
} \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
#define SWAP_TRACE(other) \
|
#define SWAP_TRACE(other) \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE != NULL) { \
|
if (TRACE_FILE != NULL) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d %s %p\n", \
|
"%p %s:%d %s %p\n", \
|
||||||
this, \
|
this, \
|
||||||
fn, line, \
|
fn, \
|
||||||
__func__, \
|
line, \
|
||||||
&other); \
|
__func__, \
|
||||||
} \
|
&other); \
|
||||||
|
} \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
#define POINT_TRACE(name) \
|
#define POINT_TRACE(name) \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE) { \
|
if (TRACE_FILE) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf( \
|
||||||
"0x0 %s:%d point %s\n", \
|
TRACE_FILE, "0x0 %s:%d point %s\n", __FILE__, __LINE__, name); \
|
||||||
__FILE__, __LINE__, \
|
} \
|
||||||
name); \
|
|
||||||
} \
|
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
#define FORMAT_TRACE(elist) \
|
#define FORMAT_TRACE(elist) \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE) { \
|
if (TRACE_FILE) { \
|
||||||
const data_format &df = elist.el_format; \
|
const data_format& df = elist.el_format; \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d format %d %s %s %s %s %s\n", \
|
"%p %s:%d format %d %s %s %s %s %s\n", \
|
||||||
&elist, \
|
&elist, \
|
||||||
__FILE__, __LINE__, \
|
__FILE__, \
|
||||||
|
__LINE__, \
|
||||||
group_depth, \
|
group_depth, \
|
||||||
data_scanner::token2name(df.df_appender), \
|
data_scanner::token2name(df.df_appender), \
|
||||||
data_scanner::token2name(df.df_terminator), \
|
data_scanner::token2name(df.df_terminator), \
|
||||||
data_scanner::token2name(df.df_qualifier), \
|
data_scanner::token2name(df.df_qualifier), \
|
||||||
data_scanner::token2name(df.df_separator), \
|
data_scanner::token2name(df.df_separator), \
|
||||||
data_scanner::token2name(df.df_prefix_terminator)); \
|
data_scanner::token2name(df.df_prefix_terminator)); \
|
||||||
} \
|
} \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
#define CONSUMED_TRACE(elist) \
|
#define CONSUMED_TRACE(elist) \
|
||||||
do { \
|
do { \
|
||||||
if (TRACE_FILE) { \
|
if (TRACE_FILE) { \
|
||||||
fprintf(TRACE_FILE, \
|
fprintf(TRACE_FILE, \
|
||||||
"%p %s:%d consumed\n", \
|
"%p %s:%d consumed\n", \
|
||||||
&elist, \
|
&elist, \
|
||||||
__FILE__, __LINE__); \
|
__FILE__, \
|
||||||
} \
|
__LINE__); \
|
||||||
|
} \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
class data_parser {
|
class data_parser {
|
||||||
@ -217,7 +210,7 @@ public:
|
|||||||
static data_format FORMAT_COMMA;
|
static data_format FORMAT_COMMA;
|
||||||
static data_format FORMAT_PLAIN;
|
static data_format FORMAT_PLAIN;
|
||||||
|
|
||||||
static FILE *TRACE_FILE;
|
static FILE* TRACE_FILE;
|
||||||
|
|
||||||
typedef byte_array<2, uint64_t> schema_id_t;
|
typedef byte_array<2, uint64_t> schema_id_t;
|
||||||
|
|
||||||
@ -225,35 +218,39 @@ public:
|
|||||||
/* typedef std::list<element> element_list_t; */
|
/* typedef std::list<element> element_list_t; */
|
||||||
|
|
||||||
class element_list_t : public std::list<element> {
|
class element_list_t : public std::list<element> {
|
||||||
public:
|
public:
|
||||||
element_list_t(const char *varname, const char *fn, int line, int group_depth = -1)
|
element_list_t(const char* varname,
|
||||||
|
const char* fn,
|
||||||
|
int line,
|
||||||
|
int group_depth = -1)
|
||||||
{
|
{
|
||||||
LIST_INIT_TRACE;
|
LIST_INIT_TRACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
element_list_t()
|
element_list_t()
|
||||||
{
|
{
|
||||||
const char *varname = "_anon2_";
|
const char* varname = "_anon2_";
|
||||||
const char *fn = __FILE__;
|
const char* fn = __FILE__;
|
||||||
int line = __LINE__;
|
int line = __LINE__;
|
||||||
int group_depth = -1;
|
int group_depth = -1;
|
||||||
|
|
||||||
LIST_INIT_TRACE;
|
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;
|
this->el_format = other.el_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
~element_list_t()
|
~element_list_t()
|
||||||
{
|
{
|
||||||
const char *fn = __FILE__;
|
const char* fn = __FILE__;
|
||||||
int line = __LINE__;
|
int line = __LINE__;
|
||||||
|
|
||||||
LIST_DEINIT_TRACE;
|
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;
|
ELEMENT_TRACE;
|
||||||
|
|
||||||
@ -261,7 +258,7 @@ public:
|
|||||||
this->std::list<element>::push_front(elem);
|
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;
|
ELEMENT_TRACE;
|
||||||
|
|
||||||
@ -269,38 +266,39 @@ public:
|
|||||||
this->std::list<element>::push_back(elem);
|
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;
|
LIST_TRACE;
|
||||||
|
|
||||||
this->std::list<element>::pop_front();
|
this->std::list<element>::pop_front();
|
||||||
};
|
};
|
||||||
|
|
||||||
void pop_back(const char *fn, int line)
|
void pop_back(const char* fn, int line)
|
||||||
{
|
{
|
||||||
LIST_TRACE;
|
LIST_TRACE;
|
||||||
|
|
||||||
this->std::list<element>::pop_back();
|
this->std::list<element>::pop_back();
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear2(const char *fn, int line)
|
void clear2(const char* fn, int line)
|
||||||
{
|
{
|
||||||
LIST_TRACE;
|
LIST_TRACE;
|
||||||
|
|
||||||
this->std::list<element>::clear();
|
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);
|
SWAP_TRACE(other);
|
||||||
|
|
||||||
this->std::list<element>::swap(other);
|
this->std::list<element>::swap(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
void splice(iterator pos,
|
void splice(iterator pos,
|
||||||
element_list_t &other,
|
element_list_t& other,
|
||||||
iterator first,
|
iterator first,
|
||||||
iterator last,
|
iterator last,
|
||||||
const char *fn,
|
const char* fn,
|
||||||
int line)
|
int line)
|
||||||
{
|
{
|
||||||
SPLICE_TRACE;
|
SPLICE_TRACE;
|
||||||
@ -314,64 +312,64 @@ public:
|
|||||||
struct element {
|
struct element {
|
||||||
element();
|
element();
|
||||||
|
|
||||||
element(element_list_t &subs,
|
element(element_list_t& subs,
|
||||||
data_token_t token,
|
data_token_t token,
|
||||||
bool assign_subs_elements = true);
|
bool assign_subs_elements = true);
|
||||||
|
|
||||||
element(const element &other);
|
element(const element& other);
|
||||||
|
|
||||||
~element();
|
~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();
|
void update_capture();
|
||||||
|
|
||||||
const element &get_pair_value() const;
|
const element& get_pair_value() const;
|
||||||
|
|
||||||
data_token_t value_token() 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;
|
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 {
|
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;
|
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);
|
return (*this)(token, elem);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct element_if {
|
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;
|
return a.e_token == this->ei_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
data_token_t ei_token;
|
data_token_t ei_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct discover_format_state {
|
struct discover_format_state {
|
||||||
discover_format_state();
|
discover_format_state();
|
||||||
|
|
||||||
void update_for_element(const element &elem);
|
void update_for_element(const element& elem);
|
||||||
|
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
@ -383,28 +381,30 @@ private:
|
|||||||
data_format dfs_format;
|
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,
|
void pairup(schema_id_t* schema,
|
||||||
element_list_t &in_list, int group_depth = 0);
|
element_list_t& pairs_out,
|
||||||
|
element_list_t& in_list,
|
||||||
|
int group_depth = 0);
|
||||||
|
|
||||||
void discover_format();
|
void discover_format();
|
||||||
|
|
||||||
void end_of_value(element_list_t &el_stack,
|
void end_of_value(element_list_t& el_stack,
|
||||||
element_list_t &key_comps,
|
element_list_t& key_comps,
|
||||||
element_list_t &value,
|
element_list_t& value,
|
||||||
const element_list_t &in_list,
|
const element_list_t& in_list,
|
||||||
int group_depth);
|
int group_depth);
|
||||||
|
|
||||||
void parse();
|
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::vector<data_token_t> dp_group_token;
|
||||||
std::list<element_list_t> dp_group_stack;
|
std::list<element_list_t> dp_group_stack;
|
||||||
@ -412,11 +412,11 @@ private:
|
|||||||
element_list_t dp_errors;
|
element_list_t dp_errors;
|
||||||
|
|
||||||
element_list_t dp_pairs;
|
element_list_t dp_pairs;
|
||||||
schema_id_t dp_schema_id;
|
schema_id_t dp_schema_id;
|
||||||
std::string *dp_msg_format;
|
std::string* dp_msg_format;
|
||||||
int dp_msg_format_begin;
|
int dp_msg_format_begin;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
data_scanner *dp_scanner;
|
data_scanner* dp_scanner;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,137 +21,219 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "data_scanner.hh"
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "pcrepp/pcrepp.hh"
|
#include "pcrepp/pcrepp.hh"
|
||||||
#include "data_scanner.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
const char *name;
|
const char* name;
|
||||||
pcrepp pcre;
|
pcrepp pcre;
|
||||||
} MATCHERS[DT_TERMINAL_MAX] = {
|
} MATCHERS[DT_TERMINAL_MAX] = {
|
||||||
{ "quot", pcrepp("\\A(?:(?:u|r)?\"((?:\\\\.|[^\"])+)\"|"
|
{
|
||||||
"(?:u|r)?'((?:\\\\.|[^'])+)')"), },
|
"quot",
|
||||||
{ "url", pcrepp("\\A([\\w]+://[^\\s'\"\\[\\](){}]+[/a-zA-Z0-9\\-=&])"),
|
pcrepp("\\A(?:(?:u|r)?\"((?:\\\\.|[^\"])+)\"|"
|
||||||
|
"(?:u|r)?'((?:\\\\.|[^'])+)')"),
|
||||||
},
|
},
|
||||||
{ "path", pcrepp("\\A((?:/|\\./|\\.\\./)[\\w\\.\\-_\\~/]*)"),
|
{
|
||||||
|
"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"),
|
||||||
},
|
},
|
||||||
{ "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:=,]+)*)"), }, */
|
/* { "qual", pcrepp("\\A([^\\s:=]+:[^\\s:=,]+(?!,)(?::[^\\s:=,]+)*)"), }, */
|
||||||
{ "ipv6", pcrepp("\\A(::|[:\\da-fA-F\\.]+[a-fA-F\\d](?:%\\w+)?)"), },
|
{
|
||||||
{ "hexd", pcrepp(
|
"ipv6",
|
||||||
"\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F])+)"), },
|
pcrepp("\\A(::|[:\\da-fA-F\\.]+[a-fA-F\\d](?:%\\w+)?)"),
|
||||||
|
|
||||||
{ "xmlt", pcrepp(
|
|
||||||
"\\A(<\\??[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
|
|
||||||
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
|
|
||||||
"))*\\s*(?:/|\\?)>)"), },
|
|
||||||
{ "xmlo", pcrepp(
|
|
||||||
"\\A(<[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
|
|
||||||
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
|
|
||||||
"))*\\s*>)"), },
|
|
||||||
|
|
||||||
{ "xmlc", pcrepp("\\A(</[\\w:]+\\s*>)"), },
|
|
||||||
|
|
||||||
{ "coln", pcrepp("\\A(:)"),
|
|
||||||
},
|
},
|
||||||
{ "eq", pcrepp("\\A(=)"),
|
{
|
||||||
},
|
"hexd",
|
||||||
{ "comm", pcrepp("\\A(,)"),
|
pcrepp("\\A([0-9a-fA-F][0-9a-fA-F](?::[0-9a-fA-F][0-9a-fA-F])+)"),
|
||||||
},
|
|
||||||
{ "semi", pcrepp("\\A(;)"),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "empt", pcrepp("\\A(\\(\\)|\\{\\}|\\[\\])"),
|
{
|
||||||
|
"xmlt",
|
||||||
|
pcrepp("\\A(<\\??[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
|
||||||
|
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
|
||||||
|
"))*\\s*(?:/|\\?)>)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"xmlo",
|
||||||
|
pcrepp("\\A(<[\\w:]+\\s*(?:[\\w:]+(?:\\s*=\\s*"
|
||||||
|
"(?:\"((?:\\\\.|[^\"])+)\"|'((?:\\\\.|[^'])+)'|[^>]+)"
|
||||||
|
"))*\\s*>)"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "lcurly", pcrepp("\\A({)"),
|
{
|
||||||
},
|
"xmlc",
|
||||||
{ "rcurly", pcrepp("\\A(})"),
|
pcrepp("\\A(</[\\w:]+\\s*>)"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "lsquare", pcrepp("\\A(\\[)"),
|
{
|
||||||
|
"coln",
|
||||||
|
pcrepp("\\A(:)"),
|
||||||
},
|
},
|
||||||
{ "rsquare", pcrepp("\\A(\\])"),
|
{
|
||||||
|
"eq",
|
||||||
|
pcrepp("\\A(=)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comm",
|
||||||
|
pcrepp("\\A(,)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"semi",
|
||||||
|
pcrepp("\\A(;)"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "lparen", pcrepp("\\A(\\()"),
|
{
|
||||||
},
|
"empt",
|
||||||
{ "rparen", pcrepp("\\A(\\))"),
|
pcrepp("\\A(\\(\\)|\\{\\}|\\[\\])"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "langle", pcrepp("\\A(\\<)"),
|
{
|
||||||
|
"lcurly",
|
||||||
|
pcrepp("\\A({)"),
|
||||||
},
|
},
|
||||||
{ "rangle", pcrepp("\\A(\\>)"),
|
{
|
||||||
|
"rcurly",
|
||||||
|
pcrepp("\\A(})"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "ipv4", pcrepp("\\A("
|
{
|
||||||
"(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}"
|
"lsquare",
|
||||||
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?![\\d]))"),
|
pcrepp("\\A(\\[)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rsquare",
|
||||||
|
pcrepp("\\A(\\])"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "uuid", pcrepp(
|
{
|
||||||
"\\A([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})"), },
|
"lparen",
|
||||||
|
pcrepp("\\A(\\()"),
|
||||||
{ "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)"),
|
{
|
||||||
},
|
"rparen",
|
||||||
{ "pcnt", pcrepp("\\A(-?[0-9]+(\\.[0-9]+)?[ ]*%\\b)"),
|
pcrepp("\\A(\\))"),
|
||||||
},
|
|
||||||
{ "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|$))"),
|
|
||||||
},
|
|
||||||
{ "sym", pcrepp(
|
|
||||||
"\\A([^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]+"
|
|
||||||
"(?:::[^\";\\s:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]+)*)"),
|
|
||||||
},
|
|
||||||
{ "line", pcrepp("\\A(\r?\n|\r|;)"),
|
|
||||||
},
|
|
||||||
{ "wspc", pcrepp("\\A([ \\r\\t\\n]+)"),
|
|
||||||
},
|
|
||||||
{ "dot", pcrepp("\\A(\\.)"),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "gbg", pcrepp("\\A(.)"),
|
{
|
||||||
|
"langle",
|
||||||
|
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]))"),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"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"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"oct",
|
||||||
|
pcrepp("\\A(-?0[0-7]+\\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])"),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"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:=,\\(\\)\\{\\}\\[\\]\\+#!@%\\^&\\*'\\?<>\\~`\\|\\\\]"
|
||||||
|
"+)*)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"line",
|
||||||
|
pcrepp("\\A(\r?\n|\r|;)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wspc",
|
||||||
|
pcrepp("\\A([ \\r\\t\\n]+)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dot",
|
||||||
|
pcrepp("\\A(\\.)"),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"gbg",
|
||||||
|
pcrepp("\\A(.)"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *DNT_NAMES[DNT_MAX - DNT_KEY] = {
|
const char* DNT_NAMES[DNT_MAX - DNT_KEY] = {
|
||||||
"key",
|
"key",
|
||||||
"pair",
|
"pair",
|
||||||
"val",
|
"val",
|
||||||
@ -164,24 +246,22 @@ const char *DNT_NAMES[DNT_MAX - DNT_KEY] = {
|
|||||||
"grp",
|
"grp",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *data_scanner::token2name(data_token_t token)
|
const char*
|
||||||
|
data_scanner::token2name(data_token_t token)
|
||||||
{
|
{
|
||||||
if (token < 0) {
|
if (token < 0) {
|
||||||
return "inv";
|
return "inv";
|
||||||
}
|
} else if (token < DT_TERMINAL_MAX) {
|
||||||
else if (token < DT_TERMINAL_MAX) {
|
|
||||||
return MATCHERS[token].name;
|
return MATCHERS[token].name;
|
||||||
}
|
} else if (token == DT_ANY) {
|
||||||
else if (token == DT_ANY) {
|
|
||||||
return "any";
|
return "any";
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
return DNT_NAMES[token - DNT_KEY];
|
return DNT_NAMES[token - DNT_KEY];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static bool
|
||||||
bool find_string_end(const char *str, size_t &start, size_t length, char term)
|
find_string_end(const char* str, size_t& start, size_t length, char term)
|
||||||
{
|
{
|
||||||
for (; start < length; start++) {
|
for (; start < length; start++) {
|
||||||
if (str[start] == term) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void single_char_capture(pcre_context &pc, pcre_input &pi)
|
single_char_capture(pcre_context& pc, pcre_input& pi)
|
||||||
{
|
{
|
||||||
pc.all()[0].c_begin = pi.pi_offset;
|
pc.all()[0].c_begin = pi.pi_offset;
|
||||||
pc.all()[0].c_end = pi.pi_offset + 1;
|
pc.all()[0].c_end = pi.pi_offset + 1;
|
||||||
pc.all()[1] = pc.all()[0];
|
pc.all()[1] = pc.all()[0];
|
||||||
pc.set_count(2);
|
pc.set_count(2);
|
||||||
pi.pi_next_offset = pi.pi_offset + 1;
|
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();
|
const char* str = this->ds_pcre_input.get_string();
|
||||||
pcre_input &pi = this->ds_pcre_input;
|
pcre_input& pi = this->ds_pcre_input;
|
||||||
int lpc;
|
int lpc;
|
||||||
|
|
||||||
token_out = data_token_t(-1);
|
token_out = data_token_t(-1);
|
||||||
|
|
||||||
if (this->ds_pcre_input.pi_next_offset > this->ds_pcre_input.pi_length) {
|
if (this->ds_pcre_input.pi_next_offset > this->ds_pcre_input.pi_length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (this->ds_pcre_input.pi_next_offset
|
||||||
else if (this->ds_pcre_input.pi_next_offset ==
|
== this->ds_pcre_input.pi_length) {
|
||||||
this->ds_pcre_input.pi_length) {
|
|
||||||
this->ds_pcre_input.pi_next_offset += 1;
|
this->ds_pcre_input.pi_next_offset += 1;
|
||||||
token_out = DT_LINE;
|
token_out = DT_LINE;
|
||||||
return false;
|
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++) {
|
for (lpc = 0; lpc < DT_TERMINAL_MAX; lpc++) {
|
||||||
switch (lpc) {
|
switch (lpc) {
|
||||||
case DT_QUOTED_STRING: {
|
case DT_QUOTED_STRING: {
|
||||||
size_t str_start, str_end;
|
size_t str_start, str_end;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
pi.pi_offset = pi.pi_next_offset;
|
pi.pi_offset = pi.pi_next_offset;
|
||||||
str_end = str_start = pi.pi_offset + 1;
|
str_end = str_start = pi.pi_offset + 1;
|
||||||
switch (str[pi.pi_offset]) {
|
switch (str[pi.pi_offset]) {
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'r':
|
case 'r':
|
||||||
if (pi.pi_offset + 1 < pi.pi_length &&
|
if (pi.pi_offset + 1 < pi.pi_length
|
||||||
(str[pi.pi_offset + 1] == '\'' ||
|
&& (str[pi.pi_offset + 1] == '\''
|
||||||
str[pi.pi_offset + 1] == '\"')) {
|
|| str[pi.pi_offset + 1] == '\"'))
|
||||||
str_start += 1;
|
{
|
||||||
str_end += 1;
|
str_start += 1;
|
||||||
found = find_string_end(str,
|
str_end += 1;
|
||||||
str_end,
|
found = find_string_end(str,
|
||||||
pi.pi_length,
|
str_end,
|
||||||
str[pi.pi_offset + 1]);
|
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_EQUALS: {
|
|
||||||
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;
|
|
||||||
|
|
||||||
case DT_COMMA: {
|
|
||||||
pi.pi_offset = pi.pi_next_offset;
|
|
||||||
|
|
||||||
if (str[pi.pi_offset] == ',') {
|
|
||||||
token_out = data_token_t(DT_COMMA);
|
|
||||||
single_char_capture(pc, pi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DT_SEMI: {
|
|
||||||
pi.pi_offset = pi.pi_next_offset;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
this->ds_pcre_input.pi_next_offset =
|
|
||||||
this->ds_pcre_input.pi_offset;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
case '\'':
|
||||||
token_out = data_token_t(lpc);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
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_EQUALS: {
|
||||||
|
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;
|
||||||
|
|
||||||
|
case DT_COMMA: {
|
||||||
|
pi.pi_offset = pi.pi_next_offset;
|
||||||
|
|
||||||
|
if (str[pi.pi_offset] == ',') {
|
||||||
|
token_out = data_token_t(DT_COMMA);
|
||||||
|
single_char_capture(pc, pi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DT_SEMI: {
|
||||||
|
pi.pi_offset = pi.pi_next_offset;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -36,7 +36,7 @@
|
|||||||
#include "shared_buffer.hh"
|
#include "shared_buffer.hh"
|
||||||
|
|
||||||
enum data_token_t {
|
enum data_token_t {
|
||||||
DT_INVALID = -1,
|
DT_INVALID = -1,
|
||||||
|
|
||||||
DT_QUOTED_STRING = 0,
|
DT_QUOTED_STRING = 0,
|
||||||
DT_URL,
|
DT_URL,
|
||||||
@ -91,7 +91,7 @@ enum data_token_t {
|
|||||||
|
|
||||||
DT_TERMINAL_MAX = DT_GARBAGE + 1,
|
DT_TERMINAL_MAX = DT_GARBAGE + 1,
|
||||||
|
|
||||||
DNT_KEY = 50,
|
DNT_KEY = 50,
|
||||||
DNT_PAIR,
|
DNT_PAIR,
|
||||||
DNT_VALUE,
|
DNT_VALUE,
|
||||||
DNT_ROW,
|
DNT_ROW,
|
||||||
@ -109,19 +109,24 @@ enum data_token_t {
|
|||||||
|
|
||||||
class data_scanner {
|
class data_scanner {
|
||||||
public:
|
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)
|
data_scanner(const std::string& line,
|
||||||
: ds_line(line),
|
size_t off = 0,
|
||||||
ds_pcre_input(ds_line.c_str(), off, len)
|
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] == '.') {
|
if (!line.empty() && line[line.length() - 1] == '.') {
|
||||||
this->ds_pcre_input.pi_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)
|
data_scanner(shared_buffer_ref& line,
|
||||||
: ds_sbr(line), ds_pcre_input(line.get_data(), off, len == (size_t) -1 ? line.length() : len)
|
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());
|
require(len == (size_t) -1 || len <= line.length());
|
||||||
if (line.length() > 0 && line.get_data()[line.length() - 1] == '.') {
|
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 tokenize(pcre_context& pc, data_token_t& token_out);
|
||||||
bool tokenize2(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();
|
this->ds_pcre_input.reset_next_offset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
163208
src/data_scanner_re.cc
163208
src/data_scanner_re.cc
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
#include "db_sub_source.hh"
|
||||||
|
|
||||||
#include "base/date_time_scanner.hh"
|
#include "base/date_time_scanner.hh"
|
||||||
#include "base/time_util.hh"
|
#include "base/time_util.hh"
|
||||||
|
#include "config.h"
|
||||||
#include "yajlpp/json_ptr.hh"
|
#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;
|
constexpr size_t MAX_COLUMN_WIDTH = 120;
|
||||||
|
|
||||||
void db_label_source::text_value_for_line(textview_curses &tc, int row,
|
void
|
||||||
std::string &label_out,
|
db_label_source::text_value_for_line(textview_curses& tc,
|
||||||
text_sub_source::line_flags_t flags)
|
int row,
|
||||||
|
std::string& label_out,
|
||||||
|
text_sub_source::line_flags_t flags)
|
||||||
{
|
{
|
||||||
static const std::string TAB_SYMBOL = "\u21e5";
|
static const std::string TAB_SYMBOL = "\u21e5";
|
||||||
static const std::string LF_SYMBOL = "\u240a";
|
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();
|
label_out.clear();
|
||||||
if (row >= (int)this->dls_rows.size()) {
|
if (row >= (int) this->dls_rows.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int lpc = 0; lpc < (int)this->dls_rows[row].size(); lpc++) {
|
for (int lpc = 0; lpc < (int) this->dls_rows[row].size(); lpc++) {
|
||||||
auto actual_col_size = std::min(MAX_COLUMN_WIDTH,
|
auto actual_col_size
|
||||||
this->dls_headers[lpc].hm_column_size);
|
= std::min(MAX_COLUMN_WIDTH, this->dls_headers[lpc].hm_column_size);
|
||||||
auto raw_cell_str = std::string(this->dls_rows[row][lpc]);
|
auto raw_cell_str = std::string(this->dls_rows[row][lpc]);
|
||||||
std::string cell_str;
|
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);
|
truncate_to(cell_str, MAX_COLUMN_WIDTH);
|
||||||
|
|
||||||
auto cell_length = utf8_string_length(cell_str)
|
auto cell_length
|
||||||
.unwrapOr(actual_col_size);
|
= utf8_string_length(cell_str).unwrapOr(actual_col_size);
|
||||||
auto padding = actual_col_size - cell_length;
|
auto padding = actual_col_size - cell_length;
|
||||||
this->dls_cell_width[lpc] = cell_str.length() + padding;
|
this->dls_cell_width[lpc] = cell_str.length() + padding;
|
||||||
if (this->dls_headers[lpc].hm_column_type != SQLITE3_TEXT) {
|
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,
|
void
|
||||||
string_attrs_t &sa)
|
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 lr(0, 0);
|
||||||
struct line_range lr2(0, -1);
|
struct line_range lr2(0, -1);
|
||||||
|
|
||||||
if (row >= (int)this->dls_rows.size()) {
|
if (row >= (int) this->dls_rows.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t lpc = 0; lpc < this->dls_headers.size() - 1; lpc++) {
|
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;
|
int left = 0;
|
||||||
for (size_t lpc = 0; lpc < this->dls_headers.size(); lpc++) {
|
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);
|
size_t row_len = strlen(row_value);
|
||||||
|
|
||||||
if (this->dls_headers[lpc].hm_graphable) {
|
if (this->dls_headers[lpc].hm_graphable) {
|
||||||
double num_value;
|
double num_value;
|
||||||
|
|
||||||
if (sscanf(row_value, "%lf", &num_value) == 1) {
|
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 &&
|
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] == '}')
|
||||||
(row_value[0] == '[' && row_value[row_len - 1] == ']'))) {
|
|| (row_value[0] == '[' && row_value[row_len - 1] == ']')))
|
||||||
|
{
|
||||||
json_ptr_walk jpw;
|
json_ptr_walk jpw;
|
||||||
|
|
||||||
if (jpw.parse(row_value, row_len) == yajl_status_ok &&
|
if (jpw.parse(row_value, row_len) == yajl_status_ok
|
||||||
jpw.complete_parse() == yajl_status_ok) {
|
&& jpw.complete_parse() == yajl_status_ok)
|
||||||
for (auto &jpw_value : jpw.jpw_values) {
|
{
|
||||||
|
for (auto& jpw_value : jpw.jpw_values) {
|
||||||
double num_value;
|
double num_value;
|
||||||
|
|
||||||
if (jpw_value.wt_type == yajl_t_number &&
|
if (jpw_value.wt_type == yajl_t_number
|
||||||
sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) {
|
&& sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value)
|
||||||
this->dls_chart.chart_attrs_for_value(tc, left,
|
== 1)
|
||||||
jpw_value.wt_ptr, num_value, sa);
|
{
|
||||||
|
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,
|
void
|
||||||
bool graphable)
|
db_label_source::push_header(const std::string& colstr,
|
||||||
|
int type,
|
||||||
|
bool graphable)
|
||||||
{
|
{
|
||||||
this->dls_headers.emplace_back(colstr);
|
this->dls_headers.emplace_back(colstr);
|
||||||
this->dls_cell_width.push_back(0);
|
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_size = utf8_string_length(colstr).unwrapOr(colstr.length());
|
||||||
hm.hm_column_type = type;
|
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();
|
int index = this->dls_rows.back().size();
|
||||||
double num_value = 0.0;
|
double num_value = 0.0;
|
||||||
size_t value_len;
|
size_t value_len;
|
||||||
|
|
||||||
if (colstr == nullptr) {
|
if (colstr == nullptr) {
|
||||||
colstr = NULL_STR;
|
colstr = NULL_STR;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
colstr = strdup(colstr);
|
colstr = strdup(colstr);
|
||||||
if (colstr == nullptr) {
|
if (colstr == nullptr) {
|
||||||
throw "out of memory";
|
throw "out of memory";
|
||||||
@ -192,36 +202,39 @@ void db_label_source::push_column(const char *colstr)
|
|||||||
tv.tv_sec = -1;
|
tv.tv_sec = -1;
|
||||||
tv.tv_usec = -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_index = -1;
|
||||||
this->dls_time_column.clear();
|
this->dls_time_column.clear();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this->dls_time_column.push_back(tv);
|
this->dls_time_column.push_back(tv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->dls_rows.back().push_back(colstr);
|
this->dls_rows.back().push_back(colstr);
|
||||||
this->dls_headers[index].hm_column_size =
|
this->dls_headers[index].hm_column_size
|
||||||
std::max(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));
|
utf8_string_length(colstr, value_len).unwrapOr(value_len));
|
||||||
|
|
||||||
if (colstr != nullptr && this->dls_headers[index].hm_graphable) {
|
if (colstr != nullptr && this->dls_headers[index].hm_graphable) {
|
||||||
if (sscanf(colstr, "%lf", &num_value) != 1) {
|
if (sscanf(colstr, "%lf", &num_value) != 1) {
|
||||||
num_value = 0.0;
|
num_value = 0.0;
|
||||||
}
|
}
|
||||||
this->dls_chart.add_value(this->dls_headers[index].hm_name, num_value);
|
this->dls_chart.add_value(this->dls_headers[index].hm_name, num_value);
|
||||||
}
|
} else if (value_len > 2
|
||||||
else if (value_len > 2 &&
|
&& ((colstr[0] == '{' && colstr[value_len - 1] == '}')
|
||||||
((colstr[0] == '{' && colstr[value_len - 1] == '}') ||
|
|| (colstr[0] == '[' && colstr[value_len - 1] == ']')))
|
||||||
(colstr[0] == '[' && colstr[value_len - 1] == ']'))) {
|
{
|
||||||
json_ptr_walk jpw;
|
json_ptr_walk jpw;
|
||||||
|
|
||||||
if (jpw.parse(colstr, value_len) == yajl_status_ok &&
|
if (jpw.parse(colstr, value_len) == yajl_status_ok
|
||||||
jpw.complete_parse() == yajl_status_ok) {
|
&& jpw.complete_parse() == yajl_status_ok)
|
||||||
for (auto &jpw_value : jpw.jpw_values) {
|
{
|
||||||
if (jpw_value.wt_type == yajl_t_number &&
|
for (auto& jpw_value : jpw.jpw_values) {
|
||||||
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)
|
||||||
|
{
|
||||||
this->dls_chart.add_value(jpw_value.wt_ptr, num_value);
|
this->dls_chart.add_value(jpw_value.wt_ptr, num_value);
|
||||||
this->dls_chart.with_attrs_for_ident(
|
this->dls_chart.with_attrs_for_ident(
|
||||||
jpw_value.wt_ptr, vc.attrs_for_ident(jpw_value.wt_ptr));
|
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_chart.clear();
|
||||||
this->dls_headers.clear();
|
this->dls_headers.clear();
|
||||||
for (size_t row = 0; row < this->dls_rows.size(); row++) {
|
for (size_t row = 0; row < this->dls_rows.size(); row++) {
|
||||||
for (size_t col = 0; col < this->dls_rows[row].size(); col++) {
|
for (size_t col = 0; col < this->dls_rows[row].size(); col++) {
|
||||||
if (this->dls_rows[row][col] != NULL_STR) {
|
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();
|
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;
|
std::vector<header_meta>::const_iterator iter;
|
||||||
|
|
||||||
iter = std::find(this->dls_headers.begin(),
|
iter = std::find(this->dls_headers.begin(), this->dls_headers.end(), name);
|
||||||
this->dls_headers.end(),
|
|
||||||
name);
|
|
||||||
if (iter == this->dls_headers.end()) {
|
if (iter == this->dls_headers.end()) {
|
||||||
return -1;
|
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);
|
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;
|
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;
|
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;
|
size_t retval = 1;
|
||||||
|
|
||||||
@ -284,9 +299,9 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
view_colors &vc = view_colors::singleton();
|
view_colors& vc = view_colors::singleton();
|
||||||
vis_line_t top = lv.get_top();
|
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;
|
unsigned long width;
|
||||||
vis_line_t height;
|
vis_line_t height;
|
||||||
|
|
||||||
@ -294,22 +309,24 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
|
|||||||
|
|
||||||
this->dos_lines.clear();
|
this->dos_lines.clear();
|
||||||
for (size_t col = 0; col < cols.size(); col++) {
|
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);
|
size_t col_len = strlen(col_value);
|
||||||
|
|
||||||
if (!(col_len >= 2 &&
|
if (!(col_len >= 2
|
||||||
((col_value[0] == '{' && col_value[col_len - 1] == '}') ||
|
&& ((col_value[0] == '{' && col_value[col_len - 1] == '}')
|
||||||
(col_value[0] == '[' && col_value[col_len - 1] == ']')))) {
|
|| (col_value[0] == '[' && col_value[col_len - 1] == ']'))))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_ptr_walk jpw;
|
json_ptr_walk jpw;
|
||||||
|
|
||||||
if (jpw.parse(col_value, col_len) == yajl_status_ok &&
|
if (jpw.parse(col_value, col_len) == yajl_status_ok
|
||||||
jpw.complete_parse() == 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);
|
this->dos_lines.emplace_back(" JSON Column: " + header);
|
||||||
|
|
||||||
retval += 1;
|
retval += 1;
|
||||||
@ -318,14 +335,13 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
|
|||||||
stacked_bar_chart<std::string> chart;
|
stacked_bar_chart<std::string> chart;
|
||||||
int start_line = this->dos_lines.size();
|
int start_line = this->dos_lines.size();
|
||||||
|
|
||||||
chart.with_stacking_enabled(false)
|
chart.with_stacking_enabled(false).with_margins(3, 0);
|
||||||
.with_margins(3, 0);
|
|
||||||
|
|
||||||
for (auto &jpw_value : jpw.jpw_values) {
|
for (auto& jpw_value : jpw.jpw_values) {
|
||||||
this->dos_lines.emplace_back(" " + jpw_value.wt_ptr + " = " +
|
this->dos_lines.emplace_back(" " + jpw_value.wt_ptr + " = "
|
||||||
jpw_value.wt_value);
|
+ 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);
|
struct line_range lr(1, 2);
|
||||||
|
|
||||||
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LTEE);
|
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;
|
double num_value = 0.0;
|
||||||
|
|
||||||
if (jpw_value.wt_type == yajl_t_number &&
|
if (jpw_value.wt_type == yajl_t_number
|
||||||
sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value) == 1) {
|
&& sscanf(jpw_value.wt_value.c_str(), "%lf", &num_value)
|
||||||
|
== 1)
|
||||||
|
{
|
||||||
int attrs = vc.attrs_for_ident(jpw_value.wt_ptr);
|
int attrs = vc.attrs_for_ident(jpw_value.wt_ptr);
|
||||||
|
|
||||||
chart.add_value(jpw_value.wt_ptr, num_value);
|
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;
|
int curr_line = start_line;
|
||||||
for (auto iter = jpw.jpw_values.begin();
|
for (auto iter = jpw.jpw_values.begin();
|
||||||
iter != jpw.jpw_values.end();
|
iter != jpw.jpw_values.end();
|
||||||
++iter, curr_line++) {
|
++iter, curr_line++)
|
||||||
|
{
|
||||||
double num_value = 0.0;
|
double num_value = 0.0;
|
||||||
|
|
||||||
if (iter->wt_type == yajl_t_number &&
|
if (iter->wt_type == yajl_t_number
|
||||||
sscanf(iter->wt_value.c_str(), "%lf", &num_value) == 1) {
|
&& sscanf(iter->wt_value.c_str(), "%lf", &num_value) == 1)
|
||||||
string_attrs_t &sa = this->dos_lines[curr_line].get_attrs();
|
{
|
||||||
|
string_attrs_t& sa = this->dos_lines[curr_line].get_attrs();
|
||||||
int left = 3;
|
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) {
|
if (retval > 1) {
|
||||||
this->dos_lines.emplace_back("");
|
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);
|
struct line_range lr(1, 2);
|
||||||
|
|
||||||
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
|
bool
|
||||||
int bottom, vis_line_t row,
|
db_overlay_source::list_value_for_overlay(const listview_curses& lv,
|
||||||
attr_line_t &value_out)
|
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) {
|
if (y == 0) {
|
||||||
this->list_overlay_count(lv);
|
this->list_overlay_count(lv);
|
||||||
std::string &line = value_out.get_string();
|
std::string& line = value_out.get_string();
|
||||||
db_label_source *dls = this->dos_labels;
|
db_label_source* dls = this->dos_labels;
|
||||||
string_attrs_t &sa = value_out.get_attrs();
|
string_attrs_t& sa = value_out.get_attrs();
|
||||||
|
|
||||||
for (size_t lpc = 0;
|
for (size_t lpc = 0; lpc < this->dos_labels->dls_headers.size(); lpc++)
|
||||||
lpc < this->dos_labels->dls_headers.size();
|
{
|
||||||
lpc++) {
|
|
||||||
auto actual_col_size = std::min(
|
auto actual_col_size = std::min(
|
||||||
MAX_COLUMN_WIDTH, dls->dls_headers[lpc].hm_column_size);
|
MAX_COLUMN_WIDTH, dls->dls_headers[lpc].hm_column_size);
|
||||||
std::string cell_title = dls->dls_headers[lpc].hm_name;
|
std::string cell_title = dls->dls_headers[lpc].hm_name;
|
||||||
|
|
||||||
truncate_to(cell_title, MAX_COLUMN_WIDTH);
|
truncate_to(cell_title, MAX_COLUMN_WIDTH);
|
||||||
|
|
||||||
auto cell_length = utf8_string_length(cell_title)
|
auto cell_length
|
||||||
.unwrapOr(actual_col_size);
|
= utf8_string_length(cell_title).unwrapOr(actual_col_size);
|
||||||
int before, total_fill = actual_col_size - cell_length;
|
int before, total_fill = actual_col_size - cell_length;
|
||||||
auto line_len_before = line.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());
|
struct line_range header_range(line_len_before, line.length());
|
||||||
|
|
||||||
int attrs =
|
int attrs
|
||||||
vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) | A_REVERSE;
|
= vc.attrs_for_ident(dls->dls_headers[lpc].hm_name) | A_REVERSE;
|
||||||
if (!this->dos_labels->dls_headers[lpc].hm_graphable) {
|
if (!this->dos_labels->dls_headers[lpc].hm_graphable) {
|
||||||
attrs = A_UNDERLINE;
|
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);
|
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD | A_UNDERLINE);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (this->dos_active && y >= 2
|
||||||
else if (this->dos_active && y >= 2 && ((size_t) y) < (this->dos_lines.size() + 2)) {
|
&& ((size_t) y) < (this->dos_lines.size() + 2))
|
||||||
|
{
|
||||||
value_out = this->dos_lines[y - 2];
|
value_out = this->dos_lines[y - 2];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,60 +30,68 @@
|
|||||||
#ifndef db_sub_source_hh
|
#ifndef db_sub_source_hh
|
||||||
#define db_sub_source_hh
|
#define db_sub_source_hh
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
#include "textview_curses.hh"
|
|
||||||
#include "hist_source.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:
|
public:
|
||||||
~db_label_source() {
|
~db_label_source()
|
||||||
|
{
|
||||||
this->clear();
|
this->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_log_time_column() const {
|
bool has_log_time_column() const
|
||||||
|
{
|
||||||
return !this->dls_time_column.empty();
|
return !this->dls_time_column.empty();
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t text_line_count() {
|
size_t text_line_count()
|
||||||
|
{
|
||||||
return this->dls_rows.size();
|
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);
|
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;
|
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;
|
retval += dls_header.hm_column_size + 1;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
void text_value_for_line(textview_curses &tc,
|
void text_value_for_line(textview_curses& tc,
|
||||||
int row,
|
int row,
|
||||||
std::string &label_out,
|
std::string& label_out,
|
||||||
line_flags_t flags);
|
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();
|
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<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())) {
|
if ((row < 0_vl) || (((size_t) row) >= this->dls_time_column.size())) {
|
||||||
return nonstd::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
@ -93,15 +101,13 @@ public:
|
|||||||
|
|
||||||
struct header_meta {
|
struct header_meta {
|
||||||
explicit header_meta(std::string name)
|
explicit header_meta(std::string name)
|
||||||
: hm_name(std::move(name)),
|
: hm_name(std::move(name)), hm_column_type(SQLITE3_TEXT),
|
||||||
hm_column_type(SQLITE3_TEXT),
|
hm_graphable(false), hm_log_time(false), hm_column_size(0){
|
||||||
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;
|
return this->hm_name == name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,25 +121,26 @@ public:
|
|||||||
|
|
||||||
stacked_bar_chart<std::string> dls_chart;
|
stacked_bar_chart<std::string> dls_chart;
|
||||||
std::vector<header_meta> dls_headers;
|
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<struct timeval> dls_time_column;
|
||||||
std::vector<size_t> dls_cell_width;
|
std::vector<size_t> dls_cell_width;
|
||||||
int dls_time_column_index{-1};
|
int dls_time_column_index{-1};
|
||||||
|
|
||||||
static const char *NULL_STR;
|
static const char* NULL_STR;
|
||||||
};
|
};
|
||||||
|
|
||||||
class db_overlay_source : public list_overlay_source {
|
class db_overlay_source : public list_overlay_source {
|
||||||
public:
|
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,
|
bool list_value_for_overlay(const listview_curses& lv,
|
||||||
int y, int bottom,
|
int y,
|
||||||
|
int bottom,
|
||||||
vis_line_t row,
|
vis_line_t row,
|
||||||
attr_line_t &value_out) override;
|
attr_line_t& value_out) override;
|
||||||
|
|
||||||
bool dos_active{false};
|
bool dos_active{false};
|
||||||
db_label_source *dos_labels{nullptr};
|
db_label_source* dos_labels{nullptr};
|
||||||
std::vector<attr_line_t> dos_lines;
|
std::vector<attr_line_t> dos_lines;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -34,8 +34,7 @@
|
|||||||
|
|
||||||
#include "statusview_curses.hh"
|
#include "statusview_curses.hh"
|
||||||
|
|
||||||
class doc_status_source
|
class doc_status_source : public status_data_source {
|
||||||
: public status_data_source {
|
|
||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TSF_TITLE,
|
TSF_TITLE,
|
||||||
@ -45,7 +44,8 @@ public:
|
|||||||
TSF__MAX
|
TSF__MAX
|
||||||
} field_t;
|
} field_t;
|
||||||
|
|
||||||
doc_status_source() {
|
doc_status_source()
|
||||||
|
{
|
||||||
this->tss_fields[TSF_TITLE].set_width(14);
|
this->tss_fields[TSF_TITLE].set_width(14);
|
||||||
this->tss_fields[TSF_TITLE].set_left_pad(1);
|
this->tss_fields[TSF_TITLE].set_left_pad(1);
|
||||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_STATUS_TITLE);
|
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);
|
this->tss_fields[TSF_DESCRIPTION].set_role(view_colors::VCR_STATUS);
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t statusview_fields() override {
|
size_t statusview_fields() override
|
||||||
|
{
|
||||||
return TSF__MAX;
|
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];
|
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);
|
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);
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "elem_to_json.hh"
|
#include "elem_to_json.hh"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "yajlpp/yajlpp.hh"
|
#include "yajlpp/yajlpp.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static
|
static void
|
||||||
void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &elem)
|
element_to_json(yajl_gen gen, data_parser& dp, const data_parser::element& elem)
|
||||||
{
|
{
|
||||||
size_t value_len;
|
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()) {
|
switch (elem.value_token()) {
|
||||||
case DT_NUMBER: {
|
case DT_NUMBER: {
|
||||||
@ -48,20 +48,21 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DNT_GROUP: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DNT_PAIR: {
|
case DNT_PAIR: {
|
||||||
const data_parser::element &pair_elem = elem.get_pair_elem();
|
const data_parser::element& pair_elem = elem.get_pair_elem();
|
||||||
string key_str = dp.get_element_string(pair_elem.e_sub_elements->front());
|
string key_str
|
||||||
|
= dp.get_element_string(pair_elem.e_sub_elements->front());
|
||||||
|
|
||||||
if (!key_str.empty()) {
|
if (!key_str.empty()) {
|
||||||
yajlpp_map singleton_map(gen);
|
yajlpp_map singleton_map(gen);
|
||||||
|
|
||||||
singleton_map.gen(key_str);
|
singleton_map.gen(key_str);
|
||||||
element_to_json(gen, dp, pair_elem.get_pair_value());
|
element_to_json(gen, dp, pair_elem.get_pair_value());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
element_to_json(gen, dp, pair_elem.get_pair_value());
|
element_to_json(gen, dp, pair_elem.get_pair_value());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -69,11 +70,9 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
|
|||||||
case DT_CONSTANT: {
|
case DT_CONSTANT: {
|
||||||
if (strncasecmp("true", value_str, value_len) == 0) {
|
if (strncasecmp("true", value_str, value_len) == 0) {
|
||||||
yajl_gen_bool(gen, true);
|
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);
|
yajl_gen_bool(gen, false);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
yajl_gen_null(gen);
|
yajl_gen_null(gen);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -84,22 +83,24 @@ void element_to_json(yajl_gen gen, data_parser &dp, const data_parser::element &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void map_elements_to_json2(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
|
map_elements_to_json2(yajl_gen gen,
|
||||||
|
data_parser& dp,
|
||||||
|
data_parser::element_list_t* el)
|
||||||
{
|
{
|
||||||
yajlpp_map root_map(gen);
|
yajlpp_map root_map(gen);
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
|
||||||
for (auto &iter : *el) {
|
for (auto& iter : *el) {
|
||||||
const data_parser::element &pvalue = iter.get_pair_value();
|
const data_parser::element& pvalue = iter.get_pair_value();
|
||||||
|
|
||||||
if (pvalue.value_token() == DT_INVALID) {
|
if (pvalue.value_token() == DT_INVALID) {
|
||||||
log_debug("invalid!!");
|
log_debug("invalid!!");
|
||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string key_str = dp.get_element_string(
|
std::string key_str
|
||||||
iter.e_sub_elements->front());
|
= dp.get_element_string(iter.e_sub_elements->front());
|
||||||
|
|
||||||
if (key_str.empty()) {
|
if (key_str.empty()) {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
@ -113,46 +114,51 @@ void map_elements_to_json2(yajl_gen gen, data_parser &dp, data_parser::element_l
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void list_body_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
|
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);
|
element_to_json(gen, dp, iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void list_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
|
list_elements_to_json(yajl_gen gen,
|
||||||
|
data_parser& dp,
|
||||||
|
data_parser::element_list_t* el)
|
||||||
{
|
{
|
||||||
yajlpp_array root_array(gen);
|
yajlpp_array root_array(gen);
|
||||||
|
|
||||||
list_body_elements_to_json(gen, dp, el);
|
list_body_elements_to_json(gen, dp, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void map_elements_to_json(yajl_gen gen, data_parser &dp, data_parser::element_list_t *el)
|
map_elements_to_json(yajl_gen gen,
|
||||||
|
data_parser& dp,
|
||||||
|
data_parser::element_list_t* el)
|
||||||
{
|
{
|
||||||
bool unique_names = el->size() > 1;
|
bool unique_names = el->size() > 1;
|
||||||
vector<string> names;
|
vector<string> names;
|
||||||
|
|
||||||
for (auto &iter : *el) {
|
for (auto& iter : *el) {
|
||||||
const data_parser::element &pvalue = iter.get_pair_value();
|
const data_parser::element& pvalue = iter.get_pair_value();
|
||||||
|
|
||||||
if (pvalue.value_token() == DT_INVALID) {
|
if (pvalue.value_token() == DT_INVALID) {
|
||||||
log_debug("invalid!!");
|
log_debug("invalid!!");
|
||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string key_str = dp.get_element_string(
|
std::string key_str
|
||||||
iter.e_sub_elements->front());
|
= dp.get_element_string(iter.e_sub_elements->front());
|
||||||
if (key_str.empty()) {
|
if (key_str.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (find(names.begin(), names.end(), key_str) != names.end()) {
|
if (find(names.begin(), names.end(), key_str) != names.end()) {
|
||||||
unique_names = false;
|
unique_names = false;
|
||||||
break;
|
break;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
names.push_back(key_str);
|
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) {
|
if (unique_names) {
|
||||||
map_elements_to_json2(gen, dp, el);
|
map_elements_to_json2(gen, dp, el);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
list_elements_to_json(gen, dp, el);
|
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()) {
|
if (el->empty()) {
|
||||||
yajl_gen_null(gen);
|
yajl_gen_null(gen);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
switch (el->front().e_token) {
|
switch (el->front().e_token) {
|
||||||
case DNT_PAIR: {
|
case DNT_PAIR: {
|
||||||
if (root && el->size() == 1) {
|
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(
|
std::string key_str = dp.get_element_string(
|
||||||
pair_elem.e_sub_elements->front());
|
pair_elem.e_sub_elements->front());
|
||||||
|
|
||||||
if (key_str.empty() &&
|
if (key_str.empty()
|
||||||
el->front().get_pair_value().value_token() == DNT_GROUP) {
|
&& el->front().get_pair_value().value_token()
|
||||||
|
== DNT_GROUP) {
|
||||||
element_to_json(gen, dp, el->front().get_pair_value());
|
element_to_json(gen, dp, el->front().get_pair_value());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
yajlpp_map singleton_map(gen);
|
yajlpp_map singleton_map(gen);
|
||||||
|
|
||||||
if (key_str.empty()) {
|
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);
|
singleton_map.gen(key_str);
|
||||||
element_to_json(gen, dp, pair_elem.get_pair_value());
|
element_to_json(gen, dp, pair_elem.get_pair_value());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
map_elements_to_json(gen, dp, el);
|
map_elements_to_json(gen, dp, el);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,9 +30,12 @@
|
|||||||
#ifndef elem_to_json_hh
|
#ifndef elem_to_json_hh
|
||||||
#define elem_to_json_hh
|
#define elem_to_json_hh
|
||||||
|
|
||||||
#include "yajl/api/yajl_gen.h"
|
|
||||||
#include "data_parser.hh"
|
#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
|
#endif
|
||||||
|
@ -21,26 +21,26 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "environ_vtab.hh"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "auto_mem.hh"
|
#include "auto_mem.hh"
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "environ_vtab.hh"
|
#include "config.h"
|
||||||
|
|
||||||
using namespace std;
|
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.
|
-- Access lnav's environment variables through this table.
|
||||||
CREATE TABLE environ (
|
CREATE TABLE environ (
|
||||||
name text PRIMARY KEY,
|
name text PRIMARY KEY,
|
||||||
@ -49,27 +49,29 @@ CREATE TABLE environ (
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
struct vtab {
|
struct vtab {
|
||||||
sqlite3_vtab base;
|
sqlite3_vtab base;
|
||||||
sqlite3 * db;
|
sqlite3* db;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vtab_cursor {
|
struct vtab_cursor {
|
||||||
sqlite3_vtab_cursor base;
|
sqlite3_vtab_cursor base;
|
||||||
char **env_cursor;
|
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,
|
static int
|
||||||
void *pAux,
|
vt_create(sqlite3* db,
|
||||||
int argc, const char *const *argv,
|
void* pAux,
|
||||||
sqlite3_vtab **pp_vt,
|
int argc,
|
||||||
char **pzErr)
|
const char* const* argv,
|
||||||
|
sqlite3_vtab** pp_vt,
|
||||||
|
char** pzErr)
|
||||||
{
|
{
|
||||||
vtab *p_vt;
|
vtab* p_vt;
|
||||||
|
|
||||||
/* Allocate the sqlite3_vtab/vtab structure itself */
|
/* 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) {
|
if (p_vt == NULL) {
|
||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
@ -85,10 +87,10 @@ static int vt_create(sqlite3 *db,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
static int vt_destructor(sqlite3_vtab *p_svt)
|
vt_destructor(sqlite3_vtab* p_svt)
|
||||||
{
|
{
|
||||||
vtab *p_vt = (vtab *)p_svt;
|
vtab* p_vt = (vtab*) p_svt;
|
||||||
|
|
||||||
/* Free the SQLite structure */
|
/* Free the SQLite structure */
|
||||||
sqlite3_free(p_vt);
|
sqlite3_free(p_vt);
|
||||||
@ -96,37 +98,44 @@ static int vt_destructor(sqlite3_vtab *p_svt)
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vt_connect(sqlite3 *db, void *p_aux,
|
static int
|
||||||
int argc, const char *const *argv,
|
vt_connect(sqlite3* db,
|
||||||
sqlite3_vtab **pp_vt, char **pzErr)
|
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);
|
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);
|
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);
|
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;
|
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) {
|
if (p_cur == NULL) {
|
||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
} else {
|
} else {
|
||||||
*pp_cursor = (sqlite3_vtab_cursor *)p_cur;
|
*pp_cursor = (sqlite3_vtab_cursor*) p_cur;
|
||||||
|
|
||||||
p_cur->base.pVtab = p_svt;
|
p_cur->base.pVtab = p_svt;
|
||||||
p_cur->env_cursor = environ;
|
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;
|
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. */
|
/* Free cursor struct. */
|
||||||
delete p_cur;
|
delete p_cur;
|
||||||
@ -145,16 +155,18 @@ static int vt_close(sqlite3_vtab_cursor *cur)
|
|||||||
return SQLITE_OK;
|
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;
|
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) {
|
if (vc->env_cursor[0] != NULL) {
|
||||||
vc->env_cursor += 1;
|
vc->env_cursor += 1;
|
||||||
@ -163,61 +175,69 @@ static int vt_next(sqlite3_vtab_cursor *cur)
|
|||||||
return SQLITE_OK;
|
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;
|
vtab_cursor* vc = (vtab_cursor*) cur;
|
||||||
const char *eq = strchr(vc->env_cursor[0], '=');
|
const char* eq = strchr(vc->env_cursor[0], '=');
|
||||||
|
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case 0:
|
case 0:
|
||||||
sqlite3_result_text(ctx,
|
sqlite3_result_text(ctx,
|
||||||
vc->env_cursor[0], eq - vc->env_cursor[0],
|
vc->env_cursor[0],
|
||||||
SQLITE_TRANSIENT);
|
eq - vc->env_cursor[0],
|
||||||
break;
|
SQLITE_TRANSIENT);
|
||||||
case 1:
|
break;
|
||||||
sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
|
case 1:
|
||||||
break;
|
sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQLITE_OK;
|
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;
|
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;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vt_filter(sqlite3_vtab_cursor *p_vtc,
|
static int
|
||||||
int idxNum, const char *idxStr,
|
vt_filter(sqlite3_vtab_cursor* p_vtc,
|
||||||
int argc, sqlite3_value **argv)
|
int idxNum,
|
||||||
|
const char* idxStr,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value** argv)
|
||||||
{
|
{
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vt_update(sqlite3_vtab *tab,
|
static int
|
||||||
int argc,
|
vt_update(sqlite3_vtab* tab,
|
||||||
sqlite3_value **argv,
|
int argc,
|
||||||
sqlite_int64 *rowid)
|
sqlite3_value** argv,
|
||||||
|
sqlite_int64* rowid)
|
||||||
{
|
{
|
||||||
const char *name = (
|
const char* name
|
||||||
argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : nullptr);
|
= (argc > 2 ? (const char*) sqlite3_value_text(argv[2]) : nullptr);
|
||||||
vtab *p_vt = (vtab *)tab;
|
vtab* p_vt = (vtab*) tab;
|
||||||
int retval = SQLITE_ERROR;
|
int retval = SQLITE_ERROR;
|
||||||
|
|
||||||
if (argc != 1 &&
|
if (argc != 1
|
||||||
(argc < 3 ||
|
&& (argc < 3 || sqlite3_value_type(argv[2]) == SQLITE_NULL
|
||||||
sqlite3_value_type(argv[2]) == SQLITE_NULL ||
|
|| sqlite3_value_type(argv[3]) == SQLITE_NULL
|
||||||
sqlite3_value_type(argv[3]) == SQLITE_NULL ||
|
|| sqlite3_value_text(argv[2])[0] == '\0'))
|
||||||
sqlite3_value_text(argv[2])[0] == '\0')) {
|
{
|
||||||
tab->zErrMsg = sqlite3_mprintf(
|
tab->zErrMsg = sqlite3_mprintf(
|
||||||
"A non-empty name and value must be provided when inserting an "
|
"A non-empty name and value must be provided when inserting an "
|
||||||
"environment variable");
|
"environment variable");
|
||||||
@ -233,8 +253,8 @@ static int vt_update(sqlite3_vtab *tab,
|
|||||||
|
|
||||||
if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
|
if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
|
||||||
int64_t index = sqlite3_value_int64(argv[0]);
|
int64_t index = sqlite3_value_int64(argv[0]);
|
||||||
const char *var = (const char *)index;
|
const char* var = (const char*) index;
|
||||||
const char *eq = strchr(var, '=');
|
const char* eq = strchr(var, '=');
|
||||||
size_t namelen = eq - var;
|
size_t namelen = eq - var;
|
||||||
char name[namelen + 1];
|
char name[namelen + 1];
|
||||||
|
|
||||||
@ -249,26 +269,26 @@ static int vt_update(sqlite3_vtab *tab,
|
|||||||
|
|
||||||
rc = sqlite3_vtab_on_conflict(p_vt->db);
|
rc = sqlite3_vtab_on_conflict(p_vt->db);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case SQLITE_FAIL:
|
case SQLITE_FAIL:
|
||||||
case SQLITE_ABORT:
|
case SQLITE_ABORT:
|
||||||
tab->zErrMsg = sqlite3_mprintf(
|
tab->zErrMsg = sqlite3_mprintf(
|
||||||
"An environment variable with the name '%s' already exists",
|
"An environment variable with the name '%s' already exists",
|
||||||
name);
|
name);
|
||||||
return rc;
|
return rc;
|
||||||
case SQLITE_IGNORE:
|
case SQLITE_IGNORE:
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
case SQLITE_REPLACE:
|
case SQLITE_REPLACE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != nullptr && argc == 4) {
|
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;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@ -277,37 +297,43 @@ static int vt_update(sqlite3_vtab *tab,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static sqlite3_module vtab_module = {
|
static sqlite3_module vtab_module = {
|
||||||
0, /* iVersion */
|
0, /* iVersion */
|
||||||
vt_create, /* xCreate - create a vtable */
|
vt_create, /* xCreate - create a vtable */
|
||||||
vt_connect, /* xConnect - associate a vtable with a connection */
|
vt_connect, /* xConnect - associate a vtable with a connection */
|
||||||
vt_best_index, /* xBestIndex - best index */
|
vt_best_index, /* xBestIndex - best index */
|
||||||
vt_disconnect, /* xDisconnect - disassociate a vtable with a connection */
|
vt_disconnect, /* xDisconnect - disassociate a vtable with a connection */
|
||||||
vt_destroy, /* xDestroy - destroy a vtable */
|
vt_destroy, /* xDestroy - destroy a vtable */
|
||||||
vt_open, /* xOpen - open a cursor */
|
vt_open, /* xOpen - open a cursor */
|
||||||
vt_close, /* xClose - close a cursor */
|
vt_close, /* xClose - close a cursor */
|
||||||
vt_filter, /* xFilter - configure scan constraints */
|
vt_filter, /* xFilter - configure scan constraints */
|
||||||
vt_next, /* xNext - advance a cursor */
|
vt_next, /* xNext - advance a cursor */
|
||||||
vt_eof, /* xEof - inidicate end of result set*/
|
vt_eof, /* xEof - inidicate end of result set*/
|
||||||
vt_column, /* xColumn - read data */
|
vt_column, /* xColumn - read data */
|
||||||
vt_rowid, /* xRowid - read data */
|
vt_rowid, /* xRowid - read data */
|
||||||
vt_update, /* xUpdate - write data */
|
vt_update, /* xUpdate - write data */
|
||||||
NULL, /* xBegin - begin transaction */
|
NULL, /* xBegin - begin transaction */
|
||||||
NULL, /* xSync - sync transaction */
|
NULL, /* xSync - sync transaction */
|
||||||
NULL, /* xCommit - commit transaction */
|
NULL, /* xCommit - commit transaction */
|
||||||
NULL, /* xRollback - rollback transaction */
|
NULL, /* xRollback - rollback transaction */
|
||||||
NULL, /* xFindFunction - function overloading */
|
NULL, /* xFindFunction - function overloading */
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_environ_vtab(sqlite3 *db)
|
int
|
||||||
|
register_environ_vtab(sqlite3* db)
|
||||||
{
|
{
|
||||||
auto_mem<char, sqlite3_free> errmsg;
|
auto_mem<char, sqlite3_free> errmsg;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
|
rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
|
||||||
ensure(rc == SQLITE_OK);
|
ensure(rc == SQLITE_OK);
|
||||||
if ((rc = sqlite3_exec(db,
|
if ((rc = sqlite3_exec(
|
||||||
|
db,
|
||||||
"CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
|
"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());
|
fprintf(stderr, "unable to create environ table %s\n", errmsg.in());
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
#include <sqlite3.h>
|
#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
|
#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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "base/humanize.time.hh"
|
|
||||||
#include "lnav_util.hh"
|
|
||||||
#include "ansi_scrubber.hh"
|
|
||||||
#include "vtab_module.hh"
|
|
||||||
#include "relative_time.hh"
|
|
||||||
#include "field_overlay_source.hh"
|
#include "field_overlay_source.hh"
|
||||||
#include "readline_highlighters.hh"
|
|
||||||
#include "vtab_module_json.hh"
|
#include "ansi_scrubber.hh"
|
||||||
|
#include "base/humanize.time.hh"
|
||||||
|
#include "config.h"
|
||||||
|
#include "lnav_util.hh"
|
||||||
#include "log_format_ext.hh"
|
#include "log_format_ext.hh"
|
||||||
#include "log_vtab_impl.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;
|
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);
|
auto& tc = dynamic_cast<const textview_curses&>(lv);
|
||||||
textfile_sub_source &tss = this->fos_tss;
|
textfile_sub_source& tss = this->fos_tss;
|
||||||
logfile_sub_source &lss = this->fos_lss;
|
logfile_sub_source& lss = this->fos_lss;
|
||||||
|
|
||||||
this->fos_summary_lines.clear();
|
this->fos_summary_lines.clear();
|
||||||
|
|
||||||
{
|
{
|
||||||
vis_line_t filled_rows = lv.rows_available(
|
vis_line_t filled_rows
|
||||||
lv.get_top(), listview_curses::RD_DOWN);
|
= lv.rows_available(lv.get_top(), listview_curses::RD_DOWN);
|
||||||
vis_line_t height, free_rows;
|
vis_line_t height, free_rows;
|
||||||
unsigned long width;
|
unsigned long width;
|
||||||
long rate_len = 0;
|
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());
|
free_rows = height - filled_rows - vis_line_t(this->fos_lines.size());
|
||||||
if (free_rows < 2 || !this->fos_show_status) {
|
if (free_rows < 2 || !this->fos_show_status) {
|
||||||
this->fos_summary_lines.clear();
|
this->fos_summary_lines.clear();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
string time_span;
|
string time_span;
|
||||||
double error_rate = 0.0;
|
double error_rate = 0.0;
|
||||||
|
|
||||||
if (lv.get_inner_height() == 0) {
|
if (lv.get_inner_height() == 0) {
|
||||||
time_span = "None";
|
time_span = "None";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
logline *first_line, *last_line;
|
logline *first_line, *last_line;
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
|
|
||||||
first_line = lss.find_line(lss.at(vis_line_t(0)));
|
first_line = lss.find_line(lss.at(vis_line_t(0)));
|
||||||
last_line = lss.find_line(lss.at(lv.get_bottom()));
|
last_line = lss.find_line(lss.at(lv.get_bottom()));
|
||||||
time_span = humanize::time::duration::from_tv(
|
time_span
|
||||||
last_line->get_timeval() - first_line->get_timeval())
|
= humanize::time::duration::from_tv(
|
||||||
.to_string();
|
last_line->get_timeval() - first_line->get_timeval())
|
||||||
|
.to_string();
|
||||||
|
|
||||||
time_t local_now = convert_log_time_to_local(now);
|
time_t local_now = convert_log_time_to_local(now);
|
||||||
time_t five_minutes_ago = local_now - (5 * 60 * 60);
|
time_t five_minutes_ago = local_now - (5 * 60 * 60);
|
||||||
time_t ten_secs_ago = local_now - 10;
|
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 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);
|
auto error_bm_iter = bm.find(&logfile_sub_source::BM_ERRORS);
|
||||||
|
|
||||||
if (now > last_line->get_time() && from_five_min_ago_opt &&
|
if (now > last_line->get_time() && from_five_min_ago_opt
|
||||||
error_bm_iter != bm.end()) {
|
&& error_bm_iter != bm.end())
|
||||||
|
{
|
||||||
auto& error_bookmarks = error_bm_iter->second;
|
auto& error_bookmarks = error_bm_iter->second;
|
||||||
auto five_min_lower =
|
auto five_min_lower
|
||||||
lower_bound(error_bookmarks.begin(),
|
= lower_bound(error_bookmarks.begin(),
|
||||||
error_bookmarks.end(),
|
error_bookmarks.end(),
|
||||||
from_five_min_ago_opt.value());
|
from_five_min_ago_opt.value());
|
||||||
if (five_min_lower != error_bookmarks.end()) {
|
if (five_min_lower != error_bookmarks.end()) {
|
||||||
double error_count = distance(
|
double error_count
|
||||||
five_min_lower, error_bookmarks.end());
|
= distance(five_min_lower, error_bookmarks.end());
|
||||||
double time_diff = 5.0;
|
double time_diff = 5.0;
|
||||||
|
|
||||||
if (first_line->get_time() > five_minutes_ago) {
|
if (first_line->get_time() > five_minutes_ago) {
|
||||||
time_diff = (double) (local_now - first_line->get_time()) /
|
time_diff
|
||||||
60.0;
|
= (double) (local_now - first_line->get_time())
|
||||||
|
/ 60.0;
|
||||||
}
|
}
|
||||||
error_rate = error_count / time_diff;
|
error_rate = error_count / time_diff;
|
||||||
|
|
||||||
if (from_ten_secs_ago_opt) {
|
if (from_ten_secs_ago_opt) {
|
||||||
auto ten_sec_lower =
|
auto ten_sec_lower
|
||||||
lower_bound(error_bookmarks.begin(),
|
= lower_bound(error_bookmarks.begin(),
|
||||||
error_bookmarks.end(),
|
error_bookmarks.end(),
|
||||||
from_ten_secs_ago_opt.value());
|
from_ten_secs_ago_opt.value());
|
||||||
if (ten_sec_lower != error_bookmarks.end()) {
|
if (ten_sec_lower != error_bookmarks.end()) {
|
||||||
double recent_error_count = distance(
|
double recent_error_count = distance(
|
||||||
ten_sec_lower, error_bookmarks.end());
|
ten_sec_lower, error_bookmarks.end());
|
||||||
double recent_error_rate =
|
double recent_error_rate
|
||||||
recent_error_count / 10.0;
|
= recent_error_count / 10.0;
|
||||||
double long_error_rate =
|
double long_error_rate
|
||||||
error_count / (time_diff * 60.0 / 10.0);
|
= error_count / (time_diff * 60.0 / 10.0);
|
||||||
|
|
||||||
if (long_error_rate == 0.0) {
|
if (long_error_rate == 0.0) {
|
||||||
long_error_rate = 1.0;
|
long_error_rate = 1.0;
|
||||||
}
|
}
|
||||||
long computed_rate_len = lrint(ceil(
|
long computed_rate_len
|
||||||
(recent_error_rate * 40.0) / long_error_rate));
|
= lrint(ceil((recent_error_rate * 40.0)
|
||||||
|
/ long_error_rate));
|
||||||
rate_len = min(10L, computed_rate_len);
|
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();
|
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()) {
|
if (tss.empty()) {
|
||||||
sum_line.with_ansi_string(
|
sum_line.with_ansi_string(
|
||||||
" "
|
" "
|
||||||
@ -160,44 +164,35 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
|||||||
error_rate,
|
error_rate,
|
||||||
time_span.c_str());
|
time_span.c_str());
|
||||||
}
|
}
|
||||||
string &sum_msg = sum_line.get_string();
|
string& sum_msg = sum_line.get_string();
|
||||||
sum_line.with_attr(string_attr(
|
sum_line
|
||||||
|
.with_attr(string_attr(
|
||||||
line_range(sum_msg.find("Error rate"),
|
line_range(sum_msg.find("Error rate"),
|
||||||
sum_msg.find("Error rate") + rate_len),
|
sum_msg.find("Error rate") + rate_len),
|
||||||
&view_curses::VC_STYLE,
|
&view_curses::VC_STYLE,
|
||||||
A_REVERSE
|
A_REVERSE))
|
||||||
))
|
|
||||||
.with_attr(string_attr(
|
.with_attr(string_attr(
|
||||||
line_range(1, 2),
|
line_range(1, 2), &view_curses::VC_GRAPHIC, ACS_ULCORNER))
|
||||||
&view_curses::VC_GRAPHIC,
|
|
||||||
ACS_ULCORNER
|
|
||||||
))
|
|
||||||
.with_attr(string_attr(
|
.with_attr(string_attr(
|
||||||
line_range(2, 6),
|
line_range(2, 6), &view_curses::VC_GRAPHIC, ACS_HLINE))
|
||||||
&view_curses::VC_GRAPHIC,
|
|
||||||
ACS_HLINE
|
|
||||||
))
|
|
||||||
.with_attr(string_attr(
|
.with_attr(string_attr(
|
||||||
line_range(sum_msg.length() + 1,
|
line_range(sum_msg.length() + 1, sum_msg.length() + 5),
|
||||||
sum_msg.length() + 5),
|
|
||||||
&view_curses::VC_GRAPHIC,
|
&view_curses::VC_GRAPHIC,
|
||||||
ACS_HLINE
|
ACS_HLINE))
|
||||||
))
|
|
||||||
.with_attr(string_attr(
|
.with_attr(string_attr(
|
||||||
line_range(sum_msg.length() + 5,
|
line_range(sum_msg.length() + 5, sum_msg.length() + 6),
|
||||||
sum_msg.length() + 6),
|
|
||||||
&view_curses::VC_GRAPHIC,
|
&view_curses::VC_GRAPHIC,
|
||||||
ACS_URCORNER
|
ACS_URCORNER))
|
||||||
))
|
|
||||||
.right_justify(width - 2);
|
.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;
|
logfile_sub_source& lss = this->fos_lss;
|
||||||
view_colors &vc = view_colors::singleton();
|
view_colors& vc = view_colors::singleton();
|
||||||
|
|
||||||
this->fos_lines.clear();
|
this->fos_lines.clear();
|
||||||
|
|
||||||
@ -213,8 +208,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
|||||||
auto format = file->get_format();
|
auto format = file->get_format();
|
||||||
bool display = false;
|
bool display = false;
|
||||||
|
|
||||||
if (ll->is_time_skewed() ||
|
if (ll->is_time_skewed()
|
||||||
ll->get_msg_level() == log_level_t::LEVEL_INVALID) {
|
|| ll->get_msg_level() == log_level_t::LEVEL_INVALID) {
|
||||||
display = true;
|
display = true;
|
||||||
}
|
}
|
||||||
if (!this->fos_contexts.empty()) {
|
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: {}",
|
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)
|
auto al = attr_line_t(emsg)
|
||||||
.with_attr(string_attr(line_range{1, 2},
|
.with_attr(string_attr(line_range{1, 2},
|
||||||
&view_curses::VC_GRAPHIC,
|
&view_curses::VC_GRAPHIC,
|
||||||
ACS_LLCORNER))
|
ACS_LLCORNER))
|
||||||
.with_attr(string_attr(line_range{0, 22},
|
.with_attr(string_attr(line_range{0, 22},
|
||||||
&view_curses::VC_ROLE,
|
&view_curses::VC_ROLE,
|
||||||
view_colors::VCR_INVALID_MSG));
|
view_colors::VCR_INVALID_MSG));
|
||||||
this->fos_lines.emplace_back(al);
|
this->fos_lines.emplace_back(al);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char old_timestamp[64], curr_timestamp[64], orig_timestamp[64];
|
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;
|
attr_line_t time_line;
|
||||||
string &time_str = time_line.get_string();
|
string& time_str = time_line.get_string();
|
||||||
struct line_range time_lr;
|
struct line_range time_lr;
|
||||||
|
|
||||||
sql_strftime(curr_timestamp, sizeof(curr_timestamp),
|
sql_strftime(curr_timestamp,
|
||||||
|
sizeof(curr_timestamp),
|
||||||
ll->get_time(),
|
ll->get_time(),
|
||||||
ll->get_millis(),
|
ll->get_millis(),
|
||||||
'T');
|
'T');
|
||||||
@ -264,13 +260,13 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
|||||||
if (ll->is_time_skewed()) {
|
if (ll->is_time_skewed()) {
|
||||||
time_lr.lr_start = 1;
|
time_lr.lr_start = 1;
|
||||||
time_lr.lr_end = 2;
|
time_lr.lr_end = 2;
|
||||||
time_line.with_attr(string_attr(time_lr, &view_curses::VC_GRAPHIC,
|
time_line.with_attr(
|
||||||
ACS_LLCORNER));
|
string_attr(time_lr, &view_curses::VC_GRAPHIC, ACS_LLCORNER));
|
||||||
time_str.append(" Out-Of-Time-Order Message");
|
time_str.append(" Out-Of-Time-Order Message");
|
||||||
time_lr.lr_start = 3;
|
time_lr.lr_start = 3;
|
||||||
time_lr.lr_end = time_str.length();
|
time_lr.lr_end = time_str.length();
|
||||||
time_line.with_attr(string_attr(time_lr, &view_curses::VC_ROLE,
|
time_line.with_attr(string_attr(
|
||||||
view_colors::VCR_SKEWED_TIME));
|
time_lr, &view_curses::VC_ROLE, view_colors::VCR_SKEWED_TIME));
|
||||||
time_str.append(" --");
|
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();
|
curr_tv = this->fos_log_helper.ldh_line->get_timeval();
|
||||||
if (ll->is_time_skewed() && time_range.lr_end != -1) {
|
if (ll->is_time_skewed() && time_range.lr_end != -1) {
|
||||||
const char *time_src = this->fos_log_helper.ldh_msg.get_data() +
|
const char* time_src
|
||||||
time_range.lr_start;
|
= this->fos_log_helper.ldh_msg.get_data() + time_range.lr_start;
|
||||||
struct timeval actual_tv;
|
struct timeval actual_tv;
|
||||||
date_time_scanner dts;
|
date_time_scanner dts;
|
||||||
struct exttm tm;
|
struct exttm tm;
|
||||||
|
|
||||||
dts.set_base_time(format->lf_date_time.dts_base_time);
|
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(),
|
format->get_timestamp_formats(),
|
||||||
&tm, actual_tv,
|
&tm,
|
||||||
false) ||
|
actual_tv,
|
||||||
dts.scan(time_src, time_range.length(),
|
false)
|
||||||
nullptr,
|
|| dts.scan(
|
||||||
&tm, actual_tv,
|
time_src, time_range.length(), nullptr, &tm, actual_tv, false))
|
||||||
false)) {
|
{
|
||||||
sql_strftime(orig_timestamp, sizeof(orig_timestamp), actual_tv, 'T');
|
sql_strftime(
|
||||||
|
orig_timestamp, sizeof(orig_timestamp), actual_tv, 'T');
|
||||||
time_str.append("; Actual Time: ");
|
time_str.append("; Actual Time: ");
|
||||||
time_lr.lr_start = time_str.length();
|
time_lr.lr_start = time_str.length();
|
||||||
time_str.append(orig_timestamp);
|
time_str.append(orig_timestamp);
|
||||||
time_lr.lr_end = time_str.length();
|
time_lr.lr_end = time_str.length();
|
||||||
time_line.with_attr(string_attr(
|
time_line.with_attr(string_attr(
|
||||||
time_lr,
|
time_lr, &view_curses::VC_ROLE, view_colors::VCR_SKEWED_TIME));
|
||||||
&view_curses::VC_ROLE,
|
|
||||||
view_colors::VCR_SKEWED_TIME));
|
|
||||||
|
|
||||||
timersub(&curr_tv, &actual_tv, &diff_tv);
|
timersub(&curr_tv, &actual_tv, &diff_tv);
|
||||||
time_str.append("; Diff: ");
|
time_str.append("; Diff: ");
|
||||||
time_lr.lr_start = time_str.length();
|
time_lr.lr_start = time_str.length();
|
||||||
time_str.append(humanize::time::duration::from_tv(diff_tv)
|
time_str.append(
|
||||||
.to_string());
|
humanize::time::duration::from_tv(diff_tv).to_string());
|
||||||
time_lr.lr_end = time_str.length();
|
time_lr.lr_end = time_str.length();
|
||||||
time_line.with_attr(string_attr(
|
time_line.with_attr(
|
||||||
time_lr,
|
string_attr(time_lr, &view_curses::VC_STYLE, A_BOLD));
|
||||||
&view_curses::VC_STYLE,
|
|
||||||
A_BOLD));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
|
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
|
||||||
timersub(&curr_tv, &offset_tv, &orig_tv);
|
timersub(&curr_tv, &offset_tv, &orig_tv);
|
||||||
sql_strftime(old_timestamp, sizeof(old_timestamp),
|
sql_strftime(old_timestamp,
|
||||||
orig_tv.tv_sec, orig_tv.tv_usec / 1000,
|
sizeof(old_timestamp),
|
||||||
|
orig_tv.tv_sec,
|
||||||
|
orig_tv.tv_usec / 1000,
|
||||||
'T');
|
'T');
|
||||||
if (offset_tv.tv_sec || offset_tv.tv_usec) {
|
if (offset_tv.tv_sec || offset_tv.tv_usec) {
|
||||||
char offset_str[32];
|
char offset_str[32];
|
||||||
|
|
||||||
time_str.append(" Pre-adjust Time: ");
|
time_str.append(" Pre-adjust Time: ");
|
||||||
time_str.append(old_timestamp);
|
time_str.append(old_timestamp);
|
||||||
snprintf(offset_str, sizeof(offset_str),
|
snprintf(offset_str,
|
||||||
|
sizeof(offset_str),
|
||||||
" Offset: %+d.%03d",
|
" 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);
|
time_str.append(offset_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!this->fos_contexts.empty() && this->fos_contexts.top().c_show) ||
|
if ((!this->fos_contexts.empty() && this->fos_contexts.top().c_show)
|
||||||
diff_tv.tv_sec > 0) {
|
|| diff_tv.tv_sec > 0)
|
||||||
|
{
|
||||||
this->fos_lines.emplace_back(time_line);
|
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_known_key_size = LOG_BODY.length();
|
||||||
this->fos_unknown_key_size = 0;
|
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;
|
auto& meta = ldh_line_value.lv_meta;
|
||||||
int this_key_size = meta.lvm_name.size();
|
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();
|
for (auto iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
||||||
iter != this->fos_log_helper.ldh_parser->dp_pairs.end();
|
iter != this->fos_log_helper.ldh_parser->dp_pairs.end();
|
||||||
++iter) {
|
++iter)
|
||||||
std::string colname = this->fos_log_helper.ldh_parser->get_element_string(
|
{
|
||||||
|
std::string colname
|
||||||
|
= this->fos_log_helper.ldh_parser->get_element_string(
|
||||||
iter->e_sub_elements->front());
|
iter->e_sub_elements->front());
|
||||||
|
|
||||||
colname = this->fos_log_helper.ldh_namer->add_column(colname);
|
colname = this->fos_log_helper.ldh_namer->add_column(colname);
|
||||||
this->fos_unknown_key_size = max(
|
this->fos_unknown_key_size
|
||||||
this->fos_unknown_key_size, (int)colname.length());
|
= max(this->fos_unknown_key_size, (int) colname.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lf = this->fos_log_helper.ldh_file->get_format();
|
auto lf = this->fos_log_helper.ldh_file->get_format();
|
||||||
if (!lf->get_pattern_regex(cl).empty()) {
|
if (!lf->get_pattern_regex(cl).empty()) {
|
||||||
attr_line_t pattern_al;
|
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) + " = ";
|
pattern_str = " Pattern: " + lf->get_pattern_name(cl) + " = ";
|
||||||
int skip = pattern_str.length();
|
int skip = pattern_str.length();
|
||||||
pattern_str += lf->get_pattern_regex(cl);
|
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);
|
this->fos_lines.emplace_back(pattern_al);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this->fos_log_helper.ldh_line_values.empty()) {
|
if (this->fos_log_helper.ldh_line_values.empty()) {
|
||||||
this->fos_lines.emplace_back(" No known message fields");
|
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) {
|
if (!lv.lv_meta.lvm_format) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto curr_format = lv.lv_meta.lvm_format.value();
|
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();
|
string format_name = curr_format->get_name().to_string();
|
||||||
attr_line_t al;
|
attr_line_t al;
|
||||||
string str, value_str = lv.to_string();
|
string str, value_str = lv.to_string();
|
||||||
|
|
||||||
if (curr_format != last_format) {
|
if (curr_format != last_format) {
|
||||||
this->fos_lines.emplace_back(" Known message fields for table " +
|
this->fos_lines.emplace_back(" Known message fields for table "
|
||||||
format_name +
|
+ format_name + ":");
|
||||||
":");
|
this->fos_lines.back().with_attr(
|
||||||
this->fos_lines.back().with_attr(string_attr(
|
string_attr(line_range(32, 32 + format_name.length()),
|
||||||
line_range(32, 32 + format_name.length()),
|
&view_curses::VC_STYLE,
|
||||||
&view_curses::VC_STYLE,
|
vc.attrs_for_ident(format_name) | A_BOLD));
|
||||||
vc.attrs_for_ident(format_name) | A_BOLD));
|
|
||||||
last_format = curr_format;
|
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 (lv.lv_meta.lvm_struct_name.empty()) {
|
||||||
if (curr_elf && curr_elf->elf_body_field == lv.lv_meta.lvm_name) {
|
if (curr_elf && curr_elf->elf_body_field == lv.lv_meta.lvm_name) {
|
||||||
field_name = LOG_BODY;
|
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;
|
field_name = LOG_TIME;
|
||||||
} else {
|
} else {
|
||||||
field_name = lv.lv_meta.lvm_name.to_string();
|
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());
|
json_string js = extract(value_str.c_str());
|
||||||
|
|
||||||
al.clear()
|
al.clear()
|
||||||
.append(" extract(")
|
.append(" extract(")
|
||||||
.append(lv.lv_meta.lvm_name.get(),
|
.append(lv.lv_meta.lvm_name.get(),
|
||||||
&view_curses::VC_STYLE,
|
&view_curses::VC_STYLE,
|
||||||
vc.attrs_for_ident(lv.lv_meta.lvm_name))
|
vc.attrs_for_ident(lv.lv_meta.lvm_name))
|
||||||
.append(")")
|
.append(")")
|
||||||
.append(this->fos_known_key_size - lv.lv_meta.lvm_name.size() - 9 + 3, ' ')
|
.append(this->fos_known_key_size - lv.lv_meta.lvm_name.size()
|
||||||
.append(" = ")
|
- 9 + 3,
|
||||||
.append((const char *) js.js_content.in(), js.js_len);
|
' ')
|
||||||
|
.append(" = ")
|
||||||
|
.append((const char*) js.js_content.in(), js.js_len);
|
||||||
this->fos_lines.emplace_back(al);
|
this->fos_lines.emplace_back(al);
|
||||||
this->add_key_line_attrs(this->fos_known_key_size);
|
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()) {
|
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
|
||||||
this->fos_lines.emplace_back(" JSON fields:");
|
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();
|
for (json_iter = this->fos_log_helper.ldh_json_pairs.begin();
|
||||||
json_iter != this->fos_log_helper.ldh_json_pairs.end();
|
json_iter != this->fos_log_helper.ldh_json_pairs.end();
|
||||||
++json_iter) {
|
++json_iter)
|
||||||
json_ptr_walk::walk_list_t &jpairs = json_iter->second;
|
{
|
||||||
|
json_ptr_walk::walk_list_t& jpairs = json_iter->second;
|
||||||
|
|
||||||
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
|
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
|
||||||
this->fos_lines.emplace_back(
|
this->fos_lines.emplace_back(
|
||||||
" " +
|
" "
|
||||||
this->fos_log_helper.format_json_getter(json_iter->first, lpc) + " = " +
|
+ this->fos_log_helper.format_json_getter(json_iter->first, lpc)
|
||||||
jpairs[lpc].wt_value);
|
+ " = " + jpairs[lpc].wt_value);
|
||||||
this->add_key_line_attrs(0);
|
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;
|
auto_mem<char, sqlite3_free> xp_call;
|
||||||
|
|
||||||
qname = sql_quote_ident(xml_pair.first.first.get());
|
qname = sql_quote_ident(xml_pair.first.first.get());
|
||||||
xp_call = sqlite3_mprintf("xpath(%Q, %s)",
|
xp_call = sqlite3_mprintf(
|
||||||
xml_pair.first.second.c_str(),
|
"xpath(%Q, %s)", xml_pair.first.second.c_str(), qname.in());
|
||||||
qname.in());
|
this->fos_lines.emplace_back(
|
||||||
this->fos_lines.emplace_back(fmt::format(
|
fmt::format(" {} = {}", xp_call, xml_pair.second));
|
||||||
" {} = {}", xp_call, xml_pair.second));
|
|
||||||
this->add_key_line_attrs(0);
|
this->add_key_line_attrs(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->fos_contexts.empty() &&
|
if (!this->fos_contexts.empty()
|
||||||
!this->fos_contexts.top().c_show_discovered) {
|
&& !this->fos_contexts.top().c_show_discovered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
||||||
this->fos_lines.emplace_back(" No discovered message fields");
|
this->fos_lines.emplace_back(" No discovered message fields");
|
||||||
}
|
} else {
|
||||||
else {
|
this->fos_lines.emplace_back(
|
||||||
this->fos_lines.emplace_back(" Discovered fields for logline table from message format: ");
|
" Discovered fields for logline table from message format: ");
|
||||||
this->fos_lines.back().with_attr(string_attr(
|
this->fos_lines.back().with_attr(
|
||||||
line_range(23, 23 + 7),
|
string_attr(line_range(23, 23 + 7),
|
||||||
&view_curses::VC_STYLE,
|
&view_curses::VC_STYLE,
|
||||||
vc.attrs_for_ident("logline")
|
vc.attrs_for_ident("logline")));
|
||||||
));
|
auto& al = this->fos_lines.back();
|
||||||
auto &al = this->fos_lines.back();
|
auto& disc_str = al.get_string();
|
||||||
auto &disc_str = al.get_string();
|
|
||||||
|
|
||||||
al.with_attr(string_attr(
|
al.with_attr(string_attr(
|
||||||
line_range(disc_str.length(), -1),
|
line_range(disc_str.length(), -1), &view_curses::VC_STYLE, A_BOLD));
|
||||||
&view_curses::VC_STYLE,
|
|
||||||
A_BOLD));
|
|
||||||
disc_str.append(this->fos_log_helper.ldh_msg_format);
|
disc_str.append(this->fos_log_helper.ldh_msg_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
auto iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
||||||
for (size_t lpc = 0;
|
for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_parser->dp_pairs.size();
|
||||||
lpc < this->fos_log_helper.ldh_parser->dp_pairs.size(); lpc++, ++iter) {
|
lpc++, ++iter)
|
||||||
auto &name = this->fos_log_helper.ldh_namer->cn_names[lpc];
|
{
|
||||||
|
auto& name = this->fos_log_helper.ldh_namer->cn_names[lpc];
|
||||||
auto val = this->fos_log_helper.ldh_parser->get_element_string(
|
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));
|
attr_line_t al(fmt::format(" {} = {}", name, val));
|
||||||
|
|
||||||
al.with_attr(string_attr(
|
al.with_attr(string_attr(line_range(3, 3 + name.length()),
|
||||||
line_range(3, 3 + name.length()),
|
&view_curses::VC_STYLE,
|
||||||
&view_curses::VC_STYLE,
|
vc.attrs_for_ident(name)));
|
||||||
vc.attrs_for_ident(name)));
|
|
||||||
|
|
||||||
this->fos_lines.emplace_back(al);
|
this->fos_lines.emplace_back(al);
|
||||||
this->add_key_line_attrs(this->fos_unknown_key_size,
|
this->add_key_line_attrs(
|
||||||
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
|
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,
|
void
|
||||||
std::vector<attr_line_t> &dst,
|
field_overlay_source::build_meta_line(const listview_curses& lv,
|
||||||
vis_line_t row)
|
std::vector<attr_line_t>& dst,
|
||||||
|
vis_line_t row)
|
||||||
{
|
{
|
||||||
content_line_t cl = this->fos_lss.at(row);
|
content_line_t cl = this->fos_lss.at(row);
|
||||||
auto const &bm = this->fos_lss.get_user_bookmark_metadata();
|
auto const& bm = this->fos_lss.get_user_bookmark_metadata();
|
||||||
view_colors &vc = view_colors::singleton();
|
view_colors& vc = view_colors::singleton();
|
||||||
auto iter = bm.find(cl);
|
auto iter = bm.find(cl);
|
||||||
|
|
||||||
if (iter != bm.end()) {
|
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();
|
size_t filename_width = this->fos_lss.get_filename_offset();
|
||||||
|
|
||||||
if (!line_meta.bm_comment.empty()) {
|
if (!line_meta.bm_comment.empty()) {
|
||||||
attr_line_t al;
|
attr_line_t al;
|
||||||
|
|
||||||
al.with_string(" + ")
|
al.with_string(" + ")
|
||||||
.with_attr(string_attr(
|
.with_attr(string_attr(
|
||||||
line_range(1, 2),
|
line_range(1, 2),
|
||||||
&view_curses::VC_GRAPHIC,
|
&view_curses::VC_GRAPHIC,
|
||||||
line_meta.bm_tags.empty() ? ACS_LLCORNER : ACS_LTEE
|
line_meta.bm_tags.empty() ? ACS_LLCORNER : ACS_LTEE))
|
||||||
))
|
.append(line_meta.bm_comment);
|
||||||
.append(line_meta.bm_comment);
|
|
||||||
al.insert(0, filename_width, ' ');
|
al.insert(0, filename_width, ' ');
|
||||||
dst.emplace_back(al);
|
dst.emplace_back(al);
|
||||||
}
|
}
|
||||||
if (!line_meta.bm_tags.empty()) {
|
if (!line_meta.bm_tags.empty()) {
|
||||||
attr_line_t al;
|
attr_line_t al;
|
||||||
|
|
||||||
al.with_string(" +")
|
al.with_string(" +").with_attr(string_attr(
|
||||||
.with_attr(string_attr(
|
line_range(1, 2), &view_curses::VC_GRAPHIC, ACS_LLCORNER));
|
||||||
line_range(1, 2),
|
for (const auto& str : line_meta.bm_tags) {
|
||||||
&view_curses::VC_GRAPHIC,
|
al.append(1, ' ').append(
|
||||||
ACS_LLCORNER
|
str, &view_curses::VC_STYLE, vc.attrs_for_ident(str));
|
||||||
));
|
|
||||||
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) {
|
if (tc) {
|
||||||
const auto &hm = tc->get_highlights();
|
const auto& hm = tc->get_highlights();
|
||||||
auto hl_iter = hm.find({highlight_source_t::PREVIEW, "search"});
|
auto hl_iter = hm.find({highlight_source_t::PREVIEW, "search"});
|
||||||
|
|
||||||
if (hl_iter != hm.end()) {
|
if (hl_iter != hm.end()) {
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -40,32 +40,37 @@
|
|||||||
|
|
||||||
class field_overlay_source : public list_overlay_source {
|
class field_overlay_source : public list_overlay_source {
|
||||||
public:
|
public:
|
||||||
explicit field_overlay_source(logfile_sub_source &lss, textfile_sub_source &tss)
|
explicit field_overlay_source(logfile_sub_source& lss,
|
||||||
: fos_lss(lss), fos_tss(tss), fos_log_helper(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) {
|
void add_key_line_attrs(int key_size, bool last_line = false)
|
||||||
string_attrs_t &sa = this->fos_lines.back().get_attrs();
|
{
|
||||||
|
string_attrs_t& sa = this->fos_lines.back().get_attrs();
|
||||||
struct line_range lr(1, 2);
|
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_start = 3 + key_size + 3;
|
||||||
lr.lr_end = -1;
|
lr.lr_end = -1;
|
||||||
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
|
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool list_value_for_overlay(const listview_curses &lv,
|
bool list_value_for_overlay(const listview_curses& lv,
|
||||||
int y, int bottom,
|
int y,
|
||||||
|
int bottom,
|
||||||
vis_line_t row,
|
vis_line_t row,
|
||||||
attr_line_t &value_out) override {
|
attr_line_t& value_out) override
|
||||||
|
{
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
this->build_field_lines(lv);
|
this->build_field_lines(lv);
|
||||||
this->build_summary_lines(lv);
|
this->build_summary_lines(lv);
|
||||||
return false;
|
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];
|
value_out = this->fos_lines[y - 1];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -89,17 +94,18 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void build_field_lines(const listview_curses &lv);
|
void build_field_lines(const listview_curses& lv);
|
||||||
void build_summary_lines(const listview_curses &lv);
|
void build_summary_lines(const listview_curses& lv);
|
||||||
void build_meta_line(const listview_curses &lv,
|
void build_meta_line(const listview_curses& lv,
|
||||||
std::vector<attr_line_t> &dst,
|
std::vector<attr_line_t>& dst,
|
||||||
vis_line_t row);
|
vis_line_t row);
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
context(std::string prefix, bool show, bool show_discovered)
|
context(std::string prefix, bool show, bool show_discovered)
|
||||||
: c_prefix(std::move(prefix)), c_show(show),
|
: c_prefix(std::move(prefix)), c_show(show),
|
||||||
c_show_discovered(show_discovered)
|
c_show_discovered(show_discovered)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string c_prefix;
|
std::string c_prefix;
|
||||||
bool c_show{false};
|
bool c_show{false};
|
||||||
@ -108,8 +114,8 @@ public:
|
|||||||
|
|
||||||
bool fos_show_status{true};
|
bool fos_show_status{true};
|
||||||
std::stack<context> fos_contexts;
|
std::stack<context> fos_contexts;
|
||||||
logfile_sub_source &fos_lss;
|
logfile_sub_source& fos_lss;
|
||||||
textfile_sub_source &fos_tss;
|
textfile_sub_source& fos_tss;
|
||||||
log_data_helper fos_log_helper;
|
log_data_helper fos_log_helper;
|
||||||
int fos_known_key_size{0};
|
int fos_known_key_size{0};
|
||||||
int fos_unknown_key_size{0};
|
int fos_unknown_key_size{0};
|
||||||
@ -118,4 +124,4 @@ public:
|
|||||||
std::vector<attr_line_t> fos_meta_lines;
|
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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file file_collection.cc
|
* @file file_collection.cc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "file_collection.hh"
|
||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "base/opt_util.hh"
|
|
||||||
#include "base/humanize.network.hh"
|
#include "base/humanize.network.hh"
|
||||||
#include "base/isc.hh"
|
#include "base/isc.hh"
|
||||||
#include "logfile.hh"
|
#include "base/opt_util.hh"
|
||||||
#include "file_collection.hh"
|
#include "config.h"
|
||||||
#include "pcrepp/pcrepp.hh"
|
|
||||||
#include "tailer/tailer.looper.hh"
|
|
||||||
#include "service_tags.hh"
|
|
||||||
#include "lnav_util.hh"
|
#include "lnav_util.hh"
|
||||||
|
#include "logfile.hh"
|
||||||
#include "pcap_manager.hh"
|
#include "pcap_manager.hh"
|
||||||
|
#include "pcrepp/pcrepp.hh"
|
||||||
|
#include "service_tags.hh"
|
||||||
|
#include "tailer/tailer.looper.hh"
|
||||||
|
|
||||||
static std::mutex REALPATH_CACHE_MUTEX;
|
static std::mutex REALPATH_CACHE_MUTEX;
|
||||||
static std::unordered_map<std::string, std::string> REALPATH_CACHE;
|
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) {
|
if (!this->cp_child) {
|
||||||
return child_poll_result_t::FINISHED;
|
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();
|
auto poll_res = std::move(this->cp_child.value()).poll();
|
||||||
this->cp_child = nonstd::nullopt;
|
this->cp_child = nonstd::nullopt;
|
||||||
return poll_res.match(
|
return poll_res.match(
|
||||||
[this](auto_pid<process_state::RUNNING>& alive) {
|
[this](auto_pid<process_state::running>& alive) {
|
||||||
this->cp_child = std::move(alive);
|
this->cp_child = std::move(alive);
|
||||||
return child_poll_result_t::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);
|
this->cp_finalizer(fc, finished);
|
||||||
return child_poll_result_t::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) {
|
for (const auto& lf : files) {
|
||||||
auto actual_path_opt = lf->get_actual_path();
|
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 {
|
} else {
|
||||||
this->fc_file_names.erase(lf->get_filename());
|
this->fc_file_names.erase(lf->get_filename());
|
||||||
}
|
}
|
||||||
auto file_iter = find(this->fc_files.begin(),
|
auto file_iter = find(this->fc_files.begin(), this->fc_files.end(), lf);
|
||||||
this->fc_files.end(),
|
|
||||||
lf);
|
|
||||||
if (file_iter != this->fc_files.end()) {
|
if (file_iter != this->fc_files.end()) {
|
||||||
this->fc_files.erase(file_iter);
|
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();
|
this->regenerate_unique_file_names();
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_collection::regenerate_unique_file_names()
|
void
|
||||||
|
file_collection::regenerate_unique_file_names()
|
||||||
{
|
{
|
||||||
unique_path_generator upg;
|
unique_path_generator upg;
|
||||||
|
|
||||||
for (const auto &lf : this->fc_files) {
|
for (const auto& lf : this->fc_files) {
|
||||||
upg.add_source(lf);
|
upg.add_source(lf);
|
||||||
}
|
}
|
||||||
|
|
||||||
upg.generate();
|
upg.generate();
|
||||||
|
|
||||||
this->fc_largest_path_length = 0;
|
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();
|
auto path = ghc::filesystem::path(pair.first).filename().string();
|
||||||
|
|
||||||
if (path.length() > this->fc_largest_path_length) {
|
if (path.length() > this->fc_largest_path_length) {
|
||||||
this->fc_largest_path_length = path.length();
|
this->fc_largest_path_length = path.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &lf : this->fc_files) {
|
for (const auto& lf : this->fc_files) {
|
||||||
const auto &path = lf->get_unique_path();
|
const auto& path = lf->get_unique_path();
|
||||||
|
|
||||||
if (path.length() > this->fc_largest_path_length) {
|
if (path.length() > this->fc_largest_path_length) {
|
||||||
this->fc_largest_path_length = 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) {
|
switch (pair.second.ofd_format) {
|
||||||
case file_format_t::FF_UNKNOWN:
|
case file_format_t::FF_UNKNOWN:
|
||||||
case file_format_t::FF_ARCHIVE:
|
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_recursive = this->fc_recursive || other.fc_recursive;
|
||||||
this->fc_rotated = this->fc_rotated || other.fc_rotated;
|
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) {
|
for (const auto& lf : other.fc_files) {
|
||||||
this->fc_name_to_errors.erase(lf->get_filename());
|
this->fc_name_to_errors.erase(lf->get_filename());
|
||||||
}
|
}
|
||||||
this->fc_files.insert(this->fc_files.end(),
|
this->fc_files.insert(
|
||||||
other.fc_files.begin(),
|
this->fc_files.end(), other.fc_files.begin(), other.fc_files.end());
|
||||||
other.fc_files.end());
|
|
||||||
this->fc_files_generation += 1;
|
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);
|
pair.first->set_filename(pair.second);
|
||||||
}
|
}
|
||||||
this->fc_closed_files.insert(other.fc_closed_files.begin(),
|
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.
|
* Functor used to compare files based on their device and inode number.
|
||||||
*/
|
*/
|
||||||
struct same_file {
|
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.
|
* 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
|
* @return True if the dev/inode values in the stat given in the
|
||||||
* constructor matches the stat in the logfile object.
|
* 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() &&
|
return !lf->is_closed() && this->sf_stat.st_dev == lf->get_stat().st_dev
|
||||||
this->sf_stat.st_dev == lf->get_stat().st_dev &&
|
&& this->sf_stat.st_ino == lf->get_stat().st_ino;
|
||||||
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.
|
* @param required Specifies whether or not the file must exist and be valid.
|
||||||
*/
|
*/
|
||||||
std::future<file_collection>
|
std::future<file_collection>
|
||||||
file_collection::watch_logfile(const std::string &filename,
|
file_collection::watch_logfile(const std::string& filename,
|
||||||
logfile_open_options &loo, bool required)
|
logfile_open_options& loo,
|
||||||
|
bool required)
|
||||||
{
|
{
|
||||||
file_collection retval;
|
file_collection retval;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -237,8 +237,8 @@ file_collection::watch_logfile(const std::string &filename,
|
|||||||
if (S_ISDIR(st.st_mode) && this->fc_recursive) {
|
if (S_ISDIR(st.st_mode) && this->fc_recursive) {
|
||||||
std::string wilddir = filename + "/*";
|
std::string wilddir = filename + "/*";
|
||||||
|
|
||||||
if (this->fc_file_names.find(wilddir) ==
|
if (this->fc_file_names.find(wilddir) == this->fc_file_names.end())
|
||||||
this->fc_file_names.end()) {
|
{
|
||||||
retval.fc_file_names.emplace(wilddir, logfile_open_options());
|
retval.fc_file_names.emplace(wilddir, logfile_open_options());
|
||||||
}
|
}
|
||||||
return lnav::futures::make_ready_future(std::move(retval));
|
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 (rc == -1) {
|
||||||
if (required) {
|
if (required) {
|
||||||
retval.fc_name_to_errors.emplace(filename, file_error_info{
|
retval.fc_name_to_errors.emplace(filename,
|
||||||
time(nullptr),
|
file_error_info{
|
||||||
std::string(strerror(errno)),
|
time(nullptr),
|
||||||
});
|
std::string(strerror(errno)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return lnav::futures::make_ready_future(std::move(retval));
|
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(),
|
auto stat_iter = find_if(this->fc_new_stats.begin(),
|
||||||
this->fc_new_stats.end(),
|
this->fc_new_stats.end(),
|
||||||
[&st](auto& elem) {
|
[&st](auto& elem) {
|
||||||
return st.st_ino == elem.st_ino &&
|
return st.st_ino == elem.st_ino
|
||||||
st.st_dev == elem.st_dev;
|
&& st.st_dev == elem.st_dev;
|
||||||
});
|
});
|
||||||
if (stat_iter != this->fc_new_stats.end()) {
|
if (stat_iter != this->fc_new_stats.end()) {
|
||||||
// this file is probably a link that we have already scanned in this
|
// 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);
|
this->fc_new_stats.emplace_back(st);
|
||||||
auto file_iter = find_if(this->fc_files.begin(),
|
auto file_iter
|
||||||
this->fc_files.end(),
|
= find_if(this->fc_files.begin(), this->fc_files.end(), same_file(st));
|
||||||
same_file(st));
|
|
||||||
|
|
||||||
if (file_iter == this->fc_files.end()) {
|
if (file_iter == this->fc_files.end()) {
|
||||||
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
|
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
|
||||||
return lnav::futures::make_ready_future(std::move(retval));
|
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;
|
file_collection retval;
|
||||||
|
|
||||||
if (errs.find(filename) != errs.end()) {
|
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);
|
loo.loo_fd = std::move(convert_res.cr_destination);
|
||||||
retval.fc_child_pollers.emplace_back(child_poller{
|
retval.fc_child_pollers.emplace_back(child_poller{
|
||||||
std::move(convert_res.cr_child),
|
std::move(convert_res.cr_child),
|
||||||
[filename, st, error_queue = convert_res.cr_error_queue](auto& fc, auto& child) {
|
[filename,
|
||||||
if (child.was_normal_exit() && child.exit_status() == EXIT_SUCCESS) {
|
st,
|
||||||
log_info("pcap[%d] exited normally", child.in());
|
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;
|
return;
|
||||||
}
|
}
|
||||||
log_error("pcap[%d] exited with %d", child.in(), child.status());
|
log_error("pcap[%d] exited with %d",
|
||||||
fc.fc_name_to_errors.emplace(filename, file_error_info{
|
child.in(),
|
||||||
st.st_mtime,
|
child.status());
|
||||||
fmt::format("{}", fmt::join(*error_queue, "\n")),
|
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);
|
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());
|
retval.fc_files.push_back(open_res.unwrap());
|
||||||
} else {
|
} else {
|
||||||
retval.fc_name_to_errors.emplace(
|
retval.fc_name_to_errors.emplace(
|
||||||
filename, file_error_info{
|
filename,
|
||||||
|
file_error_info{
|
||||||
st.st_mtime,
|
st.st_mtime,
|
||||||
open_res.unwrapErr(),
|
open_res.unwrapErr(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
retval.fc_name_to_errors.emplace(filename, file_error_info{
|
retval.fc_name_to_errors.emplace(filename,
|
||||||
st.st_mtime,
|
file_error_info{
|
||||||
res.unwrapErr(),
|
st.st_mtime,
|
||||||
});
|
res.unwrapErr(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case file_format_t::FF_ARCHIVE: {
|
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;
|
prog_iter_opt;
|
||||||
|
|
||||||
if (loo.loo_source == logfile_name_source::ARCHIVE) {
|
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(
|
auto res = archive_manager::walk_archive_files(
|
||||||
filename,
|
filename,
|
||||||
[prog, &prog_iter_opt](
|
[prog, &prog_iter_opt](const auto& path,
|
||||||
const auto &path,
|
const auto total) {
|
||||||
const auto total) {
|
|
||||||
safe::WriteAccess<safe_scan_progress> sp(*prog);
|
safe::WriteAccess<safe_scan_progress> sp(*prog);
|
||||||
|
|
||||||
prog_iter_opt | [&sp](auto prog_iter) {
|
prog_iter_opt | [&sp](auto prog_iter) {
|
||||||
sp->sp_extractions.erase(prog_iter);
|
sp->sp_extractions.erase(prog_iter);
|
||||||
};
|
};
|
||||||
auto prog_iter = sp->sp_extractions.emplace(
|
auto prog_iter = sp->sp_extractions.emplace(
|
||||||
sp->sp_extractions.begin(),
|
sp->sp_extractions.begin(), path, total);
|
||||||
path, total);
|
|
||||||
prog_iter_opt = prog_iter;
|
prog_iter_opt = prog_iter;
|
||||||
|
|
||||||
return &(*prog_iter);
|
return &(*prog_iter);
|
||||||
},
|
},
|
||||||
[&filename, &retval](
|
[&filename, &retval](const auto& tmp_path,
|
||||||
const auto &tmp_path,
|
const auto& entry) {
|
||||||
const auto &entry) {
|
|
||||||
auto arc_path = ghc::filesystem::relative(
|
auto arc_path = ghc::filesystem::relative(
|
||||||
entry.path(), tmp_path);
|
entry.path(), tmp_path);
|
||||||
auto custom_name = filename / arc_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",
|
log_error("archive extraction failed: %s",
|
||||||
res.unwrapErr().c_str());
|
res.unwrapErr().c_str());
|
||||||
retval.clear();
|
retval.clear();
|
||||||
retval.fc_name_to_errors.emplace(
|
retval.fc_name_to_errors.emplace(filename,
|
||||||
filename,
|
file_error_info{
|
||||||
file_error_info{
|
st.st_mtime,
|
||||||
st.st_mtime,
|
res.unwrapErr(),
|
||||||
res.unwrapErr(),
|
});
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
retval.fc_other_files[filename] = ff;
|
retval.fc_other_files[filename] = ff;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
prog_iter_opt |
|
prog_iter_opt | [&prog](auto prog_iter) {
|
||||||
[&prog](auto prog_iter) {
|
|
||||||
prog->writeAccess()->sp_extractions.erase(
|
prog->writeAccess()->sp_extractions.erase(
|
||||||
prog_iter);
|
prog_iter);
|
||||||
};
|
};
|
||||||
@ -425,10 +438,10 @@ file_collection::watch_logfile(const std::string &filename,
|
|||||||
auto open_res = logfile::open(filename, loo);
|
auto open_res = logfile::open(filename, loo);
|
||||||
if (open_res.isOk()) {
|
if (open_res.isOk()) {
|
||||||
retval.fc_files.push_back(open_res.unwrap());
|
retval.fc_files.push_back(open_res.unwrap());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
retval.fc_name_to_errors.emplace(
|
retval.fc_name_to_errors.emplace(
|
||||||
filename, file_error_info{
|
filename,
|
||||||
|
file_error_info{
|
||||||
st.st_mtime,
|
st.st_mtime,
|
||||||
open_res.unwrapErr(),
|
open_res.unwrapErr(),
|
||||||
});
|
});
|
||||||
@ -460,10 +473,12 @@ file_collection::watch_logfile(const std::string &filename,
|
|||||||
* @param path The glob pattern to expand.
|
* @param path The glob pattern to expand.
|
||||||
* @param required Passed to watch_logfile.
|
* @param required Passed to watch_logfile.
|
||||||
*/
|
*/
|
||||||
void file_collection::expand_filename(lnav::futures::future_queue<file_collection> &fq,
|
void
|
||||||
const std::string &path,
|
file_collection::expand_filename(
|
||||||
logfile_open_options &loo,
|
lnav::futures::future_queue<file_collection>& fq,
|
||||||
bool required)
|
const std::string& path,
|
||||||
|
logfile_open_options& loo,
|
||||||
|
bool required)
|
||||||
{
|
{
|
||||||
static_root_mem<glob_t, globfree> gl;
|
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;
|
file_collection retval;
|
||||||
|
|
||||||
isc::to<tailer::looper &, services::remote_tailer_t>()
|
isc::to<tailer::looper&, services::remote_tailer_t>().send(
|
||||||
.send([=](auto &tlooper) {
|
[=](auto& tlooper) { tlooper.add_remote(rp, loo); });
|
||||||
tlooper.add_remote(rp, loo);
|
|
||||||
});
|
|
||||||
retval.fc_other_files[path] = file_format_t::FF_REMOTE;
|
retval.fc_other_files[path] = file_format_t::FF_REMOTE;
|
||||||
{
|
{
|
||||||
this->fc_progress->writeAccess()->
|
this->fc_progress->writeAccess()
|
||||||
sp_tailers[fmt::format("{}", rp.home())].tp_message =
|
->sp_tailers[fmt::format("{}", rp.home())]
|
||||||
"Initializing...";
|
.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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
required = false;
|
required = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gl->gl_pathc > 1 ||
|
if (gl->gl_pathc > 1 || strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
|
||||||
strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
|
|
||||||
required = false;
|
required = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,13 +544,15 @@ void file_collection::expand_filename(lnav::futures::future_queue<file_collectio
|
|||||||
if (iter == REALPATH_CACHE.end()) {
|
if (iter == REALPATH_CACHE.end()) {
|
||||||
auto_mem<char> abspath;
|
auto_mem<char> abspath;
|
||||||
|
|
||||||
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) ==
|
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) == nullptr)
|
||||||
nullptr) {
|
{
|
||||||
auto errmsg = strerror(errno);
|
auto errmsg = strerror(errno);
|
||||||
|
|
||||||
if (required) {
|
if (required) {
|
||||||
fprintf(stderr, "Cannot find file: %s -- %s",
|
fprintf(stderr,
|
||||||
gl->gl_pathv[lpc], errmsg);
|
"Cannot find file: %s -- %s",
|
||||||
|
gl->gl_pathv[lpc],
|
||||||
|
errmsg);
|
||||||
} else if (loo.loo_source != logfile_name_source::REMOTE) {
|
} else if (loo.loo_source != logfile_name_source::REMOTE) {
|
||||||
// XXX The remote code path adds the file name before
|
// XXX The remote code path adds the file name before
|
||||||
// the file exists... not sure checking for that here
|
// 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;
|
file_collection retval;
|
||||||
|
|
||||||
if (gl->gl_pathc == 1) {
|
if (gl->gl_pathc == 1) {
|
||||||
retval.fc_name_to_errors.emplace(
|
retval.fc_name_to_errors.emplace(path,
|
||||||
path, file_error_info{
|
file_error_info{
|
||||||
time(nullptr),
|
time(nullptr),
|
||||||
errmsg,
|
errmsg,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
retval.fc_name_to_errors.emplace(
|
retval.fc_name_to_errors.emplace(path_str,
|
||||||
path_str, file_error_info{
|
file_error_info{
|
||||||
time(nullptr),
|
time(nullptr),
|
||||||
errmsg,
|
errmsg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fq.push_back(lnav::futures::make_ready_future(std::move(retval)));
|
fq.push_back(lnav::futures::make_ready_future(
|
||||||
|
std::move(retval)));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} 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;
|
file_collection retval;
|
||||||
lnav::futures::future_queue<file_collection> fq([&retval](auto &fc) {
|
lnav::futures::future_queue<file_collection> fq(
|
||||||
retval.merge(fc);
|
[&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) {
|
if (pair.second.loo_fd == -1) {
|
||||||
this->expand_filename(fq, pair.first, pair.second, required);
|
this->expand_filename(fq, pair.first, pair.second, required);
|
||||||
if (this->fc_rotated) {
|
if (this->fc_rotated) {
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -32,19 +32,18 @@
|
|||||||
#ifndef lnav_file_collection_hh
|
#ifndef lnav_file_collection_hh
|
||||||
#define lnav_file_collection_hh
|
#define lnav_file_collection_hh
|
||||||
|
|
||||||
|
#include <forward_list>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <list>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <forward_list>
|
|
||||||
|
|
||||||
#include "safe/safe.h"
|
|
||||||
|
|
||||||
#include "base/future_util.hh"
|
|
||||||
#include "logfile_fwd.hh"
|
|
||||||
#include "archive_manager.hh"
|
#include "archive_manager.hh"
|
||||||
|
#include "base/future_util.hh"
|
||||||
#include "file_format.hh"
|
#include "file_format.hh"
|
||||||
|
#include "logfile_fwd.hh"
|
||||||
|
#include "safe/safe.h"
|
||||||
#include "tailer/tailer.looper.hh"
|
#include "tailer/tailer.looper.hh"
|
||||||
|
|
||||||
struct tailer_progress {
|
struct tailer_progress {
|
||||||
@ -64,7 +63,9 @@ struct other_file_descriptor {
|
|||||||
|
|
||||||
other_file_descriptor(file_format_t format = file_format_t::FF_UNKNOWN,
|
other_file_descriptor(file_format_t format = file_format_t::FF_UNKNOWN,
|
||||||
std::string description = "")
|
std::string description = "")
|
||||||
: ofd_format(format), ofd_description(std::move(description)) {}
|
: ofd_format(format), ofd_description(std::move(description))
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file_error_info {
|
struct file_error_info {
|
||||||
@ -81,16 +82,22 @@ enum class child_poll_result_t {
|
|||||||
|
|
||||||
class child_poller {
|
class child_poller {
|
||||||
public:
|
public:
|
||||||
explicit child_poller(auto_pid<process_state::RUNNING> child,
|
explicit child_poller(
|
||||||
std::function<void(file_collection&, auto_pid<process_state::FINISHED>&)> finalizer)
|
auto_pid<process_state::running> child,
|
||||||
: cp_child(std::move(child)), cp_finalizer(std::move(finalizer)) {
|
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
|
child_poller(child_poller&& other) noexcept
|
||||||
: cp_child(std::move(other.cp_child)),
|
: 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_child = std::move(other.cp_child);
|
||||||
this->cp_finalizer = std::move(other.cp_finalizer);
|
this->cp_finalizer = std::move(other.cp_finalizer);
|
||||||
|
|
||||||
@ -100,9 +107,11 @@ public:
|
|||||||
~child_poller() noexcept = default;
|
~child_poller() noexcept = default;
|
||||||
|
|
||||||
child_poll_result_t poll(file_collection& fc);
|
child_poll_result_t poll(file_collection& fc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nonstd::optional<auto_pid<process_state::RUNNING>> cp_child;
|
nonstd::optional<auto_pid<process_state::running>> cp_child;
|
||||||
std::function<void(file_collection&, auto_pid<process_state::FINISHED>&)> cp_finalizer;
|
std::function<void(file_collection&, auto_pid<process_state::finished>&)>
|
||||||
|
cp_finalizer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file_collection {
|
struct file_collection {
|
||||||
@ -127,7 +136,8 @@ struct file_collection {
|
|||||||
|
|
||||||
file_collection()
|
file_collection()
|
||||||
: fc_progress(std::make_shared<safe::Safe<scan_progress>>())
|
: fc_progress(std::make_shared<safe::Safe<scan_progress>>())
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
@ -141,22 +151,20 @@ struct file_collection {
|
|||||||
|
|
||||||
file_collection rescan_files(bool required = false);
|
file_collection rescan_files(bool required = false);
|
||||||
|
|
||||||
void
|
void expand_filename(lnav::futures::future_queue<file_collection>& fq,
|
||||||
expand_filename(lnav::futures::future_queue<file_collection> &fq,
|
const std::string& path,
|
||||||
const std::string &path,
|
logfile_open_options& loo,
|
||||||
logfile_open_options &loo,
|
bool required);
|
||||||
bool required);
|
|
||||||
|
|
||||||
std::future<file_collection>
|
std::future<file_collection> watch_logfile(const std::string& filename,
|
||||||
watch_logfile(const std::string &filename, logfile_open_options &loo,
|
logfile_open_options& loo,
|
||||||
bool required);
|
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();
|
void regenerate_unique_file_names();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,88 +21,83 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @file file_format.hh
|
* @file file_format.hh
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "file_format.hh"
|
||||||
|
|
||||||
|
#include "archive_manager.hh"
|
||||||
|
#include "auto_fd.hh"
|
||||||
#include "base/fs_util.hh"
|
#include "base/fs_util.hh"
|
||||||
#include "base/intern_string.hh"
|
#include "base/intern_string.hh"
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
#include "auto_fd.hh"
|
#include "config.h"
|
||||||
#include "file_format.hh"
|
|
||||||
#include "archive_manager.hh"
|
|
||||||
|
|
||||||
static bool is_pcap_header(uint8_t *buffer)
|
static bool
|
||||||
|
is_pcap_header(uint8_t* buffer)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
if (buffer[0] == 0x0a &&
|
if (buffer[0] == 0x0a && buffer[1] == 0x0d && buffer[2] == 0x0d
|
||||||
buffer[1] == 0x0d &&
|
&& buffer[3] == 0x0a)
|
||||||
buffer[2] == 0x0d &&
|
{
|
||||||
buffer[3] == 0x0a) {
|
|
||||||
offset += sizeof(uint32_t) * 2;
|
offset += sizeof(uint32_t) * 2;
|
||||||
if (buffer[offset + 0] == 0x1a &&
|
if (buffer[offset + 0] == 0x1a && buffer[offset + 1] == 0x2b
|
||||||
buffer[offset + 1] == 0x2b &&
|
&& buffer[offset + 2] == 0x3c && buffer[offset + 3] == 0x4d)
|
||||||
buffer[offset + 2] == 0x3c &&
|
{
|
||||||
buffer[offset + 3] == 0x4d) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[offset + 0] == 0x4d &&
|
if (buffer[offset + 0] == 0x4d && buffer[offset + 1] == 0x3c
|
||||||
buffer[offset + 1] == 0x3c &&
|
&& buffer[offset + 2] == 0x2b && buffer[offset + 3] == 0x1a)
|
||||||
buffer[offset + 2] == 0x2b &&
|
{
|
||||||
buffer[offset + 3] == 0x1a) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[0] == 0xa1 &&
|
if (buffer[0] == 0xa1 && buffer[1] == 0xb2 && buffer[2] == 0xc3
|
||||||
buffer[1] == 0xb2 &&
|
&& buffer[3] == 0xd4)
|
||||||
buffer[2] == 0xc3 &&
|
{
|
||||||
buffer[3] == 0xd4) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[0] == 0xd4 &&
|
if (buffer[0] == 0xd4 && buffer[1] == 0xc3 && buffer[2] == 0xb2
|
||||||
buffer[1] == 0xc3 &&
|
&& buffer[3] == 0xa1)
|
||||||
buffer[2] == 0xb2 &&
|
{
|
||||||
buffer[3] == 0xa1) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[0] == 0xa1 &&
|
if (buffer[0] == 0xa1 && buffer[1] == 0xb2 && buffer[2] == 0x3c
|
||||||
buffer[1] == 0xb2 &&
|
&& buffer[3] == 0x4d)
|
||||||
buffer[2] == 0x3c &&
|
{
|
||||||
buffer[3] == 0x4d) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[0] == 0x4d &&
|
if (buffer[0] == 0x4d && buffer[1] == 0x3c && buffer[2] == 0xb2
|
||||||
buffer[1] == 0x3c &&
|
&& buffer[3] == 0xa1)
|
||||||
buffer[2] == 0xb2 &&
|
{
|
||||||
buffer[3] == 0xa1) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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)) {
|
if (archive_manager::is_archive(filename)) {
|
||||||
return file_format_t::FF_ARCHIVE;
|
return file_format_t::FF_ARCHIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_format_t retval = file_format_t::FF_UNKNOWN;
|
file_format_t retval = file_format_t::FF_UNKNOWN;
|
||||||
auto_fd fd;
|
auto_fd fd;
|
||||||
|
|
||||||
if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) != -1) {
|
if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) != -1) {
|
||||||
uint8_t buffer[32];
|
uint8_t buffer[32];
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
@ -49,7 +49,7 @@ namespace fmt {
|
|||||||
template<>
|
template<>
|
||||||
struct formatter<file_format_t> : formatter<string_view> {
|
struct formatter<file_format_t> : formatter<string_view> {
|
||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(file_format_t ff, FormatContext &ctx)
|
auto format(file_format_t ff, FormatContext& ctx)
|
||||||
{
|
{
|
||||||
string_view name = "unknown";
|
string_view name = "unknown";
|
||||||
switch (ff) {
|
switch (ff) {
|
||||||
@ -71,6 +71,6 @@ struct formatter<file_format_t> : formatter<string_view> {
|
|||||||
return formatter<string_view>::format(name, ctx);
|
return formatter<string_view>::format(name, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace fmt
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,34 +21,33 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "base/injector.bind.hh"
|
#include "base/injector.bind.hh"
|
||||||
#include "base/lnav.gzip.hh"
|
#include "base/lnav.gzip.hh"
|
||||||
#include "base/lnav_log.hh"
|
#include "base/lnav_log.hh"
|
||||||
|
#include "config.h"
|
||||||
#include "file_collection.hh"
|
#include "file_collection.hh"
|
||||||
|
#include "file_vtab.cfg.hh"
|
||||||
|
#include "log_format.hh"
|
||||||
#include "logfile.hh"
|
#include "logfile.hh"
|
||||||
#include "session_data.hh"
|
#include "session_data.hh"
|
||||||
#include "vtab_module.hh"
|
#include "vtab_module.hh"
|
||||||
#include "log_format.hh"
|
|
||||||
#include "file_vtab.cfg.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct lnav_file : public tvt_iterator_cursor<lnav_file> {
|
struct lnav_file : public tvt_iterator_cursor<lnav_file> {
|
||||||
using iterator = vector<shared_ptr<logfile>>::iterator;
|
using iterator = vector<shared_ptr<logfile>>::iterator;
|
||||||
|
|
||||||
static constexpr const char *NAME = "lnav_file";
|
static constexpr const char* NAME = "lnav_file";
|
||||||
static constexpr const char *CREATE_STMT = R"(
|
static constexpr const char* CREATE_STMT = R"(
|
||||||
-- Access lnav's open file list through this table.
|
-- Access lnav's open file list through this table.
|
||||||
CREATE TABLE lnav_file (
|
CREATE TABLE lnav_file (
|
||||||
device integer, -- The device the file is stored on.
|
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();
|
return this->lf_collection.fc_files.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() {
|
iterator end()
|
||||||
|
{
|
||||||
return this->lf_collection.fc_files.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;
|
auto lf = *vc.iter;
|
||||||
const struct stat &st = lf->get_stat();
|
const struct stat& st = lf->get_stat();
|
||||||
const string &name = lf->get_filename();
|
const string& name = lf->get_filename();
|
||||||
auto format = lf->get_format();
|
auto format = lf->get_format();
|
||||||
const char *format_name =
|
const char* format_name = format != nullptr ? format->get_name().get()
|
||||||
format != nullptr ? format->get_name().get() : nullptr;
|
: nullptr;
|
||||||
|
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -117,35 +118,32 @@ CREATE TABLE lnav_file (
|
|||||||
} else {
|
} else {
|
||||||
auto fd = lf->get_fd();
|
auto fd = lf->get_fd();
|
||||||
auto_mem<char> buf;
|
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);
|
auto rc = pread(fd, buf, lf_stat.st_size, 0);
|
||||||
|
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
auto errmsg = fmt::format("unable to read file: {}",
|
auto errmsg = fmt::format("unable to read file: {}",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|
||||||
sqlite3_result_error(ctx, errmsg.c_str(),
|
sqlite3_result_error(
|
||||||
errmsg.length());
|
ctx, errmsg.c_str(), errmsg.length());
|
||||||
} else if (rc != lf_stat.st_size) {
|
} else if (rc != lf_stat.st_size) {
|
||||||
auto errmsg = fmt::format("short read of file: {} < {}",
|
auto errmsg = fmt::format(
|
||||||
rc, lf_stat.st_size);
|
"short read of file: {} < {}", rc, lf_stat.st_size);
|
||||||
|
|
||||||
sqlite3_result_error(ctx, errmsg.c_str(),
|
sqlite3_result_error(
|
||||||
errmsg.length());
|
ctx, errmsg.c_str(), errmsg.length());
|
||||||
} else if (lnav::gzip::is_gzipped(buf, rc)) {
|
} else if (lnav::gzip::is_gzipped(buf, rc)) {
|
||||||
lnav::gzip::uncompress(lf->get_unique_path(), buf, rc)
|
lnav::gzip::uncompress(lf->get_unique_path(), buf, rc)
|
||||||
.then([ctx](auto uncomp) {
|
.then([ctx](auto uncomp) {
|
||||||
auto pair = uncomp.release();
|
auto pair = uncomp.release();
|
||||||
|
|
||||||
sqlite3_result_blob64(ctx,
|
sqlite3_result_blob64(
|
||||||
pair.first,
|
ctx, pair.first, pair.second, free);
|
||||||
pair.second,
|
|
||||||
free);
|
|
||||||
})
|
})
|
||||||
.otherwise([ctx](auto msg) {
|
.otherwise([ctx](auto msg) {
|
||||||
sqlite3_result_error(ctx,
|
sqlite3_result_error(
|
||||||
msg.c_str(),
|
ctx, msg.c_str(), msg.size());
|
||||||
msg.size());
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
sqlite3_result_blob64(ctx, buf.release(), rc, free);
|
sqlite3_result_blob64(ctx, buf.release(), rc, free);
|
||||||
@ -161,28 +159,30 @@ CREATE TABLE lnav_file (
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_row(sqlite3_vtab *vt, sqlite3_int64 rowid) {
|
int delete_row(sqlite3_vtab* vt, sqlite3_int64 rowid)
|
||||||
vt->zErrMsg = sqlite3_mprintf(
|
{
|
||||||
"Rows cannot be deleted from this table");
|
vt->zErrMsg = sqlite3_mprintf("Rows cannot be deleted from this table");
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
};
|
};
|
||||||
|
|
||||||
int insert_row(sqlite3_vtab *tab, sqlite3_int64 &rowid_out) {
|
int insert_row(sqlite3_vtab* tab, sqlite3_int64& rowid_out)
|
||||||
tab->zErrMsg = sqlite3_mprintf(
|
{
|
||||||
"Rows cannot be inserted into this table");
|
tab->zErrMsg
|
||||||
|
= sqlite3_mprintf("Rows cannot be inserted into this table");
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
};
|
};
|
||||||
|
|
||||||
int update_row(sqlite3_vtab *tab,
|
int update_row(sqlite3_vtab* tab,
|
||||||
sqlite3_int64 &rowid,
|
sqlite3_int64& rowid,
|
||||||
int64_t device,
|
int64_t device,
|
||||||
int64_t inode,
|
int64_t inode,
|
||||||
std::string path,
|
std::string path,
|
||||||
const char *text_format,
|
const char* text_format,
|
||||||
const char *format,
|
const char* format,
|
||||||
int64_t lines,
|
int64_t lines,
|
||||||
int64_t time_offset,
|
int64_t time_offset,
|
||||||
const char *content) {
|
const char* content)
|
||||||
|
{
|
||||||
auto lf = this->lf_collection.fc_files[rowid];
|
auto lf = this->lf_collection.fc_files[rowid];
|
||||||
struct timeval tv = {
|
struct timeval tv = {
|
||||||
(int) (time_offset / 1000LL),
|
(int) (time_offset / 1000LL),
|
||||||
@ -197,7 +197,8 @@ CREATE TABLE lnav_file (
|
|||||||
"real file paths cannot be updated, only symbolic ones");
|
"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()) {
|
if (iter != this->lf_collection.fc_file_names.end()) {
|
||||||
auto loo = std::move(iter->second);
|
auto loo = std::move(iter->second);
|
||||||
@ -216,7 +217,7 @@ CREATE TABLE lnav_file (
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
file_collection &lf_collection;
|
file_collection& lf_collection;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct injectable_lnav_file : vtab_module<lnav_file> {
|
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&);
|
using injectable = injectable_lnav_file(file_collection&);
|
||||||
};
|
};
|
||||||
|
|
||||||
static auto file_binder = injector::bind_multiple<vtab_module_base>()
|
static auto file_binder
|
||||||
.add<injectable_lnav_file>();
|
= 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
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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};
|
int64_t fvc_max_content_size{32 * 1024 * 1024};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace file_vtab
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,27 +21,27 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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.hh"
|
||||||
#include "base/humanize.network.hh"
|
#include "base/humanize.network.hh"
|
||||||
#include "base/opt_util.hh"
|
#include "base/opt_util.hh"
|
||||||
#include "base/string_util.hh"
|
#include "base/string_util.hh"
|
||||||
|
#include "config.h"
|
||||||
|
#include "lnav.hh"
|
||||||
#include "mapbox/variant.hpp"
|
#include "mapbox/variant.hpp"
|
||||||
|
|
||||||
#include "lnav.hh"
|
|
||||||
#include "files_sub_source.hh"
|
|
||||||
|
|
||||||
namespace files_model {
|
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;
|
int sel = (int) sel_vis;
|
||||||
|
|
||||||
if (sel < fc.fc_name_to_errors.size()) {
|
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{};
|
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) {
|
switch (ch) {
|
||||||
case KEY_ENTER:
|
case KEY_ENTER:
|
||||||
case '\r': {
|
case '\r': {
|
||||||
auto sel = files_model::from_selection(lv.get_selection());
|
auto sel = files_model::from_selection(lv.get_selection());
|
||||||
|
|
||||||
sel.match(
|
sel.match([](files_model::no_selection) {},
|
||||||
[](files_model::no_selection) {},
|
[](files_model::error_selection) {},
|
||||||
[](files_model::error_selection) {},
|
[](files_model::other_selection) {},
|
||||||
[](files_model::other_selection) {},
|
[&](files_model::file_selection& fs) {
|
||||||
[&](files_model::file_selection& fs) {
|
auto& lss = lnav_data.ld_log_source;
|
||||||
auto& lss = lnav_data.ld_log_source;
|
auto lf = *fs.sb_iter;
|
||||||
auto lf = *fs.sb_iter;
|
|
||||||
|
|
||||||
lss.find_data(lf) | [](auto ld) {
|
lss.find_data(lf) | [](auto ld) {
|
||||||
ld->set_visibility(true);
|
ld->set_visibility(true);
|
||||||
lnav_data.ld_log_source.text_filters_changed();
|
lnav_data.ld_log_source.text_filters_changed();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (lf->get_format() != nullptr) {
|
if (lf->get_format() != nullptr) {
|
||||||
auto& log_view = lnav_data.ld_views[LNV_LOG];
|
auto& log_view = lnav_data.ld_views[LNV_LOG];
|
||||||
lss.row_for_time(lf->front().get_timeval()) | [](auto row) {
|
lss.row_for_time(lf->front().get_timeval()) |
|
||||||
lnav_data.ld_views[LNV_LOG].set_top(row);
|
[](auto row) {
|
||||||
};
|
lnav_data.ld_views[LNV_LOG].set_top(row);
|
||||||
ensure_view(&log_view);
|
};
|
||||||
} else {
|
ensure_view(&log_view);
|
||||||
auto& tv = lnav_data.ld_views[LNV_TEXT];
|
} else {
|
||||||
auto& tss = lnav_data.ld_text_source;
|
auto& tv = lnav_data.ld_views[LNV_TEXT];
|
||||||
|
auto& tss = lnav_data.ld_text_source;
|
||||||
|
|
||||||
tss.to_front(lf);
|
tss.to_front(lf);
|
||||||
tv.reload_data();
|
tv.reload_data();
|
||||||
ensure_view(&tv);
|
ensure_view(&tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv.reload_data();
|
lv.reload_data();
|
||||||
lnav_data.ld_mode = LNM_PAGING;
|
lnav_data.ld_mode = LNM_PAGING;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -124,29 +121,27 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||||||
case ' ': {
|
case ' ': {
|
||||||
auto sel = files_model::from_selection(lv.get_selection());
|
auto sel = files_model::from_selection(lv.get_selection());
|
||||||
|
|
||||||
sel.match(
|
sel.match([](files_model::no_selection) {},
|
||||||
[](files_model::no_selection) {},
|
[](files_model::error_selection) {},
|
||||||
[](files_model::error_selection) {},
|
[](files_model::other_selection) {},
|
||||||
[](files_model::other_selection) {},
|
[&](files_model::file_selection& fs) {
|
||||||
[&](files_model::file_selection& fs) {
|
auto& lss = lnav_data.ld_log_source;
|
||||||
auto& lss = lnav_data.ld_log_source;
|
auto lf = *fs.sb_iter;
|
||||||
auto lf = *fs.sb_iter;
|
|
||||||
|
|
||||||
lss.find_data(lf) | [](auto ld) {
|
lss.find_data(lf) | [](auto ld) {
|
||||||
ld->set_visibility(!ld->ld_visible);
|
ld->set_visibility(!ld->ld_visible);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto top_view = *lnav_data.ld_view_stack.top();
|
auto top_view = *lnav_data.ld_view_stack.top();
|
||||||
auto tss = top_view->get_sub_source();
|
auto tss = top_view->get_sub_source();
|
||||||
|
|
||||||
if (tss != nullptr) {
|
if (tss != nullptr) {
|
||||||
tss->text_filters_changed();
|
tss->text_filters_changed();
|
||||||
top_view->reload_data();
|
top_view->reload_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
lv.reload_data();
|
lv.reload_data();
|
||||||
}
|
});
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
@ -158,83 +153,87 @@ bool files_sub_source::list_input_handle_key(listview_curses &lv, int ch)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case '/': {
|
case '/': {
|
||||||
execute_command(lnav_data.ld_exec_context,
|
execute_command(lnav_data.ld_exec_context, "prompt search-files");
|
||||||
"prompt search-files");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 'X': {
|
case 'X': {
|
||||||
auto sel = files_model::from_selection(lv.get_selection());
|
auto sel = files_model::from_selection(lv.get_selection());
|
||||||
|
|
||||||
sel.match(
|
sel.match([](files_model::no_selection) {},
|
||||||
[](files_model::no_selection) {},
|
[&](files_model::error_selection& es) {
|
||||||
[&](files_model::error_selection& es) {
|
auto& fc = lnav_data.ld_active_files;
|
||||||
auto &fc = lnav_data.ld_active_files;
|
|
||||||
|
|
||||||
fc.fc_file_names.erase(es.sb_iter->first);
|
fc.fc_file_names.erase(es.sb_iter->first);
|
||||||
|
|
||||||
auto name_iter = fc.fc_file_names.begin();
|
auto name_iter = fc.fc_file_names.begin();
|
||||||
while (name_iter != fc.fc_file_names.end()) {
|
while (name_iter != fc.fc_file_names.end()) {
|
||||||
if (name_iter->first == es.sb_iter->first) {
|
if (name_iter->first == es.sb_iter->first) {
|
||||||
name_iter = fc.fc_file_names.erase(name_iter);
|
name_iter = fc.fc_file_names.erase(name_iter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rp_opt = humanize::network::path::from_str(name_iter->first);
|
auto rp_opt = humanize::network::path::from_str(
|
||||||
|
name_iter->first);
|
||||||
|
|
||||||
if (rp_opt) {
|
if (rp_opt) {
|
||||||
auto rp = *rp_opt;
|
auto rp = *rp_opt;
|
||||||
|
|
||||||
if (fmt::format("{}", rp.home()) == es.sb_iter->first) {
|
if (fmt::format("{}", rp.home())
|
||||||
fc.fc_other_files.erase(name_iter->first);
|
== es.sb_iter->first) {
|
||||||
name_iter = fc.fc_file_names.erase(name_iter);
|
fc.fc_other_files.erase(name_iter->first);
|
||||||
continue;
|
name_iter
|
||||||
}
|
= fc.fc_file_names.erase(name_iter);
|
||||||
}
|
continue;
|
||||||
++name_iter;
|
}
|
||||||
}
|
}
|
||||||
|
++name_iter;
|
||||||
|
}
|
||||||
|
|
||||||
fc.fc_name_to_errors.erase(es.sb_iter);
|
fc.fc_name_to_errors.erase(es.sb_iter);
|
||||||
fc.fc_invalidate_merge = true;
|
fc.fc_invalidate_merge = true;
|
||||||
lv.reload_data();
|
lv.reload_data();
|
||||||
},
|
},
|
||||||
[](files_model::other_selection) {},
|
[](files_model::other_selection) {},
|
||||||
[](files_model::file_selection) {}
|
[](files_model::file_selection) {});
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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_mode = LNM_PAGING;
|
||||||
lnav_data.ld_filter_view.reload_data();
|
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() +
|
return fc.fc_name_to_errors.size() + fc.fc_other_files.size()
|
||||||
fc.fc_other_files.size() +
|
+ fc.fc_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;
|
return 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
void files_sub_source::text_value_for_line(textview_curses &tc, int line,
|
void
|
||||||
std::string &value_out,
|
files_sub_source::text_value_for_line(textview_curses& tc,
|
||||||
text_sub_source::line_flags_t flags)
|
int line,
|
||||||
|
std::string& value_out,
|
||||||
|
text_sub_source::line_flags_t flags)
|
||||||
{
|
{
|
||||||
const auto dim = tc.get_dimensions();
|
const auto dim = tc.get_dimensions();
|
||||||
const auto &fc = lnav_data.ld_active_files;
|
const auto& fc = lnav_data.ld_active_files;
|
||||||
auto filename_width =
|
auto filename_width
|
||||||
std::min(fc.fc_largest_path_length,
|
= std::min(fc.fc_largest_path_length,
|
||||||
std::max((size_t) 40, (size_t) dim.second - 30));
|
std::max((size_t) 40, (size_t) dim.second - 30));
|
||||||
|
|
||||||
if (line < fc.fc_name_to_errors.size()) {
|
if (line < fc.fc_name_to_errors.size()) {
|
||||||
auto iter = fc.fc_name_to_errors.begin();
|
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();
|
auto fn = path.filename().string();
|
||||||
|
|
||||||
truncate_to(fn, filename_width);
|
truncate_to(fn, filename_width);
|
||||||
value_out = fmt::format(
|
value_out = fmt::format(FMT_STRING(" {:<{}} {}"),
|
||||||
FMT_STRING(" {:<{}} {}"),
|
fn,
|
||||||
fn, filename_width, iter->second.fei_description);
|
filename_width,
|
||||||
|
iter->second.fei_description);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,16 +258,17 @@ void files_sub_source::text_value_for_line(textview_curses &tc, int line,
|
|||||||
auto fn = path.string();
|
auto fn = path.string();
|
||||||
|
|
||||||
truncate_to(fn, filename_width);
|
truncate_to(fn, filename_width);
|
||||||
value_out = fmt::format(
|
value_out = fmt::format(FMT_STRING(" {:<{}} {:14} {}"),
|
||||||
FMT_STRING(" {:<{}} {:14} {}"),
|
fn,
|
||||||
fn, filename_width, iter->second.ofd_format,
|
filename_width,
|
||||||
iter->second.ofd_description);
|
iter->second.ofd_format,
|
||||||
|
iter->second.ofd_description);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
line -= fc.fc_other_files.size();
|
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();
|
auto fn = lf->get_unique_path();
|
||||||
char start_time[64] = "", end_time[64] = "";
|
char start_time[64] = "", end_time[64] = "";
|
||||||
std::vector<std::string> file_notes;
|
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()) {
|
for (const auto& pair : lf->get_notes()) {
|
||||||
file_notes.push_back(pair.second);
|
file_notes.push_back(pair.second);
|
||||||
}
|
}
|
||||||
value_out = fmt::format(
|
value_out = fmt::format(FMT_STRING(" {:<{}} {:>8} {} \u2014 {} {}"),
|
||||||
FMT_STRING(" {:<{}} {:>8} {} \u2014 {} {}"),
|
fn,
|
||||||
fn,
|
filename_width,
|
||||||
filename_width,
|
humanize::file_size(lf->get_index_size()),
|
||||||
humanize::file_size(lf->get_index_size()),
|
start_time,
|
||||||
start_time,
|
end_time,
|
||||||
end_time,
|
fmt::join(file_notes, "; "));
|
||||||
fmt::join(file_notes, "; "));
|
this->fss_last_line_len
|
||||||
this->fss_last_line_len =
|
= filename_width + 23 + strlen(start_time) + strlen(end_time);
|
||||||
filename_width + 23 + strlen(start_time) + strlen(end_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
|
void
|
||||||
string_attrs_t &value_out)
|
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();
|
bool selected
|
||||||
const auto &fc = lnav_data.ld_active_files;
|
= lnav_data.ld_mode == LNM_FILES && line == tc.get_selection();
|
||||||
auto &vcolors = view_colors::singleton();
|
const auto& fc = lnav_data.ld_active_files;
|
||||||
|
auto& vcolors = view_colors::singleton();
|
||||||
const auto dim = tc.get_dimensions();
|
const auto dim = tc.get_dimensions();
|
||||||
auto filename_width =
|
auto filename_width
|
||||||
std::min(fc.fc_largest_path_length,
|
= std::min(fc.fc_largest_path_length,
|
||||||
std::max((size_t) 40, (size_t) dim.second - 30));
|
std::max((size_t) 40, (size_t) dim.second - 30));
|
||||||
|
|
||||||
if (selected) {
|
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()) {
|
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);
|
view_colors::VCR_DISABLED_FOCUSED);
|
||||||
}
|
}
|
||||||
if (line == fc.fc_other_files.size() - 1) {
|
if (line == fc.fc_other_files.size() - 1) {
|
||||||
value_out.emplace_back(line_range{0, -1},
|
value_out.emplace_back(
|
||||||
&view_curses::VC_STYLE,
|
line_range{0, -1}, &view_curses::VC_STYLE, A_UNDERLINE);
|
||||||
A_UNDERLINE);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -338,13 +341,12 @@ void files_sub_source::text_attrs_for_line(textview_curses &tc, int line,
|
|||||||
line -= fc.fc_other_files.size();
|
line -= fc.fc_other_files.size();
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
value_out.emplace_back(line_range{0, -1},
|
value_out.emplace_back(
|
||||||
&view_curses::VC_ROLE,
|
line_range{0, -1}, &view_curses::VC_ROLE, view_colors::VCR_FOCUSED);
|
||||||
view_colors::VCR_FOCUSED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& lss = lnav_data.ld_log_source;
|
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);
|
auto ld_opt = lss.find_data(lf);
|
||||||
|
|
||||||
chtype visible = ACS_DIAMOND;
|
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);
|
value_out.emplace_back(line_range{2, 3}, &view_curses::VC_GRAPHIC, visible);
|
||||||
if (visible == ACS_DIAMOND) {
|
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));
|
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_start = this->fss_last_line_len;
|
||||||
lr.lr_end = -1;
|
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));
|
vcolors.ansi_to_theme_color(COLOR_YELLOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t files_sub_source::text_size_for_line(textview_curses &tc, int line,
|
size_t
|
||||||
text_sub_source::line_flags_t raw)
|
files_sub_source::text_size_for_line(textview_curses& tc,
|
||||||
|
int line,
|
||||||
|
text_sub_source::line_flags_t raw)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static auto
|
||||||
auto spinner_index()
|
spinner_index()
|
||||||
{
|
{
|
||||||
auto now = ui_clock::now();
|
auto now = ui_clock::now();
|
||||||
|
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
now.time_since_epoch()).count() / 100;
|
now.time_since_epoch())
|
||||||
|
.count()
|
||||||
|
/ 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
files_overlay_source::list_value_for_overlay(const listview_curses &lv, int y,
|
files_overlay_source::list_value_for_overlay(const listview_curses& lv,
|
||||||
int bottom, vis_line_t line,
|
int y,
|
||||||
attr_line_t &value_out)
|
int bottom,
|
||||||
|
vis_line_t line,
|
||||||
|
attr_line_t& value_out)
|
||||||
{
|
{
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
static const char PROG[] = "-\\|/";
|
static const char PROG[] = "-\\|/";
|
||||||
constexpr size_t PROG_SIZE = sizeof(PROG) - 1;
|
constexpr size_t PROG_SIZE = sizeof(PROG) - 1;
|
||||||
|
|
||||||
auto &fc = lnav_data.ld_active_files;
|
auto& fc = lnav_data.ld_active_files;
|
||||||
auto &fc_prog = fc.fc_progress;
|
auto& fc_prog = fc.fc_progress;
|
||||||
safe::WriteAccess<safe_scan_progress> sp(*fc_prog);
|
safe::WriteAccess<safe_scan_progress> sp(*fc_prog);
|
||||||
|
|
||||||
if (!sp->sp_extractions.empty()) {
|
if (!sp->sp_extractions.empty()) {
|
||||||
const auto& prog = sp->sp_extractions.front();
|
const auto& prog = sp->sp_extractions.front();
|
||||||
|
|
||||||
value_out.with_ansi_string(fmt::format(
|
value_out.with_ansi_string(fmt::format(
|
||||||
"{} Extracting "
|
"{} Extracting " ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
|
||||||
ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
|
"... {:>8}/{}",
|
||||||
"... {:>8}/{}",
|
|
||||||
PROG[spinner_index() % PROG_SIZE],
|
PROG[spinner_index() % PROG_SIZE],
|
||||||
prog.ep_path.filename().string(),
|
prog.ep_path.filename().string(),
|
||||||
humanize::file_size(prog.ep_out_size),
|
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();
|
auto first_iter = sp->sp_tailers.begin();
|
||||||
|
|
||||||
value_out.with_ansi_string(fmt::format(
|
value_out.with_ansi_string(fmt::format(
|
||||||
"{} Connecting to "
|
"{} Connecting to " ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
|
||||||
ANSI_COLOR(COLOR_CYAN) "{}" ANSI_NORM
|
": {}",
|
||||||
": {}",
|
|
||||||
PROG[spinner_index() % PROG_SIZE],
|
PROG[spinner_index() % PROG_SIZE],
|
||||||
first_iter->first,
|
first_iter->first,
|
||||||
first_iter->second.tp_message));
|
first_iter->second.tp_message));
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
@ -30,31 +30,35 @@
|
|||||||
#ifndef files_sub_source_hh
|
#ifndef files_sub_source_hh
|
||||||
#define files_sub_source_hh
|
#define files_sub_source_hh
|
||||||
|
|
||||||
#include "textview_curses.hh"
|
|
||||||
#include "file_collection.hh"
|
#include "file_collection.hh"
|
||||||
|
#include "textview_curses.hh"
|
||||||
|
|
||||||
class files_sub_source
|
class files_sub_source
|
||||||
: public text_sub_source, public list_input_delegate {
|
: public text_sub_source
|
||||||
|
, public list_input_delegate {
|
||||||
public:
|
public:
|
||||||
files_sub_source();
|
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_count() override;
|
||||||
|
|
||||||
size_t text_line_width(textview_curses &curses) override;
|
size_t text_line_width(textview_curses& curses) override;
|
||||||
|
|
||||||
void
|
void text_value_for_line(textview_curses& tc,
|
||||||
text_value_for_line(textview_curses &tc, int line, std::string &value_out,
|
int line,
|
||||||
line_flags_t flags) override;
|
std::string& value_out,
|
||||||
|
line_flags_t flags) override;
|
||||||
|
|
||||||
void text_attrs_for_line(textview_curses &tc, int line,
|
void text_attrs_for_line(textview_curses& tc,
|
||||||
string_attrs_t &value_out) override;
|
int line,
|
||||||
|
string_attrs_t& value_out) override;
|
||||||
|
|
||||||
size_t
|
size_t text_size_for_line(textview_curses& tc,
|
||||||
text_size_for_line(textview_curses &tc, int line, line_flags_t raw) override;
|
int line,
|
||||||
|
line_flags_t raw) override;
|
||||||
|
|
||||||
bool fss_editing{false};
|
bool fss_editing{false};
|
||||||
bool fss_filter_state{false};
|
bool fss_filter_state{false};
|
||||||
@ -62,21 +66,25 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct files_overlay_source : public list_overlay_source {
|
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,
|
vis_line_t line,
|
||||||
attr_line_t &value_out) override;
|
attr_line_t& value_out) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace files_model {
|
namespace files_model {
|
||||||
|
|
||||||
struct no_selection {};
|
struct no_selection {
|
||||||
|
};
|
||||||
|
|
||||||
template<typename C, typename T>
|
template<typename C, typename T>
|
||||||
struct selection_base {
|
struct selection_base {
|
||||||
int sb_index{0};
|
int sb_index{0};
|
||||||
T sb_iter;
|
T sb_iter;
|
||||||
|
|
||||||
static C build(int index, T iter) {
|
static C build(int index, T iter)
|
||||||
|
{
|
||||||
C retval;
|
C retval;
|
||||||
|
|
||||||
retval.sb_index = index;
|
retval.sb_index = index;
|
||||||
@ -86,22 +94,26 @@ struct selection_base {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct error_selection
|
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
|
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
|
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<
|
using files_list_selection = mapbox::util::
|
||||||
no_selection, error_selection, other_selection, file_selection>;
|
variant<no_selection, error_selection, other_selection, file_selection>;
|
||||||
|
|
||||||
files_list_selection from_selection(vis_line_t sel_vis);
|
files_list_selection from_selection(vis_line_t sel_vis);
|
||||||
|
|
||||||
}
|
} // namespace files_model
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,22 +21,22 @@
|
|||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "log_format.hh"
|
|
||||||
|
|
||||||
#include "filter_observer.hh"
|
#include "filter_observer.hh"
|
||||||
|
|
||||||
void line_filter_observer::logline_new_lines(const logfile &lf,
|
#include "config.h"
|
||||||
logfile::const_iterator ll_begin,
|
#include "log_format.hh"
|
||||||
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);
|
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) {
|
if (lf.get_format() != nullptr) {
|
||||||
lf.get_format()->get_subline(*ll_begin, sbr);
|
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) {
|
if (filter->lf_deleted) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (offset >=
|
if (offset
|
||||||
this->lfo_filter_state.tfs_filter_count[filter->get_index()]) {
|
>= this->lfo_filter_state.tfs_filter_count[filter->get_index()])
|
||||||
|
{
|
||||||
filter->add_line(this->lfo_filter_state, ll_begin, sbr);
|
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) {
|
if (iter->lf_deleted) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user