2

I'm working on a C program which uses getopt to read options, then iterates through the remainder of argc to read the non-optional arguments. Some of those non-optional arguments are numbers, some of which are negative. Common problem, I know, and I understand the fix is simply putting a "--" terminator between the end of the options and the beginning of the non-optional arguments. However, this doesn't seem to work with my current setup.

Here's the snippet of my code that reads the optional and non-optional arguments:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <math.h>

static const struct option longOpts[] = {
  {"inputconstheight", required_argument, 0, 'c'},
  {"inputheightfile", required_argument, 0, 'f'},
  {"alongtrackfile", required_argument, 0, 'g'},
  {"crosstrackfile", required_argument, 0, 'h'},
  {"lensconstant", required_argument, 0, 'm'},
  {"nonlinearoptics", required_argument, 0, 'n'},
  {"verbose", required_argument, 0, 'v'},
  {"rolloffset", required_argument, 0, 'x'},
  {"pitchoffset", required_argument, 0, 'y'},
  {"yawoffset", required_argument, 0, 'z'},
  {0, 0, 0, 0}
};

    int main(int argv, char **argc)
    {
    //skipping variable declaration for brevity
      while((opt = getopt_long(argv, argc, "cef:", longOpts, &longIndex))!=-1)
        {
          switch(opt)
        {
        case 'c': //constheight
          constantheightflag=1;
          constantheight=atof(optarg);
          break;
        case 'f': //inputheightfile
          constantheightflag=0;
          inputheightfilename=optarg;
          break;
        case 'g': //alongtrackfile
          inputalongtrackanglefilename=optarg;
          break;
        case 'h': //crosstrackfile
          inputcrosstrackanglefilename=optarg;
          break;
        case 'm': //lensconstant
          lensconstantflag=1;
          lensconstant=atof(optarg);
          break;
        case 'n': //nonlinearopticsflag
          nonlinearoptics=atoi(optarg);
          break;
        case 'v': //verbose
          verboseflag=1;
          break;
        case 'x': //rolloffset
          rolloffset=atof(optarg);
          break;
        case 'y': //pitchoffset
          pitchoffset=atof(optarg);
          break;
        case 'z': //yawoffset
          yawoffset=atof(optarg);
          break;
        case '?': 
          opterror=1;
          break;
        }
        }

      /*get non-optional arguments*/
      if((opterror==1)||((argv-optind)!=14)) {
        printf("Usage: geolocateplane -[cfghmnvxyz] -- outputlatfile outputlonfile imagexsize imageysize detectorxsize detectorysize fov_x fov_y lat lon alt roll pitch yaw\n");
        return 1;}
      else {
        outputlatfilename=argc[optind+0];
        outputlonfilename=argc[optind+1];
        imagexsize=atoi(argc[optind+2]);
        imageysize=atoi(argc[optind+3]);
        detectorxsize=atof(argc[optind+4]);
        detectorysize=atof(argc[optind+5]);
        fov_x=atof(argc[optind+6]);
        fov_y=atof(argc[optind+7]);
        cameralat=atof(argc[optind+8]);
        cameralon=atof(argc[optind+9]);
        cameraalt=atof(argc[optind+10]);
        cameraroll=atof(argc[optind+11]);
        camerapitch=atof(argc[optind+12]);
        camerayaw=atof(argc[optind+13]);
      }

Here is the function call and output:

XXXXXX:~/XXXX$ /XXX/geolocateplane --inputconstheight=0 --nonlinearoptics=0 --lensconstant=5.9982225412 --rolloffset=-1.0 --pitchoffset=-0.7 --yawoffset=0.0 --verbose -- /XXX/PACS.20130122.red.020756.lat.dat /XXX/PACS.20130122.red.020756.lon.dat 1024 1024 18.0 18.0 110 110 36.2927288472 -119.6177822504 19875.8 -0.3 0.7 -26.9
/XXX/geolocateplane: invalid option -- '1'
/XXX/geolocateplane: invalid option -- '1'
/XXX/geolocateplane: invalid option -- '9'
//etc...etc...

Any idea why this is happening, or what the fix is?

alk
  • 69,737
  • 10
  • 105
  • 255
Frank Harris
  • 305
  • 1
  • 6
  • 16
  • 2
    GNU `getopt()` doesn't work in a POSIX-ly correct manner unless you tell it to by setting POSIXLY_CORRECT=1 (any value does) in the environment. Though it should be OK because of the `--` unless the option preceding the `--` is supposed to an argument, in which case the `--` may be treated as the argument (to `--verbose`). You've not shown the long options data structure, sadly. – Jonathan Leffler Apr 30 '14 at 16:57
  • I added the data structure, and you solved my problem. I accidentally left --verbose as "required_argument." I changed it to "no_argument" and the code now works! Thanks! About the POSIXLY_CORRECT=1, is that a line I should add to my .bashrc? – Frank Harris Apr 30 '14 at 17:05
  • "*... in which case the -- may be treated as the argument (to --verbose).*" Got him ...;) @JonathanLeffler – alk Apr 30 '14 at 17:08
  • Up to you...probably not. One of the trickier problems I had to debug, a year or two ago, was someone else's script that failed when I ran it because I had POSIXLY_CORRECT in my environment and they did not expect that at all. In a sense, when you're using `getopt_long()`, POSIX correctness is immaterial; the whole long-option thing is not POSIX. You sometimes need to be aware of it. In this case, the trouble was the required argument. – Jonathan Leffler Apr 30 '14 at 17:08
  • @JonathanLeffler Will you put this in an answer? – Frank Harris Apr 30 '14 at 17:09

1 Answers1

3

Attempt 1

GNU getopt() doesn't work in a POSIX-ly correct manner unless you tell it to by setting POSIXLY_CORRECT=1 (any value does) in the environment. Having said that, your example should be OK because of the -- unless the option preceding the -- is supposed to take an argument, in which case the -- will be treated as the argument (to --verbose).

You've not shown the long options data structure, sadly.

Attempt 2

After the update, the problem is self-evident: --verbose was requiring an argument, so it did indeed chew up the -- as its option argument, leaving the rest of the line open to misinterpretation.

To set POSIXLY_CORRECT or not to set it

I'm not keen on the POSIX-ly incorrect behaviour, but other people like it. It means you have to be careful to use -- when you want the following arguments to be treated as non-option arguments.

However, setting POSIXLY_CORRECT can confuse things too. I have systems where I do and others where I don't set it. Both work.

On average, you're probably better off not setting it.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278