#include "lyxtextclass.h"
#include "support/path_defines.h"
#include "support/filetools.h"
+#include "support/lstrings.h"
+#include "support/lyxlib.h"
#include "support/os.h"
#include <boost/function.hpp>
using std::stringstream;
using std::string;
using std::vector;
+using std::map;
+using lyx::support::isStrUnsignedInt;
+using lyx::support::ltrim;
+using lyx::support::rtrim;
+using lyx::support::strToUnsignedInt;
using lyx::support::system_lyxdir;
using lyx::support::user_lyxdir;
using lyx::support::IsFileReadable;
// Hacks to allow the thing to link in the lyxlayout stuff
LyXErr lyxerr(std::cerr.rdbuf());
-void handle_comment(Parser & p)
-{
- string s;
- while (p.good()) {
- Token const & t = p.get_token();
- if (t.cat() == catNewline)
- break;
- s += t.asString();
- }
- //cerr << "comment: " << s << "\n";
- p.skip_spaces();
-}
-
string const trim(string const & a, char const * p)
{
}
-char const ** is_known(string const & str, char const ** what)
+char const * const * is_known(string const & str, char const * const * what)
{
for ( ; *what; ++what)
if (str == *what)
}
+map<string, vector<ArgumentType> > known_commands;
+
+
+void add_known_command(string const & command, string const & o1,
+ bool o2)
+{
+ // We have to handle the following cases:
+ // definition o1 o2 invocation result
+ // \newcommand{\foo}{bar} "" false \foo bar
+ // \newcommand{\foo}[1]{bar #1} "[1]" false \foo{x} bar x
+ // \newcommand{\foo}[1][]{bar #1} "[1]" true \foo bar
+ // \newcommand{\foo}[1][]{bar #1} "[1]" true \foo[x] bar x
+ // \newcommand{\foo}[1][x]{bar #1} "[1]" true \foo[x] bar x
+ unsigned int nargs = 0;
+ vector<ArgumentType> arguments;
+ string const opt1 = rtrim(ltrim(o1, "["), "]");
+ if (isStrUnsignedInt(opt1)) {
+ // The command has arguments
+ nargs = strToUnsignedInt(opt1);
+ if (nargs > 0 && o2) {
+ // The first argument is optional
+ arguments.push_back(optional);
+ --nargs;
+ }
+ }
+ for (unsigned int i = 0; i < nargs; ++i)
+ arguments.push_back(required);
+ known_commands[command] = arguments;
+}
+
+
+namespace {
+
+
+/*!
+ * Read a list of TeX commands from a reLyX compatible syntax file.
+ * Since this list is used after all commands that have a LyX counterpart
+ * are handled, it does not matter that the "syntax.default" file from reLyX
+ * has almost all of them listed. For the same reason the reLyX-specific
+ * reLyXre environment is ignored.
+ */
+void read_syntaxfile(string const & file_name)
+{
+ if (!IsFileReadable(file_name)) {
+ cerr << "Could not open syntax file \"" << file_name
+ << "\" for reading." << endl;
+ exit(2);
+ }
+ ifstream is(file_name.c_str());
+ // We can use our TeX parser, since the syntax of the layout file is
+ // modeled after TeX.
+ // Unknown tokens are just silently ignored, this helps us to skip some
+ // reLyX specific things.
+ Parser p(is);
+ while (p.good()) {
+ Token const & t = p.get_token();
+ if (t.cat() == catEscape) {
+ string command = t.asInput();
+ if (p.next_token().asInput() == "*") {
+ p.get_token();
+ command += '*';
+ }
+ p.skip_spaces();
+ vector<ArgumentType> arguments;
+ while (p.next_token().cat() == catBegin ||
+ p.next_token().asInput() == "[") {
+ if (p.next_token().cat() == catBegin) {
+ string const arg = p.getArg('{', '}');
+ if (arg == "translate")
+ arguments.push_back(required);
+ else
+ arguments.push_back(verbatim);
+ } else {
+ p.getArg('[', ']');
+ arguments.push_back(optional);
+ }
+ }
+ known_commands[command] = arguments;
+ }
+ }
+}
+
+
string documentclass;
+string syntaxfile;
bool overwrite_files = false;
"\t-f Force creation of .lyx files even if they exist already\n"
"\t-userdir dir try to set user directory to dir\n"
"\t-sysdir dir try to set system directory to dir\n"
- "\t-c textclass declare the textclass" << endl;
+ "\t-c textclass declare the textclass\n"
+ "\t-s syntaxfile read additional syntax file" << endl;
exit(0);
}
}
+int parse_syntaxfile(string const & arg, string const &)
+{
+ if (arg.empty()) {
+ cerr << "Missing syntaxfile string after -s switch" << endl;
+ exit(1);
+ }
+ syntaxfile = arg;
+ return 1;
+}
+
+
int parse_sysdir(string const & arg, string const &)
{
if (arg.empty()) {
void easyParse(int & argc, char * argv[])
{
- std::map<string, cmd_helper> cmdmap;
+ map<string, cmd_helper> cmdmap;
cmdmap["-c"] = parse_class;
cmdmap["-f"] = parse_force;
+ cmdmap["-s"] = parse_syntaxfile;
cmdmap["-help"] = parse_help;
cmdmap["--help"] = parse_help;
cmdmap["-sysdir"] = parse_sysdir;
}
+// path of the parsed file
+string masterFilePath;
+
+} // anonymous namespace
+
+
+string getMasterFilePath()
+{
+ return masterFilePath;
+}
+
+
void tex2lyx(std::istream &is, std::ostream &os)
{
Parser p(is);
Context context(true, textclass);
parse_text(p, ss, FLAG_END, true, context);
context.check_end_layout(ss);
- ss << "\n\\end_document\n";
+ ss << "\n\\end_body\n\\end_document\n";
active_environments.pop_back();
ss.seekg(0);
os << ss.str();
+#ifdef TEST_PARSER
+ p.reset();
+ ofstream parsertest("parsertest.tex");
+ while (p.good())
+ parsertest << p.get_token().asInput();
+ // <origfile> and parsertest.tex should now have identical content
+#endif
}
return 2;
}
- lyx::support::os::init(&argc, &argv);
+ lyx::support::os::init(argc, argv);
lyx::support::setLyxPaths();
+ string const system_syntaxfile = lyx::support::LibFileSearch("reLyX", "syntax.default");
+ if (system_syntaxfile.empty()) {
+ cerr << "Error: Could not find syntax file \"syntax.default\"." << endl;
+ exit(1);
+ }
+ read_syntaxfile(system_syntaxfile);
+ if (!syntaxfile.empty())
+ read_syntaxfile(syntaxfile);
+
if (!IsFileReadable(argv[1])) {
cerr << "Could not open input file \"" << argv[1]
<< "\" for reading." << endl;
return 2;
}
+
+ if (lyx::support::AbsolutePath(argv[1]))
+ masterFilePath = lyx::support::OnlyPath(argv[1]);
+ else
+ masterFilePath = lyx::support::getcwd();
+
ifstream is(argv[1]);
tex2lyx(is, cout);