View Issue Details

IDProjectCategoryView StatusLast Update
0019842FPCRTLpublic2019-01-19 20:58
ReporternicotuxAssigned ToMichael Van Canneyt 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
PlatformallOSallOS Versionall
Product Version2.4.5Product Buildall 
Target Version3.2.0Fixed in Version3.3.1 
Summary0019842: broken getopts misordering parameters when using permute flag
DescriptionParse of commandlines parameters is still not working. Order and indexes of non option parameters are not correct when permure flag is set. This is a very old issue athat affect every versions and the patch is easy and was send many times. I send it once more

Steps To ReproduceSimply take a look at any commandline tool with a little bit complex (anything will do) optionlist
Additional InformationPatch:

 getopts.pp:476

-inc(optind)
+inc(optind);
+if ordering=permute then
+ if (first_nonopt<>last_nonopt) and (last_nonopt<>optind) then
+ exchange;

Now fpc becomes usable for usefull commandline tools ;) this is a major issue in that it make potential users say fpc does not work after 2 or 3 first tests and thus fail to use it
TagsNo tags attached.
Fixed in Revision40908
FPCOldBugId
FPCTarget
Attached Files
  • test.pas (981 bytes)
    uses
      GetOpts;
    
    var
      Opts: array[1..2] of TOption;
      c: Char;
      L: Longint;
    
    begin
      with Opts[1] do
      begin
        name := 'aaa';
        has_arg:=0;
        flag:=nil;
        value:=#0;
      end;
      with Opts[2] do
      begin
        name := 'bbb';
        has_arg:=1;
        flag:=nil;
        value:=#0;
      end;
    
      c := #0;
      repeat
        c := getopts.GetLongOpts('ab:',@Opts[1],L);
        case c of
          #0 : begin
               write ('Long option : ',opts[L].name);
               if opts[L].has_arg>0 then
                 writeln (' : ',optarg)
               else
                 writeln
               end;
          'a' : writeln ('Option a.');
          'b' : writeln ('Option b :', optarg);
          '?',':' : writeln ('Error with opt : ',optopt);
       end; { case }
      until c = endofoptions;
      if optind<=paramcount then
      begin
        write ('Non options : ');
        while optind<=paramcount do
        begin
          write (paramstr(optind),' ');
          inc(optind)
        end;
        writeln;
      end;
    end.
    
    test.pas (981 bytes)
  • getopts.diff (433 bytes)
    Index: rtl/inc/getopts.pp
    ===================================================================
    --- rtl/inc/getopts.pp	(revision 40745)
    +++ rtl/inc/getopts.pp	(working copy)
    @@ -167,7 +167,7 @@
         if (top-middle>middle-bottom) then
           begin
           len:=middle-bottom;
    -      for i:=1 to len-1 do
    +      for i:=0 to len-1 do
             begin
             temp:=argv[bottom+i];
             argv[bottom+i]:=argv[top-(middle-bottom)+i];
    
    getopts.diff (433 bytes)

Activities

Marco van de Voort

2011-07-31 22:02

manager   ~0050319

Please submit a little program that demonstrates the bug.

Marco van de Voort

2011-08-21 19:39

manager   ~0051002

See above. I don't know this option too well, so I would like a program (and the arguments that trigger the problem)

nicotux

2011-10-16 09:34

reporter   ~0053039

Last edited: 2011-10-16 19:56

There is no need to write any example as every command line application is affected and this option is the default one.
To figure out the bug try "./bin2obj bin2obj -c prefix" which fails not being able to open prefix
Next try "./bin2obj - c prefix bin2obj" which works
assuming you are in the folder that contains 2bin2obj

Bart Broersma

2018-09-22 16:39

reporter  

test.pas (981 bytes)
uses
  GetOpts;

var
  Opts: array[1..2] of TOption;
  c: Char;
  L: Longint;

begin
  with Opts[1] do
  begin
    name := 'aaa';
    has_arg:=0;
    flag:=nil;
    value:=#0;
  end;
  with Opts[2] do
  begin
    name := 'bbb';
    has_arg:=1;
    flag:=nil;
    value:=#0;
  end;

  c := #0;
  repeat
    c := getopts.GetLongOpts('ab:',@Opts[1],L);
    case c of
      #0 : begin
           write ('Long option : ',opts[L].name);
           if opts[L].has_arg>0 then
             writeln (' : ',optarg)
           else
             writeln
           end;
      'a' : writeln ('Option a.');
      'b' : writeln ('Option b :', optarg);
      '?',':' : writeln ('Error with opt : ',optopt);
   end; { case }
  until c = endofoptions;
  if optind<=paramcount then
  begin
    write ('Non options : ');
    while optind<=paramcount do
    begin
      write (paramstr(optind),' ');
      inc(optind)
    end;
    writeln;
  end;
end.
test.pas (981 bytes)

Bart Broersma

2018-09-22 16:45

reporter   ~0110953

