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