0

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);
 
  
   
}
devMe
  • 126
  • 10
  • yep it parses. but when i parse `--` the optarg does not save the argument for the variables – devMe Feb 05 '23 at 07:31
  • devMe, `file = optarg;` and `directory = optarg;` are questionable. Is not `optarg` changed after each `getopt_long_only()` call? Perhaps copy the string and not the pointer? That later `printf("%s\n",directory);` is a risk. – chux - Reinstate Monica Feb 05 '23 at 08:30
  • @chux-ReinstateMonica *`file = optarg;` and `directory = optarg;` are questionable* I think `file = optarg;` and similar might be fine. I *think* offhand that `optarg` points to the actual string in `argv`, so as long as the `argv` values passed to `getopt_long()` aren't modified, the pointer value copied from the value of `optarg` for that iteration is valid as it will still refer to something in `argv` even after `optarg` is assigned a new value for the next iteration. – Andrew Henle Feb 05 '23 at 09:59

1 Answers1

3

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);
Harith
  • 4,663
  • 1
  • 5
  • 20
  • I need to copy the optarg value when the user pass `--file` or `--directory` but when the `--` option is used the optarg doesn't copy the values because the switch statement is only checking for the `-h` or `-d` or `-f` options. how can i copy the optarg if the long options are parsed?. – devMe Feb 05 '23 at 09:56
  • so removing the flag and setting it to `0` fixed the issue. but what is the purpose of the flag?. – devMe Feb 05 '23 at 11:00
  • *"If flag is not a null pointer, it should be the address of an int variable which is the flag for this option. The value in val is the value to store in the flag to indicate that the option was seen"* – Harith Feb 05 '23 at 11:06
  • so why does setting flag doesn't return the value?. – devMe Feb 05 '23 at 11:24
  • It's used for a different purpose. See the manual: https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html – Harith Feb 05 '23 at 11:29