Click here to Skip to main content
15,891,943 members
Articles / Desktop Programming / MFC

ParamContainer - easy-to-use command-line parameter parser

Rate me:
Please Sign up or sign in to vote.
2.06/5 (9 votes)
3 Feb 20051 min read 58.2K   874   32  
ParamContainer is a simple and easy to use C++ class to parse command line parameters. Parameters format are derived from UNIX getopt_long() function syntax but may contain nested parameters as well.
#include <stdio.h>
#include <math.h>

#ifdef WIN32
#include <windows.h>
#endif

#include "ParamContainer.h"

#define _PI 3.14159265

using namespace std;

const char *projsignature="ParamContainer Sample Project";

/*
Class representing coords, which can be initialized in either Cartesian or polar manner
*/
class Coords {
	double x,y;
public:
	// This static method sets ParamContainer to accept Coords values
	static string initParam(ParamContainer &p) {
		ParamContainer xy;
		xy.initOptions(false);
		xy.setHelpString("Point coordinates: xy = Cartesian coordinates. Syntax:");
		xy.addParam("x", 0, xy.noname|xy.required, "X coordinate of point");
		xy.addParam("y", 0, xy.noname|xy.required, "Y coordinate of point");
		p.addParamType("xy", xy);

		ParamContainer polar;
		polar.initOptions(false);
		polar.setHelpString("Point coordinates: polar = polar coordinates. Syntax:");
		polar.addParam("r", 0, polar.noname|polar.required, "Norm");
		polar.addParam("phi", 0, polar.noname, "Azimuth (0 by default)", "0");
		p.addParamType("polar", polar);
		return "xy|polar";
	}
	Coords():x(0),y(0) {}
	// Construct the object from ParamContainer
	Coords(string ctype, const ParamContainer &p) {
		if(ctype=="xy") {
			x=atof(p["x"].c_str());
			y=atof(p["y"].c_str());
		} else {
			x=atof(p["r"].c_str())*cos(atof(p["phi"].c_str()));
			y=atof(p["r"].c_str())*sin(atof(p["phi"].c_str()));
		}
	}
	// get coordinates
	double getX() const {return x;}
	double getY() const {return y;}
};

/*
Interface representing shape
*/
class Shape {
public:
	// calculate shape area
	virtual double getArea() = 0;
};

/*
Square
*/
class Square:public Shape {
	Coords c1, c2;
public:
	static string initParam(ParamContainer &p) {
		ParamContainer p1;
		// spdump=false, we don't need to see several explanations of coords initialization in 
		// our help screen. Change it to p1.initOptions(false, true), run program without arguments
		// and see, what's the difference.
		p1.initOptions(false, false);
		p1.setHelpString("Shape: square. Syntax:");
		// Initializing subtypes of coordinates representation
		string ctypes=Coords::initParam(p1);
		p1.addParam("lefttop", 0, p1.noname|p1.required, "Coords of left-top corner", "", ctypes);
		p1.addParam("rightbottom", 0, p1.noname|p1.required, "Coords of right-bottom corner", "", ctypes);
		p.addParamType("square", p1);
		return "square";
		
	}
	// constructing
	Square(const ParamContainer &p) {
		c1=Coords(p["lefttop"], p.child("lefttop"));
		c2=Coords(p["rightbottom"], p.child("rightbottom"));
	}
	virtual double getArea() {
		return fabs((c2.getX()-c1.getX())*(c2.getY()-c1.getY()));
	}
};

/*
Circle
*/
class Circle:public Shape {
	Coords c;
	double r;
public:
	static string initParam(ParamContainer &p) {
		ParamContainer p1;
		p1.initOptions(false, false);
		p1.setHelpString("Shape: circle. Syntax:");
		string ctypes=Coords::initParam(p1);
		p1.addParam("center", 'c', p1.required, "Coords of the center", "", ctypes);
		p1.addParam("radius", 'r', p1.required, "Radius");
		p.addParamType("circle", p1);
		return "circle";
		
	}	
	Circle(const ParamContainer &p) {
		c=Coords(p["center"], p.child("center"));
		r=atof(p["radius"].c_str());
	}
	virtual double getArea() {
		return _PI*r*r;
	}
};

int main(int argc, char* argv[])
{
	int width;
#ifdef WIN32
		// Get window width to output help and erro messages better
		CONSOLE_SCREEN_BUFFER_INFO csbi;
		GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
		if(csbi.dwSize.X<=0)
		{
			GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
			if(csbi.dwSize.X<=0) width=78; else width=csbi.dwSize.X-1;
		}
		else width=csbi.dwSize.X-1;
#else
		// Add here code to obtain width in your system
		width=78;
#endif

	// ParamContainer initialization
	ParamContainer p;
	p.initOptions(false);	// Don't allow unknown parameters
	p.setHelpString(string("Test ParamContainer application\nUsage: ")+argv[0]+" ");

	// Initializing subtypes of shape representation
	// maybe it'll look better inside some Shape Factory class
	string shapesquare=Square::initParam(p);
	string shapecircle=Circle::initParam(p);
	string shapetypes=shapesquare+"|"+shapecircle;

	string coordstypes=Coords::initParam(p);	// Initializing subtypes of coordinates representation

	// Creating parameter list
	p.addParam("startpoint", 'p', p.required, "Start point coordinates", "", coordstypes);
	p.addParam("shape", 's', p.required, "Shape", "", shapetypes);
	p.addParam("projfile", 0, p.noname, "Project file name to load parameters from");
	p.addParam("save", 'o', p.novalue, "Save parameters to the project file instead of loading");

	// No arguments: show help and quit
	if(argc==1)
	{
		p.dumpHelp(stdout, true, width);
		return 2;
	}
	// Parsing
	ParamContainer::errcode err=p.parseCommandLine(argc, argv);
	// Projectfile specified: loading data from it
	if((err==p.errOk || err==p.errRequiredParameterMissing) && p["projfile"]!="" && p["save"]=="")
		err=p.loadParams(p["projfile"], projsignature);
	// Parse error: print error message and exit
	if(err!=p.errOk)
	{
		int errpos;
		printf("%s\n", p.getErrCmdLine(errpos, width-5).c_str());
		for(;errpos-->0;) printf(" ");
		printf("^\n");
		printf("%s\n", p.getErrorMessage(err).c_str());
		return 1;
	}
	// All seems to be ok: creating objects
	Coords pt(p["startpoint"], p.child("startpoint"));

	Shape *s;

	// Creating shape
	// maybe it'll look better inside some Shape Factory class
	if(p["shape"]==shapecircle) s=new Circle(p.child("shape"));
	if(p["shape"]==shapesquare) s=new Square(p.child("shape"));

	// Saving project if needed
	if(p["projfile"]!="" && p["save"]!="")
	{
		std::string fname=p["projfile"];
		p.unsetParam("save");
		p.unsetParam("projfile");
		p.saveParams(fname, projsignature);
	}

	// Some code using our objects
	printf("Point coords: (%g, %g)\n", pt.getX(), pt.getY());
	printf("Shape area: %g\n", s->getArea());

	// Cleaning up
	delete s;
	return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions