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:
optind step 2 over previous means the current option is expecting argument.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.