Prefer Windows.GetCommandLine over ParamStr() when parsing command line parameters. ParamStr() removes double quotes.

This commit is contained in:
Ansgar Becker
2013-09-07 11:46:58 +00:00
parent 1006dbda2c
commit 7e9c433bf0
2 changed files with 53 additions and 44 deletions

View File

@ -299,7 +299,7 @@ type
procedure InheritFont(AFont: TFont); procedure InheritFont(AFont: TFont);
function GetLightness(AColor: TColor): Byte; function GetLightness(AColor: TColor): Byte;
function ReformatSQL(SQL: String): String; function ReformatSQL(SQL: String): String;
function ParamBlobToStr(lpData: Pointer): TStringlist; function ParamBlobToStr(lpData: Pointer): String;
function ParamStrToBlob(out cbData: DWORD): Pointer; function ParamStrToBlob(out cbData: DWORD): Pointer;
function CheckForSecondInstance: Boolean; function CheckForSecondInstance: Boolean;
function GetParentFormOrFrame(Comp: TWinControl): TWinControl; function GetParentFormOrFrame(Comp: TWinControl): TWinControl;
@ -321,8 +321,7 @@ type
function ErrorDialog(Msg: string): Integer; overload; function ErrorDialog(Msg: string): Integer; overload;
function ErrorDialog(const Title, Msg: string): Integer; overload; function ErrorDialog(const Title, Msg: string): Integer; overload;
function GetHTMLCharsetByEncoding(Encoding: TEncoding): String; function GetHTMLCharsetByEncoding(Encoding: TEncoding): String;
procedure ParseCommandLine(Parameters: TStringlist; procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
function f_(const Pattern: string; const Args: array of const): string; function f_(const Pattern: string; const Args: array of const): string;
function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String; function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String;
function GetOutputFilenamePlaceholders: TStringList; function GetOutputFilenamePlaceholders: TStringList;
@ -1843,36 +1842,22 @@ end;
// Slightly modified to better integrate that into our code, comments translated from german. // Slightly modified to better integrate that into our code, comments translated from german.
// Fetch and separate command line parameters into strings // Fetch and separate command line parameters into strings
function ParamBlobToStr(lpData: Pointer): TStringlist; function ParamBlobToStr(lpData: Pointer): String;
var var
pStr: PChar; pStr: PChar;
begin begin
Result := TStringlist.Create;
pStr := lpData; pStr := lpData;
while pStr[0] <> #0 do Result := string(pStr);
begin
Result.Add(string(pStr));
pStr := @pStr[lstrlen(pStr) + 1];
end;
end; end;
// Pack current command line parameters // Pack current command line parameters
function ParamStrToBlob(out cbData: DWORD): Pointer; function ParamStrToBlob(out cbData: DWORD): Pointer;
var var
Loop: Integer; cmd: String;
pStr: PChar;
begin begin
for Loop := 1 to ParamCount do cmd := Windows.GetCommandLine;
cbData := cbData + DWORD(Length(ParamStr(Loop))*2 + 1); cbData := Length(cmd)*2 + 3;
cbData := cbData + 2; // include appending #0#0 Result := PChar(cmd);
Result := GetMemory(cbData);
ZeroMemory(Result, cbData);
pStr := Result;
for Loop := 1 to ParamCount do
begin
lstrcpy(pStr, PChar(ParamStr(Loop)));
pStr := @pStr[lstrlen(pStr) + 1];
end;
end; end;
procedure HandleSecondInstance; procedure HandleSecondInstance;
@ -2407,28 +2392,52 @@ begin
end; end;
procedure ParseCommandLine(Parameters: TStringlist; procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
var ConnectionParams: TConnectionParameters; var FileNames: TStringList);
var var
rx: TRegExpr; rx: TRegExpr;
AllParams, SessName, Host, User, Pass, Socket: String; ExeName, SessName, Host, User, Pass, Socket: String;
i, Port: Integer; Port: Integer;
AbsentFiles: TStringList;
function GetParamValue(ShortName, LongName: String): String; function GetParamValue(ShortName, LongName: String): String;
begin begin
// Return one command line switch. Doublequotes are not mandatory.
Result := ''; Result := '';
rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')\s*\=?\s*\"([^\-][^\"]*)\"';
if rx.Exec(CommandLine) then
Result := rx.Match[2]
else begin
rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')\s*\=?\s*([^\-]\S*)'; rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')\s*\=?\s*([^\-]\S*)';
if rx.Exec(AllParams) then if rx.Exec(CommandLine) then
Result := rx.Match[2]; Result := rx.Match[2];
end; end;
end;
procedure GetFileNames(Expression: String);
begin
rx.Expression := Expression;
if rx.Exec(CommandLine) then while true do begin
if FileExists(rx.Match[1]) then
FileNames.Add(rx.Match[1])
else
AbsentFiles.Add(rx.Match[1]);
if not rx.ExecNext then
break;
end;
end;
begin begin
// Parse command line, probably sent by blocked second application instance.
// Try to build connection parameters out of it.
SessName := ''; SessName := '';
FileNames := TStringList.Create; FileNames := TStringList.Create;
AbsentFiles := TStringList.Create;
// Prepend a space, so the regular expression can request a mandantory space // Add leading (and trailing) space, so the regular expressions can request a mandantory space
// before each param name including the first one // before (and after) each param (and filename) including the first one (and last one)
AllParams := ' ' + ImplodeStr(' ', Parameters); ExeName := ExtractFileName(ParamStr(0));
CommandLine := Copy(CommandLine, Pos(ExeName, CommandLine)+Length(ExeName)+1, Length(CommandLine));
CommandLine := CommandLine + ' ';
rx := TRegExpr.Create; rx := TRegExpr.Create;
SessName := GetParamValue('d', 'description'); SessName := GetParamValue('d', 'description');
if SessName <> '' then begin if SessName <> '' then begin
@ -2441,7 +2450,6 @@ begin
SessName := ''; SessName := '';
end; end;
end; end;
end; end;
// Test if params were passed. If given, override previous values loaded from registry. // Test if params were passed. If given, override previous values loaded from registry.
@ -2471,11 +2479,15 @@ begin
ConnectionParams.SessionPath := ConnectionParams.Hostname; ConnectionParams.SessionPath := ConnectionParams.Hostname;
end; end;
// Check for valid filename(s) in parameters // Check for valid filename(s) in parameters.
for i:=0 to Parameters.Count-1 do begin // We support doublequoted and unquoted parameters.
if FileExists(Parameters[i]) then GetFileNames('\"([^\"]+\.sql)\"');
FileNames.Add(Parameters[i]); GetFileNames('\s([^\s\"]+\.sql)\b');
end; if AbsentFiles.Count > 0 then
ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text);
AbsentFiles.Free;
rx.Free;
end; end;

View File

@ -1695,7 +1695,7 @@ end;
} }
procedure TMainForm.AfterFormCreate; procedure TMainForm.AfterFormCreate;
var var
CmdlineParameters, LastSessions, FileNames: TStringlist; LastSessions, FileNames: TStringlist;
Connection: TDBConnection; Connection: TDBConnection;
LoadedParams, ConnectionParams: TConnectionParameters; LoadedParams, ConnectionParams: TConnectionParameters;
LastUpdatecheck, LastStatsCall, LastConnect: TDateTime; LastUpdatecheck, LastStatsCall, LastConnect: TDateTime;
@ -1765,10 +1765,7 @@ begin
end; end;
end; end;
CmdlineParameters := TStringList.Create; ParseCommandLine(Windows.GetCommandLine, ConnectionParams, FileNames);
for i:=1 to ParamCount do
CmdlineParameters.Add(ParamStr(i));
ParseCommandLine(CmdlineParameters, ConnectionParams, FileNames);
if Assigned(ConnectionParams) then begin if Assigned(ConnectionParams) then begin
// Minimal parameter for command line mode is hostname // Minimal parameter for command line mode is hostname
InitConnection(ConnectionParams, True, Connection); InitConnection(ConnectionParams, True, Connection);