Oops, I forgot the changed files. Here they are.

Georg
/**
 * \file insetcommandparams.C
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Angus Leeming
 *
 * Full author contact details are available in file CREDITS.
 */

#include <config.h>

#include "insetcommandparams.h"

#include "debug.h"
#include "lyxlex.h"


using std::string;
using std::pair;

InsetCommandParams::InsetCommandParams()
{}


InsetCommandParams::InsetCommandParams(string const & n,
					string const & c,
					string const & o,
					string const & s,
					string const & sc)
	: cmdname(n), //contents(c), options(o), sec_options(s), sec_contents(sc),
	preview_(false)
{
	if (!c.empty())
		setContents(c);
	if (!sc.empty())
		setSecContents(sc);
	if (!o.empty())
		setOptions(o);
	if (!s.empty())
		setSecOptions(s);
}


InsetCommandParams::InsetCommandParams(string const & n,
					vector<string> const & c,
					vector<string> const & o)
	: cmdname(n), contents_(c) , options_(o),
	preview_(false)
{
//TODO never tested, but should work!! :/
}

//TODO apparently this function is only needed for insetBibItem.. remove after fix..
void InsetCommandParams::scanCommand(string const & cmd)
{
	string tcmdname, toptions, tsecoptions, tcontents;

	if (cmd.empty()) return;

	enum { WS, CMDNAME, OPTION, SECOPTION, CONTENT } state = WS;

	// Used to handle things like \command[foo[bar]]{foo{bar}}
	int nestdepth = 0;

	for (string::size_type i = 0; i < cmd.length(); ++i) {
		char const c = cmd[i];
		if ((state == CMDNAME && c == ' ') ||
		    (state == CMDNAME && c == '[') ||
		    (state == CMDNAME && c == '{')) {
			state = WS;
		}
		if ((state == OPTION  && c == ']') ||
		    (state == SECOPTION  && c == ']') ||
		    (state == CONTENT && c == '}')) {
			if (nestdepth == 0) {
				state = WS;
			} else {
				--nestdepth;
			}
		}
		if ((state == OPTION  && c == '[') ||
		    (state == SECOPTION  && c == '[') ||
		    (state == CONTENT && c == '{')) {
			++nestdepth;
		}
		switch (state) {
		case CMDNAME:	tcmdname += c; break;
		case OPTION:	toptions += c; break;
		case SECOPTION:	tsecoptions += c; break;
		case CONTENT:	tcontents += c; break;
		case WS: {
			char const b = i? cmd[i-1]: 0;
			if (c == '\\') {
				state = CMDNAME;
			} else if (c == '[' && b != ']') {
				state = OPTION;
				nestdepth = 0; // Just to be sure
			} else if (c == '[' && b == ']') {
				state = SECOPTION;
				nestdepth = 0; // Just to be sure
			} else if (c == '{') {
				state = CONTENT;
				nestdepth = 0; // Just to be sure
			}
			break;
		}
		}
	}

	// Don't mess with this.
	if (!tcmdname.empty())
		setCmdName(tcmdname);
	if (!toptions.empty())
		setOptions(toptions);
	if (!tsecoptions.empty())
		setSecOptions(tsecoptions);
	if (!tcontents.empty())
		setContents(tcontents);

	if (lyxerr.debugging(Debug::PARSER))
		lyxerr << "Command <" <<  cmd
		       << "> == <" << getCommand()
		       << "> == <" << getCmdName()
		       << '|' << getContents()
		       << '|' << getOptions()
		       << '|' << getSecOptions() << '>' << endl;
}


void InsetCommandParams::read(LyXLex & lex)
{
	string token;
///////////////////////////////////////////////////////////////////////
// left for compatibility issues. remove if necessary!!
	if (lex.eatLine()) {
		token = lex.getString();
		//scanCommand(token);
	} else {
		lex.printError("InsetCommand: Parse error: `$$Token'");
	}
///////////////////////////////////////////////////////////////////////
	options_.clear();
	contents_.clear();

	while (lex.isOK()) {
		lex.next();
		token = lex.getString();
		if (token == "\\end_inset")
			break;
		if (token == "\\command_name") {
			lex.eatLine();
			setCmdName(clearText(lex.getString()));
		}
		if (token == "\\add_contents") {
			lex.eatLine();
			addContents(clearText(lex.getString()));
		}
		if (token == "\\add_options") {
			lex.eatLine();
			addOptions(clearText(lex.getString()));
		}
		if (hasKey(token)) {
			lex.eatLine();
			entrymap_.insert(pair<string,string>(token,clearText(lex.getString())));
		}		
		if (token == "preview") {
			lex.next();
			preview_ = lex.getBool();
		}
	}
	if (token != "\\end_inset") {
		lex.printError("Missing \\end_inset at this point. "
		               "Read: `$$Token'");
	}
}


// it is necessary to put the input into {}, since some options or contents 
// should be set even if it is null..
// nest depth stuff that was introduced in scanCommand should be avoided,
// since user can enter an erroneous input like foo{boo . 
// It is not necessary to mix up things even more! :)
string InsetCommandParams::clearText(string const & cmd)
{
	return string(cmd,
	              cmd.find_first_not_of('{', 0         ),
	              cmd.find_last_not_of ('}', cmd.size()));
}


