2

I am beginning to teach myself C. I have run into a few bumps here and there but right now I am stumped by getOpt(). The main thing thats giving me trouble is when I try to make certain flags dependent on other flags. For example I want these to work:

./myfile -a -b -c blue

But none of the other options to work without -a. Thus ./myfile -b -c purple would be invalid. Is it possible for getopt to handle this kind of "flag dependent" criteria? How would I go about doing that? Secondly, lets say that no matter which flags are passed, along with it must be a colour.

So ./myfile -a -b green and ./myfile red are both valid. I understand that this all lies within the options parameter of getOpt() (which is currently set up to look something like this "abc"), but how would I make one parameter required for each instance without doing "a:b:c:" since this would not include the mandatory colour if no flags are passed.

sudobangbang
  • 1,406
  • 10
  • 32
  • 55
  • The first question (make -b only valid in combination with -a) is not possible with getopt - however it's easy to check that situation on your own when iterating over the given parameters. – maja Jan 25 '15 at 18:19
  • How would I iterate over the parameters? Im sorry, again very new to C. How can I iterate over parameters – sudobangbang Jan 25 '15 at 18:24
  • You always iterate over the parameters when you're using getopt. You are simply calling `getopt` multiple times. (Note that this function internally stores it's state, so it always knows which parameter to return next). abligh already posted an example. – maja Jan 25 '15 at 18:36

1 Answers1

1

Here's the example (from the manpage) of getopt:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
  int flags, opt;
  int nsecs, tfnd;

  nsecs = 0;
  tfnd = 0;
  flags = 0;
  while ((opt = getopt (argc, argv, "nt:")) != -1)
    {
      switch (opt)
        {
        case 'n':
          flags = 1;
          break;
        case 't':
          nsecs = atoi (optarg);
          tfnd = 1;
          break;
        default:               /* '?' */
          fprintf (stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
          exit (EXIT_FAILURE);
        }
    }

  printf ("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);

  if (optind >= argc)
    {
      fprintf (stderr, "Expected argument after options\n");
      exit (EXIT_FAILURE);
    }

  printf ("name argument = %s\n", argv[optind]);

  /* Other code omitted */

  exit (EXIT_SUCCESS);
}

Note you'll need to add some declarations, and a main() function to get that to work.

You can see the example n above is a flag, and works like your b option. The t option above takes a parameter and works like your c option. If you want to have an a option that is also a flag, you would make the getopt parameter "abf:" (i.e. add an a in without a colon), and a stanza to the switch like this:

         case 'a':
                 aflag = 1;
                 break;

having first set aflag to 0. At the end you would check for the illegal condition where other options were passed without aflag being set.

So all in all, it would look like this:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
  int flags, opt;
  int nsecs, tfnd;
  int aflag;

  nsecs = 0;
  tfnd = 0;
  flags = 0;
  aflag = 0;
  while ((opt = getopt (argc, argv, "ant:")) != -1)
    {
      switch (opt)
        {
        case 'a':
          aflag = 1;
          break;
        case 'n':
          flags = 1;
          break;
        case 't':
          nsecs = atoi (optarg);
          tfnd = 1;
          break;
        default:               /* '?' */
          fprintf (stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
          exit (EXIT_FAILURE);
        }
    }

  printf ("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);

  if (optind >= argc)
    {
      fprintf (stderr, "Expected argument after options\n");
      exit (EXIT_FAILURE);
    }

  if (!aflag && (flags || tfnd))
    {
      fprintf (stderr, "Must specify a flag to use n or t flag\n");
      exit (EXIT_FAILURE);
    }

  printf ("name argument = %s\n", argv[optind]);

  /* Other code omitted */

  exit (EXIT_SUCCESS);
}
abligh
  • 24,573
  • 4
  • 47
  • 84