Add import functionality
This commit is contained in:
		
							parent
							
								
									2a0bffd8bb
								
							
						
					
					
						commit
						454d23a975
					
				| 
						 | 
					@ -19,7 +19,7 @@ set(DEFINITIONS "")
 | 
				
			||||||
# imgui include because https://github.com/ocornut/imgui/issues/6184#issuecomment-1439570929
 | 
					# imgui include because https://github.com/ocornut/imgui/issues/6184#issuecomment-1439570929
 | 
				
			||||||
list(APPEND INCLUDES thirdparty thirdparty/imgui /usr/include/SDL2)
 | 
					list(APPEND INCLUDES thirdparty thirdparty/imgui /usr/include/SDL2)
 | 
				
			||||||
list(APPEND SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp filters.cpp misc.cpp pcre2_wrapper.cpp
 | 
					list(APPEND SOURCES main.cpp event_loop.cpp logcat_thread.cpp logcat_entry.cpp log.cpp config.cpp filters.cpp misc.cpp pcre2_wrapper.cpp
 | 
				
			||||||
    group_panel.cpp fragments/filters.cpp fragments/export.cpp windows/logs.cpp windows/settings.cpp windows/main.cpp)
 | 
					    group_panel.cpp fragments/filters.cpp fragments/export.cpp fragments/import.cpp windows/logs.cpp windows/settings.cpp windows/main.cpp)
 | 
				
			||||||
list(APPEND IMGUI_SOURCES thirdparty/imgui/imgui.cpp thirdparty/imgui/imgui_draw.cpp thirdparty/imgui/imgui_widgets.cpp thirdparty/imgui/imgui_tables.cpp
 | 
					list(APPEND IMGUI_SOURCES thirdparty/imgui/imgui.cpp thirdparty/imgui/imgui_draw.cpp thirdparty/imgui/imgui_widgets.cpp thirdparty/imgui/imgui_tables.cpp
 | 
				
			||||||
    thirdparty/imgui/misc/cpp/imgui_stdlib.cpp thirdparty/imgui/misc/freetype/imgui_freetype.cpp
 | 
					    thirdparty/imgui/misc/cpp/imgui_stdlib.cpp thirdparty/imgui/misc/freetype/imgui_freetype.cpp
 | 
				
			||||||
    thirdparty/imgui/backends/imgui_impl_sdl2.cpp thirdparty/imgui/backends/imgui_impl_opengl3.cpp)
 | 
					    thirdparty/imgui/backends/imgui_impl_sdl2.cpp thirdparty/imgui/backends/imgui_impl_opengl3.cpp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ enum class ExportAmount : int {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, File& file);
 | 
					static inline void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, File& file);
 | 
				
			||||||
static inline void export_logcat_entries_to_clipboard(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers);
 | 
					static inline void export_logcat_entries_to_clipboard(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers);
 | 
				
			||||||
static inline void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, auto cb);
 | 
					static void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, auto cb);
 | 
				
			||||||
