0

OK, so basically I would like getopt_long to only modify a flag variable if the user supplied a command-line option to do so. Otherwise, I want the flag left alone. I've found a solution for this, but it's not very beautiful. In particular, if there are lots of flags, then this gets pretty verbose. Is there a better way?:

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

// I would like this function to only override myflag and myvariable if the user supplies them.
int parse_commandLineOptions(int argc, char *argv[], int *pointer_myflag){

  // Non-flag parameters "need" to be static or global to be accessible to getopt_long()
  static int set_myflag, unset_myflag;
  static struct option longopts[] = {

    // This is what I'd really like to do, but it's not permitted because myflag isn't static.
    // Do you haz teh codez?
    //{"set",        no_argument,       pointer_myflag, true},
    //{"unset",      no_argument,       pointer_myflag, false}

    // Instead this is the best I've come up with.
    {"set",          no_argument,       &set_myflag, 1},
    {"unset",        no_argument,       &unset_myflag, 1}
  };

  // This normally wouldn't be empty.
  char shortopts[] = "";

  int curChar=0;
  while(curChar!=-1){

    // Get the character representing the current command-line argument
    int option_index=0;
    curChar=getopt_long(argc, argv, shortopts, longopts, &option_index);
    if(curChar== -1)
      break;
    switch(curChar){

    // The user supplied one of the flag-setting options.
    case 0:
      break;

    // Normally I would parse non-flag parameters here.
    //case 'x':
    //  do something.

    // getopt_long will itself print an error message in this case.
    case '?':
      fprintf(stderr, "# Usage: not what you did.\n");
      exit(1);

    // This should never happen.
    default:
      fprintf(stderr, "# Error: Could not parse curChar in parse_commandLineOptions().\n");
      exit(1);

    } // Closes switch(curChar)

  } // Closes while(curChar!=-1)

  // Normally I would parse non-argument parameters here.

  // :(
  if(set_myflag) *pointer_myflag=1;
  else if(unset_myflag) *pointer_myflag=0;

  return 0;

}

int main(int argc, char *argv[]){

  // If the user supplies --set, myflag will be 1
  // If the user supplies --unset, myflag will be 0
  // If the user doesn't supply anything, myflag will be left as is.
  int myflag=1337;
  parse_commandLineOptions(argc, argv, &myflag);
  printf("myflag = %d\n", myflag);

}
Douglas B. Staple
  • 10,510
  • 8
  • 31
  • 58

2 Answers2

0

All I had to do was lose the static keyword on longopts!

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

// This function only overrides myflag and myvariable if the user supplies them.
int parse_commandLineOptions(int argc, char *argv[], int *pointer_myflag){

  // ALL YOUR BASE ARE BELONG TO US!
  struct option longopts[] = {
    {"set",        no_argument,       pointer_myflag, 1},
    {"unset",      no_argument,       pointer_myflag, 0}
  };

  // This normally wouldn't be empty.
  char shortopts[] = "";

  int curChar=0;
  while(curChar!=-1){

    // Get the character representing the current command-line argument
    int option_index=0;
    curChar=getopt_long(argc, argv, shortopts, longopts, &option_index);
    if(curChar== -1)
      break;
    switch(curChar){

    // The user supplied one of the flag-setting options.
    case 0:
      break;

    // Normally I would parse non-flag parameters here.
    //case 'x':
    //  do something.

    // getopt_long will itself print an error message in this case.
    case '?':
      fprintf(stderr, "# Usage: not what you did.\n");
      exit(1);

    // This should never happen.
    default:
      fprintf(stderr, "# Error: Could not parse curChar in parse_commandLineOptions().\n");
      exit(1);

    } // Closes switch(curChar)

  } // Closes while(curChar!=-1)

  // Normally I would parse non-argument parameters here.

  // :)
  return 0;

}

int main(int argc, char *argv[]){

  // If the user supplies --set, myflag will be 1
  // If the user supplies --unset, myflag will be 0
  // If the user doesn't supply anything, myflag will be left as is.
  int myflag=1337;
  parse_commandLineOptions(argc, argv, &myflag);
  printf("myflag = %d\n", myflag);

}
Douglas B. Staple
  • 10,510
  • 8
  • 31
  • 58
-1

Man, check out the code here. I think it is doing exactly what you want, except that it is not using true/false but integers instead.

In special, check theses lines:

/* Flag set by ‘--verbose’. */
static int verbose_flag;

static struct option long_options[] = {
    /* These options set a flag. */
    {"verbose", no_argument,       &verbose_flag, 1}, // HERE
    {"brief",   no_argument,       &verbose_flag, 0}, // AND HERE!
    /* These options don't set a flag.
    We distinguish them by their indices. */
    {"add",     no_argument,       0, 'a'},
    /* ... */
    {0, 0, 0, 0}
};

This is the approach that I used for my program:

/** Little hack to hide the enum from the global scope */
class EFlags {
    public:
        enum Type {
            HELP,
            FLAG_A,
            FLAG_B,
            COUNT
        };
};

/* Using static to keep everything private to my cpp file */
static int g_flags[EFlags::COUNT];

/** List of options accepted by the program */
static const struct option g_option_list[] = {
    /* These options set a flag. */
    { "help"        , no_argument       , &g_flags[EFlags::HELP]    , 1 },
    { "optionA"     , no_argument       , &g_flags[EFlags::FLAG_A]  , 1 },
    { "nooptionA"   , no_argument       , &g_flags[EFlags::FLAG_A]  , 0 },
    { "optionB"     , no_argument       , &g_flags[EFlags::FLAG_B]  , 1 },
    { "nooptionB"   , no_argument       , &g_flags[EFlags::FLAG_B]  , 0 }
    {0, 0, 0, 0}
};

int main( int argc, char * argc[] ) {
    for( int i = 0; i < EFlags::COUNT; i++ ) {
        g_flags[i] = 0;
    }

    ...
}
Canella
  • 444
  • 4
  • 15
  • That's very similar to the code I posted; the problem is how to do it (1) without a static flag and (2) without modifying the flag if the user passes no option. – Douglas B. Staple Jun 23 '14 at 23:42
  • (1): Well, the flag being static shouldn't really be a problem here... AFAIK, static will only make that variable private to the `cpp` file. In my own program, I used an array of flags, and declared an enum to index and loop through them. (2): If you want a default value, you can assign it to the variable when you declare it. In my array approach, I am zeroing the array during the program initialization, even though they should all contain zeros. – Canella Jun 24 '14 at 13:04
  • It is a considered a "best pratice" to leave a comment explaining why you are downvoting the answer. For the problem you posted, I believe that this answer is good enough. – Canella Jun 24 '14 at 13:23
  • Ok, I see the changes in your code. I didn't realize at the time that you were passing the flag by parameter. – Canella Jun 24 '14 at 13:31