Skip to content
Snippets Groups Projects
zipr_new_options.cpp 5.49 KiB
/*
 * Copyright (c) 2014 - Zephyr Software LLC
 *
 * This file may be used and modified for non-commercial purposes as long as
 * all copyright, permission, and nonwarranty notices are preserved.
 * Redistribution is prohibited without prior written consent from Zephyr
 * Software.
 *
 * Please contact the authors for restrictions applying to commercial use.
 *
 * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: Zephyr Software
 * e-mail: jwd@zephyr-software.com
 * URL   : http://www.zephyr-software.com/
 *
 */

#include <zipr_sdk.h>
#include <unistd.h>
#include <iostream>
#include <cstddef>

#ifndef IMPLEMENTATION_DEBUG
#define IMPLEMENTATION_DEBUG 0
#endif

using namespace Zipr_SDK;
using namespace std;

void ZiprOptionsNamespace_t::PrintNamespace() {
	ZiprOptionsNamespace_t::const_iterator it = begin();
	ZiprOptionsNamespace_t::const_iterator it_end = end();
	for (it; it != it_end; it++) {
		cout << (*it)->Key() << ": " << (*it)->StringValue() << endl;
	}
}

bool ZiprOptionsNamespace_t::RequirementsMet() {
	ZiprOptionsNamespace_t::const_iterator it = begin();
	ZiprOptionsNamespace_t::const_iterator it_end = end();
	for (it; it != it_end; it++) {
		if (!(*it)->RequirementMet())
			return false;
	}
	return true;
}

void ZiprOptionsNamespace_t::AddOption(ZiprUntypedOption_t *option) {
	insert(option);
}

ZiprUntypedOption_t *ZiprOptionsNamespace_t::OptionByKey(string key) {
	ZiprOptionsNamespace_t::const_iterator it = begin();
	ZiprOptionsNamespace_t::const_iterator it_end = end();
	for (it; it != it_end; it++) {
		if ((*it)->Key() == key)
			return *it;
	}
	return NULL;
}

void ZiprOptionsNamespace_t::PrintUsage(int tabs, ostream &out) {
	ZiprOptionsNamespace_t::const_iterator it = begin();
	ZiprOptionsNamespace_t::const_iterator it_end = end();
	for (it; it != it_end; it++) {
		string description = (*it)->Description();
		{ int t = 0; for (; t<tabs; t++) cout << "\t"; }
		out << Namespace() << ":" << description << endl;
	}
}

void ZiprNewOptions_t::PrintUsage(ostream &out) {
	set<ZiprOptionsNamespace_t*>::const_iterator it = m_namespaces.begin();
	set<ZiprOptionsNamespace_t*>::const_iterator it_end = m_namespaces.end();
	for (it; it != it_end; it++)
		(*it)->PrintUsage(1, out);
}	

bool ZiprNewOptions_t::RequirementsMet() {
	set<ZiprOptionsNamespace_t*>::const_iterator it = m_namespaces.begin();
	set<ZiprOptionsNamespace_t*>::const_iterator it_end = m_namespaces.end();
	for (it; it != it_end; it++)
		if (!(*it)->RequirementsMet())
			return false;
	return true;
}

ZiprNewOptions_t::ZiprNewOptions_t(int argc, char **argv) {
	int i = 0;
	for (i = 0; i<argc; i++) {
		m_arguments.push_back(string(argv[i]));
	}
}

bool ZiprNewOptions_t::Parse(ostream &warn) {
	vector<string>::const_iterator it = m_arguments.begin();
	vector<string>::const_iterator it_end = m_arguments.end();

	for (it; it != it_end; it++) {
		string ns, key, argument = *it;
		string::size_type location = 0;
		ZiprOptionsNamespace_t *option_ns;
		ZiprUntypedOption_t *option_option;

		if (0 != (location = argument.find_first_of("--"))) {
			warn << "Warning: " << argument << " does not start with --" << endl;
			continue;
		}
#if IMPLEMENTATION_DEBUG
		cout << "location: " << location << endl;
#endif
		argument = argument.substr(location+2, string::npos);
		if (string::npos == (location = argument.find_first_of(":"))) {
			warn << "Warning: " << argument << " going in global namespace." << endl;
			ns = "global";
			location = -1;
		} else {
			ns = argument.substr(0, location);
		}
#if IMPLEMENTATION_DEBUG
		cout << "argument: " << argument << endl;
#endif
		key = argument.substr(location+1, string::npos);
#if IMPLEMENTATION_DEBUG
		cout << "ns: " << ns << endl;
		cout << "key: " << key << endl;
#endif
		if (!(option_ns = Namespace(ns))) {
			warn << "Invalid namespace: " << ns << endl;
			continue;
		}
		if (!(option_option = option_ns->OptionByKey(key))) {
			warn << ns << " does not accept key " << key << endl;
			continue;
		}
		/*
		 * By default, options need and take values. Some, though,
		 * take values but don't need them. Finally, some neither
		 * take nor need values.
		 */
		if (option_option->NeedsValue()) {
			if ((it + 1) == it_end)
			{
				warn << ns << ":" << key << " is missing value." << endl;
				continue;
			}
			option_option->SetValue(*(++it));
		} else if (option_option->TakesValue()) {
			/*
			 * Check to see if the next argument starts with --.
			 * If it does, we consider it the next option
			 * and not the value to the previous option.
			 */
			if (((it+1) != it_end) && 
			    (0 != (location = (*(it+1)).find_first_of("--")))) {
				option_option->SetValue(*(++it));
			} else {
				option_option->Set();
			}
		} else {
			option_option->Set();
		}
	}
	return true;
}

ZiprOptionsNamespace_t *ZiprNewOptions_t::Namespace(string ns) {
	set<ZiprOptionsNamespace_t*>::const_iterator it = m_namespaces.begin();
	set<ZiprOptionsNamespace_t*>::const_iterator it_end = m_namespaces.end();
	for (it; it != it_end; it++) {
		if ((*it)->Namespace() == ns)
			return *it;
	}
	return NULL;
}

void ZiprNewOptions_t::AddNamespace(ZiprOptionsNamespace_t *ns) {
	m_namespaces.insert(ns);
}

void ZiprNewOptions_t::PrintNamespaces() {
	set<ZiprOptionsNamespace_t*>::const_iterator it = m_namespaces.begin();
	set<ZiprOptionsNamespace_t*>::const_iterator it_end = m_namespaces.end();

	for (it; it != it_end; it++) {
		cout << (*it)->Namespace() << endl;
		(*it)->PrintNamespace();
	}
}