diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e1bf07..16d0000 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,7 @@ jobs: cmake --build . --config Release - name: Test binary exists + shell: bash run: | if [ "${{ matrix.os }}" == "windows-latest" ]; then test -f build/Release/smartproxy.exe || test -f build/smartproxy.exe diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69350f7..a8034a0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ jobs: cc: arm-linux-gnueabihf-gcc cxx: arm-linux-gnueabihf-g++ cross: true - cflags: -march=armv6 -mfpu=vfp -mfloat-abi=hard + cflags: -march=armv6 -mfpu=vfp -mfloat-abi=softfp -marm # Linux MIPS64 - os: ubuntu-latest target: linux diff --git a/CMakeLists.txt b/CMakeLists.txt index 43131f0..953f7c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,13 +49,19 @@ else() # Allow cross-compilation flags from environment if(CMAKE_CROSSCOMPILING) if(DEFINED ENV{CFLAGS}) - target_compile_options(smartproxy PRIVATE $ENV{CFLAGS}) + # Convert space-separated string to CMake list + string(REPLACE " " ";" CFLAGS_LIST "$ENV{CFLAGS}") + target_compile_options(smartproxy PRIVATE ${CFLAGS_LIST}) endif() if(DEFINED ENV{CXXFLAGS}) - target_compile_options(smartproxy PRIVATE $ENV{CXXFLAGS}) + # Convert space-separated string to CMake list + string(REPLACE " " ";" CXXFLAGS_LIST "$ENV{CXXFLAGS}") + target_compile_options(smartproxy PRIVATE ${CXXFLAGS_LIST}) endif() if(DEFINED ENV{LDFLAGS}) - target_link_options(smartproxy PRIVATE $ENV{LDFLAGS}) + # Convert space-separated string to CMake list + string(REPLACE " " ";" LDFLAGS_LIST "$ENV{LDFLAGS}") + target_link_options(smartproxy PRIVATE ${LDFLAGS_LIST}) endif() endif() endif() diff --git a/health.cpp b/health.cpp index 2ac304f..82630ab 100644 --- a/health.cpp +++ b/health.cpp @@ -1,6 +1,17 @@ #include "health.h" #include #include +#include + +// Undefine Windows min/max macros that conflict with std::min/std::max +#ifdef _WIN32 +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif +#endif HealthMonitor::HealthMonitor( std::shared_ptr runway_manager, diff --git a/logger.cpp b/logger.cpp index e9ae35e..039f27c 100644 --- a/logger.cpp +++ b/logger.cpp @@ -126,14 +126,22 @@ void Logger::close() { std::string Logger::format_timestamp(uint64_t timestamp) { std::time_t time_val = static_cast(timestamp); - std::tm* tm_info = std::localtime(&time_val); + std::tm tm_info; - if (!tm_info) { +#ifdef _WIN32 + // Use localtime_s on Windows (thread-safe) + if (localtime_s(&tm_info, &time_val) != 0) { return "0000-00-00 00:00:00"; } +#else + // Use localtime_r on POSIX (thread-safe) + if (localtime_r(&time_val, &tm_info) == nullptr) { + return "0000-00-00 00:00:00"; + } +#endif std::stringstream ss; - ss << std::put_time(tm_info, "%Y-%m-%d %H:%M:%S"); + ss << std::put_time(&tm_info, "%Y-%m-%d %H:%M:%S"); return ss.str(); } diff --git a/tui.cpp b/tui.cpp index 539e5b9..768f494 100644 --- a/tui.cpp +++ b/tui.cpp @@ -17,6 +17,13 @@ #include #include #include +// Undefine Windows min/max macros that conflict with std::min/std::max +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif #else #include #include @@ -24,6 +31,13 @@ #include #endif +// Cross-platform unused parameter macro +#ifdef _WIN32 +#define UNUSED_PARAM(x) +#else +#define UNUSED_PARAM(x) __attribute__((unused)) +#endif + TUI::TUI(std::shared_ptr runway_manager, std::shared_ptr routing_engine, std::shared_ptr tracker, @@ -344,65 +358,31 @@ void TUI::draw() { return; } - // Calculate available space with margins - int available_rows = rows - MARGIN_TOP - MARGIN_BOTTOM; - int available_cols = cols - MARGIN_LEFT - MARGIN_RIGHT; - - if (available_rows < 10 || available_cols < 60) { - std::cout << "\033[2J\033[1;1H"; - std::cout << "Terminal too small after margins\n"; - std::cout.flush(); - return; - } - // Build entire frame in stringstream for single atomic output std::stringstream output; output << "\033[2J\033[1;1H"; // Clear screen and move to top - // Add top margin (blank lines) - for (int i = 0; i < MARGIN_TOP; ++i) { - output << "\n"; - } - - // Helper lambda to add left margin - auto add_left_margin = [&]() { - for (int i = 0; i < MARGIN_LEFT; ++i) { - output << " "; - } - }; - // Draw detail view if active if (detail_view_) { - add_left_margin(); - draw_detail_view(output, available_cols, available_rows); + draw_detail_view(output, cols, rows); } else { // Status bar - add_left_margin(); - draw_status_bar(output, available_cols); + draw_status_bar(output, cols); // Tab bar - add_left_margin(); - draw_tab_bar(output, available_cols); + draw_tab_bar(output, cols); // Content area (remaining space) - use centralized constants - int content_h = available_rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; + int content_h = rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; // Content - add_left_margin(); - draw_content_area(output, available_cols, content_h); + draw_content_area(output, cols, content_h); // Summary bar - add_left_margin(); - draw_summary_bar(output, available_cols); + draw_summary_bar(output, cols); // Command bar - add_left_margin(); - draw_command_bar(output, available_cols); - } - - // Add bottom margin (blank lines) - for (int i = 0; i < MARGIN_BOTTOM; ++i) { - output << "\n"; + draw_command_bar(output, cols); } // Single atomic output for maximum responsiveness @@ -620,9 +600,9 @@ void TUI::draw_status_bar(std::stringstream& output, int cols) { " | Total: " + std::to_string(proxy_server_->get_total_connections()); // Calculate actual visible width (ANSI codes don't count) - int title_len = title.length(); - int status_len = status_text.length(); - int metrics_len = metrics.length(); + int title_len = static_cast(title.length()); + int status_len = static_cast(status_text.length()); + int metrics_len = static_cast(metrics.length()); int space_len = 1; // Space between status and metrics int total_content_len = title_len + status_len + metrics_len + space_len; @@ -716,7 +696,7 @@ void TUI::draw_content_area(std::stringstream& output, int cols, int max_rows) { // Table rendering helpers void TUI::draw_table_border(std::stringstream& output, const std::string& title, int cols) { output << "┌─ " << title; - int used = 3 + title.length(); + int used = 3 + static_cast(title.length()); for (int i = used; i < cols - 1; ++i) { output << "─"; } @@ -729,7 +709,7 @@ void TUI::draw_table_header(std::stringstream& output, const std::vector(header.length()) - 1; for (int i = 0; i < padding; ++i) { output << " "; } @@ -787,7 +767,7 @@ void TUI::draw_table_row(std::stringstream& output, const std::vector(cell.length()) - 1; for (int j = 0; j < padding; ++j) { output << " "; } @@ -1167,7 +1147,10 @@ void TUI::draw_stats_tab(std::stringstream& output, int cols, int /*max_rows*/) output << "┘\n"; } -void TUI::draw_help_tab(std::stringstream& output, int cols, int max_rows __attribute__((unused))) { +void TUI::draw_help_tab(std::stringstream& output, int cols, int max_rows UNUSED_PARAM(max_rows)) { +#ifdef _WIN32 + (void)max_rows; // Suppress unused parameter warning on Windows +#endif std::string title = "Help & Shortcuts"; draw_table_border(output, title, cols); @@ -1204,7 +1187,7 @@ void TUI::draw_help_tab(std::stringstream& output, int cols, int max_rows __attr for (const auto& shortcut : shortcuts) { output << "│ " << std::setw(12) << std::left << shortcut.first; output << " " << shortcut.second; - int used = 15 + shortcut.first.length() + shortcut.second.length(); + int used = 15 + static_cast(shortcut.first.length() + shortcut.second.length()); for (int i = used; i < cols - 1; ++i) output << " "; output << "│\n"; } @@ -1230,7 +1213,7 @@ void TUI::draw_help_tab(std::stringstream& output, int cols, int max_rows __attr for (const auto& op : mouse_ops) { output << "│ " << std::setw(15) << std::left << op.first; output << " " << op.second; - int used = 18 + op.first.length() + op.second.length(); + int used = 18 + static_cast(op.first.length() + op.second.length()); for (int i = used; i < cols - 1; ++i) output << " "; output << "│\n"; } @@ -1264,8 +1247,8 @@ void TUI::draw_summary_bar(std::stringstream& output, int cols) { std::string separator = " | "; // Calculate visible length (3 separators between 4 items) - int visible_len = stats_label.length() + runways_text.length() + targets_text.length() + - conns_text.length() + throughput_text.length() + (3 * separator.length()); + int visible_len = static_cast(stats_label.length() + runways_text.length() + targets_text.length() + + conns_text.length() + throughput_text.length() + (3 * separator.length())); // Output with ANSI codes for bold "Stats:" output << "\033[1m" << stats_label << "\033[0m"; @@ -1293,7 +1276,7 @@ void TUI::draw_command_bar(std::stringstream& output, int cols) { } output << command_text; - int used = command_text.length(); + int used = static_cast(command_text.length()); // Fill remaining space with background color fill_line_with_bg(output, used, cols, bg_color); @@ -1307,7 +1290,7 @@ void TUI::draw_detail_view(std::stringstream& output, int cols, int rows) { output << bg_color; std::string title = " Detail View "; output << title; - int used = title.length(); + int used = static_cast(title.length()); // Fill remaining space with background color fill_line_with_bg(output, used, cols, bg_color); @@ -1646,7 +1629,11 @@ void TUI::handle_mouse_click(int button, int x, int y) { } } -void TUI::handle_mouse_scroll(int direction, int x __attribute__((unused)), int y __attribute__((unused))) { +void TUI::handle_mouse_scroll(int direction, int x UNUSED_PARAM(x), int y UNUSED_PARAM(y)) { +#ifdef _WIN32 + (void)x; // Suppress unused parameter warning on Windows + (void)y; +#endif if (detail_view_ || current_tab_ == Tab::Stats || current_tab_ == Tab::Help) { return; } diff --git a/tui.h b/tui.h index 22813d3..d8ab998 100644 --- a/tui.h +++ b/tui.h @@ -129,11 +129,6 @@ class TUI { bool quit_confirmed_; // Quit confirmation flag // Layout constants - centralized for safe TUI rendering - // Change these to adjust margins dynamically - static constexpr int MARGIN_TOP = 1; - static constexpr int MARGIN_BOTTOM = 1; - static constexpr int MARGIN_LEFT = 2; - static constexpr int MARGIN_RIGHT = 2; static constexpr int STATUS_BAR_HEIGHT = 1; static constexpr int TAB_BAR_HEIGHT = 1; static constexpr int SUMMARY_BAR_HEIGHT = 1; diff --git a/tui_input.cpp b/tui_input.cpp index 8d06c30..6771ab7 100644 --- a/tui_input.cpp +++ b/tui_input.cpp @@ -6,19 +6,23 @@ #include #include #include -#include -#include -#include #ifdef _WIN32 #include #include +// Undefine Windows min/max macros that conflict with std::min/std::max +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif #else #include -#include -#include #include #include +#include +#include #endif // Non-blocking keyboard input handling (zero dependencies, standard library only) @@ -377,9 +381,8 @@ void TUI::navigate_page_up() { // Calculate visible items based on terminal size int rows = get_terminal_rows(); - // Account for margins and UI elements - use centralized constants - int available_rows = rows - MARGIN_TOP - MARGIN_BOTTOM; - int content_h = available_rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; + // Account for UI elements - use centralized constants + int content_h = rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; // Visible items in the content area (minus header and borders) int visible_items = content_h - 3; // Leave space for header and borders @@ -405,9 +408,8 @@ void TUI::navigate_page_down() { // Calculate visible items based on terminal size int rows = get_terminal_rows(); - // Account for margins and UI elements - use centralized constants - int available_rows = rows - MARGIN_TOP - MARGIN_BOTTOM; - int content_h = available_rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; + // Account for UI elements - use centralized constants + int content_h = rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; // Visible items in the content area (minus header and borders) int visible_items = content_h - 3; // Leave space for header and borders @@ -431,9 +433,8 @@ void TUI::navigate_half_page_up() { // Calculate visible items based on terminal size int rows = get_terminal_rows(); - // Account for margins and UI elements - use centralized constants - int available_rows = rows - MARGIN_TOP - MARGIN_BOTTOM; - int content_h = available_rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; + // Account for UI elements - use centralized constants + int content_h = rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; // Half page = half of visible items int visible_items = content_h - 3; @@ -461,9 +462,8 @@ void TUI::navigate_half_page_down() { // Calculate visible items based on terminal size int rows = get_terminal_rows(); - // Account for margins and UI elements - use centralized constants - int available_rows = rows - MARGIN_TOP - MARGIN_BOTTOM; - int content_h = available_rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; + // Account for UI elements - use centralized constants + int content_h = rows - STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT - SUMMARY_BAR_HEIGHT - COMMAND_BAR_HEIGHT; // Half page = half of visible items int visible_items = content_h - 3; diff --git a/utils.cpp b/utils.cpp index 5ce267a..d8cfade 100644 --- a/utils.cpp +++ b/utils.cpp @@ -10,9 +10,12 @@ #ifdef _WIN32 #include #include -#define mkdir(path, mode) _mkdir(path) +// On Windows, use _mkdir which takes only path parameter +#define MKDIR(path) _mkdir(path) #else #include +// On POSIX, use mkdir which takes path and mode parameters +#define MKDIR(path) mkdir(path, 0755) #endif #ifdef _WIN32 @@ -102,7 +105,8 @@ std::vector split(const std::string& str, char delimiter) { std::string to_lower(const std::string& str) { std::string result = str; - std::transform(result.begin(), result.end(), result.begin(), ::tolower); + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); return result; } @@ -189,15 +193,9 @@ bool create_directory(const std::string& path) { } // Create directory -#ifdef _WIN32 - if (mkdir(path.c_str()) == 0) { - return true; - } -#else - if (mkdir(path.c_str(), 0755) == 0) { + if (MKDIR(path.c_str()) == 0) { return true; } -#endif // Try to create parent directories if needed size_t pos = path.find_last_of("/\\"); @@ -205,11 +203,7 @@ bool create_directory(const std::string& path) { std::string parent = path.substr(0, pos); if (!parent.empty() && create_directory(parent)) { // Retry creating the directory -#ifdef _WIN32 - return mkdir(path.c_str()) == 0; -#else - return mkdir(path.c_str(), 0755) == 0; -#endif + return MKDIR(path.c_str()) == 0; } }