diff defical-c/src/basic/Argument_helper.cpp @ 0:ebed2bd0d300

Initial import from svn. History be damned.
author Edho P. Arief <me@myconan.net>
date Fri, 02 Apr 2010 23:11:57 +0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/defical-c/src/basic/Argument_helper.cpp	Fri Apr 02 23:11:57 2010 +0700
@@ -0,0 +1,651 @@
+/*
+*
+* Argument Helper
+*
+* Daniel Russel drussel@alumni.princeton.edu
+* Stanford University
+*
+*
+* This software is not subject to copyright protection and is in the
+* public domain. Neither Stanford nor the author assume any
+* responsibility whatsoever for its use by other parties, and makes no
+* guarantees, expressed or implied, about its quality, reliability, or
+* any other characteristic.
+*
+*/
+
+#include "Argument_helper.h"
+
+
+#include <iostream>
+#include <cstdlib>
+#include <cstdio>
+//#include <limits>
+#include <cassert>
+
+
+
+namespace dsr {
+
+	bool verbose=false, VERBOSE=false;
+
+
+
+	// This is a base class for representing one argument value.
+	/* 
+	This is inherited by many classes and which represent the different types. 
+	*/
+	class Argument_helper::Argument_target {
+	public:
+		char key;
+		std::string long_name;
+		std::string description;
+		std::string arg_description;
+
+		Argument_target(char k, const std::string lname,
+			const std::string descr,
+			const std::string arg_descr) {
+				key=k;
+				long_name=lname;
+				description=descr;
+				arg_description=arg_descr;
+		}
+		Argument_target(const std::string descr,
+			const std::string arg_descr) {
+				key=0;
+				long_name="";
+				description=descr;
+				arg_description=arg_descr;
+		}
+		virtual bool process(int &, const char **&)=0;
+		virtual void write_name(std::ostream &out) const;
+		virtual void write_value(std::ostream &out) const=0;
+		virtual void write_usage(std::ostream &out) const;
+		virtual ~Argument_target(){}
+	};
+
+	void Argument_helper::Argument_target::write_name(std::ostream &out) const {
+		if (key != 0) out << '-' << key;
+		else if (!long_name.empty()) out << "--" << long_name;
+		else out << arg_description;
+	}
+
+
+	void Argument_helper::Argument_target::write_usage(std::ostream &out) const {
+		if (key != 0) {
+			out << '-' << key;
+			out << "/--" << long_name;
+		}
+		out << ' ' << arg_description;
+		out << "\t" << description;
+		out << " Value: ";
+		write_value(out);
+		out << std::endl;
+	}
+
+	class Argument_helper::FlagTarget: public Argument_helper::Argument_target{
+	public:
+		bool &val;
+		FlagTarget(char k, const char *lname, 
+			const char *descr,
+			bool &b): Argument_target(k, std::string(lname), std::string(descr), 
+			std::string()),  val(b){}
+		virtual bool process(int &, const char **&){
+			val= !val;
+			return true;
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+
+		virtual void write_usage(std::ostream &out) const {
+			if (key != 0) {
+				out << '-' << key;
+				out << "/--" << long_name;
+			}
+			out << "\t" << description;
+			out << " Value: ";
+			write_value(out);
+			out << std::endl;
+		}
+		virtual ~FlagTarget(){}
+	};
+
+	class Argument_helper::DoubleTarget: public Argument_target{
+	public:
+		double &val;
+		DoubleTarget(char k, const char *lname, 
+			const char *arg_descr, 
+			const char *descr, double &b): Argument_target(k, std::string(lname),
+			std::string(descr),
+			std::string(arg_descr)),  val(b){}
+		DoubleTarget(const char *arg_descr, 
+			const char *descr, double &b): Argument_target(std::string(descr),
+			std::string(arg_descr)),  val(b){}
+		virtual bool process(int &argc, const char **&argv){
+			if (argc==0){
+				std::cerr << "Missing value for argument." << std::endl;
+				return false;
+			}
+			if (my_sscanf(argv[0], "%le", &val) ==1){
+				--argc;
+				++argv;
+				return true;
+			}  else {
+				std::cerr << "Double not found at " << argv[0] << std::endl;
+				return false;
+			}
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+		virtual ~DoubleTarget(){}
+	};
+
+	class Argument_helper::IntTarget: public Argument_target{
+	public:
+		int &val;
+		IntTarget(const char *arg_descr, 
+			const char *descr, int &b): Argument_target(0, std::string(),
+			std::string(descr),
+			std::string(arg_descr)),  
+			val(b){}
+		IntTarget(char k, const char *lname, 
+			const char *arg_descr, 
+			const char *descr, int &b): Argument_target(k, std::string(lname),
+			std::string(descr),
+			std::string(arg_descr)), 
+			val(b){}
+		virtual bool process(int &argc, const char **&argv){
+			if (argc==0){
+				std::cerr << "Missing value for argument." << std::endl;
+				return false;
+			}
+			if (my_sscanf(argv[0], "%d", &val) ==1){
+				--argc;
+				++argv;
+				return true;
+			}  else {
+				std::cerr << "Integer not found at " << argv[0] << std::endl;
+				return false;
+			}
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+		virtual ~IntTarget(){}
+	};
+
+	class Argument_helper::UIntTarget: public Argument_target{
+	public:
+		unsigned int &val;
+		UIntTarget(const char *arg_descr, 
+			const char *descr, unsigned int &b): Argument_target(0, std::string(),
+			std::string(descr),
+			std::string(arg_descr)),  
+			val(b){}
+		UIntTarget(char k, const char *lname, 
+			const char *arg_descr, 
+			const char *descr, unsigned int &b): Argument_target(k, std::string(lname),
+			std::string(descr),
+			std::string(arg_descr)), 
+			val(b){}
+		virtual bool process(int &argc, const char **&argv){
+			if (argc==0){
+				std::cerr << "Missing value for argument." << std::endl;
+				return false;
+			}
+			if (my_sscanf(argv[0], "%ud", &val) ==1){
+				--argc;
+				++argv;
+				return true;
+			} else {
+				std::cerr << "Unsigned integer not found at " << argv[0] << std::endl;
+				return false;
+			}
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+		virtual ~UIntTarget(){}
+	};
+
+
+	class Argument_helper::CharTarget: public Argument_target{
+	public:
+		char &val;
+		CharTarget(char k, const char *lname, 
+			const char *arg_descr, 
+			const char *descr, char &b): Argument_target(k, std::string(lname),
+			std::string(descr),
+			std::string(arg_descr)),  val(b){}
+		CharTarget(const char *arg_descr, 
+			const char *descr, char &b): Argument_target(std::string(descr),
+			std::string(arg_descr)),  val(b){}
+		virtual bool process(int &argc, const char **&argv){
+			if (argc==0){
+				std::cerr << "Missing value for argument." << std::endl;
+				return false;
+			}
+			if (my_sscanf(argv[0], "%c", &val) ==1){
+				--argc;
+				++argv;
+				return true;
+			}  else {
+				std::cerr << "Character not found at " << argv[0] << std::endl;
+				return false;
+			}
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+		virtual ~CharTarget(){}
+	};
+
+
+	class Argument_helper::StringTarget: public Argument_target{
+	public:
+		std::string &val;
+		StringTarget(const char *arg_descr, 
+			const char *descr, std::string &b): Argument_target(0, std::string(),
+			descr, 
+			arg_descr),
+			val(b){}
+
+		StringTarget(char k, const char *lname, const char *arg_descr, 
+			const char *descr, std::string &b): Argument_target(k, lname, descr, 
+			arg_descr), 
+			val(b){}
+
+		virtual bool process(int &argc, const char **&argv){
+			if (argc==0){
+				std::cerr << "Missing string argument." << std::endl;
+				return false;
+			}
+			val= argv[0];
+			--argc;
+			++argv;
+			return true;
+		}
+		virtual void write_value(std::ostream &out) const {
+			out << val;
+		}
+		virtual ~StringTarget(){}
+	};
+
+
+	class Argument_helper::StringVectorTarget: public Argument_target{
+	public:
+		std::vector<std::string> &val;
+
+		StringVectorTarget(char k, const char *lname, const char *arg_descr, 
+			const char *descr, std::vector<std::string> &b): Argument_target(k, lname, descr, 
+			arg_descr), 
+			val(b){}
+
+		virtual bool process(int &argc, const char **&argv){
+			while (argc >0 && argv[0][0] != '-'){
+				val.push_back(argv[0]);
+				--argc;
+				++argv;
+			}
+			return true;
+		}
+		virtual void write_value(std::ostream &out) const {
+			for (unsigned int i=0; i< val.size(); ++i){
+				out << val[i] << " ";
+			}
+		}
+		virtual ~StringVectorTarget(){}
+	};
+
+
+
+
+	Argument_helper::Argument_helper(){
+		author_="Someone";
+		description_= "This program does something.";
+		date_= "A long long time ago.";
+		version_=-1;
+		extra_arguments_=NULL;
+		seen_end_named_=false;
+		new_flag('v', "verbose", "Whether to print extra information", verbose);
+		new_flag('V', "VERBOSE", "Whether to print lots of extra information", VERBOSE);
+	}
+
+
+
+	void Argument_helper::set_string_vector(const char *arg_description, 
+		const char *description, 
+		std::vector<std::string> &dest){
+			assert(extra_arguments_==NULL);
+			extra_arguments_descr_= description;
+			extra_arguments_arg_descr_= arg_description;
+			extra_arguments_= &dest;
+	}
+
+	void Argument_helper::set_author(const char *author){
+		author_=author;
+	}
+
+	void Argument_helper::set_description(const char *descr){
+		description_= descr;
+	}
+
+	void Argument_helper::set_name(const char *descr){
+		name_= descr;
+	}
+
+	void Argument_helper::set_version(float v){
+		version_=v;
+	}
+
+	void Argument_helper::set_version(const char *s){
+		std::stringstream f;
+		f << s;
+		f >> version_;
+	}
+
+	void  Argument_helper::set_build_date(const char *date){
+		date_=date;
+	}
+
+	void Argument_helper::new_argument_target(Argument_target *t) {
+		assert(t!= NULL);
+		if (t->key != 0){
+			if (short_names_.find(t->key) != short_names_.end()){
+				std::cerr << "Two arguments are defined with the same character key, namely" << std::endl;
+				short_names_[t->key]->write_usage(std::cerr);
+				std::cerr << "\n and \n";
+				t->write_usage(std::cerr);
+				std::cerr << std::endl;
+			}
+			short_names_[t->key]= t;
+		} 
+		if (!t->long_name.empty()){
+			if (long_names_.find(t->long_name) != long_names_.end()){
+				std::cerr << "Two arguments are defined with the same long key, namely" << std::endl;
+				long_names_[t->long_name]->write_usage(std::cerr);
+				std::cerr << "\n and \n";
+				t->write_usage(std::cerr);
+				std::cerr << std::endl;
+			}
+			long_names_[t->long_name]= t;
+		}
+		all_arguments_.push_back(t);
+	}
+
+	void Argument_helper::new_flag(char key, const char *long_name, const char *description,bool &dest){
+		Argument_target *t= new FlagTarget(key, long_name, description, dest);
+		new_argument_target(t);
+	};
+
+
+
+	void Argument_helper::new_string(const char *arg_description, const char *description,
+		std::string &dest){
+			Argument_target *t= new StringTarget(arg_description, description, dest);
+			unnamed_arguments_.push_back(t);
+			all_arguments_.push_back(t);
+	};
+	void Argument_helper::new_optional_string(const char *arg_description, const char *description,
+		std::string &dest){
+			Argument_target *t= new StringTarget(arg_description, description, dest);
+			optional_unnamed_arguments_.push_back(t);
+	};
+	void Argument_helper::new_named_string(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		std::string &dest){
+			Argument_target *t= new StringTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+
+	void Argument_helper::new_named_string_vector(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		std::vector<std::string> &dest){
+			Argument_target *t= new StringVectorTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+
+
+	void Argument_helper::new_int(const char *arg_description, const char *description,
+		int &dest){
+			Argument_target *t= new IntTarget(arg_description, description, dest);
+			unnamed_arguments_.push_back(t);
+			all_arguments_.push_back(t);
+	};
+	void Argument_helper::new_optional_int(const char *arg_description, const char *description,
+		int &dest){
+			Argument_target *t= new IntTarget(arg_description, description, dest);
+			optional_unnamed_arguments_.push_back(t);
+	};
+	void Argument_helper::new_named_int(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		int &dest){
+			Argument_target *t= new IntTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+	void Argument_helper::new_unsigned_int(const char *arg_description, const char *description,
+		unsigned int &dest){
+			Argument_target *t= new UIntTarget(arg_description, description, dest);
+			unnamed_arguments_.push_back(t);
+			all_arguments_.push_back(t);
+	};
+	void Argument_helper::new_optional_unsigned_int(const char *arg_description, const char *description,
+		unsigned int &dest){
+			Argument_target *t= new UIntTarget(arg_description, description, dest);
+			optional_unnamed_arguments_.push_back(t);
+	};
+	void Argument_helper::new_named_unsigned_int(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		unsigned int &dest){
+			Argument_target *t= new UIntTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+
+	void Argument_helper::new_double(const char *arg_description, const char *description,
+		double &dest){
+			Argument_target *t= new DoubleTarget(arg_description, description, dest);
+			unnamed_arguments_.push_back(t);
+			all_arguments_.push_back(t);
+	};
+	void Argument_helper::new_optional_double(const char *arg_description, const char *description,
+		double &dest){
+			Argument_target *t= new DoubleTarget(arg_description, description, dest);
+			optional_unnamed_arguments_.push_back(t);
+	};
+	void Argument_helper::new_named_double(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		double &dest){
+			Argument_target *t= new DoubleTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+	void Argument_helper::new_char(const char *arg_description, const char *description,
+		char &dest){
+			Argument_target *t= new CharTarget(arg_description, description, dest);
+			unnamed_arguments_.push_back(t);
+			all_arguments_.push_back(t);
+	};
+	void Argument_helper::new_optional_char(const char *arg_description, const char *description,
+		char &dest){
+			Argument_target *t= new CharTarget(arg_description, description, dest);
+			optional_unnamed_arguments_.push_back(t);
+	};
+	void Argument_helper::new_named_char(char key, const char *long_name,
+		const char *arg_description, const char *description,
+		char &dest){
+			Argument_target *t= new CharTarget(key, long_name, arg_description, description, dest);
+			new_argument_target(t);
+	};
+
+
+
+	void Argument_helper::write_usage(std::ostream &out) const {
+		out << name_ << " version " << version_ << ", by " << author_ << std::endl;
+		out << description_ << std::endl;
+		out << "Compiled on " << date_ << std::endl << std::endl;
+		out << "Usage: " << name_  << " ";
+		for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
+			(*it)->write_name(out);
+			out << " ";
+		}
+		for (UVect::const_iterator it= optional_unnamed_arguments_.begin(); 
+			it != optional_unnamed_arguments_.end(); ++it){
+				out << "[";
+				(*it)->write_name(out);
+				out << "] ";
+		}
+		if (extra_arguments_ != NULL) {
+			out << "[" << extra_arguments_arg_descr_ << "]";
+		}    
+
+		out << std::endl << std::endl;
+		out << "All arguments:\n";
+		for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
+			(*it)->write_usage(out);
+		}
+		for (UVect::const_iterator it= optional_unnamed_arguments_.begin(); 
+			it != optional_unnamed_arguments_.end(); ++it){
+				(*it)->write_usage(out);
+		}
+
+		//out << extra_arguments_arg_descr_ << ": " << extra_arguments_descr_ << std::endl;
+		for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
+			(it->second)->write_usage(out);
+		}
+	}
+
+
+
+	void Argument_helper::write_values(std::ostream &out) const {
+		for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
+			out << (*it)->description;
+			out << ": ";
+			(*it)->write_value(out);
+			out << std::endl;
+		}
+		for (UVect::const_iterator it= optional_unnamed_arguments_.begin(); 
+			it != optional_unnamed_arguments_.end(); ++it){
+				out << (*it)->description;
+				out << ": ";
+				(*it)->write_value(out);
+				out << std::endl;
+		}
+		if (extra_arguments_!=NULL){
+			for (std::vector<std::string>::const_iterator it= extra_arguments_->begin(); 
+				it != extra_arguments_->end(); ++it){
+					out << *it << " ";
+			}
+		}
+
+		for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
+			out << it->second->description;
+			out << ": ";
+			it->second->write_value(out);
+			out << std::endl;
+		}
+	}
+
+	Argument_helper::~Argument_helper(){
+		for (std::vector<Argument_target*>::iterator it= all_arguments_.begin();
+			it != all_arguments_.end(); ++it){
+				delete *it;
+		}
+	}
+
+
+	void Argument_helper::process(int argc,  const char **argv){
+		name_= argv[0];
+		++argv;
+		--argc;
+
+		current_unnamed_= unnamed_arguments_.begin();
+		current_optional_unnamed_= optional_unnamed_arguments_.begin();
+
+		for ( int i=0; i< argc; ++i){
+			if (strcmp(argv[i], "--help") == 0){
+				write_usage(std::cout);
+				exit(0);
+			}
+		}
+
+		while (argc != 0){
+
+			const char* cur_arg= argv[0];
+			if (cur_arg[0]=='-' && !seen_end_named_){
+				--argc; ++argv;
+				if (cur_arg[1]=='-'){
+					if (cur_arg[2] == '\0') {
+						//std::cout << "Ending flags " << std::endl;
+						seen_end_named_=true;
+					} else {
+						// long argument
+						LMap::iterator f= long_names_.find(cur_arg+2);
+						if ( f != long_names_.end()){
+							if (!f->second->process(argc, argv)) {
+								handle_error();
+							}
+						} else {
+							std::cerr<< "Invalid long argument "<< cur_arg << ".\n";
+							handle_error();
+						}
+					}
+				} else {
+					if (cur_arg[1]=='\0') {
+						std::cerr << "Invalid argument " << cur_arg << ".\n";
+						handle_error();
+					}
+					SMap::iterator f= short_names_.find(cur_arg[1]);
+					if ( f != short_names_.end()){
+						if (!f->second->process(argc, argv)) {
+							handle_error();
+						}
+					} else {
+						std::cerr<< "Invalid short argument "<< cur_arg << ".\n";
+						handle_error();
+					}
+				}
+			} else {
+				if (current_unnamed_ != unnamed_arguments_.end()){
+					Argument_target *t= *current_unnamed_;
+					t->process(argc, argv);
+					++current_unnamed_;
+				} else if (current_optional_unnamed_ != optional_unnamed_arguments_.end()){
+					Argument_target *t= *current_optional_unnamed_;
+					t->process(argc, argv);
+					++current_optional_unnamed_;
+				} else if (extra_arguments_!= NULL){
+					extra_arguments_->push_back(cur_arg);
+					--argc;
+					++argv;
+				} else {
+					std::cerr << "Invalid extra argument " << argv[0] << std::endl;
+					handle_error();
+				}
+			}
+		}
+
+		if (current_unnamed_ != unnamed_arguments_.end()){
+			std::cerr << "Missing required arguments:" << std::endl;
+			for (; current_unnamed_ != unnamed_arguments_.end(); ++current_unnamed_){
+				(*current_unnamed_)->write_name(std::cerr);
+				std::cerr << std::endl;
+			}
+			std::cerr << std::endl;
+			handle_error();
+		}
+
+		if (VERBOSE) verbose=true;
+	}
+
+	void Argument_helper::handle_error() const {
+		write_usage(std::cerr);
+		exit(1);
+	}
+}
+