Search code examples
ccommand-line-argumentsgetopt-long

getopt_long `--' options does not work for switch statement


I have this c program which use getopt_long to parse - and -- options, but when i parse -- options the optarg does not work for the program. how can i assing the optarg value for the varibale if -- is parsed for the program.

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>


#include "file_handle.c"
//#include "songs.c"
#include "getoptions.c"

//Mix_Music *music = NULL;



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

  //init();

  int f = 0;
  int d = 0;
  char *file = NULL;
  char *directory = NULL;



  const struct option long_options[] = {
      /*
        {"verbose",no_argument,&verbose_flag,1}
      */
      {"help", no_argument, 0, 'h'},
      {"file", required_argument, &f, 'f'},
      {"directory", required_argument, &d, 'd'},
      {0, 0, 0, 0}
  };

  int opt;

  if (argc <= 1)
  {
    fprintf(stderr, "No arguments provided!\nTry 'cplay --help' for more information.\n");
  }
  else
  {
    while ((opt = getopt_long(argc, argv, "d:f:h", long_options, NULL)) != -1)
    {
      printf("optarg %s\n",optarg);
      switch(opt){
        case 'h':
          //print_help();
          break;
        case 'f':
          puts("test f");
          file = optarg;
          break;
        case 'd':
        
          directory = optarg;
          break;
       default:
          break;

      }
    }
  }


  if(f && d){
    printf("OPTION -f, --file and -d, --directory are given\n");
    printf("%s\n",directory);
    int valid = 0;
    char response;

    while(!valid)
    {
      printf("Enter one option [f\\d]: ");
      scanf(" %c",&response);

      if(response == 'd' || response == 'f'){
        valid = 1;
      }
      else
        printf("Wrong Input given press f for single file and d for directory option\n");
    }   

   
  }
  printf("%d\n %d",f,d);
 
  
   
}

Solution

  • Re: "the switch statement is only checking for the -h or -d or -f options."


    From the GNU manual:

    When getopt_long encounters a long option, it takes actions based on the flag and val fields of the definition of that option. The option name may be abbreviated as long as the abbreviation is unique.

    If flag is a null pointer, then getopt_long returns the contents of val to indicate which option it found.

    If flag (The third member of the struct option) is NULL, then getopt_long returns the contents of val (the fourth member of struct option) to indicate which option it found.

    So if the long option was --help, and the corresponding val member was assigned h, then getopt_long would return h.


    Some remarks:

    1. Typically, this condition:
    if(f && d)
    

    shouldn't be reached. Keep flags and check if the f flag is already given before assigning true to the d flag.

    bool f_flag = false;
    bool d_flag = false;
    

    Then check for the f_flag:

    ...
    case 'd':
          if (f_flag) {
              /* Both file and directory flags are 
              *  present. Print usage message and exit.
              */
          } else {
               strcpy (directory, optarg);
               break;
          }
    

    1. Given two pointers p and q, the statement:
    p = q;
    

    doesn't copy the contents of the memory pointed to by q to the contents of the memory pointed to by p. It copies the pointer values, such that both p and q now point to the same memory, and any change to the memory via p is reflected when q is used.

    So, given:

    file = optarg;
    

    and

    directory = optarg;
    

    these statements copies the pointer values, not the pointed to memory. This could be a problem if a subsequent operation modified argv, because it would change the memory pointed to by optarg and file / directory too.

    Instead, copy the memory to the pointers with strcpy():

    strcpy (file, optarg);
    strcpy (directory, optarg);