Search code examples
ccommand-line-argumentsgetopt-long

getopt_long: only modify flag if user supplied command-line option


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);

}

Solution

  • 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);
    
    }