From d9958ff5ff777854752dd4476bb5da76f4874ef0 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Thu, 22 Jan 2026 08:39:45 -0800 Subject: [PATCH] kicad-cli: Preprocess vector args argparse required long-form functions to use an equal sign to process a string like --rotate='-45,0,45' but would accept long-form args that didn't have a negative like --output test.png without the equal sign. Since this is an intrinsic limitation of our library, we work around it by detecting these vector forms and changing them into an equality under the hood. Fixes https://gitlab.com/kicad/code/kicad/-/issues/20191 (cherry picked from commit a9ce9da5511f8f0865181447f69b4227df61aac4) --- kicad/kicad_cli.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/kicad/kicad_cli.cpp b/kicad/kicad_cli.cpp index b045438116..68d42d5ac4 100644 --- a/kicad/kicad_cli.cpp +++ b/kicad/kicad_cli.cpp @@ -36,6 +36,8 @@ #include #include +#include +#include #include #include "pgm_kicad.h" @@ -297,6 +299,74 @@ static void printHelp( argparse::ArgumentParser& argParser ) } +/** + * Check if a string looks like a numeric vector value that happens to start with a minus sign. + * + * This handles values like "-45,0,45" or "-3.5,0,1.2" which are valid vector arguments + * but get misinterpreted by argparse as unknown options because they start with '-'. + */ +static bool looksLikeNegativeVectorValue( const std::string& aValue ) +{ + if( aValue.empty() || aValue[0] != '-' ) + return false; + + if( aValue.find( ',' ) == std::string::npos ) + return false; + + for( size_t i = 1; i < aValue.size(); ++i ) + { + char c = aValue[i]; + + if( !std::isdigit( c ) && c != '.' && c != ',' && c != '-' && c != '+' ) + return false; + } + + return true; +} + + +/** + * Pre-process command line arguments to handle negative numeric values. + * + * The argparse library interprets values starting with '-' as option flags. + * For arguments that accept vector values (like --rotate, --pan, --pivot), + * we wrap negative values in single quotes to prevent argparse from treating + * them as options. The parsing code in command_pcb_render.cpp already strips + * these quotes via getToVector3(). + * + * Example: "--rotate -45,0,45" becomes "--rotate='-45,0,45'" + */ +static std::vector preprocessArgs( int argc, char** argv ) +{ + std::vector result; + + static const std::set vectorArgs = { + "--rotate", "--pan", "--pivot" + }; + + for( int i = 0; i < argc; ++i ) + { + std::string current( argv[i] ); + + if( vectorArgs.count( current ) && i + 1 < argc ) + { + std::string next( argv[i + 1] ); + + if( looksLikeNegativeVectorValue( next ) ) + { + result.push_back( current + "='" + next + "'" ); + ++i; + continue; + } + } + + result.push_back( current ); + } + + return result; +} + + bool PGM_KICAD::OnPgmInit() { PGM_BASE::BuildArgvUtf8(); @@ -349,7 +419,11 @@ int PGM_KICAD::OnPgmRun() // Use the C locale to parse arguments // Otherwise the decimal separator for the locale will be applied LOCALE_IO dummy; - argParser.parse_args( m_argcUtf8, m_argvUtf8 ); + + // Pre-process arguments to handle negative vector values (e.g., --rotate -45,0,45) + // which argparse would otherwise interpret as unknown options + std::vector args = preprocessArgs( m_argcUtf8, m_argvUtf8 ); + argParser.parse_args( args ); } // std::runtime_error doesn't seem to be enough for the scan<>() catch( const std::exception& err )