See attached sample program test.pas

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>fpc test.pas
Free Pascal Compiler version 3.1.1 [2018/07/18] for i386
Copyright (c) 1993-2018 by Florian Klaempfl and others
Target OS: Win32 for i386
...

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test -a -b bee NonOpt1 NonOpt2
Option a.
Option b :bee
Non options : NonOpt1 NonOpt2

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test -a NonOpt1 -b bee
Option a.
Option b :bee
Non options : bee [Expected: NonOpt1]

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test -a NonOpt1 NonOpt2 -b bee
Option a.
Option b :bee
Non options : NonOpt1 NonOpt2

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test --aaa --bbb bee NonOpt1 NonOpt2
Long option : aaa
Long option : bbb : bee
Non options : NonOpt1 NonOpt2

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test --aaa NonOpt1 --bbb bee
Long option : aaa
Long option : bbb : bee
Non options : bee [Expected: NonOpt1]

C:\Users\Bart\LazarusProjecten\bugs\Console\getopts>test --aaa NonOpt1 NonOpt2 --bbb bee
Long option : aaa
Long option : bbb : bee
Non options : NonOpt1 NonOpt2

Bart Broersma

2018-12-25 15:28

reporter   ~0112872

Last edited: 2018-12-25 23:03

View 2 revisions

Hope this helps:
test NA -b bee

It calls exchange with: first_nonopt=1 last_nonopt=2 optind=4
Exchange changes argv[] from NA -b bee into -b NA bee
Upon exit of exchange: first_nonopt=3 last_nonopt=4 optind=4

Output:
Option b: bee
Non options : bee

test NA NB -b bee
It calls exchange with: first_nonopt=1 last_nonopt=3 optind=5
Exchange changes argv[] from NA NB -b bee into -b bee NA NB
Upon exit of exchange: first_nonopt=3 last_nonopt=5 optind=5

Output:
Option b: bee
Non options : NA NB

Bart Broersma

2018-12-28 16:44

reporter   ~0112950

Can the "feedback" status be removed?
The reason for the feedback status was the request of a testprogram, which is provided.

Bart Broersma

2019-01-15 23:11

reporter   ~0113433

I tried the proposed fix (it's not a proper patch, but I think it should go in 5 lines from the bottom of the Internal_getopt function), and it does not fix the issue.

test NA -b bee

Still gives:

Option b: bee
Non options : bee

Bart Broersma

2019-01-16 16:14

reporter  

getopts.diff (433 bytes)
Index: rtl/inc/getopts.pp
===================================================================
--- rtl/inc/getopts.pp	(revision 40745)
+++ rtl/inc/getopts.pp	(working copy)
@@ -167,7 +167,7 @@
     if (top-middle>middle-bottom) then
       begin
       len:=middle-bottom;
-      for i:=1 to len-1 do
+      for i:=0 to len-1 do
         begin
         temp:=argv[bottom+i];
         argv[bottom+i]:=argv[top-(middle-bottom)+i];
getopts.diff (433 bytes)

Bart Broersma

2019-01-16 16:17

reporter   ~0113439

I attached a possible fix.

test NA -b bee will now give:

Option b: bee
Non options : NA

I'm not sure this is the correct fix though.

Michael Van Canneyt

2019-01-19 17:36

administrator   ~0113488

Fixed using your patch, it looks correct to me.
Cleaned up the IFDEF's somewhat.

Issue History

Date Modified Username Field Change
2011-07-31 15:24 nicotux New Issue
2011-07-31 22:02 Marco van de Voort Note Added: 0050319
2011-08-21 19:39 Marco van de Voort Note Added: 0051002
2011-08-21 19:39 Marco van de Voort Status new => feedback
2011-10-16 09:34 nicotux Note Added: 0053039
2011-10-16 19:56 nicotux Note Edited: 0053039
2018-09-22 16:39 Bart Broersma File Added: test.pas
2018-09-22 16:45 Bart Broersma Note Added: 0110953
2018-12-25 15:28 Bart Broersma Note Added: 0112872
2018-12-25 23:03 Bart Broersma Note Edited: 0112872 View Revisions
2018-12-28 15:09 Marco van de Voort Category Compiler => RTL
2018-12-28 16:44 Bart Broersma Note Added: 0112950
2019-01-14 15:08 Michael Van Canneyt Assigned To => Michael Van Canneyt
2019-01-14 15:08 Michael Van Canneyt Status feedback => assigned
2019-01-15 23:11 Bart Broersma Note Added: 0113433
2019-01-16 16:14 Bart Broersma File Added: getopts.diff
2019-01-16 16:17 Bart Broersma Note Added: 0113439
2019-01-19 17:36 Michael Van Canneyt Fixed in Revision => 40908
2019-01-19 17:36 Michael Van Canneyt Note Added: 0113488
2019-01-19 17:36 Michael Van Canneyt Status assigned => resolved
2019-01-19 17:36 Michael Van Canneyt Fixed in Version => 3.3.1
2019-01-19 17:36 Michael Van Canneyt Resolution open => fixed
2019-01-19 17:36 Michael Van Canneyt Target Version => 3.2.0