Skip to content

Commit f436354

Browse files
committed
fix: when parsing the command line, make use of Application.GetOptionValue and friends, instead of ParamStr(x) with regular expressions
- Fixes broken detection of argument values with spaces - Removes some short options with two or more chars, which is not supported by GetOptionValue - Short options now must not have an equal sign: -h localhost - Long options now require en equal sign: --host=localhost
1 parent 51023c3 commit f436354

2 files changed

Lines changed: 52 additions & 87 deletions

File tree

source/apphelpers.pas

Lines changed: 50 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ TAppSettings = class(TObject)
411411
function ErrorDialog(const Title, Msg: string): Integer; overload;
412412
function GetLocaleString(const ResourceId: Integer): String;
413413
function GetHTMLCharsetByEncoding(Encoding: TEncoding): String;
414-
procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String);
414+
procedure ParseCommandLine(var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
415415
procedure InitMoFile(LangCode: String);
416416
function _(const Pattern: string): string;
417417
function f_(const Pattern: string; const Args: array of const): string;
@@ -2502,63 +2502,30 @@ function GetHTMLCharsetByEncoding(Encoding: TEncoding): String;
25022502
end;
25032503

25042504

2505-
procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String);
2505+
procedure ParseCommandLine(var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
2506+
const
2507+
ShortOpts: String = 'd:n:h:l:u:p:S:P:';
2508+
LongOpts: array[0..24] of String = (
2509+
'description:',
2510+
'nettype:', 'host:', 'library:', 'user:', 'password:', 'cleartextenabled:', 'socket:', 'port:', 'databases:', 'winauth:',
2511+
'ssl:', 'sslprivatekey:', 'sslcacertificate:', 'sslcertificate:', 'sslcipher:', 'sslverification:',
2512+
'ssh-executable:', 'ssh-host:', 'ssh-port:', 'ssh-local-port:', 'ssh-user:', 'ssh-password:', 'ssh-key:', 'ssh-timeout:'
2513+
);
25062514
var
2507-
rx: TRegExpr;
2508-
ExeName, SessName, Host, Lib, Port, User, Pass, Socket, AllDatabases,
2515+
i: Integer;
2516+
SessName, Host, Lib, Port, User, Pass, Socket, AllDatabases,
25092517
SSLPrivateKey, SSLCACertificate, SSLCertificate, SSLCipher,
25102518
SshExe, SshHost, SshPort, SshLocalPort, SshUser, SshPassword, SshKey, SshTimeout: String;
25112519
NetType, WindowsAuth, WantSSL, CleartextPluginEnabled, SSLVerification: Integer;
25122520
AbsentFiles: TStringList;
2513-
2514-
function GetParamValue(ShortName, LongName: String): String;
2515-
begin
2516-
// Return one command line switch. Doublequotes are not mandatory.
2517-
Result := '';
2518-
rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')[\s\=]\"([^\"]+)\"';
2519-
if rx.Exec(CommandLine) then
2520-
Result := rx.Match[2]
2521-
else begin
2522-
rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')[\s\=](\S+)';
2523-
if rx.Exec(CommandLine) then
2524-
Result := rx.Match[2];
2525-
end;
2526-
end;
2527-
2528-
procedure GetFileNames(Expression: String);
2529-
begin
2530-
rx.Expression := Expression;
2531-
if rx.Exec(CommandLine) then while true do begin
2532-
if FileExists(rx.Match[1]) then
2533-
FileNames.Add(rx.Match[1])
2534-
else
2535-
AbsentFiles.Add(rx.Match[1]);
2536-
// Remove match from input string, so the second call to GetFileNames without quotes
2537-
// does not detect filenames cut at whitespace
2538-
Delete(CommandLine, rx.MatchPos[1], rx.MatchLen[1]);
2539-
if not rx.ExecNext then
2540-
break;
2541-
end;
2542-
end;
2543-
25442521
begin
2545-
// Parse command line, probably sent by blocked second application instance.
2522+
// Parse command line
25462523
// Try to build connection parameters out of it.
25472524
SessName := '';
25482525
FileNames := TStringList.Create;
25492526
AbsentFiles := TStringList.Create;
25502527

2551-
// Add leading (and trailing) space, so the regular expressions can request a mandantory space
2552-
// before (and after) each param (and filename) including the first one (and last one)
2553-
ExeName := ExtractFileName(ParamStr(0));
2554-
CommandLine := Copy(CommandLine, Pos(ExeName, CommandLine)+Length(ExeName), Length(CommandLine));
2555-
CommandLine := CommandLine + ' ';
2556-
rx := TRegExpr.Create;
2557-
2558-
// --runfrom=scheduler after build update
2559-
RunFrom := GetParamValue('rf', 'runfrom');
2560-
2561-
SessName := GetParamValue('d', 'description');
2528+
SessName := Application.GetOptionValue('d', 'description');
25622529
if SessName <> '' then begin
25632530
try
25642531
ConnectionParams := TConnectionParameters.Create(SessName);
@@ -2572,31 +2539,31 @@ procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectio
25722539

25732540
// Test if params were passed. If given, override previous values loaded from registry.
25742541
// Enables the user to log into a session with a different, non-stored user: -dSession -uSomeOther
2575-
NetType := StrToIntDef(GetParamValue('n', 'nettype'), 0);
2576-
Host := GetParamValue('h', 'host');
2577-
Lib := GetParamValue('l', 'library');
2578-
User := GetParamValue('u', 'user');
2579-
Pass := GetParamValue('p', 'password');
2580-
CleartextPluginEnabled := StrToIntDef(GetParamValue('cte', 'cleartextenabled'), -1);
2581-
Socket := GetParamValue('S', 'socket');
2582-
Port := GetParamValue('P', 'port');
2583-
AllDatabases := GetParamValue('db', 'databases');
2584-
WindowsAuth := StrToIntDef(GetParamValue('W', 'winauth'), -1);
2585-
WantSSL := StrToIntDef(GetParamValue('ssl', 'ssl'), -1);
2586-
SSLPrivateKey := GetParamValue('sslpk', 'sslprivatekey');
2587-
SSLCACertificate := GetParamValue('sslca', 'sslcacertificate');
2588-
SSLCertificate := GetParamValue('sslcert', 'sslcertificate');
2589-
SSLCipher := GetParamValue('sslcip', 'sslcipher');
2590-
SSLVerification := StrToIntDef(GetParamValue('sslvrf', 'sslverification'), -1);
2542+
NetType := StrToIntDef(Application.GetOptionValue('n', 'nettype'), 0);
2543+
Host := Application.GetOptionValue('h', 'host');
2544+
Lib := Application.GetOptionValue('l', 'library');
2545+
User := Application.GetOptionValue('u', 'user');
2546+
Pass := Application.GetOptionValue('p', 'password');
2547+
CleartextPluginEnabled := StrToIntDef(Application.GetOptionValue('cleartextenabled'), -1);
2548+
Socket := Application.GetOptionValue('S', 'socket');
2549+
Port := Application.GetOptionValue('P', 'port');
2550+
AllDatabases := Application.GetOptionValue('databases');
2551+
WindowsAuth := StrToIntDef(Application.GetOptionValue('winauth'), -1);
2552+
WantSSL := StrToIntDef(Application.GetOptionValue('ssl'), -1);
2553+
SSLPrivateKey := Application.GetOptionValue('sslprivatekey');
2554+
SSLCACertificate := Application.GetOptionValue('sslcacertificate');
2555+
SSLCertificate := Application.GetOptionValue('sslcertificate');
2556+
SSLCipher := Application.GetOptionValue('sslcipher');
2557+
SSLVerification := StrToIntDef(Application.GetOptionValue('sslverification'), -1);
25912558
// Leave out support for startup script, seems reasonable for command line connecting
2592-
SshExe := GetParamValue('se', 'ssh-executable');
2593-
SshHost := GetParamValue('sh', 'ssh-host');
2594-
SshPort := GetParamValue('sP', 'ssh-port');
2595-
SshLocalPort := GetParamValue('sLP', 'ssh-local-port');
2596-
SshUser := GetParamValue('su', 'ssh-user');
2597-
SshPassword := GetParamValue('sp', 'ssh-password');
2598-
SshKey := GetParamValue('sk', 'ssh-key');
2599-
SshTimeout := GetParamValue('st', 'ssh-timeout');
2559+
SshExe := Application.GetOptionValue('ssh-executable');
2560+
SshHost := Application.GetOptionValue('ssh-host');
2561+
SshPort := Application.GetOptionValue('ssh-port');
2562+
SshLocalPort := Application.GetOptionValue('ssh-local-port');
2563+
SshUser := Application.GetOptionValue('ssh-user');
2564+
SshPassword := Application.GetOptionValue('ssh-password');
2565+
SshKey := Application.GetOptionValue('ssh-key');
2566+
SshTimeout := Application.GetOptionValue('ssh-timeout');
26002567

26012568
if (Host <> '') or (User <> '') or (Pass <> '') or (Port <> '') or (Socket <> '') or (AllDatabases <> '') then begin
26022569
if not Assigned(ConnectionParams) then begin
@@ -2668,14 +2635,21 @@ procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectio
26682635
end;
26692636

26702637
// Check for valid filename(s) in parameters.
2671-
// We support doublequoted and unquoted parameters.
2672-
GetFileNames('\"([^\"]+\.sql)\"');
2673-
GetFileNames('\s([^\s\"]+\.sql)\b');
2638+
try
2639+
Application.GetNonOptions(ShortOpts, LongOpts, FileNames);
2640+
except
2641+
on E:EListError do
2642+
ErrorDialog(E.Message);
2643+
end;
2644+
for i:=FileNames.Count-1 downto 0 do begin
2645+
if (not Filenames[i].EndsWith('.sql', True)) or (not FileExists(Filenames[i])) then begin
2646+
AbsentFiles.Add(Filenames[i]);
2647+
Filenames.Delete(i);
2648+
end;
2649+
end;
26742650
if AbsentFiles.Count > 0 then
26752651
ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text);
26762652
AbsentFiles.Free;
2677-
2678-
rx.Free;
26792653
end;
26802654