void InsetCommandParams::write(ostream & os) const
{
	os << "LatexCommand " << getCommand() << "\n";
	os << "\\command_name {" << getCmdName() << "}\n";
	for (unsigned int ii = 0; ii < options_.size(); ++ii)
		os << "\\add_options {" << getOptions(ii) << "}\n";
	for (unsigned int ii = 0; ii < contents_.size(); ++ii)
		os << "\\add_contents {" << getContents(ii) << "}\n";
}


string const InsetCommandParams::getCommand() const
{
	string s;
	if (!getCmdName().empty())
		s += '\\' + getCmdName();
	for (unsigned int ii = 0; ii < options_.size(); ++ii)
		s += '[' + getOptions(ii) + ']';
	if (getNumContents() == 0)
		s += "{}";
	for (unsigned int ii = 0; ii < contents_.size(); ++ii)
		s += '{' + getContents(ii) + '}';
	return s;
}


bool operator==(InsetCommandParams const & o1,
		InsetCommandParams const & o2)
{
	bool isequal = (o1.getNumOptions() == o2.getNumOptions()) &&
	               (o1.getNumContents() == o2.getNumContents());
	for (int ii = 0; ii < o1.getNumOptions() && isequal; ++ii)
		isequal = o1.getOptions(ii) == o2.getOptions(ii);
	for (int ii = 0; ii < o1.getNumContents() && isequal; ++ii)
		isequal = o1.getContents(ii) == o2.getContents(ii);
	return isequal && (o1.getCmdName() == o2.getCmdName());
}


bool operator!=(InsetCommandParams const & o1,
		InsetCommandParams const & o2)
{
	return !(o1 == o2);
}
// -*- C++ -*-
/**
 * \file insetcommandparams.h
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Angus Leeming
 *
 * Full author contact details are available in file CREDITS.
 */

#ifndef INSETCOMMANDPARAMS_H
#define INSETCOMMANDPARAMS_H

#include <string>
#include <iosfwd>
#include <vector>
#include <map>

#include "debug.h"

class LyXLex;
using std::string;
using std::endl;
using std::ostream;
using std::vector;
using std::map;

class InsetCommandParams {
public:
	///
	InsetCommandParams();
	///
	explicit InsetCommandParams(std::string const & n,
			std::string const & c = std::string(),
			std::string const & o = std::string(),
			std::string const & s = std::string(),
			std::string const & sc = std::string());
	explicit InsetCommandParams(std::string const & n,
			std::vector<std::string> const & c,
			std::vector<std::string> const & o);
	///
	void read(LyXLex &);
	///Parse the command
	void scanCommand(std::string const &);
	///
	void write(std::ostream &) const;
	///
	std::string const & getCmdName() const { return cmdname; }
	///
	std::string const & getOptions() const { return (options_.size()) ? options_[0] : null_str; }
	///
	std::string const & getSecOptions() const { return (options_.size() > 1) ? options_[1] : null_str; }
	///
	std::string const & getContents() const { return (contents_.size()) ? contents_[0] : null_str; }
	///
	std::string const & getSecContents() const { return (contents_.size() > 1) ? contents_[1] : null_str; }
	///
	int getNumOptions() const { return options_.size(); }
	///
	int getNumContents() const { return contents_.size(); }
	///
	void setCmdName(std::string const & n) { cmdname = n; }
	///
	void setOptions(std::string  const & c){ setElement(options_, 0, c); }
	///
	void setSecOptions(std::string const & c) { setElement(options_, 1, c); }
	///
	void setContents(std::string const & c) { setElement(contents_, 0, c); }
	///
	void setSecContents(std::string const & s) { setElement(contents_, 1, s); }
	///
	bool preview() const { return preview_; }
	///
	void preview(bool p) { preview_ = p; }
	///
	void addOptions(std::string const & o) { options_.push_back(o); }
	///
	void addContents(std::string const & c) { contents_.push_back(c); }
	///
	std::string const & getOptions(int i) const { return options_[i]; }
	///
	std::string const & getContents(int i) const { return contents_[i]; }
	///
	std::vector<std::string> getValuesForKeys(std::string const & v) /*TODO*/;
	///
	std::string getValueForKeys(std::string const & v) { return (*(std::multimap<std::string,std::string>::iterator(entrymap_.find(v)))).first; }
	/// Build the complete LaTeX command
	std::string const getCommand() const;


private:
	///
	std::string clearText(std::string const &);
	///
	bool hasKey(std::string const & k) {return !(find(keys_.begin() , keys_.end() ,k) == keys_.end());};
	///
	void setElement(std::vector<std::string> & , int , std::string const & c);
	///
	std::string cmdname;
	///
	std::string null_str;
	///
	bool preview_;
	///
	std::vector<std::string> contents_;
	///
	std::vector<std::string> options_;
	///
	std::vector<std::string> keys_;
	///
	std::multimap<std::string,std::string> entrymap_;

};

///
inline void InsetCommandParams::setElement(std::vector<std::string> & vec_, int ii, std::string const & c)
{
	for (int i = vec_.size(); i <= ii; ++i)
		vec_.push_back("");
	vec_[ii] = c;
}
///
bool operator==(InsetCommandParams const &, InsetCommandParams const &);

///
bool operator!=(InsetCommandParams const &, InsetCommandParams const &);

#endif

Reply via email to