• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 249
  • Last Modified:

Command Line

I once thought this was a simple exercise in cutting strings, but only now I started to comprehend how sophisticated this combina is.

OK, I have a command line string of an application (many, actually - TStrings, but I process them uno by uno). I need to strip them off their parameters and unify them (i.e. UpperCase(ExtractShortPathName())   ).

I use this function, and it is rather good, but it only works for 70 percent of the cases, the others seem to slip away. I have broken my head trying to find a common pattern to all the command line, but could not distinguish more than I already did(without actually searching for the files).

Function StripParams(Path:String):string;
Const
PossibleParams='/*?"><|';
var
Temp:String;
Posit,i:integer;
begin
  Temp:=Path;
    For i:=1 to Length(PossibleParams) do
      begin
        Posit:=pos(PossibleParams[i],Temp);
        if posit>0 then
          Temp:=Copy(Temp,1,Posit-1);
      end;
    //Maybe in Windows or Windows system directory and path not given?
    If ExtractFilePath(Temp)='' then
      begin
        if FileExists(MainForm.WinDir+Temp) then
          Temp:=MainForm.WinDir+Temp
        else if FileExists(MainForm.SysDir+Temp)then
          Temp:=MainForm.SysDir+Temp;
      end;
    Temp:=UpperCase(ExtractShortPathName(Temp));
   Result:=Temp;
end;



Here are some strings that slipped away(taken from my registry autorun section for sake of testing):

Rundll32.exe powrprof.dll,LoadCurrentPwrScheme
"C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe" -reg



Alright, as you see this func is far from perfect (the number 70 is just an estimate) so all suggestions for improvement would be welcome.
0
duke_n
Asked:
duke_n
  • 16
  • 11
  • 8
  • +1
1 Solution
 
bnemmersCommented:
Duke,

Have you look at two function
FindCmdLineSwitch and ParamStr in Sysutils.pas and System.pas
0
 
duke_nAuthor Commented:
this is no good.
'-' and ' ' can be part of a file or dir name also!
0
 
EpsylonCommented:
Then the job will be impossible. How do you know if -reg is a file/dir or a switch?
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
EpsylonCommented:
And if a file or dir has a ' ', it must be between double-quotes.
0
 
EpsylonCommented:
if I use you string as parameter and use this code

var i: Integer;
begin
  for i := 0 to ParamCount do
    Memo1.Lines.Add(Format('ParamStr(%d) = %s', [i, ParamStr(i)]));

I get this output:

ParamStr(0) = C:\WINDOWS\DESKTOP\PARAMS\PROJECT1.EXE
ParamStr(1) = Rundll32.exe
ParamStr(2) = powrprof.dll,LoadCurrentPwrScheme
ParamStr(3) = C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe
ParamStr(4) = -reg


A lot easier to handle IMHO.
0
 
duke_nAuthor Commented:
wait a second.
doesn't paramstr get the parameter string of the current application?

are you saying there is a way to apply it to an abstract string(Remember-I am not getting those command line strings as my command line param - but rather from inside the GUI)?
0
 
EpsylonCommented:
ParamStr(0) and Application.ExeNam contain the current app (see my previous comment).
0
 
duke_nAuthor Commented:
Yes, but I do not get these stringss into my app command line param (look MY previous comment :)  )
0
 
MadshiCommented:
I'm using these functions which work fine for me. Hmmm... They need my unit madStrings, which is available for free from my homepage. It's inside the "madBasic" package.

function ExtractExefile(pathWithPara: string) : string;
var c1 : cardinal;
begin
  result := pathWithPara;
  c1 := 0;
  repeat
    c1 := PosChars([' ','"'], result, c1 + 1);
    if (c1 > 0) and (result[c1] = '"') then
      c1 := PosStr('"', result, c1 + 1);
  until (c1 = 0) or (result[c1] = ' ');
  if c1 > 0 then Delete(result, c1, maxInt);
  KillChar(result, '"');
  TrimStr(result);
end;

function ExtractParameters(pathWithPara: string) : string;
var c1 : cardinal;
begin
  result := pathWithPara;
  c1 := 0;
  repeat
    c1 := PosChars([' ','"'], result, c1 + 1);
    if (c1 > 0) and (result[c1] = '"') then
      c1 := PosStr('"', result, c1 + 1);
  until (c1 = 0) or (result[c1] = ' ');
  if c1 > 0 then result := RetTrimStr(RetDelete(result, 1, c1))
  else           result := '';
end;

Regards, Madshi.

http://www.madshi.net
http://help.madshi.net/Data/madStringsUnit.htm
0
 
duke_nAuthor Commented:
Dude, your page has quite a design.
Bene, I will check it out.
0
 
duke_nAuthor Commented:
nope, both functions return '' in 100% of the cases.
0
 
MadshiCommented:
What!? I can't believe that! I just tested it again and it works perfectly!

Try this:

MessageBox(0, pchar(ExtractExeFile(cmdLine)), 'our exe', 0);

Regards, Madshi.
0
 
MadshiCommented:
Please recheck it, I'm absolutely sure that my functions do work correctly... Thank you...
0
 
duke_nAuthor Commented:
Oh, right :)
I forgot to do a lil' thing there.


However your function does not work always.
I keep getting 'C:\Program' out of everything from C:\program files\something
0
 
duke_nAuthor Commented:
I got an idea.
we can combine our 2 functions so that if mine returns bad stuff then we use yours and vise versa.
0
 
