symBLOG home

Dealing with args using getopt() [Part.2]

4 July 2014 – Shanghai

In my previous post Dealing with args with getopt()[Part.1], I was very happy to find out a standard GNU library called getopt() which can help me out from the dirty job with commandline options.

Everything just work fine when you type in the options and arguments correctly. BUT the world is full of exceptions :( Below is my own commandline option setup:

Usage : soundView [-h] [-v volume] [-t Max_dB] [-f Floor_dB] filename

Let’s say I miss the volume argument after option -v, getopt won’t return ':' as promised. What actually happened is the next option -t was feeded as an argument for option -v, so the options after -v is totaly messed up! My code is tring to assign my variable: float volume = atof("-t") which always return 0.

Luckly I was able to get help from Stackoverflow . It’s a solution by manualy verify the optarg whether the first charator is "-" which solve my problem.

This is what my code piece finally looks like:

 1 //
 2 // Commandline argument processing
 3 //
 4 if(argc < 2){
 5     help();
 6     return 1;
 7 }
 8 
 9 // Setup default argument
10 paUserData.max_db = 80;
11 paUserData.floor_db = -180;
12 paUserData.volume = 0.2;
13 
14 int optionChar, prev_ind;
15 while(prev_ind = optind, (optionChar = getopt(argc,argv,"hv:t:f:"))!=EOF){
16     if(optind == prev_ind + 2 && *optarg == '-' && atof(optarg)==0){
17         optionChar = ':';
18         -- optind;
19     }
20     switch(optionChar){
21         case 'v':
22             paUserData.volume = atof(optarg);
23             cout << "Volume     :" << paUserData.volume << endl;
24             break;
25         case 'f':
26             paUserData.floor_db = atoi(optarg);
27             cout << "Floor dB   :" << paUserData.floor_db<< endl;
28             break;
29         case 't':
30             paUserData.max_db = atoi(optarg);
31             cout << "Max dB     :" << paUserData.max_db<< endl;
32             break;
33         case '?':
34         case ':':
35             cerr << "Argument error !" << endl;
36         case 'h':
37             help();
38             return 1;
39             break;
40     }
41 }
42 
43 char* fileName;
44 if(optind < argc){
45     fileName = argv[optind];
46 } else {
47     cout << "Sound file name must be specified." << endl;
48     return 1;
49 }

Still something to notice while reading the code above. First is the if statment

if(optind == prev_ind + 2 && *optarg == '-' && atof(optarg)==0){
    optionChar = ':';
    -- optind;
}

There are three conditions:

  1. If current optind step 2 over previous means the current option is expecting argument.
  2. the first charactor of the argument eq. “-”.
  3. make sure it is not a negative number :)

While all conditions match, manually set returning optionChar to “:” and step optind back 1, so the following options won’t be messed up.

Another things to be noticed, the last args index left after processed by getopt is the filename we supplied. Currently pointed by optind, use argv[optind] to acquire it.

comments powered by Disqus
Fork me on GitHub