Question

I'm trying to parse two options in a C program.

The program is called like this:

./a.out [OPTIONS] [DIRECTORY 1] [DIRECTORY 2]

The program syncs two directories and has two options. (-r) for recursive syncing (folder inside folder), and (-n) to copy file from local to remote in case it doesn't exist in remote.

Options are:
-r : recursive
-n : copy file if it doesn't exist in remote folder

So calling:

./a.out -r D1 D2

would recursively sync all files and directories from D1 to D2. Files presents in D1 and not present in D2 are ignored.

And calling:

./a.cout -rn D1 D2

would do the same thing but files present in D1 and not present in D2 are copied to D2.

The problem is that calling ./a.out -rn is not the same as calling ./a.out -nr and ./a.out -r -n is not working neither because (-n) is not D1.

Here is how I implement the main.

int main(int argc, char** argv) {
  int next_option = 0;
  const char* const short_options = "hrn:";

  const struct option long_options[] = {
    { "help",      0, NULL,  'h' },
    { "recursive", 1, NULL,  'r' },
    { "new", 1, NULL,  'n' },
    { NULL,        0, NULL,  0   }
  };

  int recursive = 0;
  int new = 0;

  do {
    next_option = getopt_long(argc, argv, short_options, long_options, NULL);

    switch(next_option) {
      case 'r':
        recursive = 1;
        break;

      case 'n':
        new = 1;
        break;

      case 'h':
        print_help();
        return 0;

      case -1:
        break;

      default:
        print_help();
        return -1;
    }

  } while(next_option != -1);

  sync(argv[2], argv[3], recursive, new);

  return EXIT_SUCCESS;
}
Was it helpful?

Solution

You have two (potential) problems here:

  1. You have a stray : in your short option string. This makes -n take an option that swallows any following r. You also have the long options set to take mandatory arguments.

  2. You've hard coded the argument numbers in an inflexible way, and you don't test that they exist.

Try this:

int main(int argc, char** argv) {
  int next_option = 0;
  const char* const short_options = "hrn";
  extern int optind;

  const struct option long_options[] = {
    { "help",      no_argument, NULL,  'h' },
    { "recursive", no_argument, NULL,  'r' },
    { "new",       no_argument, NULL,  'n' },
    { NULL,        no_argument, NULL,  0   }
  };

  int recursive = 0;
  int new = 0;

  do {
    next_option = getopt_long(argc, argv, short_options, long_options, NULL);

    switch(next_option) {
      case 'r':
        recursive = 1;
        break;

      case 'n':
        new = 1;
        break;

      case 'h':
        print_help();
        return 0;

      case -1:
        break;

      default:
        print_help();
        return -1;
    }

  } while(next_option != -1);

  if (optind + 1 >= argc)
    return -1;

  sync(argv[optind], argv[optind+1], recursive, new);

  return EXIT_SUCCESS;
}

OTHER TIPS

The problem with using a command line such as -r -n is because you have hard-coded the indexes in the call to sync. You should not do that.

If you read the getopt_long manual page (always do when you have problems with a function!) then you would notice this line:

If there are no more option characters, getopt() returns -1. Then optind is the index in argv of the first argv-element that is not an option.

Read the second sentence carefully.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top