static inline std::optional<File> save_file_picker();
 | 
					static inline std::optional<File> save_file_picker();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void export_fragment(const LogcatEntries& logcat_entries) {
 | 
					void export_fragment(const LogcatEntries& logcat_entries) {
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,7 @@ static inline void export_logcat_entries_to_clipboard(const LogcatEntries& logca
 | 
				
			||||||
    ImGui::SetClipboardText(text.c_str());
 | 
					    ImGui::SetClipboardText(text.c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, auto cb) {
 | 
					static void export_logcat_entries(const LogcatEntries& logcat_entries, ExportAmount export_amount, bool export_buffers, auto cb) {
 | 
				
			||||||
    size_t size;
 | 
					    size_t size;
 | 
				
			||||||
    const LogcatEntry& (LogcatEntries::*get_fn)(size_t) const;
 | 
					    const LogcatEntry& (LogcatEntries::*get_fn)(size_t) const;
 | 
				
			||||||
    unsigned int buffers_printed = 0;
 | 
					    unsigned int buffers_printed = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,5 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LogcatEntries; // forward declaration from ../logcat_entry.h
 | 
					class LogcatEntries; // forward declaration from ../logcat_entry.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void export_fragment(const LogcatEntries& logcat_entries);
 | 
					void export_fragment(const LogcatEntries& logcat_entries);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,154 @@
 | 
				
			||||||
 | 
					#include <imgui/imgui.h>
 | 
				
			||||||
 | 
					#include <nativefiledialog-extended/src/include/nfd.h>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../file.h"
 | 
				
			||||||
 | 
					#include "../logcat_entry.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, File& file);
 | 
				
			||||||
 | 
					static inline void import_logcat_entries_from_clipboard(LogcatEntries& logcat_entries, bool ignore_buffer_lines);
 | 
				
			||||||
 | 
					static void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, auto cb);
 | 
				
			||||||
 | 
					static inline std::optional<File> open_file_picker();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void import_fragment(LogcatEntries& logcat_entries) {
 | 
				
			||||||
 | 
					    static bool ignore_buffer_lines = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ImGui::Checkbox("Ignore buffer lines", &ignore_buffer_lines);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ImGui::Button("Import from File")) {
 | 
				
			||||||
 | 
					        std::optional<File> file = open_file_picker();
 | 
				
			||||||
 | 
					        if (file) {
 | 
				
			||||||
 | 
					            ImGui::CloseCurrentPopup();
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                import_logcat_entries(logcat_entries, ignore_buffer_lines, *file);
 | 
				
			||||||
 | 
					            } catch (const std::exception& e) {
 | 
				
			||||||
 | 
					                log(std::string("Failed to import logcat entries: ") + e.what());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ImGui::SameLine();
 | 
				
			||||||
 | 
					    if (ImGui::Button("Import from Clipboard")) {
 | 
				
			||||||
 | 
					        ImGui::CloseCurrentPopup();
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            import_logcat_entries_from_clipboard(logcat_entries, ignore_buffer_lines);
 | 
				
			||||||
 | 
					        } catch (const std::exception& e) {
 | 
				
			||||||
 | 
					            log(std::string("Failed to import logcat entries: ") + e.what());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, File& file) {
 | 
				
			||||||
 | 
					    auto handle_valid_char = [](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length, char c) -> std::optional<bool> {
 | 
				
			||||||
 | 
					        if (c == '\n') {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*line_length == MAX_LOGCAT_LINE_SIZE) {
 | 
				
			||||||
 | 
					            throw std::runtime_error("Received line longer than 512k");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line[*line_length] = c;
 | 
				
			||||||
 | 
					        (*line_length)++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return std::nullopt;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    auto handle_char = [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length, int c) -> std::optional<bool> {
 | 
				
			||||||
 | 
					        if (c != EOF) {
 | 
				
			||||||
 | 
					            return handle_valid_char(line, line_length, static_cast<char>(c));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (feof(file.get())) {
 | 
				
			||||||
 | 
					            return *line_length != 0;
 | 
				
			||||||
 | 
					        } else if (ferror(file.get())) {
 | 
				
			||||||
 | 
					            throw_system_error("fread()");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            throw std::runtime_error("fgetc() returned EOF without setting anything");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return std::nullopt;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    import_logcat_entries(logcat_entries, ignore_buffer_lines, [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length) {
 | 
				
			||||||
 | 
					        *line_length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (true) {
 | 
				
			||||||
 | 
					            int c = fgetc(file.get());
 | 
				
			||||||
 | 
					            std::optional<bool> ret = handle_char(line, line_length, c);
 | 
				
			||||||
 | 
					            if (ret) {
 | 
				
			||||||
 | 
					                return *ret;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void import_logcat_entries_from_clipboard(LogcatEntries& logcat_entries, bool ignore_buffer_lines) {
 | 
				
			||||||
 | 
					    const char* text = ImGui::GetClipboardText();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    import_logcat_entries(logcat_entries, ignore_buffer_lines, [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length) {
 | 
				
			||||||
 | 
					        if (!text) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const char* newline_offset = strchr(text, '\n');
 | 
				
			||||||
 | 
					        *line_length = newline_offset ? static_cast<size_t>(newline_offset - text) : strlen(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (*line_length > MAX_LOGCAT_LINE_SIZE) {
 | 
				
			||||||
 | 
					            throw std::runtime_error("Received line longer than 512k");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        memcpy(line, text, *line_length);
 | 
				
			||||||
 | 
					        text = newline_offset ? &newline_offset[1] : nullptr;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, auto cb) {
 | 
				
			||||||
 | 
					    char line[MAX_LOGCAT_LINE_SIZE];
 | 
				
			||||||
 | 
					    size_t line_length;
 | 
				
			||||||
 | 
					    Buffer buffer = Buffer::Unknown;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (cb(line, &line_length)) {
 | 
				
			||||||
 | 
					        if (line_length == 0) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::optional<LogcatEntry> logcat_entry = try_parse_logcat_entry(line, line_length, buffer);
 | 
				
			||||||
 | 
					        if (logcat_entry) {
 | 
				
			||||||
 | 
					            logcat_entries.push_back(std::move(*logcat_entry));
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::optional<Buffer> new_buffer = try_parse_buffer(line, line_length);
 | 
				
			||||||
 | 
					        if (new_buffer) {
 | 
				
			||||||
 | 
					            if (!ignore_buffer_lines) {
 | 
				
			||||||
 | 
					                buffer = *new_buffer;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        throw std::invalid_argument(std::string("Cannot parse line: ") + std::string(line, line_length));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline std::optional<File> open_file_picker() {
 | 
				
			||||||
 | 
					    nfdchar_t* path;
 | 
				
			||||||
 | 
					    nfdfilteritem_t filters[1] = {{"Log file", "log"}};
 | 
				
			||||||
 | 
					    nfdresult_t res = NFD_OpenDialog(&path, filters, 1, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (res == NFD_OKAY) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            File file(path, "r");
 | 
				
			||||||
 | 
					            NFD_FreePath(path);
 | 
				
			||||||
 | 
					            return std::move(file);
 | 
				
			||||||
 | 
					        } catch (const std::exception& e) {
 | 
				
			||||||
 | 
					            NFD_FreePath(path);
 | 
				
			||||||
 | 
					            log(std::string("Failed to open file from file picker: ") + e.what());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (res == NFD_CANCEL) {
 | 
				
			||||||
 | 
					        // dialog was canceled, shrug
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // ignore error when failing to open the file picker
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::nullopt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogcatEntries; // forward declaration from ../logcat_entry.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void import_fragment(LogcatEntries& logcat_entries);
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
#include "pcre2_wrapper.h"
 | 
					#include "pcre2_wrapper.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const Pcre2Regex LogcatEntryRegex(
 | 
					static const Pcre2Regex LogcatEntryRegex(
 | 
				
			||||||
    "^ *(\\d+)(?:\\.\\d+)?" // time
 | 
					    "^ *(?:(\\d+)(?:\\.\\d+)?|(\\d{4,})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2}))" // time and date
 | 
				
			||||||
    "(?: +([\\w\\d._-]+))?" // optional user
 | 
					    "(?: +([\\w\\d._-]+))?" // optional user
 | 
				
			||||||
    " +(\\d+)" // pid
 | 
					    " +(\\d+)" // pid
 | 
				
			||||||
    " +(\\d+)" // tid
 | 
					    " +(\\d+)" // tid
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@ static inline char to_char(Priority priority);
 | 
				
			||||||
static inline std::string rightpad(const std::string& str, size_t characters);
 | 
					static inline std::string rightpad(const std::string& str, size_t characters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline Priority priority_from(char c);
 | 
					static inline Priority priority_from(char c);
 | 
				
			||||||
 | 
					static inline int to_int(const char* str, const char* expected_end);
 | 
				
			||||||
static inline long to_long(const char* str, const char* expected_end);
 | 
					static inline long to_long(const char* str, const char* expected_end);
 | 
				
			||||||
static unsigned long long to_ull(const char* str, const char* expected_end);
 | 
					static unsigned long long to_ull(const char* str, const char* expected_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +79,7 @@ std::string to_string(const LogcatEntry& logcat_entry) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buffer buffer) {
 | 
					std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buffer buffer) {
 | 
				
			||||||
    regmatch_t matches[8];
 | 
					    regmatch_t matches[14];
 | 
				
			||||||
    matches[0].rm_so = 0;
 | 
					    matches[0].rm_so = 0;
 | 
				
			||||||
    matches[0].rm_eo = static_cast<regoff_t>(length);
 | 
					    matches[0].rm_eo = static_cast<regoff_t>(length);
 | 
				
			||||||
    if (static_cast<size_t>(matches[0].rm_eo) != length) {
 | 
					    if (static_cast<size_t>(matches[0].rm_eo) != length) {
 | 
				
			||||||
| 
						 | 
					@ -90,6 +91,7 @@ std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buff
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto group_exists = [](const regmatch_t& match) { return match.rm_so > -1 && match.rm_eo > -1; };
 | 
					    auto group_exists = [](const regmatch_t& match) { return match.rm_so > -1 && match.rm_eo > -1; };
 | 
				
			||||||
 | 
					    auto group_int = [&](const regmatch_t& match) { return to_int(&buf[match.rm_so], &buf[match.rm_eo]); };
 | 
				
			||||||
    auto group_long = [&](const regmatch_t& match) { return to_long(&buf[match.rm_so], &buf[match.rm_eo]); };
 | 
					    auto group_long = [&](const regmatch_t& match) { return to_long(&buf[match.rm_so], &buf[match.rm_eo]); };
 | 
				
			||||||
    auto group_ull = [&](const regmatch_t& match) { return to_ull(&buf[match.rm_so], &buf[match.rm_eo]); };
 | 
					    auto group_ull = [&](const regmatch_t& match) { return to_ull(&buf[match.rm_so], &buf[match.rm_eo]); };
 | 
				
			||||||
    auto group_string = [&](const regmatch_t& match) { return std::string(&buf[match.rm_so], static_cast<size_t>(match.rm_eo - match.rm_so)); };
 | 
					    auto group_string = [&](const regmatch_t& match) { return std::string(&buf[match.rm_so], static_cast<size_t>(match.rm_eo - match.rm_so)); };
 | 
				
			||||||
| 
						 | 
					@ -98,17 +100,33 @@ std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buff
 | 
				
			||||||
    // if pcre2 gives us negative offsets then i'll die
 | 
					    // if pcre2 gives us negative offsets then i'll die
 | 
				
			||||||
    LogcatEntry logcat_entry = {
 | 
					    LogcatEntry logcat_entry = {
 | 
				
			||||||
        .buffer   = buffer,
 | 
					        .buffer   = buffer,
 | 
				
			||||||
        // time to be set at the end
 | 
					        // time to be set later
 | 
				
			||||||
        .user     = group_exists(matches[2]) ? std::optional(group_string(matches[2])) : std::nullopt,
 | 
					        .user     = group_exists(matches[8]) ? std::optional(group_string(matches[8])) : std::nullopt,
 | 
				
			||||||
        .pid      = group_ull(matches[3]),
 | 
					        .pid      = group_ull(matches[9]),
 | 
				
			||||||
        .tid      = group_ull(matches[4]),
 | 
					        .tid      = group_ull(matches[10]),
 | 
				
			||||||
        .priority = group_priority(matches[5]),
 | 
					        .priority = group_priority(matches[11]),
 | 
				
			||||||
        .tag      = group_string(matches[6]),
 | 
					        .tag      = group_string(matches[12]),
 | 
				
			||||||
        .message  = group_string(matches[7]),
 | 
					        .message  = group_string(matches[13]),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (group_exists(matches[1])) {
 | 
				
			||||||
        time_t time = group_long(matches[1]);
 | 
					        time_t time = group_long(matches[1]);
 | 
				
			||||||
        localtime_r(&time, &logcat_entry.time);
 | 
					        localtime_r(&time, &logcat_entry.time);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        struct tm tm = {
 | 
				
			||||||
 | 
					            .tm_sec = group_int(matches[7]),
 | 
				
			||||||
 | 
					            .tm_min = group_int(matches[6]),
 | 
				
			||||||
 | 
					            .tm_hour = group_int(matches[5]),
 | 
				
			||||||
 | 
					            .tm_mday = group_int(matches[4]),
 | 
				
			||||||
 | 
					            .tm_mon = group_int(matches[3]),
 | 
				
			||||||
 | 
					            .tm_year = group_int(matches[2]) - 1900,
 | 
				
			||||||
 | 
					            .tm_isdst = -1,
 | 
				
			||||||
 | 
					            .tm_gmtoff = 0,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        time_t time = mktime(&tm) + tm.tm_gmtoff; // for some reason you have to add the local time offset?
 | 
				
			||||||
 | 
					        localtime_r(&time, &logcat_entry.time);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return std::move(logcat_entry);
 | 
					    return std::move(logcat_entry);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,6 +255,16 @@ static inline Priority priority_from(char c) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int to_int(const char* str, const char* expected_end) {
 | 
				
			||||||
 | 
					    long res = to_long(str, expected_end);
 | 
				
			||||||
 | 
					    if (res > INT_MAX) {
 | 
				
			||||||
 | 
					        throw std::overflow_error(std::string(str) + " is too big");
 | 
				
			||||||
 | 
					    } else if (res < INT_MIN) {
 | 
				
			||||||
 | 
					        throw std::underflow_error(std::string(str) + " is too small");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return static_cast<int>(res);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline long to_long(const char* str, const char* expected_end) {
 | 
					static inline long to_long(const char* str, const char* expected_end) {
 | 
				
			||||||
    char* endptr;
 | 
					    char* endptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Config; // forward declaration from config.h
 | 
					struct Config; // forward declaration from config.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_LOGCAT_LINE_SIZE 512 * 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Buffer {
 | 
					enum class Buffer {
 | 
				
			||||||
    Unknown = 0b1,
 | 
					    Unknown = 0b1,
 | 
				
			||||||
    Main = 0b10,
 | 
					    Main = 0b10,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ static void mark_nonblock(int fd) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void look_for_newlines(char buf[NEWLINE_BUF_SIZE], size_t* used, size_t previous_used,
 | 
					static inline void look_for_newlines(char buf[MAX_LOGCAT_LINE_SIZE], size_t* used, size_t previous_used,
 | 
				
			||||||
        void(LogcatThread::*handle_line)(char*, size_t, bool), LogcatThread* logcat_thread, bool is_stdout) {
 | 
					        void(LogcatThread::*handle_line)(char*, size_t, bool), LogcatThread* logcat_thread, bool is_stdout) {
 | 
				
			||||||
    size_t search_offset = previous_used;
 | 
					    size_t search_offset = previous_used;
 | 
				
			||||||
    size_t real_offset = 0;
 | 
					    size_t real_offset = 0;
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,7 @@ static inline void look_for_newlines(char buf[NEWLINE_BUF_SIZE], size_t* used, s
 | 
				
			||||||
static inline void handle_fd(int fd, char* buf, size_t* used,
 | 
					static inline void handle_fd(int fd, char* buf, size_t* used,
 | 
				
			||||||
        void(LogcatThread::*handle_line)(char*, size_t, bool), LogcatThread* logcat_thread, bool is_stdout) {
 | 
					        void(LogcatThread::*handle_line)(char*, size_t, bool), LogcatThread* logcat_thread, bool is_stdout) {
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
        ssize_t read_size_u = read(fd, &buf[*used], (NEWLINE_BUF_SIZE - *used) * sizeof(char));
 | 
					        ssize_t read_size_u = read(fd, &buf[*used], (MAX_LOGCAT_LINE_SIZE - *used) * sizeof(char));
 | 
				
			||||||
        if (read_size_u == 0) {
 | 
					        if (read_size_u == 0) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        } else if (read_size_u < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 | 
					        } else if (read_size_u < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 | 
				
			||||||
| 
						 | 
					@ -66,7 +66,7 @@ static inline void handle_fd(int fd, char* buf, size_t* used,
 | 
				
			||||||
            throw_system_error("read()");
 | 
					            throw_system_error("read()");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        size_t read_size = static_cast<size_t>(read_size_u) / sizeof(char);
 | 
					        size_t read_size = static_cast<size_t>(read_size_u) / sizeof(char);
 | 
				
			||||||
        if (*used + read_size > NEWLINE_BUF_SIZE) {
 | 
					        if (*used + read_size > MAX_LOGCAT_LINE_SIZE) {
 | 
				
			||||||
            throw std::runtime_error("Received line longer than 512k");
 | 
					            throw std::runtime_error("Received line longer than 512k");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        size_t previous_used = *used;
 | 
					        size_t previous_used = *used;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,6 @@
 | 
				
			||||||
#include "logcat_entry.h"
 | 
					#include "logcat_entry.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef std::variant<LogEntry, LogcatEntry> LogcatThreadItem;
 | 
					typedef std::variant<LogEntry, LogcatEntry> LogcatThreadItem;
 | 
				
			||||||
#define NEWLINE_BUF_SIZE 512 * 1024
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class LogcatProcessRequest {
 | 
					enum class LogcatProcessRequest {
 | 
				
			||||||
    None,
 | 
					    None,
 | 
				
			||||||
| 
						 | 
					@ -54,9 +53,9 @@ private:
 | 
				
			||||||
    int _stderr_read_fd = -1;
 | 
					    int _stderr_read_fd = -1;
 | 
				
			||||||
    int _stderr_write_fd = -1;
 | 
					    int _stderr_write_fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char _stdout_buf[NEWLINE_BUF_SIZE];
 | 
					    char _stdout_buf[MAX_LOGCAT_LINE_SIZE];
 | 
				
			||||||
    size_t _stdout_buf_used = 0;
 | 
					    size_t _stdout_buf_used = 0;
 | 
				
			||||||
    char _stderr_buf[NEWLINE_BUF_SIZE];
 | 
					    char _stderr_buf[MAX_LOGCAT_LINE_SIZE];
 | 
				
			||||||
    size_t _stderr_buf_used = 0;
 | 
					    size_t _stderr_buf_used = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pid_t _logcat_pid = -1;
 | 
					    pid_t _logcat_pid = -1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include "../logcat_entry.h"
 | 
					#include "../logcat_entry.h"
 | 
				
			||||||
#include "../logcat_thread.h"
 | 
					#include "../logcat_thread.h"
 | 
				
			||||||
#include "../fragments/export.h"
 | 
					#include "../fragments/export.h"
 | 
				
			||||||
 | 
					#include "../fragments/import.h"
 | 
				
			||||||
#include "main.h"
 | 
					#include "main.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void render_table_item_context_menu(const LogcatEntry& logcat_entry) {
 | 
					static inline void render_table_item_context_menu(const LogcatEntry& logcat_entry) {
 | 
				
			||||||
| 
						 | 
					@ -164,10 +165,12 @@ void main_window(bool latest_log_entries_read, ImFont* monospace_font, LogcatThr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImGui::SameLine();
 | 
					    ImGui::SameLine();
 | 
				
			||||||
    ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
 | 
					    ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImGui::SameLine();
 | 
					    ImGui::SameLine();
 | 
				
			||||||
    if (ImGui::Button("Clear")) {
 | 
					    if (ImGui::Button("Clear")) {
 | 
				
			||||||
        logcat_entries.clear();
 | 
					        logcat_entries.clear();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImGui::SameLine();
 | 
					    ImGui::SameLine();
 | 
				
			||||||
    if (ImGui::Button("Export")) {
 | 
					    if (ImGui::Button("Export")) {
 | 
				
			||||||
        ImGui::OpenPopup("export_logcat");
 | 
					        ImGui::OpenPopup("export_logcat");
 | 
				
			||||||
| 
						 | 
					@ -177,6 +180,15 @@ void main_window(bool latest_log_entries_read, ImFont* monospace_font, LogcatThr
 | 
				
			||||||
        ImGui::EndPopup();
 | 
					        ImGui::EndPopup();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ImGui::SameLine();
 | 
				
			||||||
 | 
					    if (ImGui::Button("Import")) {
 | 
				
			||||||
 | 
					        ImGui::OpenPopup("import_logcat");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ImGui::BeginPopup("import_logcat")) {
 | 
				
			||||||
 | 
					        import_fragment(logcat_entries);
 | 
				
			||||||
 | 
					        ImGui::EndPopup();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImGui::Separator();
 | 
					    ImGui::Separator();
 | 
				
			||||||
    // copied from imgui/imgui_demo.cpp: [SECTION] Example App: Debug Console / ShowExampleAppConsole()
 | 
					    // copied from imgui/imgui_demo.cpp: [SECTION] Example App: Debug Console / ShowExampleAppConsole()
 | 
				
			||||||
    // and [SECTION] Example App: Long Text / ShowExampleAppLongText()
 | 
					    // and [SECTION] Example App: Long Text / ShowExampleAppLongText()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue