-3

I'm trying to parse some arguments using getopt() like this:

char *fileName = "medit.db";
char c = ' ';

while((c = getopt(argc, argv, "f")) != -1){
    switch(c){
        case 'f':
            fileName = optarg;
            printf("%s\n\n", fileName);
            break;
    }
}

The thing is when I go to the command line and write

./server -f test

It just gives me a null result but if I write it like this

./server -ftest

All together it works just fine.

Any reason why this code wouldn't work like it intended?

EDIT: As an experiment I tried to put the colon like this f: It works as intended.. Can anyone explain this?

  • 2
    going off memory here, but don't you need to pass in `"f:"` to tell `getopt` to expect an argument after `-f`? – yano Oct 26 '18 at 16:53
  • that is correct if `f` has a *required* arg – Rafael Oct 26 '18 at 16:53
  • It should but it's an optional argument, if I dont specify the -f, it will just go to the default "medit.db" –  Oct 26 '18 at 16:54
  • not sure I understand the question then. You want to know why, given the code presented, `./server -f test` doesn't work but `./server -ftest` does work? If `-f` is an option argument, then use `"f:"` and either pass in `-f [filename]` or nothing at all. – yano Oct 26 '18 at 17:04
  • @yano I tried that as an experiment but I don't know why it worked –  Oct 26 '18 at 17:08
  • `"f:"` tells `getopt` "there's going to be an argument after `-f`, this isn't simply a flag", so it will point `optarg` to the next argument. In the case of `./server -ftest` it sees `argv[1]` has a `strlen` greater than `strlen("-f")`, so "next argument" means the rest of `argv[1]` after `-f`, so `optarg` points to `test`. In the case of `./server -f test` it sees that `argv[1]` is only `-f`, so it points `optarg` to the next argument, `argv[2]`. In either case, `"f:"` tells `getopt` to expect an argument after the `-f`, and it should throw you an error if you don't provide it. – yano Oct 26 '18 at 17:51
  • I don't know if `getopt` actually uses `strlen`, I haven't looked at the code, but that's the logic of what it's doing. `"f:"` doesn't tell `getopt` that the `-f` option is mandatory, it tells `getopt` that _if_ `-f` is provided, _then_ it _must_ have some additional data after it. – yano Oct 26 '18 at 17:53

2 Answers2

2

Just like getchar, getopt returns an int. Pretty much everything said there applies here too.

Prototype from getopt(3):

int getopt(int argc, char * const argv[], const char *optstring);

To declare f as requiring an argument:

If such a character is followed by a colon, the option requires an argument, so getopt() places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg.

I.e. the format is:

int c = ' ';

while((c = getopt(argc, argv, "f:")) != -1) {
    switch(c){
        case 'f':
            fileName = optarg;
            printf("%s\n\n", fileName);
            break;
    }
}
2

You need to put two colons AND you need to stop assigning optarg to fileName when an arg is not provided:

getopt(argc, argv, "f::")
case 'f':
    if (optarg)//CHECK FIRST
        fileName = optarg;
    printf("%s\n\n", fileName);
    break;

optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so getopt() places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option takes an optional arg;

Rafael
  • 7,605
  • 13
  • 31
  • 46
  • I know that i can put `::` to specify it's an optional argument but that's not the issue here.. What I meant was that if I don't use the `-f` bit, it just reverts to what's in the initializer –  Oct 26 '18 at 16:59
  • You NEED to tell the parser what to expect using two colons AND you should not assign to `fileName` if an argument is not present. Why are you doing that? – Rafael Oct 26 '18 at 17:21