Recent

Author Topic: Improvement of function TCustomApplication.FindOptionIndex  (Read 2192 times)

lagprogramming

  • Sr. Member
  • ****
  • Posts: 407
Improvement of function TCustomApplication.FindOptionIndex
« on: October 06, 2023, 01:29:42 pm »
packages/fcl-base/src/custapp.pp has
Code: Pascal  [Select][+][-]
  1. function TCustomApplication.FindOptionIndex(const S: String;
  2.   var Longopt: Boolean; StartAt : Integer = -1): Integer;
  3.  
  4. Var
  5.   SO,O : String;
  6.   I,P : Integer;
  7.  
  8. begin
  9.   If Not CaseSensitiveOptions then
  10.     SO:=UpperCase(S)
  11.   else
  12.     SO:=S;
  13.   Result:=-1;
  14.   I:=StartAt;
  15.   if (I=-1) then
  16.     I:=ParamCount;
  17.   While (Result=-1) and (I>0) do
  18.     begin
  19.     O:=Params[i];
  20.     // - must be seen as an option value
  21.     If (Length(O)>1) and (O[1]=FOptionChar) then
  22.       begin
  23.       Delete(O,1,1);
  24.       LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);
  25.       If LongOpt then
  26.         begin
  27.         Delete(O,1,1);
  28.         P:=Pos('=',O);
  29.         If (P<>0) then
  30.           O:=Copy(O,1,P-1);
  31.         end;
  32.       If Not CaseSensitiveOptions then
  33.         O:=UpperCase(O);
  34.       If (O=SO) then
  35.         Result:=i;
  36.       end;
  37.     Dec(i);
  38.     end;
  39. end;

1/4 The following lines contain a useless condition
Code: Pascal  [Select][+][-]
  1.     If (Length(O)>1) and (O[1]=FOptionChar) then
  2.       begin
  3.       Delete(O,1,1);
  4.       LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);
The condition (Length(O)>0) is always true because before deleting the first character using "Delete(O,1,1);" the length of variable O was at least 2(due to the "If (Length(O)>1)" condition).
So, "LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);" has been replaced with "LongOpt:=(O[1]=FOptionChar);".

2/4 After that, "If (P<>0) then O:=Copy(O,1,P-1);" has been replaced with "If P<>0 then SetLength(O,P-1);".

3/4 A -1 value is assigned to Result prior to the while loop and inside the loop the only place the Result value is modified is at the "Result:=i;" assignment. At the "Result:=i;" assignment, the value of variable I is guaranteed to be greater than zero due to the existence of the I>0 condition at the while loop. So, once we assign the value of I to Result, we can simply exit the routine because there's nothing else to be done.
So, "While (Result=-1) and (I>0) do" has been changed to "While I>0 do" by also changing "If (O=SO) then Result:=i;" with "If O=SO then Exit(I);".

4/4 When using a long option the code calls Delete(O,1,1) twice, which is a waste. It would have been nice to use a single Delete(O,1,1+ord(LongOpt)) call but according to a forum topic, optimizations using ord in order to get 0, 1 and -1 or not(0) values are not guaranteed for any targeted architecture. It's a programming practice without a documented support so the code had to be modified using the classic approach from:
Code: Pascal  [Select][+][-]
  1. Delete(O,1,1);
  2. LongOpt:=(O[1]=FOptionChar);
  3. If LongOpt then
  4.   begin
  5.   Delete(O,1,1);
  6.   P:=Pos('=',O);
  7.   If P<>0 then
  8.   SetLength(O,P-1);
  9.   end;
to
Code: Pascal  [Select][+][-]
  1. LongOpt:=(O[2]=FOptionChar);
  2. If LongOpt then
  3.   begin
  4.   Delete(O,1,2);
  5.   P:=Pos('=',O);
  6.   If P<>0 then
  7.     SetLength(O,P-1);
  8.   end
  9. else
  10.   Delete(O,1,1);

In the end, the function becomes
Code: Pascal  [Select][+][-]
  1. function TCustomApplication.FindOptionIndex(const S: String;
  2.   var Longopt: Boolean; StartAt : Integer = -1): Integer;
  3.  
  4. Var
  5.   SO,O : String;
  6.   I,P : Integer;
  7.  
  8. begin
  9.   If Not CaseSensitiveOptions then
  10.     SO:=UpperCase(S)
  11.   else
  12.     SO:=S;
  13.   Result:=-1;
  14.   I:=StartAt;
  15.   if I=-1 then
  16.     I:=ParamCount;
  17.   While I>0 do
  18.     begin
  19.     O:=Params[I];
  20.     // - must be seen as an option value
  21.     If (Length(O)>1) and (O[1]=FOptionChar) then
  22.       begin
  23.       LongOpt:=(O[2]=FOptionChar);
  24.       If LongOpt then
  25.         begin
  26.         Delete(O,1,2); // remove the leading -- characters of the option
  27.         P:=Pos('=',O);
  28.         If P<>0 then
  29.           SetLength(O,P-1);
  30.         end
  31.       else
  32.         Delete(O,1,1); // remove the leading - character of the option
  33.       If Not CaseSensitiveOptions then
  34.         O:=UpperCase(O);
  35.       If O=SO then
  36.         Exit(I);
  37.       end;
  38.     Dec(I);
  39.     end;
  40. end;

A patch is attached


 

TinyPortal © 2005-2018