Lesson 11 - Command Lines
11.1 Accessing command line arguments
// ex11-1 - accessing command line arguments
#include <iostream>
#include <string>
using namespace std;
int main(int argc,char *argv[])
{
cout << "argc=" << argc << endl;
for (int i=1;i<argc;i++)
cout << "argv[" << i << "]="
<< argv[i] << endl;
return(0);
}
|
ex11-1 hello testing one two
argc=5
argv[1]=hello
argv[2]=testing
argv[3]=one
argv[4]=two
|
Example ex11-1 shows how a C++ program can gain access to 'program arguments',
that is any information put on the command line after the name of the program
itself. Such arguments are commonly used to specify, for example,
the names of any files on which the program is to operate, or to specify
any different modes of operation of the program. Thus the command
line:
XCOPY *.CPP A:\
is a MS-DOS command which executes the program XCOPY with two arguments:
'*.CPP' which means 'all files with names ending in .CPP' and 'A:\' which
is the name of the root directory on the diskette drive. The program
XCOPY retrieves these two arguments to work out exactly what copying function
is required.
As you might expect, the command line arguments are provided as arguments
to the main function. However they are not supplied, as you could
reasonably have expected, as a string variable, but as a more primitive
array type of primitive 'C' string objects. This is just a historical
hang-over from how access to the program arguments was performed in the
'C' language. Nevertheless, apart from the declaration of the main
function, access to the strings is fairly straightforward.
The main function must be declared as taking two arguments, one to
hold the number of strings passed to main(), and one to hold a table of
string 'pointers'. Thus the declaration
int main(int argc,char *argv[])
can be read as declaring a function called main, of type int, that takes
two arguments: the first 'argc' is the argument count and is of type int,
while the second 'argv' is a variable-length array '[]' of pointers '*' to arguments
stored as characters 'char'.
This aside, you can see that we can access each of the arguments with
the [] indexing notation we used for vectors. Furthermore argc contains
the total number of words on the command line, including the name of the
program itself. Thus the actual arguments are in indexes from 1 to
argc-1. The element argv[0] normally contains the name of the program,
but this shouldn't be relied upon - anyway it is unusual for a program
not to know its own name! |
11.2 Accessing command line arguments as a vector
// ex11-2 - accessing command line arguments
// as a vector
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main(int argc,char *argv[])
{
// create an empty vector of strings
vector<string> args;
// copy program arguments into vector
int i;
for (i=1;i<argc;i++)
args.push_back(argv[i]);
// sort vector
sort(args.begin(),args.end());
// list sorted arguments
cout << "Sorted arguments:";
for (i=0;i<args.size();i++)
cout << " " << args[i];
cout << endl;
return(0);
}
|
ex11-2 one two three four five
Sorted arguments: five four one three two
|
Example ex11-2 shows a simple way of copying the arguments into real C++
strings, so that we can do normal types of operations on them. We
create an empty vector of strings called 'args', then use a for loop to
append the program arguments to the vector using push_back(). We
can now call functions like 'sort()' if we like on the vector, or do comparisons
with '<', or use substr() or find(), etc on the strings. |
11.3 Command line decoding
// ex11-3.cpp - command line decoding
#include <iostream>
#include <string>
using namespace std;
// global program settings
int iparam=0; // integer parameter
double dparam=0; // double parameter
string sparam=""; // string parameter
int fparam=0; // boolean flag
// main program
int main(int argc,char *argv[])
{
int optind=1;
// decode arguments
while ((optind < argc) && (argv[optind][0]=='-')) {
string sw = argv[optind];
if (sw=="-i") {
optind++;
iparam = atoi(argv[optind]);
}
else if (sw=="-d") {
optind++;
dparam = atof(argv[optind]);
}
else if (sw=="-s") {
optind++;
sparam = argv[optind];
}
else if (sw=="-f")
fparam=1;
else
cout << "Unknown switch: "
<< argv[optind] << endl;
optind++;
}
// report settings
cout << "Integer parameter = " << iparam << endl;
cout << "Double parameter = " << dparam << endl;
cout << "String parameter = " << sparam << endl;
cout << "Flag parameter = " << fparam << endl;
// report rest of command line
cout << "Remaining arguments = ";
for (;optind<argc;optind++) cout << argv[optind];
cout << endl;
return(0);
}
|
ex11-3 -i 10 -d 2.5 -s "hello there" -f file1 file2
Integer parameter = 10
Double parameter = 2.5
String parameter = hello there
Flag parameter = 1
Remaining arguments = file1 file2
|
Example ex11-3 is an extended example of command line argument processing.
In this example we accept a variable number of arguments of different types
in arbitrary order. We do this by preceding each argument with an
indicator (often called a 'switch') which identifies the argument, and
hence its type. In the example the switches are
-i |
integer argument |
-d |
double argument |
-s |
string argument |
-f |
flag with no argument |
The program processes the switches in the order specified on the command
line, irrespective of the nature of the switch. A for loop passes over
the arguments, assigning each to a string variable sw so that it can be
compared to each switch type in turn using '==' operators. If a match
is found, then the appropriate operation is performed, setting the values
of an integer parameter iparam, a double parameter dparam, a string parameter
sparam, or a flag parameter fparam, appropriately. Notice that all
parameters have been given values in their declaration: these are the values
the parameters have by default: if no program argument sets them.
In the example these program parameters have been made 'global' variables,
that is accessible by all program functions, by declaring them outside
the main function.
To process the arguments, it is first necessary to test if they
are switches by comparing the first character of each argument with
the character '-'.
Since the program arguments are provided as character sequences, we
need to 'convert' these to store them into integer or double variables.
The function which converts a string of alphanumeric characters to an integer
value is called 'atoi()'; while the function which converts a string of
alphanumeric characters into a double value is called 'atof()'. If
the program finds an argument not preceded by a known switch it stops processing
arguments. In the example, the values of the parameters are then
printed, along with any unprocessed arguments. |
11.4 Exercises
a. Write a program (ttable.cpp) that prints a
times table for every number specified on the command line, as in:
ttable 6 10 12
1 6 10 12
2 12 20 24
3 18 30 36
etc
12 72 120 144
b. Write a program (scalc.cpp) that does simple
arithmetic calculations which are specified on the command line. Allow
operators '+', '-', '*' and '/'. Check that any arguments provided are
sensible before doing the calculation, as in:
scalc 3 + 5
3 + 5 = 8
scalc 2.5 * 1.5
2.5 * 1.5 = 3.75
scalc 5 /
Usage: scalc number operator number
scalc 5 / 0
Error: division by zero
|