+string const Parser::plainEnvironment(string const & name)
+{
+ if (!good())
+ return string();
+
+ ostringstream os;
+ for (Token t = get_token(); good(); t = get_token()) {
+ if (t.asInput() == "\\end") {
+ string const end = getArg('{', '}');
+ if (end == name)
+ return os.str();
+ else
+ os << "\\end{" << end << '}';
+ } else
+ os << t.asInput();
+ }
+ cerr << "unexpected end of input" << endl;
+ return os.str();
+}
+
+
+string const Parser::plainCommand(char left, char right, string const & name)
+{
+ if (!good())
+ return string();
+ // check if first token is really the start character
+ Token tok = get_token();
+ if (tok.character() != left) {
+ cerr << "first character does not match start character of command \\" << name << endl;
+ return string();
+ }
+ ostringstream os;
+ for (Token t = get_token(); good(); t = get_token()) {
+ if (t.character() == right) {
+ return os.str();
+ } else
+ os << t.asInput();
+ }
+ cerr << "unexpected end of input" << endl;
+ return os.str();
+}
+
+
+Parser::Arg Parser::verbatimStuff(string const & end_string, bool const allow_linebreak)
+{
+ if (!good())
+ return Arg(false, string());
+
+ pushPosition();
+ ostringstream oss;
+ size_t match_index = 0;
+ setCatcodes(VERBATIM_CATCODES);
+ for (Token t = get_token(); good(); t = get_token()) {
+ // FIXME t.asInput() might be longer than we need ?
+ if (t.asInput() == end_string.substr(match_index,
+ t.asInput().length())) {
+ match_index += t.asInput().length();
+ if (match_index >= end_string.length())
+ break;
+ } else {
+ if (!allow_linebreak && t.asInput() == "\n") {
+ cerr << "unexpected end of input" << endl;
+ popPosition();
+ setCatcodes(NORMAL_CATCODES);
+ return Arg(false, string());
+ }
+ if (match_index) {
+ oss << end_string.substr(0, match_index)
+ << t.asInput();
+ match_index = 0;
+ } else
+ oss << t.asInput();
+ }
+ }
+
+ if (!good()) {
+ cerr << "unexpected end of input" << endl;
+ popPosition();
+ setCatcodes(NORMAL_CATCODES);
+ return Arg(false, string());
+ }
+ setCatcodes(NORMAL_CATCODES);
+ dropPosition();
+ return Arg(true, oss.str());
+}
+
+
+string const Parser::verbatimEnvironment(string const & name)
+{
+ //FIXME: do something if endstring is not found
+ string s = verbatimStuff("\\end{" + name + "}").second;
+ // ignore one newline at beginning or end of string
+ if (prefixIs(s, "\n"))
+ s.erase(0,1);
+ if (suffixIs(s, "\n"))
+ s.erase(s.length() - 1,1);
+ return s;
+}
+
+
+string Parser::verbatimOption()
+{
+ string res;
+ if (next_token().character() == '[') {
+ Token t = get_token();
+ for (t = get_token(); t.character() != ']' && good(); t = get_token()) {
+ if (t.cat() == catBegin) {
+ putback();
+ res += '{' + verbatim_item() + '}';
+ } else
+ res += t.asInput();
+ }
+ }
+ return res;
+}
+
+
+string Parser::verbatim_item()
+{
+ if (!good())
+ error("stream bad");
+ skip_spaces();
+ if (next_token().cat() == catBegin) {
+ Token t = get_token(); // skip brace
+ string res;
+ for (Token t = get_token(); t.cat() != catEnd && good(); t = get_token()) {
+ if (t.cat() == catBegin) {
+ putback();
+ res += '{' + verbatim_item() + '}';
+ }
+ else
+ res += t.asInput();
+ }
+ return res;
+ }
+ return get_token().asInput();
+}
+
+