EpsylonCommented:
I've rewritten the ParamStr and ParamCount function:


function GetParamStr(P: PChar; var Param: string): PChar;
var
  Len: Integer;
  Buffer: array[0..4095] of Char;
begin
  while True do
  begin
    while (P[0] <> #0) and (P[0] <= ' ') do Inc(P);
    if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
  end;
  Len := 0;
  while (P[0] > ' ') and (Len < SizeOf(Buffer)) do
    if P[0] = '"' then
    begin
      Inc(P);
      while (P[0] <> #0) and (P[0] <> '"') do
      begin
        Buffer[Len] := P[0];
        Inc(Len);
        Inc(P);
      end;
      if P[0] <> #0 then Inc(P);
    end else
    begin
      Buffer[Len] := P[0];
      Inc(Len);
      Inc(P);
    end;
  SetString(Param, Buffer, Len);
  Result := P;
end;

function ParamCountEx(command: String): Integer;
var
  P: PChar;
  S: string;
begin
  P := GetParamStr(PChar(command), S);
  Result := 0;
  while True do
  begin
    P := GetParamStr(P, S);
    if S = '' then Break;
    Inc(Result);
  end;
end;

function ParamStrEx(Index: Integer; command: String): string;
var
  P: PChar;
  Buffer: array[0..260] of Char;
begin
  P := PChar(command);
  while True do
  begin
    P := GetParamStr(P, Result);
    if (Index = 0) or (Result = '') then Break;
    Dec(Index);
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
    s: String;
begin
  s := 'Rundll32.exe powrprof.dll,LoadCurrentPwrScheme "C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe" -reg';
  for i := 0 to ParamCountEx(s) do
    Memo1.Lines.Add(ParamStrEx(i, s));
end;
0
 
duke_nAuthor Commented:
Epsylon, the effectiveness of your string is exactly like madshi's. If a path has a space in it(i.e. Program Files), the path is whacked.
0
 
EpsylonCommented:
It works fine here as long as the entire path is between "".
0
 
EpsylonCommented:
There is no other way to know these part belong together without some pre-knowledge.
0
 
MadshiCommented:
Epsylon is right. But what you could do is this:

Check whether the exe returned by Epsylons or my function does exist (GetFileAttributes(...) <> dword(-1)). If yes, you're done. If not, append the first parameter to the exefile. Does it exist now? If yes, you're done. If not, append the second parameter to the exefile and so on...

Regards, Madshi.
0
 
duke_nAuthor Commented:
hmmm.
That is not a foolproof situation either. there could be a file or folder named c:\program .......


but I see that this is the best we can have.
OK, it is obvious how one appends later params with Epsylon's function, but it is not obvious how to do so with madshi's.

so I give Epsylon the pts.
0
 
MadshiCommented:
ok
0
 
duke_nAuthor Commented:
sorry, mate.
the bloody comp has stuck.
I will accept in a sec :)
0
 
EpsylonCommented:
Thanks  :o)
0
 
duke_nAuthor Commented:
Oops, haha, when I checked it, the idea didn't work :)

here is what I do:
    For i:=0 to ParamCountEx(Path) do
      if not FileExists(Temp) then
        Temp:=Temp+ParamStrEx(i,Path);


The reason it doesn't work is that it cuts out the param modifiers:
'C:\Program Files'='C:\Program'+'Files'='C:\ProgramFiles'.

so we are back where we were (My function up there ^ still is more effective, I think)
0
 
EpsylonCommented:
Madshi, did you get a notification of duke_n last comment? I didn't. There seems to be a major bug in EE  :o((((
0
 
EpsylonCommented:
duke_n, I'm puzzled... it cuts out param modifiers?
0
 
duke_nAuthor Commented:
I mean spaces,slashes and stuff.
does it not?
:)
0
 
duke_nAuthor Commented:
ah, the bug you've mentioned seems to be far worse.
did you know that I cannot see this question in my asked Qs list??
0
 
MadshiCommented:
Wow, just now I got notification about 2 comments. So I lost at least 3 notifications...   :-(
0
 
MadshiCommented:
About the problem: An ugly but possible solution would be this:

procedure SplitToExeFileAndParams(cmdLine: string; var exeFile, params: string);
var i1 : integer;
begin
  i1 := Length(ParamStrEx(1, cmdLine));
  while (i1 < Length(cmdLine)) and (not FileExists(Copy(cmdLine, 1, i1)) do
    inc(i1);
  exeFile := Copy(cmdLine, 1, i1);
  params  := Copy(cmdLine, i1 + 1, maxInt);
end;

Regards, Madshi.
0
 
EpsylonCommented:
> did you know that I cannot see this question in my asked Qs list??

Now you mention it, I've have that too.

EE is doomed! They don't fix anything.
0
 
MadshiCommented:
Ehm, the first code line should be this of course:

 i1 := Length(ParamStrEx(0, cmdLine));
0
 
duke_nAuthor Commented:
Yeah, they should hire us-fine programmers :)
0
 
duke_nAuthor Commented:
Madshi, this doesn't work(on the same stuff that my function doesn't work).

You know what, never mind. I see that my function was better than I thought it to be :)

I guess I will just leave it as it is
0
 
duke_nAuthor Commented:
And Epsylon, I think that EE has a special topic section for bug reports(that was a pretty smart thing to do for them, hehe).

I don't think that reporting these bugs in the Delphi section will get the Fixers' attention.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 16
  • 11
  • 8
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now