]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/preamble.C
* src/LyXAction.C: mark goto-clear-bookmark as working without buffer
[lyx.git] / src / tex2lyx / preamble.C
index bdcafa22eb6327c7361daa0d44f23ed99dd8c2a2..acb066814aeda319778ae5ee5000b572f1158ad8 100644 (file)
@@ -1,5 +1,11 @@
-/** The .tex to .lyx converter
-    \author André Pönitz (2003)
+/**
+ * \file preamble.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
  */
 
 // {[(
@@ -12,6 +18,7 @@
 #include "lyxtextclass.h"
 #include "lyxlex.h"
 #include "support/filetools.h"
+#include "support/lstrings.h"
 
 #include <algorithm>
 #include <iostream>
 #include <vector>
 #include <map>
 
-using std::cerr;
-using std::endl;
-using std::getline;
-using std::istream;
+
+namespace lyx {
+
 using std::istringstream;
 using std::ostream;
 using std::ostringstream;
 using std::string;
 using std::vector;
+using std::cerr;
+using std::endl;
 
-using lyx::support::LibFileSearch;
+using support::FileName;
+using support::libFileSearch;
 
 // special columntypes
 extern std::map<char, int> special_columns;
 
+std::map<string, vector<string> > used_packages;
+
 namespace {
 
-const char * known_languages[] = { "austrian", "babel", "bahasa", "basque",
-"breton", "british", "bulgarian", "catalan", "croatian", "czech", "danish",
-"dutch", "english", "esperanto", "estonian", "finnish", "francais",
-"frenchb", "galician", "german", "germanb", "greek", "hebcal", "hebfont",
+const char * const known_languages[] = { "austrian", "babel", "bahasa",
+"basque", "breton", "british", "bulgarian", "catalan", "croatian", "czech",
+"danish", "dutch", "english", "esperanto", "estonian", "finnish",
+"francais", "french", "frenchb", "frenchle", "frenchpro",
+"galician", "german", "germanb", "greek", "hebcal", "hebfont",
 "hebrew", "hebrew_newcode", "hebrew_oldcode", "hebrew_p", "hyphen",
 "icelandic", "irish", "italian", "latin", "lgrcmr", "lgrcmro", "lgrcmss",
 "lgrcmtt", "lgrenc", "lgrlcmss", "lgrlcmtt", "lheclas", "lhecmr",
@@ -50,7 +62,9 @@ const char * known_languages[] = { "austrian", "babel", "bahasa", "basque",
 "russianb", "samin", "scottish", "serbian", "slovak", "slovene", "spanish",
 "swedish", "turkish", "ukraineb", "usorbian", "welsh", 0};
 
-char const * known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
+const char * const known_french_languages[] = {"french", "frenchb", "francais",
+                                              "frenchle", "frenchpro", 0};
+char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
 
 // some ugly stuff
 ostringstream h_preamble;
@@ -63,25 +77,24 @@ string h_graphics                = "default";
 string h_paperfontsize           = "default";
 string h_spacing                 = "single";
 string h_papersize               = "default";
-string h_paperpackage            = "default";
-string h_use_geometry            = "0";
+string h_use_geometry            = "false";
 string h_use_amsmath             = "0";
-string h_use_natbib              = "0";
-string h_use_numerical_citations = "0";
+string h_cite_engine             = "basic";
+string h_use_bibtopic            = "false";
 string h_paperorientation        = "portrait";
 string h_secnumdepth             = "3";
 string h_tocdepth                = "3";
 string h_paragraph_separation    = "indent";
 string h_defskip                 = "medskip";
 string h_quotes_language         = "english";
-string h_quotes_times            = "2";
 string h_papercolumns            = "1";
-string h_papersides              = "1";
+string h_papersides              = string();
 string h_paperpagestyle          = "default";
-string h_tracking_changes        = "0";
+string h_tracking_changes        = "false";
+string h_output_changes          = "false";
 
 
-void handle_opt(vector<string> & opts, char const ** what, string & target)
+void handle_opt(vector<string> & opts, char const * const * what, string & target)
 {
        if (opts.empty())
                return;
@@ -98,13 +111,70 @@ void handle_opt(vector<string> & opts, char const ** what, string & target)
 }
 
 
-void handle_package(string const & name, string const & options)
+/*!
+ * Split a package options string (keyval format) into a vector.
+ * Example input:
+ *   authorformat=smallcaps,
+ *   commabeforerest,
+ *   titleformat=colonsep,
+ *   bibformat={tabular,ibidem,numbered}
+ */
+vector<string> split_options(string const & input)
+{
+       vector<string> options;
+       string option;
+       Parser p(input);
+       while (p.good()) {
+               Token const & t = p.get_token();
+               if (t.asInput() == ",") {
+                       options.push_back(option);
+                       option.erase();
+               } else if (t.asInput() == "=") {
+                       option += '=';
+                       p.skip_spaces(true);
+                       if (p.next_token().asInput() == "{")
+                               option += '{' + p.getArg('{', '}') + '}';
+               } else if (t.cat() != catSpace)
+                       option += t.asInput();
+       }
+
+       if (!option.empty())
+               options.push_back(option);
+
+       return options;
+}
+
+
+/*!
+ * Add package \p name with options \p options to used_packages.
+ * Remove options from \p options that we don't want to output.
+ */
+void add_package(string const & name, vector<string> & options)
+{
+       // every package inherits the global options
+       if (used_packages.find(name) == used_packages.end())
+               used_packages[name] = split_options(h_options);
+
+       vector<string> & v = used_packages[name];
+       v.insert(v.end(), options.begin(), options.end());
+       if (name == "jurabib") {
+               // Don't output the order argument (see the cite command
+               // handling code in text.C).
+               vector<string>::iterator end =
+                       remove(options.begin(), options.end(), "natbiborder");
+               end = remove(options.begin(), end, "jurabiborder");
+               options.erase(end, options.end());
+       }
+}
+
+
+void handle_package(string const & name, string const & opts)
 {
+       vector<string> options = split_options(opts);
+       add_package(name, options);
+
        //cerr << "handle_package: '" << name << "'\n";
-       if (name == "a4wide") {
-               h_papersize = "a4paper";
-               h_paperpackage = "widemarginsa4";
-       } else if (name == "ae")
+       if (name == "ae")
                h_fontscheme = "ae";
        else if (name == "aecompl")
                h_fontscheme = "ae";
@@ -116,32 +186,63 @@ void handle_package(string const & name, string const & options)
                ; // ignore this
        else if (name == "fontenc")
                ; // ignore this
-       else if (name == "inputenc")
-               h_inputencoding = options;
-       else if (name == "makeidx")
+       else if (name == "inputenc") {
+               h_inputencoding = opts;
+               options.clear();
+       } else if (name == "makeidx")
                ; // ignore this
        else if (name == "verbatim")
                ; // ignore this
+       else if (name == "graphicx")
+               ; // ignore this
        else if (is_known(name, known_languages)) {
-               h_language = name;
-               h_quotes_language = name;
-       } else {
-               if (options.size())
-                       h_preamble << "\\usepackage[" << options << "]{" << name << "}\n";
-               else
-                       h_preamble << "\\usepackage{" << name << "}\n";
+               if (is_known(name, known_french_languages)) {
+                       h_language = "french";
+                       h_quotes_language = "french";
+               } else {
+                       h_language = name;
+                       h_quotes_language = name;
+               }
+
+       } else if (name == "natbib") {
+               h_cite_engine = "natbib_authoryear";
+               vector<string>::iterator it =
+                       find(options.begin(), options.end(), "authoryear");
+               if (it != options.end())
+                       options.erase(it);
+               else {
+                       it = find(options.begin(), options.end(), "numbers");
+                       if (it != options.end()) {
+                               h_cite_engine = "natbib_numerical";
+                               options.erase(it);
+                       }
+               }
+       } else if (name == "jurabib") {
+               h_cite_engine = "jurabib";
+       } else if (options.empty())
+               h_preamble << "\\usepackage{" << name << "}\n";
+       else {
+               h_preamble << "\\usepackage[" << opts << "]{" << name << "}\n";
+               options.clear();
        }
+
+       // We need to do something with the options...
+       if (!options.empty())
+               cerr << "Ignoring options '" << join(options, ",")
+                    << "' of package " << name << '.' << endl;
 }
 
 
 
-void end_preamble(ostream & os, LyXTextClass const & textclass)
+void end_preamble(ostream & os, LyXTextClass const & /*textclass*/)
 {
-       os << "# tex2lyx 0.0.3 created this file\n"
-          << "\\lyxformat 224\n"
+       os << "#LyX file created by  tex2lyx 0.1.2\n"
+          << "\\lyxformat 245\n"
+          << "\\begin_document\n"
+          << "\\begin_header\n"
           << "\\textclass " << h_textclass << "\n"
           << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
-       if (h_options.size())
+       if (!h_options.empty())
           os << "\\options " << h_options << "\n";
        os << "\\language " << h_language << "\n"
           << "\\inputencoding " << h_inputencoding << "\n"
@@ -150,46 +251,57 @@ void end_preamble(ostream & os, LyXTextClass const & textclass)
           << "\\paperfontsize " << h_paperfontsize << "\n"
           << "\\spacing " << h_spacing << "\n"
           << "\\papersize " << h_papersize << "\n"
-          << "\\paperpackage " << h_paperpackage << "\n"
           << "\\use_geometry " << h_use_geometry << "\n"
           << "\\use_amsmath " << h_use_amsmath << "\n"
-          << "\\use_natbib " << h_use_natbib << "\n"
-          << "\\use_numerical_citations " << h_use_numerical_citations << "\n"
+          << "\\cite_engine " << h_cite_engine << "\n"
+          << "\\use_bibtopic " << h_use_bibtopic << "\n"
           << "\\paperorientation " << h_paperorientation << "\n"
           << "\\secnumdepth " << h_secnumdepth << "\n"
           << "\\tocdepth " << h_tocdepth << "\n"
           << "\\paragraph_separation " << h_paragraph_separation << "\n"
           << "\\defskip " << h_defskip << "\n"
           << "\\quotes_language " << h_quotes_language << "\n"
-          << "\\quotes_times " << h_quotes_times << "\n"
           << "\\papercolumns " << h_papercolumns << "\n"
           << "\\papersides " << h_papersides << "\n"
           << "\\paperpagestyle " << h_paperpagestyle << "\n"
           << "\\tracking_changes " << h_tracking_changes << "\n"
-          << "\\end_header\n\n\\begin_layout Standard\n";
+          << "\\output_changes " << h_output_changes << "\n"
+          << "\\end_header\n\n"
+          << "\\begin_body\n";
+       // clear preamble for subdocuments
+       h_preamble.str("");
 }
 
-
 } // anonymous namespace
 
-LyXTextClass const parse_preamble(Parser & p, ostream & os)
+LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & forceclass)
 {
        // initialize fixed types
        special_columns['D'] = 3;
+       bool is_full_document = false;
 
+       // determine whether this is a full document or a fragment for inclusion
        while (p.good()) {
                Token const & t = p.get_token();
 
+               if (t.cat() == catEscape && t.cs() == "documentclass") {
+                       is_full_document = true;
+                       break;
+               }
+       }
+       p.reset();
+
+       while (is_full_document && p.good()) {
+               Token const & t = p.get_token();
+
 #ifdef FILEDEBUG
-               cerr << "t: " << t << " flags: " << flags << "\n";
-               //cell->dump();
+               cerr << "t: " << t << "\n";
 #endif
 
                //
                // cat codes
                //
                if (t.cat() == catLetter ||
-                         t.cat() == catSpace ||
                          t.cat() == catSuper ||
                          t.cat() == catSub ||
                          t.cat() == catOther ||
@@ -198,24 +310,26 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                          t.cat() == catBegin ||
                          t.cat() == catEnd ||
                          t.cat() == catAlign ||
-                         t.cat() == catNewline ||
                          t.cat() == catParameter)
                h_preamble << t.character();
 
+               else if (t.cat() == catSpace || t.cat() == catNewline)
+                       h_preamble << t.asInput();
+
                else if (t.cat() == catComment)
-                       handle_comment(p);
+                       h_preamble << t.asInput();
 
                else if (t.cs() == "pagestyle")
-                       h_paperpagestyle == p.verbatim_item();
+                       h_paperpagestyle = p.verbatim_item();
 
                else if (t.cs() == "makeatletter") {
                        p.setCatCode('@', catLetter);
-                       h_preamble << "\\makeatletter\n";
+                       h_preamble << "\\makeatletter";
                }
 
                else if (t.cs() == "makeatother") {
                        p.setCatCode('@', catOther);
-                       h_preamble << "\\makeatother\n";
+                       h_preamble << "\\makeatother";
                }
 
                else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
@@ -226,27 +340,33 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                                star = true;
                        }
                        string const name = p.verbatim_item();
-                       string const opts = p.getOpt();
+                       string const opt1 = p.getOpt();
+                       string const opt2 = p.getFullOpt();
                        string const body = p.verbatim_item();
                        // only non-lyxspecific stuff
-                       if (name != "\\noun "
-                                 && name != "\\tabularnewline "
-                           && name != "\\LyX "
-                                 && name != "\\lyxline "
-                                 && name != "\\lyxaddress "
-                                 && name != "\\lyxrightaddress "
-                                 && name != "\\boldsymbol "
-                                 && name != "\\lyxarrow ") {
+                       if (   name != "\\noun"
+                           && name != "\\tabularnewline"
+                           && name != "\\LyX"
+                           && name != "\\lyxline"
+                           && name != "\\lyxaddress"
+                           && name != "\\lyxrightaddress"
+                           && name != "\\lyxdot"
+                           && name != "\\boldsymbol"
+                           && name != "\\lyxarrow") {
                                ostringstream ss;
                                ss << '\\' << t.cs();
                                if (star)
                                        ss << '*';
-                               ss << '{' << name << '}' << opts << '{' << body << "}\n";
+                               ss << '{' << name << '}' << opt1 << opt2
+                                  << '{' << body << "}";
                                h_preamble << ss.str();
+
+                               // Add the command to the known commands
+                               add_known_command(name, opt1, !opt2.empty());
 /*
                                ostream & out = in_preamble ? h_preamble : os;
                                out << "\\" << t.cs() << "{" << name << "}"
-                                   << opts << "{" << body << "}\n";
+                                   << opts << "{" << body << "}";
 */
                        }
                }
@@ -255,7 +375,13 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        vector<string> opts;
                        split(p.getArg('[', ']'), opts, ',');
                        handle_opt(opts, known_languages, h_language);
+                       if (is_known(h_language, known_french_languages))
+                               h_language = "french";
                        handle_opt(opts, known_fontsizes, h_paperfontsize);
+                       // delete "pt" at the end
+                       string::size_type i = h_paperfontsize.find("pt");
+                       if (i != string::npos)
+                               h_paperfontsize.erase(i);
                        h_quotes_language = h_language;
                        h_options = join(opts, ",");
                        h_textclass = p.getArg('{', '}');
@@ -284,9 +410,9 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        ss << p.getOpt();
                        ss << '{' << p.verbatim_item() << '}';
                        ss << '{' << p.verbatim_item() << '}';
-                       ss << '\n';
-                       if (name != "lyxcode" && name != "lyxlist"
-                                       && name != "lyxrightadress" && name != "lyxaddress")
+                       if (name != "lyxcode" && name != "lyxlist" &&
+                           name != "lyxrightadress" &&
+                           name != "lyxaddress" && name != "lyxgreyedout")
                                h_preamble << ss.str();
                }
 
@@ -294,7 +420,8 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        string name = p.get_token().cs();
                        while (p.next_token().cat() != catBegin)
                                name += p.get_token().asString();
-                       h_preamble << "\\def\\" << name << '{' << p.verbatim_item() << "}\n";
+                       h_preamble << "\\def\\" << name << '{'
+                                  << p.verbatim_item() << "}";
                }
 
                else if (t.cs() == "newcolumntype") {
@@ -302,7 +429,7 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        trim(name);
                        int nargs = 0;
                        string opts = p.getOpt();
-                       if (opts.size()) {
+                       if (!opts.empty()) {
                                istringstream is(string(opts, 1));
                                //cerr << "opt: " << is.str() << "\n";
                                is >> nargs;
@@ -311,7 +438,7 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        h_preamble << "\\newcolumntype{" << name << "}";
                        if (nargs)
                                h_preamble << "[" << nargs << "]";
-                       h_preamble << "{" << p.verbatim_item() << "}\n";
+                       h_preamble << "{" << p.verbatim_item() << "}";
                }
 
                else if (t.cs() == "setcounter") {
@@ -322,23 +449,21 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        else if (name == "tocdepth")
                                h_tocdepth = content;
                        else
-                               h_preamble << "\\setcounter{" << name << "}{" << content << "}\n";
+                               h_preamble << "\\setcounter{" << name << "}{" << content << "}";
                }
 
                else if (t.cs() == "setlength") {
                        string const name = p.verbatim_item();
                        string const content = p.verbatim_item();
+                       // Is this correct?
                        if (name == "parskip")
                                h_paragraph_separation = "skip";
                        else if (name == "parindent")
                                h_paragraph_separation = "skip";
                        else
-                               h_preamble << "\\setlength{" << name << "}{" << content << "}\n";
+                               h_preamble << "\\setlength{" << name << "}{" << content << "}";
                }
 
-               else if (t.cs() == "par")
-                       h_preamble << '\n';
-
                else if (t.cs() == "begin") {
                        string const name = p.getArg('{', '}');
                        if (name == "document")
@@ -346,14 +471,44 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os)
                        h_preamble << "\\begin{" << name << "}";
                }
 
-               else if (t.cs().size())
-                       h_preamble << '\\' << t.cs() << ' ';
-       }
+               else if (t.cs() == "jurabibsetup") {
+                       vector<string> jurabibsetup =
+                               split_options(p.getArg('{', '}'));
+                       // add jurabibsetup to the jurabib package options
+                       add_package("jurabib", jurabibsetup);
+                       if (!jurabibsetup.empty()) {
+                               h_preamble << "\\jurabibsetup{"
+                                          << join(jurabibsetup, ",") << '}';
+                       }
+               }
 
+               else if (!t.cs().empty())
+                       h_preamble << '\\' << t.cs();
+       }
+       p.skip_spaces();
+
+       // Force textclass if the user wanted it
+       if (!forceclass.empty())
+               h_textclass = forceclass;
+       if (noweb_mode && !lyx::support::prefixIs(h_textclass, "literate-"))
+               h_textclass.insert(0, "literate-");
+       FileName layoutfilename = libFileSearch("layouts", h_textclass, "layout");
+       if (layoutfilename.empty()) {
+               cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
+               exit(1);
+       }
        LyXTextClass textclass;
-       textclass.Read(LibFileSearch("layouts", h_textclass, "layout"));
+       textclass.read(layoutfilename);
+       if (h_papersides.empty()) {
+               ostringstream ss;
+               ss << textclass.sides();
+               h_papersides = ss.str();
+       }
        end_preamble(os, textclass);
        return textclass;
 }
 
 // }])
+
+
+} // namespace lyx