26812655

source/main.pas

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,7 +2156,7 @@ procedure TMainForm.AfterFormCreate;
21562156
LoadedParams, ConnectionParams: TConnectionParameters;
21572157
LastUpdatecheck, LastStatsCall, LastConnect: TDateTime;
21582158
UpdatecheckInterval, i: Integer;
2159-
LastActiveSession, Environment, RunFrom: String;
2159+
LastActiveSession, Environment: String;
21602160
frm : TfrmUpdateCheck;
21612161
StatsCall: THttpDownload;
21622162
StatsURL: String;
@@ -2227,17 +2227,8 @@ procedure TMainForm.AfterFormCreate;
22272227
end;
22282228

22292229
ConnectionParams := nil;
2230-
RunFrom := '';
22312230
FileNames := nil;
2232-
ParseCommandLine(GetCommandLine, ConnectionParams, FileNames, RunFrom);
2233-
2234-
// Delete scheduled task from previous
2235-
if RunFrom = 'scheduler' then begin
2236-
//DeleteRestartTask;
2237-
if HasDonated(False) <> nbTrue then begin
2238-
apphelpers.ShellExec(APPDOMAIN + 'after-updatecheck?rev=' + AppVerRevision.ToString);
2239-
end;
2240-
end;
2231+
ParseCommandLine(ConnectionParams, FileNames);
22412232

22422233
if ConnectionParams <> nil then begin
22432234
// Minimal parameter for command line mode is hostname

0 commit comments

Comments
 (0)