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.