]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/text.cpp
Let the Foot inset have a different Layout when inside a title
[lyx.git] / src / tex2lyx / text.cpp
index 8ebed0f53f3a0e227f8adab73772ad7aa73cb186..2c212a425fffbc7afc57b8171e0a591c94baf0fa 100644 (file)
@@ -112,66 +112,39 @@ string parse_text_snippet(Parser & p, unsigned flags, const bool outer,
 
 
 char const * const known_ref_commands[] = { "ref", "pageref", "vref",
- "vpageref", "prettyref", "eqref", 0 };
+ "vpageref", "prettyref", "nameref", "eqref", 0 };
 
 char const * const known_coded_ref_commands[] = { "ref", "pageref", "vref",
- "vpageref", "formatted", "eqref", 0 };
+ "vpageref", "formatted", "nameref", "eqref", 0 };
 
-/**
- * known polyglossia language names (including variants)
- */
-const char * const polyglossia_languages[] = {
-"albanian", "croatian", "hebrew", "norsk", "swedish", "amharic", "czech", "hindi",
-"nynorsk", "syriac", "arabic", "danish", "icelandic", "occitan", "tamil",
-"armenian", "divehi", "interlingua", "polish", "telugu", "asturian", "dutch",
-"irish", "portuges", "thai", "bahasai", "english", "italian", "romanian", "turkish",
-"bahasam", "esperanto", "lao", "russian", "turkmen", "basque", "estonian", "latin",
-"samin", "ukrainian", "bengali", "farsi", "latvian", "sanskrit", "urdu", "brazil",
-"brazilian", "finnish", "lithuanian", "scottish", "usorbian", "breton", "french",
-"lsorbian", "serbian", "vietnamese", "bulgarian", "galician", "magyar", "slovak",
-"welsh", "catalan", "german", "malayalam", "slovenian", "coptic", "greek",
-"marathi", "spanish",
-"american", "ancient", "australian", "british", "monotonic", "newzealand",
-"polytonic", 0};
+char const * const known_refstyle_commands[] = { "algref", "chapref", "corref",
+ "eqref", "enuref", "figref", "fnref", "lemref", "parref", "partref", "propref",
+ "secref", "subref", "tabref", "thmref", 0 };
+
+char const * const known_refstyle_prefixes[] = { "alg", "chap", "cor",
+ "eq", "enu", "fig", "fn", "lem", "par", "part", "prop",
+ "sec", "sub", "tab", "thm", 0 };
 
-/**
- * the same as polyglossia_languages with .lyx names
- * please keep this in sync with polyglossia_languages line by line!
- */
-const char * const coded_polyglossia_languages[] = {
-"albanian", "croatian", "hebrew", "norsk", "swedish", "amharic", "czech", "hindi",
-"nynorsk", "syriac", "arabic_arabi", "danish", "icelandic", "occitan", "tamil",
-"armenian", "divehi", "interlingua", "polish", "telugu", "asturian", "dutch",
-"irish", "portuges", "thai", "bahasa", "english", "italian", "romanian", "turkish",
-"bahasam", "esperanto", "lao", "russian", "turkmen", "basque", "estonian", "latin",
-"samin", "ukrainian", "bengali", "farsi", "latvian", "sanskrit", "urdu", "brazilian",
-"brazilian", "finnish", "lithuanian", "scottish", "uppersorbian", "breton", "french",
-"lowersorbian", "serbian", "vietnamese", "bulgarian", "galician", "magyar", "slovak",
-"welsh", "catalan", "ngerman", "malayalam", "slovene", "coptic", "greek",
-"marathi", "spanish",
-"american", "ancientgreek", "australian", "british", "greek", "newzealand",
-"polutonikogreek", 0};
 
 /**
  * supported CJK encodings
+ * JIS does not work with LyX's encoding conversion
  */
 const char * const supported_CJK_encodings[] = {
-"EUC-JP", "KS", "GB", "UTF8", 0};
+"EUC-JP", "KS", "GB", "UTF8",
+"Bg5", /*"JIS",*/ "SJIS", 0};
 
 /**
  * the same as supported_CJK_encodings with their corresponding LyX language name
+ * FIXME: The mapping "UTF8" => "chinese-traditional" is only correct for files
+ *        created by LyX.
+ * NOTE: "Bg5", "JIS" and "SJIS" are not supported by LyX, on re-export the
+ *       encodings "UTF8", "EUC-JP" and "EUC-JP" will be used.
  * please keep this in sync with supported_CJK_encodings line by line!
  */
-const char * const coded_supported_CJK_encodings[] = {
-"japanese-cjk", "korean", "chinese-simplified", "chinese-traditional", 0};
-
-string CJK2lyx(string const & encoding)
-{
-       char const * const * where = is_known(encoding, supported_CJK_encodings);
-       if (where)
-               return coded_supported_CJK_encodings[where - supported_CJK_encodings];
-       return encoding;
-}
+const char * const supported_CJK_languages[] = {
+"japanese-cjk", "korean", "chinese-simplified", "chinese-traditional",
+"chinese-traditional", /*"japanese-cjk",*/ "japanese-cjk", 0};
 
 /*!
  * natbib commands.
@@ -260,12 +233,14 @@ char const * const known_coded_font_shapes[] = { "italic", "slanted",
 "smallcaps", "up", 0};
 
 /// Known special characters which need skip_spaces_braces() afterwards
-char const * const known_special_chars[] = {"ldots", "lyxarrow",
-"textcompwordmark", "slash", 0};
+char const * const known_special_chars[] = {"ldots",
+"lyxarrow", "textcompwordmark",
+"slash", "textasciitilde", "textasciicircum", "textbackslash", 0};
 
 /// the same as known_special_chars with .lyx names
-char const * const known_coded_special_chars[] = {"ldots{}", "menuseparator",
-"textcompwordmark{}", "slash{}", 0};
+char const * const known_coded_special_chars[] = {"\\SpecialChar \\ldots{}\n",
+"\\SpecialChar \\menuseparator\n", "\\SpecialChar \\textcompwordmark{}\n",
+"\\SpecialChar \\slash{}\n", "~", "^", "\n\\backslash\n", 0};
 
 /*!
  * Graphics file extensions known by the dvips driver of the graphics package.
@@ -312,6 +287,18 @@ char const * const known_phrases[] = {"LyX", "TeX", "LaTeXe", "LaTeX", 0};
 char const * const known_coded_phrases[] = {"LyX", "TeX", "LaTeX2e", "LaTeX", 0};
 int const known_phrase_lengths[] = {3, 5, 7, 0};
 
+/// known TIPA combining diacritical marks
+char const * const known_tipa_marks[] = {"textsubwedge", "textsubumlaut",
+"textsubtilde", "textseagull", "textsubbridge", "textinvsubbridge",
+"textsubsquare", "textsubrhalfring", "textsublhalfring", "textsubplus",
+"textovercross", "textsubarch", "textsuperimposetilde", "textraising",
+"textlowering", "textadvancing", "textretracting", "textdoublegrave",
+"texthighrise", "textlowrise", "textrisefall", "textsyllabic",
+"textsubring", 0};
+
+/// TIPA tones that need special handling
+char const * const known_tones[] = {"15", "51", "45", "12", "454", 0};
+
 // string to store the float type to be able to determine the type of subfloats
 string float_type = "";
 
@@ -543,51 +530,33 @@ string convert_command_inset_arg(string s)
 }
 
 
-void handle_backslash(ostream & os, string const & s)
-{
-       for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
-               if (*it == '\\')
-                       os << "\n\\backslash\n";
-               else
-                       os << *it;
-       }
-}
-
-
-void handle_ert(ostream & os, string const & s, Context & context)
+void output_ert(ostream & os, string const & s, Context & context)
 {
-       // We must have a valid layout before outputting the ERT inset.
        context.check_layout(os);
-       Context newcontext(true, context.textclass);
-       begin_inset(os, "ERT");
-       os << "\nstatus collapsed\n";
-       newcontext.check_layout(os);
        for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
                if (*it == '\\')
                        os << "\n\\backslash\n";
                else if (*it == '\n') {
-                       newcontext.new_paragraph(os);
-                       newcontext.check_layout(os);
+                       context.new_paragraph(os);
+                       context.check_layout(os);
                } else
                        os << *it;
        }
-       newcontext.check_end_layout(os);
-       end_inset(os);
+       context.check_end_layout(os);
 }
 
 
-void handle_comment(ostream & os, string const & s, Context & context)
+void output_ert_inset(ostream & os, string const & s, Context & context)
 {
-       // TODO: Handle this better
+       // We must have a valid layout before outputting the ERT inset.
+       context.check_layout(os);
        Context newcontext(true, context.textclass);
+       InsetLayout const & layout = context.textclass.insetLayout(from_ascii("ERT"));
+       if (layout.forcePlainLayout())
+               newcontext.layout = &context.textclass.plainLayout();
        begin_inset(os, "ERT");
        os << "\nstatus collapsed\n";
-       newcontext.check_layout(os);
-       handle_backslash(os, s);
-       // make sure that our comment is the last thing on the line
-       newcontext.new_paragraph(os);
-       newcontext.check_layout(os);
-       newcontext.check_end_layout(os);
+       output_ert(os, s, newcontext);
        end_inset(os);
 }
 
@@ -668,27 +637,40 @@ void output_command_layout(ostream & os, Parser & p, bool outer,
        }
        context.check_deeper(os);
        context.check_layout(os);
-       unsigned int optargs = 0;
-       while (optargs < context.layout->optargs) {
+       // FIXME: Adjust to format 446!
+       // Since format 446, layouts do not require anymore all optional
+       // arguments before the required ones. Needs to be implemented!
+       int optargs = 0;
+       while (optargs < context.layout->optArgs()) {
                eat_whitespace(p, os, context, false);
                if (p.next_token().cat() == catEscape ||
                    p.next_token().character() != '[')
                        break;
                p.get_token(); // eat '['
-               begin_inset(os, "Argument\n");
+               // FIXME: Just a workaround. InsetArgument::updateBuffer
+               //        will compute a proper ID for all "999" Arguments
+               //        (which is also what lyx2lyx produces).
+               //        However, tex2lyx should be able to output proper IDs
+               //        itself.
+               begin_inset(os, "Argument 999\n");
                os << "status collapsed\n\n";
                parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context);
                end_inset(os);
                eat_whitespace(p, os, context, false);
                ++optargs;
        }
-       unsigned int reqargs = 0;
-       while (reqargs < context.layout->reqargs) {
+       int reqargs = 0;
+       while (reqargs < context.layout->requiredArgs()) {
                eat_whitespace(p, os, context, false);
                if (p.next_token().cat() != catBegin)
                        break;
                p.get_token(); // eat '{'
-               begin_inset(os, "Argument\n");
+               // FIXME: Just a workaround. InsetArgument::updateBuffer
+               //        will compute a proper ID for all "999" Arguments
+               //        (which is also what lyx2lyx produces).
+               //        However, tex2lyx should be able to output proper IDs
+               //        itself.
+               begin_inset(os, "Argument 999\n");
                os << "status collapsed\n\n";
                parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context);
                end_inset(os);
@@ -762,7 +744,7 @@ void parse_arguments(string const & command,
                case required:
                case req_group:
                        // This argument contains regular LaTeX
-                       handle_ert(os, ert + '{', context);
+                       output_ert_inset(os, ert + '{', context);
                        eat_whitespace(p, os, context, false);
                        if (template_arguments[i] == required)
                                parse_text(p, os, FLAG_ITEM, outer, context);
@@ -797,7 +779,7 @@ void parse_arguments(string const & command,
                        break;
                }
        }
-       handle_ert(os, ert, context);
+       output_ert_inset(os, ert, context);
 }
 
 
@@ -854,8 +836,18 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                        if (inner_type != "makebox") {
                                latex_height = p.getArg('[', ']');
                                translate_box_len(latex_height, height_value, height_unit, height_special);
-                       } else
-                               hor_pos = p.getArg('[', ']');
+                       } else {
+                               string const opt = p.getArg('[', ']');
+                               if (!opt.empty()) {
+                                       hor_pos = opt;
+                                       if (hor_pos != "l" && hor_pos != "c" &&
+                                           hor_pos != "r" && hor_pos != "s") {
+                                               cerr << "invalid hor_pos " << hor_pos
+                                                    << " for " << inner_type << endl;
+                                               hor_pos = "c";
+                                       }
+                               }
+                       }
 
                        if (p.hasOpt()) {
                                inner_pos = p.getArg('[', ']');
@@ -879,7 +871,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                        if (!opt.empty()) {
                                hor_pos = opt;
                                if (hor_pos != "l" && hor_pos != "c" &&
-                                   hor_pos != "r") {
+                                   hor_pos != "r" && hor_pos != "s") {
                                        cerr << "invalid hor_pos " << hor_pos
                                             << " for " << outer_type << endl;
                                        hor_pos = "c";
@@ -922,7 +914,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                // If yes, we need to output ERT.
                p.pushPosition();
                if (inner_flags & FLAG_END)
-                       p.verbatimEnvironment(inner_type);
+                       p.ertEnvironment(inner_type);
                else
                        p.verbatim_item();
                p.skip_spaces(true);
@@ -943,7 +935,9 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                width_unit = "in";
                width_special = "width";
        } else if (latex_width.empty() && outer_type == "framebox") {
-               use_ert = true;
+               width_value.clear();
+               width_unit.clear();
+               width_special = "none";
        }
        if (use_ert) {
                ostringstream ss;
@@ -975,14 +969,14 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                }
                if (inner_type == "shaded")
                        ss << "\\begin{shaded}";
-               handle_ert(os, ss.str(), parent_context);
+               output_ert_inset(os, ss.str(), parent_context);
                if (!inner_type.empty()) {
                        parse_text(p, os, inner_flags, outer, parent_context);
                        if (inner_flags & FLAG_END)
-                               handle_ert(os, "\\end{" + inner_type + '}',
+                               output_ert_inset(os, "\\end{" + inner_type + '}',
                                           parent_context);
                        else
-                               handle_ert(os, "}", parent_context);
+                               output_ert_inset(os, "}", parent_context);
                }
                if (!outer_type.empty()) {
                        // If we already read the inner box we have to pop
@@ -998,13 +992,10 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                        }
                        parse_text(p, os, outer_flags, outer, parent_context);
                        if (outer_flags & FLAG_END)
-                               handle_ert(os, "\\end{" + outer_type + '}',
+                               output_ert_inset(os, "\\end{" + outer_type + '}',
                                           parent_context);
-                       else if (inner_type.empty() && outer_type == "framebox")
-                               // in this case it is already closed later
-                               ;
                        else
-                               handle_ert(os, "}", parent_context);
+                               output_ert_inset(os, "}", parent_context);
                }
        } else {
                // LyX does not like empty positions, so we have
@@ -1017,7 +1008,7 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                begin_inset(os, "Box ");
                if (outer_type == "framed")
                        os << "Framed\n";
-               else if (outer_type == "framebox")
+               else if (outer_type == "framebox" || outer_type == "fbox")
                        os << "Boxed\n";
                else if (outer_type == "shadowbox")
                        os << "Shadowbox\n";
@@ -1028,18 +1019,27 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                        preamble.registerAutomaticallyLoadedPackage("color");
                } else if (outer_type == "doublebox")
                        os << "Doublebox\n";
-               else if (outer_type.empty())
+               else if (outer_type.empty() || outer_type == "mbox")
                        os << "Frameless\n";
                else
                        os << outer_type << '\n';
                os << "position \"" << position << "\"\n";
                os << "hor_pos \"" << hor_pos << "\"\n";
-               os << "has_inner_box " << !inner_type.empty() << "\n";
+               if (outer_type == "mbox")
+                       os << "has_inner_box 1\n";
+               else
+                       os << "has_inner_box " << !inner_type.empty() << "\n";
                os << "inner_pos \"" << inner_pos << "\"\n";
                os << "use_parbox " << (inner_type == "parbox" || shadedparbox)
                   << '\n';
-               os << "use_makebox " << (inner_type == "makebox") << '\n';
-               os << "width \"" << width_value << width_unit << "\"\n";
+               if (outer_type == "mbox")
+                       os << "use_makebox 1\n";
+               else
+                       os << "use_makebox " << (inner_type == "makebox") << '\n';
+               if (outer_type == "fbox" || outer_type == "mbox")
+                       os << "width \"\"\n";
+               else
+                       os << "width \"" << width_value << width_unit << "\"\n";
                os << "special \"" << width_special << "\"\n";
                os << "height \"" << height_value << height_unit << "\"\n";
                os << "height_special \"" << height_special << "\"\n";
@@ -1087,13 +1087,13 @@ void parse_box(Parser & p, ostream & os, unsigned outer_flags,
                // LyX puts a % after the end of the minipage
                if (p.next_token().cat() == catNewline && p.next_token().cs().size() > 1) {
                        // new paragraph
-                       //handle_comment(os, "%dummy", parent_context);
+                       //output_ert_inset(os, "%dummy", parent_context);
                        p.get_token();
                        p.skip_spaces();
                        parent_context.new_paragraph(os);
                }
                else if (p.next_token().cat() == catSpace || p.next_token().cat() == catNewline) {
-                       //handle_comment(os, "%dummy", parent_context);
+                       //output_ert_inset(os, "%dummy", parent_context);
                        p.get_token();
                        p.skip_spaces();
                        // We add a protected space if something real follows
@@ -1139,7 +1139,8 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer,
                        p.skip_spaces(true);
                }
        }
-       if (outer_type == "shaded") {
+       if (outer_type == "shaded" || outer_type == "fbox"
+               || outer_type == "mbox") {
                // These boxes never have an inner box
                ;
        } else if (p.next_token().asInput() == "\\parbox") {
@@ -1184,6 +1185,8 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_
        if (p.hasOpt()) {
                string arg = p.verbatimOption();
                os << "lstparams " << '"' << arg << '"' << '\n';
+               if (arg.find("\\color") != string::npos)
+                       preamble.registerAutomaticallyLoadedPackage("color");
        }
        if (in_line)
                os << "inline true\n";
@@ -1194,24 +1197,15 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_
        context.layout = &parent_context.textclass.plainLayout();
        string s;
        if (in_line) {
-               s = p.plainCommand('!', '!', "lstinline");
-               context.new_paragraph(os);
-               context.check_layout(os);
+               // set catcodes to verbatim early, just in case.
+               p.setCatcodes(VERBATIM_CATCODES);
+               string delim = p.get_token().asInput();
+               //FIXME: handler error condition
+               s = p.verbatimStuff(delim).second;
+//             context.new_paragraph(os);
        } else
-               s = p.plainEnvironment("lstlisting");
-       for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
-               if (*it == '\\')
-                       os << "\n\\backslash\n";
-               else if (*it == '\n') {
-                       // avoid adding an empty paragraph at the end
-                       if (it + 1 != et) {
-                               context.new_paragraph(os);
-                               context.check_layout(os);
-                       }
-               } else
-                       os << *it;
-       }
-       context.check_end_layout(os);
+               s = p.verbatimEnvironment("lstlisting");
+       output_ert(os, s, context);
        end_inset(os);
 }
 
@@ -1235,9 +1229,9 @@ void parse_unknown_environment(Parser & p, string const & name, ostream & os,
        bool const new_layout_allowed = parent_context.new_layout_allowed;
        if (specialfont)
                parent_context.new_layout_allowed = false;
-       handle_ert(os, "\\begin{" + name + "}", parent_context);
+       output_ert_inset(os, "\\begin{" + name + "}", parent_context);
        parse_text_snippet(p, os, flags, outer, parent_context);
-       handle_ert(os, "\\end{" + name + "}", parent_context);
+       output_ert_inset(os, "\\end{" + name + "}", parent_context);
        if (specialfont)
                parent_context.new_layout_allowed = new_layout_allowed;
 }
@@ -1268,7 +1262,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                }
        }
 
-       else if (is_known(name, polyglossia_languages)) {
+       else if (is_known(name, preamble.polyglossia_languages)) {
                // We must begin a new paragraph if not already done
                if (! parent_context.atParagraphStart()) {
                        parent_context.check_end_layout(os);
@@ -1276,7 +1270,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                }
                // save the language in the context so that it is
                // handled by parse_text
-               parent_context.font.language = polyglossia2lyx(name);
+               parent_context.font.language = preamble.polyglossia2lyx(name);
                parse_text(p, os, FLAG_END, outer, parent_context);
                // Just in case the environment is empty
                parent_context.extra_stuff.erase();
@@ -1431,69 +1425,83 @@ void parse_environment(Parser & p, ostream & os, bool outer,
        }
 
        else if (name == "verbatim") {
-               os << "\n\\end_layout\n\n\\begin_layout Verbatim\n";
-               string const s = p.plainEnvironment("verbatim");
-               string::const_iterator it2 = s.begin();
-               for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
-                       if (*it == '\\')
-                               os << "\\backslash ";
-                       else if (*it == '\n') {
-                               it2 = it + 1;
-                               // avoid adding an empty paragraph at the end
-                               // FIXME: if there are 2 consecutive spaces at the end ignore it
-                               // because LyX will re-add a \n
-                               // This hack must be removed once bug 8049 is fixed!
-                               if ((it + 1 != et) && (it + 2 != et || *it2 != '\n'))
-                                       os << "\n\\end_layout\n\\begin_layout Verbatim\n";
-                       } else 
-                               os << *it;
-               }
-               os << "\n\\end_layout\n\n";
+               // FIXME: this should go in the generic code that
+               // handles environments defined in layout file that
+               // have "PassThru 1". However, the code over there is
+               // already too complicated for my taste.
+               parent_context.new_paragraph(os);
+               Context context(true, parent_context.textclass,
+                               &parent_context.textclass[from_ascii("Verbatim")]);
+               string s = p.verbatimEnvironment("verbatim");
+               output_ert(os, s, context);
+               p.skip_spaces();
+       }
+
+       else if (name == "IPA") {
+               eat_whitespace(p, os, parent_context, false);
+               parent_context.check_layout(os);
+               begin_inset(os, "IPA\n");
+               parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+               end_inset(os);
                p.skip_spaces();
-               // reset to Standard layout
-               os << "\n\\begin_layout Standard\n";
+               preamble.registerAutomaticallyLoadedPackage("tipa");
+               preamble.registerAutomaticallyLoadedPackage("tipx");
        }
 
        else if (name == "CJK") {
-               // the scheme is \begin{CJK}{encoding}{mapping}{text}
+               // the scheme is \begin{CJK}{encoding}{mapping}text\end{CJK}
                // It is impossible to decide if a CJK environment was in its own paragraph or within
                // a line. We therefore always assume a paragraph since the latter is a rare case.
                eat_whitespace(p, os, parent_context, false);
                parent_context.check_end_layout(os);
                // store the encoding to be able to reset it
-               string const encoding_old = p.encoding_latex_;
+               string const encoding_old = p.getEncoding();
                string const encoding = p.getArg('{', '}');
-               // SJIS and BIG5 don't work with LaTeX according to the comment in unicode.cpp
-               // JIS does not work with LyX's encoding conversion
-               if (encoding != "SJIS" && encoding != "BIG5" && encoding != "JIS")
-                       p.setEncoding(encoding);
-               else
-                       p.setEncoding("utf8");
-               // LyX doesn't support the second argument so if
-               // this is used we need to output everything as ERT
-               string const mapping = p.getArg('{', '}');
-               if ( (!mapping.empty() && mapping != " ")
-                       || (!is_known(encoding, supported_CJK_encodings))) {
+               // FIXME: For some reason JIS does not work. Although the text
+               // in tests/CJK.tex is identical with the SJIS version if you
+               // convert both snippets using the recode command line utility,
+               // the resulting .lyx file contains some extra characters if
+               // you set buggy_encoding to false for JIS.
+               bool const buggy_encoding = encoding == "JIS";
+               if (!buggy_encoding)
+                       p.setEncoding(encoding, Encoding::CJK);
+               else {
+                       // FIXME: This will read garbage, since the data is not encoded in utf8.
+                       p.setEncoding("UTF-8");
+               }
+               // LyX only supports the same mapping for all CJK
+               // environments, so we might need to output everything as ERT
+               string const mapping = trim(p.getArg('{', '}'));
+               char const * const * const where =
+                       is_known(encoding, supported_CJK_encodings);
+               if (!buggy_encoding && !preamble.fontCJKSet())
+                       preamble.fontCJK(mapping);
+               bool knownMapping = mapping == preamble.fontCJK();
+               if (buggy_encoding || !knownMapping || !where) {
                        parent_context.check_layout(os);
-                       handle_ert(os, "\\begin{" + name + "}{" + encoding + "}{" + mapping + "}",
+                       output_ert_inset(os, "\\begin{" + name + "}{" + encoding + "}{" + mapping + "}",
                                       parent_context);
-                       // we must parse the content as verbatim because e.g. SJIS can contain
+                       // we must parse the content as verbatim because e.g. JIS can contain
                        // normally invalid characters
+                       // FIXME: This works only for the most simple cases.
+                       //        Since TeX control characters are not parsed,
+                       //        things like comments are completely wrong.
                        string const s = p.plainEnvironment("CJK");
-                       string::const_iterator it2 = s.begin();
                        for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
                                if (*it == '\\')
-                                       handle_ert(os, "\\", parent_context);
+                                       output_ert_inset(os, "\\", parent_context);
                                else if (*it == '$')
-                                       handle_ert(os, "$", parent_context);
-                               else 
+                                       output_ert_inset(os, "$", parent_context);
+                               else if (*it == '\n' && it + 1 != et && s.begin() + 1 != it)
+                                       os << "\n ";
+                               else
                                        os << *it;
                        }
-                       p.skip_spaces();
-                       handle_ert(os, "\\end{" + name + "}",
+                       output_ert_inset(os, "\\end{" + name + "}",
                                       parent_context);
                } else {
-                       string const lang = CJK2lyx(encoding);
+                       string const lang =
+                               supported_CJK_languages[where - supported_CJK_encodings];
                        // store the language because we must reset it at the end
                        string const lang_old = parent_context.font.language;
                        parent_context.font.language = lang;
@@ -1501,7 +1509,7 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        parent_context.font.language = lang_old;
                        parent_context.new_paragraph(os);
                }
-               p.encoding_latex_ = encoding_old;
+               p.setEncoding(encoding_old);
                p.skip_spaces();
        }
 
@@ -1517,6 +1525,37 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                        preamble.registerAutomaticallyLoadedPackage("color");
        }
 
+       else if (name == "btSect") {
+               eat_whitespace(p, os, parent_context, false);
+               parent_context.check_layout(os);
+               begin_command_inset(os, "bibtex", "bibtex");
+               string bibstyle = "plain";
+               if (p.hasOpt()) {
+                       bibstyle = p.getArg('[', ']');
+                       p.skip_spaces(true);
+               }
+               string const bibfile = p.getArg('{', '}');
+               eat_whitespace(p, os, parent_context, false);
+               Token t = p.get_token();
+               if (t.asInput() == "\\btPrintCited") {
+                       p.skip_spaces(true);
+                       os << "btprint " << '"' << "btPrintCited" << '"' << "\n";
+               }
+               if (t.asInput() == "\\btPrintNotCited") {
+                       p.skip_spaces(true);
+                       os << "btprint " << '"' << "btPrintNotCited" << '"' << "\n";
+               }
+               if (t.asInput() == "\\btPrintAll") {
+                       p.skip_spaces(true);
+                       os << "btprint " << '"' << "btPrintAll" << '"' << "\n";
+               }
+               os << "bibfiles " << '"' << bibfile << '"' << "\n";
+               os << "options " << '"' << bibstyle << '"' <<  "\n";
+               parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
+               end_inset(os);
+               p.skip_spaces();
+       }
+
        else if (name == "framed" || name == "shaded") {
                eat_whitespace(p, os, parent_context, false);
                parse_outer_box(p, os, FLAG_END, outer, parent_context, name, "");
@@ -1525,8 +1564,6 @@ void parse_environment(Parser & p, ostream & os, bool outer,
 
        else if (name == "lstlisting") {
                eat_whitespace(p, os, parent_context, false);
-               // FIXME handle the automatic color package loading
-               // uwestoehr asks: In what case color is loaded?
                parse_listings(p, os, parent_context, false);
                p.skip_spaces();
        }
@@ -1593,24 +1630,13 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                if (last_env == name) {
                        // we need to output a separator since LyX would export
                        // the two environments as one otherwise (bug 5716)
-                       docstring const sep = from_ascii("--Separator--");
                        TeX2LyXDocClass const & textclass(parent_context.textclass);
-                       if (textclass.hasLayout(sep)) {
-                               Context newcontext(parent_context);
-                               newcontext.layout = &(textclass[sep]);
-                               newcontext.check_layout(os);
-                               newcontext.check_end_layout(os);
-                       } else {
-                               parent_context.check_layout(os);
-                               begin_inset(os, "Note Note\n");
-                               os << "status closed\n";
-                               Context newcontext(true, textclass,
-                                               &(textclass.defaultLayout()));
-                               newcontext.check_layout(os);
-                               newcontext.check_end_layout(os);
-                               end_inset(os);
-                               parent_context.check_end_layout(os);
-                       }
+                       Context newcontext(true, textclass,
+                                       &(textclass.defaultLayout()));
+                       newcontext.check_layout(os);
+                       begin_inset(os, "Separator plain\n");
+                       end_inset(os);
+                       newcontext.check_end_layout(os);
                }
                switch (context.layout->latextype) {
                case  LATEX_LIST_ENVIRONMENT:
@@ -1627,14 +1653,15 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                }
                context.check_deeper(os);
                // handle known optional and required arguments
-               // layouts require all optional arguments before the required ones
+               // FIXME: Since format 446, layouts do not require anymore all optional
+               // arguments before the required ones. Needs to be implemented!
                // Unfortunately LyX can't handle arguments of list arguments (bug 7468):
                // It is impossible to place anything after the environment name,
                // but before the first \\item.
                if (context.layout->latextype == LATEX_ENVIRONMENT) {
                        bool need_layout = true;
-                       unsigned int optargs = 0;
-                       while (optargs < context.layout->optargs) {
+                       int optargs = 0;
+                       while (optargs < context.layout->optArgs()) {
                                eat_whitespace(p, os, context, false);
                                if (p.next_token().cat() == catEscape ||
                                    p.next_token().character() != '[')
@@ -1644,15 +1671,20 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                                        context.check_layout(os);
                                        need_layout = false;
                                }
-                               begin_inset(os, "Argument\n");
+                               // FIXME: Just a workaround. InsetArgument::updateBuffer
+                               //        will compute a proper ID for all "999" Arguments
+                               //        (which is also what lyx2lyx produces).
+                               //        However, tex2lyx should be able to output proper IDs
+                               //        itself.
+                               begin_inset(os, "Argument 999\n");
                                os << "status collapsed\n\n";
                                parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context);
                                end_inset(os);
                                eat_whitespace(p, os, context, false);
                                ++optargs;
                        }
-                       unsigned int reqargs = 0;
-                       while (reqargs < context.layout->reqargs) {
+                       int reqargs = 0;
+                       while (reqargs < context.layout->requiredArgs()) {
                                eat_whitespace(p, os, context, false);
                                if (p.next_token().cat() != catBegin)
                                        break;
@@ -1661,7 +1693,12 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                                        context.check_layout(os);
                                        need_layout = false;
                                }
-                               begin_inset(os, "Argument\n");
+                               // FIXME: Just a workaround. InsetArgument::updateBuffer
+                               //        will compute a proper ID for all "999" Arguments
+                               //        (which is also what lyx2lyx produces).
+                               //        However, tex2lyx should be able to output proper IDs
+                               //        itself.
+                               begin_inset(os, "Argument 999\n");
                                os << "status collapsed\n\n";
                                parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context);
                                end_inset(os);
@@ -1695,7 +1732,14 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                begin_inset(os, "Flex ");
                os << to_utf8(newinsetlayout->name()) << '\n'
                   << "status collapsed\n";
-               parse_text_in_inset(p, os, FLAG_END, false, parent_context, newinsetlayout);
+               if (newinsetlayout->isPassThru()) {
+                       string const arg = p.verbatimEnvironment(name);
+                       Context context(true, parent_context.textclass, 
+                                       &parent_context.textclass.plainLayout(),
+                                       parent_context.layout);
+                       output_ert(os, arg, parent_context);
+               } else
+                       parse_text_in_inset(p, os, FLAG_END, false, parent_context, newinsetlayout);
                end_inset(os);
        }
 
@@ -1733,12 +1777,12 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                parse_arguments("\\begin{" + name + "}", arguments, p, os,
                                outer, parent_context);
                if (contents == verbatim)
-                       handle_ert(os, p.verbatimEnvironment(name),
+                       output_ert_inset(os, p.ertEnvironment(name),
                                   parent_context);
                else
                        parse_text_snippet(p, os, FLAG_END, outer,
                                           parent_context);
-               handle_ert(os, "\\end{" + name + "}", parent_context);
+               output_ert_inset(os, "\\end{" + name + "}", parent_context);
                if (specialfont)
                        parent_context.new_layout_allowed = new_layout_allowed;
        }
@@ -1758,7 +1802,7 @@ void parse_comment(Parser & p, ostream & os, Token const & t, Context & context)
        LASSERT(t.cat() == catComment, return);
        if (!t.cs().empty()) {
                context.check_layout(os);
-               handle_comment(os, '%' + t.cs(), context);
+               output_ert_inset(os, '%' + t.cs(), context);
                if (p.next_token().cat() == catNewline) {
                        // A newline after a comment line starts a new
                        // paragraph
@@ -1768,7 +1812,7 @@ void parse_comment(Parser & p, ostream & os, Token const & t, Context & context)
                                        // done (we might get called recursively)
                                        context.new_paragraph(os);
                        } else
-                               handle_ert(os, "\n", context);
+                               output_ert_inset(os, "\n", context);
                        eat_whitespace(p, os, context, true);
                }
        } else {
@@ -1845,7 +1889,7 @@ void get_cite_arguments(Parser & p, bool natbibOrder,
 /// can understand
 string const normalize_filename(string const & name)
 {
-       Parser p(trim(name, "\""));
+       Parser p(name);
        ostringstream os;
        while (p.good()) {
                Token const & t = p.get_token();
@@ -1859,97 +1903,168 @@ string const normalize_filename(string const & name)
                } else if (t.cs() == "space") {
                        os << ' ';
                        p.skip_spaces();
+               } else if (t.cs() == "string") {
+                       // Convert \string" to " and \string~ to ~
+                       Token const & n = p.next_token();
+                       if (n.asInput() != "\"" && n.asInput() != "~")
+                               os << t.asInput();
                } else
                        os << t.asInput();
        }
-       return os.str();
+       // Strip quotes. This is a bit complicated (see latex_path()).
+       string full = os.str();
+       if (!full.empty() && full[0] == '"') {
+               string base = removeExtension(full);
+               string ext = getExtension(full);
+               if (!base.empty() && base[base.length()-1] == '"')
+                       // "a b"
+                       // "a b".tex
+                       return addExtension(trim(base, "\""), ext);
+               if (full[full.length()-1] == '"')
+                       // "a b.c"
+                       // "a b.c".tex
+                       return trim(full, "\"");
+       }
+       return full;
 }
 
 
 /// Convert \p name from TeX convention (relative to master file) to LyX
 /// convention (relative to .lyx file) if it is relative
-void fix_relative_filename(string & name)
+void fix_child_filename(string & name)
 {
-       if (FileName::isAbsolute(name))
-               return;
-
-       name = to_utf8(makeRelPath(from_utf8(makeAbsPath(name, getMasterFilePath()).absFileName()),
-                                  from_utf8(getParentFilePath())));
+       string const absMasterTeX = getMasterFilePath(true);
+       bool const isabs = FileName::isAbsolute(name);
+       // convert from "relative to .tex master" to absolute original path
+       if (!isabs)
+               name = makeAbsPath(name, absMasterTeX).absFileName();
+       bool copyfile = copyFiles();
+       string const absParentLyX = getParentFilePath(false);
+       string abs = name;
+       if (copyfile) {
+               // convert from absolute original path to "relative to master file"
+               string const rel = to_utf8(makeRelPath(from_utf8(name),
+                                                      from_utf8(absMasterTeX)));
+               // re-interpret "relative to .tex file" as "relative to .lyx file"
+               // (is different if the master .lyx file resides in a
+               // different path than the master .tex file)
+               string const absMasterLyX = getMasterFilePath(false);
+               abs = makeAbsPath(rel, absMasterLyX).absFileName();
+               // Do not copy if the new path is impossible to create. Example:
+               // absMasterTeX = "/foo/bar/"
+               // absMasterLyX = "/bar/"
+               // name = "/baz.eps" => new absolute name would be "/../baz.eps"
+               if (contains(name, "/../"))
+                       copyfile = false;
+       }
+       if (copyfile) {
+               if (isabs)
+                       name = abs;
+               else {
+                       // convert from absolute original path to
+                       // "relative to .lyx file"
+                       name = to_utf8(makeRelPath(from_utf8(abs),
+                                                  from_utf8(absParentLyX)));
+               }
+       }
+       else if (!isabs) {
+               // convert from absolute original path to "relative to .lyx file"
+               name = to_utf8(makeRelPath(from_utf8(name),
+                                          from_utf8(absParentLyX)));
+       }
 }
 
 
-/// Parse a NoWeb Scrap section. The initial "<<" is already parsed.
-void parse_noweb(Parser & p, ostream & os, Context & context)
+void copy_file(FileName const & src, string dstname)
 {
-       // assemble the rest of the keyword
-       string name("<<");
-       bool scrap = false;
-       while (p.good()) {
-               Token const & t = p.get_token();
-               if (t.asInput() == ">" && p.next_token().asInput() == ">") {
-                       name += ">>";
-                       p.get_token();
-                       scrap = (p.good() && p.next_token().asInput() == "=");
-                       if (scrap)
-                               name += p.get_token().asInput();
-                       break;
+       if (!copyFiles())
+               return;
+       string const absParent = getParentFilePath(false);
+       FileName dst;
+       if (FileName::isAbsolute(dstname))
+               dst = FileName(dstname);
+       else
+               dst = makeAbsPath(dstname, absParent);
+       string const absMaster = getMasterFilePath(false);
+       FileName const srcpath = src.onlyPath();
+       FileName const dstpath = dst.onlyPath();
+       if (equivalent(srcpath, dstpath))
+               return;
+       if (!dstpath.isDirectory()) {
+               if (!dstpath.createPath()) {
+                       cerr << "Warning: Could not create directory for file `"
+                            << dst.absFileName() << "´." << endl;
+                       return;
+               }
+       }
+       if (dst.isReadableFile()) {
+               if (overwriteFiles())
+                       cerr << "Warning: Overwriting existing file `"
+                            << dst.absFileName() << "´." << endl;
+               else {
+                       cerr << "Warning: Not overwriting existing file `"
+                            << dst.absFileName() << "´." << endl;
+                       return;
                }
-               name += t.asInput();
        }
+       if (!src.copyTo(dst))
+               cerr << "Warning: Could not copy file `" << src.absFileName()
+                    << "´ to `" << dst.absFileName() << "´." << endl;
+}
 
-       if (!scrap || !context.new_layout_allowed ||
-           !context.textclass.hasLayout(from_ascii("Scrap"))) {
-               cerr << "Warning: Could not interpret '" << name
-                    << "'. Ignoring it." << endl;
-               return;
+
+/// Parse a literate Chunk section. The initial "<<" is already parsed.
+bool parse_chunk(Parser & p, ostream & os, Context & context)
+{
+       // check whether a chunk is possible here.
+       if (!context.textclass.hasInsetLayout(from_ascii("Flex:Chunk"))) {
+               return false;
        }
 
-       // We use new_paragraph instead of check_end_layout because the stuff
-       // following the noweb chunk needs to start with a \begin_layout.
-       // This may create a new paragraph even if there was none in the
-       // noweb file, but the alternative is an invalid LyX file. Since
-       // noweb code chunks are implemented with a layout style in LyX they
-       // always must be in an own paragraph.
-       context.new_paragraph(os);
-       Context newcontext(true, context.textclass,
-               &context.textclass[from_ascii("Scrap")]);
-       newcontext.check_layout(os);
-       os << name;
-       while (p.good()) {
-               Token const & t = p.get_token();
-               // We abuse the parser a bit, because this is no TeX syntax
-               // at all.
-               if (t.cat() == catEscape)
-                       os << subst(t.asInput(), "\\", "\n\\backslash\n");
-               else {
-                       ostringstream oss;
-                       Context tmp(false, context.textclass,
-                                   &context.textclass[from_ascii("Scrap")]);
-                       tmp.need_end_layout = true;
-                       tmp.check_layout(oss);
-                       os << subst(t.asInput(), "\n", oss.str());
-               }
-               // The scrap chunk is ended by an @ at the beginning of a line.
-               // After the @ the line may contain a comment and/or
-               // whitespace, but nothing else.
-               if (t.asInput() == "@" && p.prev_token().cat() == catNewline &&
-                   (p.next_token().cat() == catSpace ||
-                    p.next_token().cat() == catNewline ||
-                    p.next_token().cat() == catComment)) {
-                       while (p.good() && p.next_token().cat() == catSpace)
-                               os << p.get_token().asInput();
-                       if (p.next_token().cat() == catComment)
-                               // The comment includes a final '\n'
-                               os << p.get_token().asInput();
-                       else {
-                               if (p.next_token().cat() == catNewline)
-                                       p.get_token();
-                               os << '\n';
-                       }
-                       break;
-               }
+       p.pushPosition();
+
+       // read the parameters
+       Parser::Arg const params = p.verbatimStuff(">>=\n", false);
+       if (!params.first) {
+               p.popPosition();
+               return false;
        }
-       newcontext.check_end_layout(os);
+
+       Parser::Arg const code = p.verbatimStuff("\n@");
+       if (!code.first) {
+               p.popPosition();
+               return false;
+       }
+       string const post_chunk = p.verbatimStuff("\n").second + '\n';
+       if (post_chunk[0] != ' ' && post_chunk[0] != '\n') {
+               p.popPosition();
+               return false;
+       }
+       // The last newline read is important for paragraph handling
+       p.putback();
+       p.deparse();
+
+       //cerr << "params=[" << params.second << "], code=[" << code.second << "]" <<endl;
+       // We must have a valid layout before outputting the Chunk inset.
+       context.check_layout(os);
+       Context chunkcontext(true, context.textclass);
+       chunkcontext.layout = &context.textclass.plainLayout();
+       begin_inset(os, "Flex Chunk");
+       os << "\nstatus open\n";
+       if (!params.second.empty()) {
+               chunkcontext.check_layout(os);
+               Context paramscontext(true, context.textclass);
+               paramscontext.layout = &context.textclass.plainLayout();
+               begin_inset(os, "Argument 1");
+               os << "\nstatus open\n";
+               output_ert(os, params.second, paramscontext);
+               end_inset(os);
+       }
+       output_ert(os, code.second, chunkcontext);
+       end_inset(os);
+
+       p.dropPosition();
+       return true;
 }
 
 
@@ -2034,10 +2149,10 @@ void parse_macro(Parser & p, ostream & os, Context & context)
 
                        // followed by number?
                        if (p.next_token().cat() == catOther) {
-                               char c = p.getChar();
-                               paramtext += c;
+                               string s = p.get_token().asInput();
+                               paramtext += s;
                                // number = current arity + 1?
-                               if (c == arity + '0' + 1)
+                               if (s.size() == 1 && s[0] == arity + '0' + 1)
                                        ++arity;
                                else
                                        simple = false;
@@ -2057,7 +2172,7 @@ void parse_macro(Parser & p, ostream & os, Context & context)
                os << "\n\\def" << ert;
                end_inset(os);
        } else
-               handle_ert(os, command + ert, context);
+               output_ert_inset(os, command + ert, context);
 }
 
 
@@ -2091,19 +2206,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        Layout const * newlayout = 0;
        InsetLayout const * newinsetlayout = 0;
        char const * const * where = 0;
-       // Store the latest bibliographystyle and nocite{*} option
-       // (needed for bibtex inset)
+       // Store the latest bibliographystyle, addcontentslineContent and
+       // nocite{*} option (needed for bibtex inset)
        string btprint;
+       string contentslineContent;
        string bibliographystyle = "default";
-       bool const use_natbib = preamble.isPackageUsed("natbib");
-       bool const use_jurabib = preamble.isPackageUsed("jurabib");
+       bool const use_natbib = isProvided("natbib");
+       bool const use_jurabib = isProvided("jurabib");
        string last_env;
        while (p.good()) {
                Token const & t = p.get_token();
 
-       // it is impossible to determine the correct document language if CJK is used.
+       // it is impossible to determine the correct encoding for non-CJK Japanese.
        // Therefore write a note at the beginning of the document
-       if (have_CJK) {
+       if (is_nonCJKJapanese) {
                context.check_layout(os);
                begin_inset(os, "Note Note\n");
                os << "status open\n\\begin_layout Plain Layout\n"
@@ -2111,12 +2227,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                   << "Important information:\n"
                   << "\\end_layout\n\n"
                   << "\\begin_layout Plain Layout\n"
-                  << "This document contains text in Chinese, Japanese or Korean.\n"
-                  << " It was therefore impossible for tex2lyx to set the correct document langue for your document."
-                  << " Please set in the document settings by yourself!\n"
+                  << "The original LaTeX source for this document is in Japanese (pLaTeX).\n"
+                  << " It was therefore impossible for tex2lyx to determine the correct encoding.\n"
+                  << " The iconv encoding " << p.getEncoding() << " was used.\n"
+                  << " If this is incorrect, you must run the tex2lyx program on the command line\n"
+                  << " and specify the encoding using the -e command-line switch.\n"
+                  << " In addition, you might want to double check that the desired output encoding\n"
+                  << " is correctly selected in Document > Settings > Language.\n"
                   << "\\end_layout\n";
                end_inset(os);
-               have_CJK = false;
+               is_nonCJKJapanese = false;
        }
 
 #ifdef FILEDEBUG
@@ -2215,19 +2335,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_braces(p);
                }
 
-               else if (t.asInput() == "<" && p.next_token().asInput() == "<") {
-                       context.check_layout(os);
-                       begin_inset(os, "Quotes ");
-                       os << "ard";
-                       end_inset(os);
-                       p.get_token();
-                       skip_braces(p);
-               }
-
                else if (t.asInput() == "<"
-                        && p.next_token().asInput() == "<" && noweb_mode) {
-                       p.get_token();
-                       parse_noweb(p, os, context);
+                        && p.next_token().asInput() == "<") {
+                       bool has_chunk = false;
+                       if (noweb_mode) {
+                               p.pushPosition();
+                               p.get_token();
+                               has_chunk = parse_chunk(p, os, context);
+                               if (!has_chunk)
+                                       p.popPosition();
+                       }
+
+                       if (!has_chunk) {
+                               context.check_layout(os);
+                               begin_inset(os, "Quotes ");
+                               //FIXME: this is a right danish quote;
+                               // why not a left french quote?
+                               os << "ard";
+                               end_inset(os);
+                               p.get_token();
+                               skip_braces(p);
+                       }
                }
 
                else if (t.cat() == catSpace || (t.cat() == catNewline && ! p.isParagraph()))
@@ -2243,7 +2371,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        else
                                cerr << "Warning: Inserting missing ']' in '"
                                     << s << "'." << endl;
-                       handle_ert(os, s, context);
+                       output_ert_inset(os, s, context);
                }
 
                else if (t.cat() == catLetter) {
@@ -2260,7 +2388,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                for (int i = 1; i < *l && p.next_token().isAlnumASCII(); ++i)
                                        phrase += p.get_token().cs();
                                if (is_known(phrase, known_coded_phrases)) {
-                                       handle_ert(os, phrase, context);
+                                       output_ert_inset(os, phrase, context);
                                        handled = true;
                                        break;
                                } else {
@@ -2284,7 +2412,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        if (context.new_layout_allowed)
                                context.new_paragraph(os);
                        else
-                               handle_ert(os, "\\par ", context);
+                               output_ert_inset(os, "\\par ", context);
                        eat_whitespace(p, os, context, true);
                }
 
@@ -2305,15 +2433,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        Token const next = p.next_token();
                        Token const end = p.next_next_token();
                        if (next.cat() == catEnd) {
-                       // {}
-                       Token const prev = p.prev_token();
-                       p.get_token();
-                       if (p.next_token().character() == '`' ||
-                           (prev.character() == '-' &&
-                            p.next_token().character() == '-'))
-                               ; // ignore it in {}`` or -{}-
-                       else
-                               handle_ert(os, "{}", context);
+                               // {}
+                               Token const prev = p.prev_token();
+                               p.get_token();
+                               if (p.next_token().character() == '`' ||
+                                   (prev.character() == '-' &&
+                                    p.next_token().character() == '-'))
+                                       ; // ignore it in {}`` or -{}-
+                               else
+                                       output_ert_inset(os, "{}", context);
                        } else if (next.cat() == catEscape &&
                                   is_known(next.cs(), known_quotes) &&
                                   end.cat() == catEnd) {
@@ -2323,6 +2451,32 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // braces here for better readability.
                                parse_text_snippet(p, os, FLAG_BRACE_LAST,
                                                   outer, context);
+                       } else if (p.next_token().asInput() == "\\ascii") {
+                               // handle the \ascii characters
+                               // (the case without braces is handled later)
+                               // the code is "{\ascii\xxx}"
+                               p.get_token(); // eat \ascii
+                               string name2 = p.get_token().asInput();
+                               p.get_token(); // eat the final '}'
+                               string const name = "{\\ascii" + name2 + "}";
+                               bool termination;
+                               docstring rem;
+                               set<string> req;
+                               // get the character from unicodesymbols
+                               docstring s = encodings.fromLaTeXCommand(from_utf8(name),
+                                       Encodings::TEXT_CMD, termination, rem, &req);
+                               if (!s.empty()) {
+                                       context.check_layout(os);
+                                       os << to_utf8(s);
+                                       if (!rem.empty())
+                                               output_ert_inset(os,
+                                                       to_utf8(rem), context);
+                                       for (set<string>::const_iterator it = req.begin();
+                                            it != req.end(); ++it)
+                                               preamble.registerAutomaticallyLoadedPackage(*it);
+                               } else
+                                       // we did not find a non-ert version
+                                       output_ert_inset(os, name, context);
                        } else {
                        context.check_layout(os);
                        // special handling of font attribute changes
@@ -2337,17 +2491,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        p.get_token();
                                } else {
                                        p.putback();
-                                       handle_ert(os, "{", context);
+                                       output_ert_inset(os, "{", context);
                                        parse_text_snippet(p, os,
                                                        FLAG_BRACE_LAST,
                                                        outer, context);
-                                       handle_ert(os, "}", context);
+                                       output_ert_inset(os, "}", context);
                                }
                        } else if (! context.new_layout_allowed) {
-                               handle_ert(os, "{", context);
+                               output_ert_inset(os, "{", context);
                                parse_text_snippet(p, os, FLAG_BRACE_LAST,
                                                   outer, context);
-                               handle_ert(os, "}", context);
+                               output_ert_inset(os, "}", context);
                        } else if (is_known(next.cs(), known_sizes)) {
                                // next will change the size, so we must
                                // reset it here
@@ -2395,10 +2549,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                           << "\n\\shape "
                                           << context.font.shape << "\n";
                        } else {
-                               handle_ert(os, "{", context);
+                               output_ert_inset(os, "{", context);
                                parse_text_snippet(p, os, FLAG_BRACE_LAST,
                                                   outer, context);
-                               handle_ert(os, "}", context);
+                               output_ert_inset(os, "}", context);
                                }
                        }
                }
@@ -2408,7 +2562,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                return;
                        }
                        cerr << "stray '}' in text\n";
-                       handle_ert(os, "}", context);
+                       output_ert_inset(os, "}", context);
                }
 
                else if (t.cat() == catComment)
@@ -2418,26 +2572,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                // control sequences
                //
 
-               else if (t.cs() == "(") {
+               else if (t.cs() == "(" || t.cs() == "[") {
+                       bool const simple = t.cs() == "(";
                        context.check_layout(os);
                        begin_inset(os, "Formula");
-                       os << " \\(";
-                       parse_math(p, os, FLAG_SIMPLE2, MATH_MODE);
-                       os << "\\)";
+                       os << " \\" << t.cs();
+                       parse_math(p, os, simple ? FLAG_SIMPLE2 : FLAG_EQUATION, MATH_MODE);
+                       os << '\\' << (simple ? ')' : ']');
                        end_inset(os);
-               }
-
-               else if (t.cs() == "[") {
-                       context.check_layout(os);
-                       begin_inset(os, "Formula");
-                       os << " \\[";
-                       parse_math(p, os, FLAG_EQUATION, MATH_MODE);
-                       os << "\\]";
-                       end_inset(os);
-                       // Prevent the conversion of a line break to a space
-                       // (bug 7668). This does not change the output, but
-                       // looks ugly in LyX.
-                       eat_whitespace(p, os, context, false);
+                       if (!simple) {
+                               // Prevent the conversion of a line break to a
+                               // space (bug 7668). This does not change the
+                               // output, but looks ugly in LyX.
+                               eat_whitespace(p, os, context, false);
+                       }
                }
 
                else if (t.cs() == "begin")
@@ -2474,17 +2622,24 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // FIXME: Do this in check_layout()!
                                context.has_item = false;
                                if (optarg)
-                                       handle_ert(os, "\\item", context);
+                                       output_ert_inset(os, "\\item", context);
                                else
-                                       handle_ert(os, "\\item ", context);
+                                       output_ert_inset(os, "\\item ", context);
                        }
                        if (optarg) {
                                if (context.layout->labeltype != LABEL_MANUAL) {
-                                       // LyX does not support \item[\mybullet]
-                                       // in itemize environments
+                                       // handle option of itemize item
+                                       begin_inset(os, "Argument item:1\n");
+                                       os << "status open\n";
+                                       os << "\n\\begin_layout Plain Layout\n";
                                        Parser p2(s + ']');
                                        os << parse_text_snippet(p2,
                                                FLAG_BRACK_LAST, outer, context);
+                                       // we must not use context.check_end_layout(os)
+                                       // because that would close the outer itemize layout
+                                       os << "\n\\end_layout\n";
+                                       end_inset(os);
+                                       eat_whitespace(p, os, context, false);
                                } else if (!s.empty()) {
                                        // LyX adds braces around the argument,
                                        // so we need to remove them here.
@@ -2496,12 +2651,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        // would misinterpret the space as
                                        // item delimiter (bug 7663)
                                        if (contains(s, ' ')) {
-                                               handle_ert(os, s, context);
+                                               output_ert_inset(os, s, context);
                                        } else {
                                                Parser p2(s + ']');
                                                os << parse_text_snippet(p2,
-                                                       FLAG_BRACK_LAST,
-                                                       outer, context);
+                                                       FLAG_BRACK_LAST, outer, context);
                                        }
                                        // The space is needed to separate the
                                        // item from the rest of the sentence.
@@ -2519,7 +2673,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        string key = convert_command_inset_arg(p.verbatim_item());
                        if (contains(label, '\\') || contains(key, '\\')) {
                                // LyX can't handle LaTeX commands in labels or keys
-                               handle_ert(os, t.asInput() + '[' + label +
+                               output_ert_inset(os, t.asInput() + '[' + label +
                                               "]{" + p.verbatim_item() + '}',
                                           context);
                        } else {
@@ -2546,7 +2700,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                                skip_braces(p);
                                                p.get_token();
                                                string name = normalize_filename(p.verbatim_item());
-                                               string const path = getMasterFilePath();
+                                               string const path = getMasterFilePath(true);
                                                // We want to preserve relative / absolute filenames,
                                                // therefore path is only used for testing
                                                // The file extension is in every case ".tex".
@@ -2561,9 +2715,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                                        if (!Gnumeric_name.empty())
                                                                name = Gnumeric_name;
                                                }
-                                               if (makeAbsPath(name, path).exists())
-                                                       fix_relative_filename(name);
-                                               else
+                                               FileName const absname = makeAbsPath(name, path);
+                                               if (absname.exists()) {
+                                                       fix_child_filename(name);
+                                                       copy_file(absname, name);
+                                               } else
                                                        cerr << "Warning: Could not find file '"
                                                             << name << "'." << endl;
                                                context.check_layout(os);
@@ -2573,7 +2729,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                                end_inset(os);
                                                context.check_layout(os);
                                                macro = false;
-                                               // register the packages that are automatically reloaded
+                                               // register the packages that are automatically loaded
                                                // by the Gnumeric template
                                                registerExternalTemplatePackages("GnumericSpreadsheet");
                                        }
@@ -2601,7 +2757,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        context.check_layout(os);
                        // FIXME: This is a hack to prevent paragraph
                        // deletion if it is empty. Handle this better!
-                       handle_comment(os,
+                       output_ert_inset(os,
                                "%dummy comment inserted by tex2lyx to "
                                "ensure that this paragraph is not empty",
                                context);
@@ -2637,7 +2793,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        for (; it != en; ++it)
                                                preamble.registerAutomaticallyLoadedPackage(*it);
                                } else
-                                       handle_ert(os,
+                                       output_ert_inset(os,
                                                "\\date{" + p.verbatim_item() + '}',
                                                context);
                        }
@@ -2673,17 +2829,26 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                }
 
                else if (t.cs() == "caption") {
+                       bool starred = false;
+                       if (p.next_token().asInput() == "*") {
+                               p.get_token();
+                               starred = true;
+                       }
                        p.skip_spaces();
                        context.check_layout(os);
                        p.skip_spaces();
-                       begin_inset(os, "Caption\n");
-                       Context newcontext(true, context.textclass);
-                       newcontext.font = context.font;
+                       if (starred)
+                               begin_inset(os, "Caption LongTableNoNumber\n");
+                       else
+                               begin_inset(os, "Caption Standard\n");
+                       Context newcontext(true, context.textclass, 0, 0, context.font);
                        newcontext.check_layout(os);
+                       // FIXME InsetArgument is now properly implemented in InsetLayout
+                       //       (for captions, but also for others)
                        if (p.next_token().cat() != catEscape &&
                            p.next_token().character() == '[') {
                                p.get_token(); // eat '['
-                               begin_inset(os, "Argument\n");
+                               begin_inset(os, "Argument 1\n");
                                os << "status collapsed\n";
                                parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context);
                                end_inset(os);
@@ -2727,9 +2892,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        // we must make sure that the caption gets a \begin_layout
                                        os << "\n\\begin_layout Plain Layout";
                                        p.skip_spaces();
-                                       begin_inset(os, "Caption\n");
-                                       Context newcontext(true, context.textclass);
-                                       newcontext.font = context.font;
+                                       begin_inset(os, "Caption Standard\n");
+                                       Context newcontext(true, context.textclass,
+                                                          0, 0, context.font);
                                        newcontext.check_layout(os);
                                        os << caption << "\n";
                                        newcontext.check_end_layout(os);
@@ -2754,10 +2919,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // output it as ERT
                                if (p.hasOpt()) {
                                        string opt_arg = convert_command_inset_arg(p.getArg('[', ']'));
-                                       handle_ert(os, t.asInput() + '[' + opt_arg +
+                                       output_ert_inset(os, t.asInput() + '[' + opt_arg +
                                               "]{" + p.verbatim_item() + '}', context);
                                } else
-                                       handle_ert(os, t.asInput() + "{" + p.verbatim_item() + '}', context);
+                                       output_ert_inset(os, t.asInput() + "{" + p.verbatim_item() + '}', context);
                        }
                }
 
@@ -2773,7 +2938,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                opts["clip"] = string();
                        string name = normalize_filename(p.verbatim_item());
 
-                       string const path = getMasterFilePath();
+                       string const path = getMasterFilePath(true);
                        // We want to preserve relative / absolute filenames,
                        // therefore path is only used for testing
                        if (!makeAbsPath(name, path).exists()) {
@@ -2808,9 +2973,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                }
                        }
 
-                       if (makeAbsPath(name, path).exists())
-                               fix_relative_filename(name);
-                       else
+                       FileName const absname = makeAbsPath(name, path);
+                       if (absname.exists()) {
+                               fix_child_filename(name);
+                               copy_file(absname, name);
+                       } else
                                cerr << "Warning: Could not find graphics file '"
                                     << name << "'." << endl;
 
@@ -2953,7 +3120,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        if (s == "\xb1" || s == "\xb3" || s == "\xb2" || s == "\xb5")
                                os << s;
                        else
-                               handle_ert(os, "\\ensuremath{" + s + "}",
+                               output_ert_inset(os, "\\ensuremath{" + s + "}",
                                           context);
                }
 
@@ -2962,7 +3129,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // swallow this
                                skip_spaces_braces(p);
                        } else
-                               handle_ert(os, t.asInput(), context);
+                               output_ert_inset(os, t.asInput(), context);
                }
 
                else if (t.cs() == "tableofcontents" || t.cs() == "lstlistoflistings") {
@@ -2974,16 +3141,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                preamble.registerAutomaticallyLoadedPackage("listings");
                }
 
-               else if (t.cs() == "listoffigures") {
-                       context.check_layout(os);
-                       begin_inset(os, "FloatList figure\n");
-                       end_inset(os);
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "listoftables") {
+               else if (t.cs() == "listoffigures" || t.cs() == "listoftables") {
                        context.check_layout(os);
-                       begin_inset(os, "FloatList table\n");
+                       if (t.cs() == "listoffigures")
+                               begin_inset(os, "FloatList figure\n");
+                       else
+                               begin_inset(os, "FloatList table\n");
                        end_inset(os);
                        skip_spaces_braces(p);
                }
@@ -2998,7 +3161,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                end_inset(os);
                                p.get_token(); // swallow second arg
                        } else
-                               handle_ert(os, "\\listof{" + name + "}", context);
+                               output_ert_inset(os, "\\listof{" + name + "}", context);
                }
 
                else if ((where = is_known(t.cs(), known_text_font_families)))
@@ -3047,7 +3210,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        preamble.registerAutomaticallyLoadedPackage("color");
                        } else
                                // for custom defined colors
-                               handle_ert(os, t.asInput() + "{" + color + "}", context);
+                               output_ert_inset(os, t.asInput() + "{" + color + "}", context);
                }
 
                else if (t.cs() == "underbar" || t.cs() == "uline") {
@@ -3091,11 +3254,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        string localtime = p.getArg('{', '}');
                        preamble.registerAuthor(name);
                        Author const & author = preamble.getAuthor(name);
-                       // from_ctime() will fail if LyX decides to output the
-                       // time in the text language. It might also use a wrong
-                       // time zone (if the original LyX document was exported
-                       // with a different time zone).
-                       time_t ptime = from_ctime(localtime);
+                       // from_asctime_utc() will fail if LyX decides to output the
+                       // time in the text language.
+                       time_t ptime = from_asctime_utc(localtime);
                        if (ptime == static_cast<time_t>(-1)) {
                                cerr << "Warning: Could not parse time `" << localtime
                                     << "´ for change tracking, using current time instead.\n";
@@ -3129,6 +3290,61 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        }
                }
 
+               else if (t.cs() == "textipa") {
+                       context.check_layout(os);
+                       begin_inset(os, "IPA\n");
+                       parse_text_in_inset(p, os, FLAG_ITEM, outer, context);
+                       end_inset(os);
+                       preamble.registerAutomaticallyLoadedPackage("tipa");
+                       preamble.registerAutomaticallyLoadedPackage("tipx");
+               }
+
+               else if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") {
+                       context.check_layout(os);
+                       begin_inset(os, "IPADeco " + t.cs().substr(4) + "\n");
+                       os << "status open\n";
+                       parse_text_in_inset(p, os, FLAG_ITEM, outer, context);
+                       end_inset(os);
+                       p.skip_spaces();
+               }
+
+               else if (t.cs() == "textvertline") {
+                       // FIXME: This is not correct, \textvertline is higher than |
+                       os << "|";
+                       skip_braces(p);
+                       continue;
+               }
+
+               else if (t.cs() == "tone" ) {
+                       context.check_layout(os);
+                       // register the tone package
+                       preamble.registerAutomaticallyLoadedPackage("tone");
+                       string content = trimSpaceAndEol(p.verbatim_item());
+                       string command = t.asInput() + "{" + content + "}";
+                       // some tones can be detected by unicodesymbols, some need special code
+                       if (is_known(content, known_tones)) {
+                               os << "\\IPAChar " << command << "\n";
+                               continue;
+                       }
+                       // try to see whether the string is in unicodesymbols
+                       bool termination;
+                       docstring rem;
+                       set<string> req;
+                       docstring s = encodings.fromLaTeXCommand(from_utf8(command),
+                               Encodings::TEXT_CMD | Encodings::MATH_CMD,
+                               termination, rem, &req);
+                       if (!s.empty()) {
+                               os << to_utf8(s);
+                               if (!rem.empty())
+                                       output_ert_inset(os, to_utf8(rem), context);
+                               for (set<string>::const_iterator it = req.begin();
+                                    it != req.end(); ++it)
+                                       preamble.registerAutomaticallyLoadedPackage(*it);
+                       } else
+                               // we did not find a non-ert version
+                               output_ert_inset(os, command, context);
+               }
+
                else if (t.cs() == "phantom" || t.cs() == "hphantom" ||
                             t.cs() == "vphantom") {
                        context.check_layout(os);
@@ -3146,8 +3362,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
 
                else if (t.cs() == "href") {
                        context.check_layout(os);
-                       string target = p.getArg('{', '}');
-                       string name = p.getArg('{', '}');
+                       string target = convert_command_inset_arg(p.verbatim_item());
+                       string name = convert_command_inset_arg(p.verbatim_item());
                        string type;
                        size_t i = target.find(':');
                        if (i != string::npos) {
@@ -3222,7 +3438,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_spaces_braces(p);
                }
 
-               else if ((where = is_known(t.cs(), known_ref_commands))) {
+               // handle refstyle first to catch \eqref which can also occur
+               // without refstyle. Only recognize these commands if
+               // refstyle.sty was found in the preamble (otherwise \eqref
+               // and user defined ref commands could be misdetected).
+               else if ((where = is_known(t.cs(), known_refstyle_commands)) &&
+                        preamble.refstyle()) {
+                       context.check_layout(os);
+                       begin_command_inset(os, "ref", "formatted");
+                       os << "reference \"";
+                       os << known_refstyle_prefixes[where - known_refstyle_commands]
+                          << ":";
+                       os << convert_command_inset_arg(p.verbatim_item())
+                          << "\"\n";
+                       end_inset(os);
+                       preamble.registerAutomaticallyLoadedPackage("refstyle");
+               }
+
+               // if refstyle is used, we must not convert \prettyref to a
+               // formatted reference, since that would result in a refstyle command.
+               else if ((where = is_known(t.cs(), known_ref_commands)) &&
+                        (t.cs() != "prettyref" || !preamble.refstyle())) {
                        string const opt = p.getOpt();
                        if (opt.empty()) {
                                context.check_layout(os);
@@ -3234,11 +3470,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                end_inset(os);
                                if (t.cs() == "vref" || t.cs() == "vpageref")
                                        preamble.registerAutomaticallyLoadedPackage("varioref");
-
+                               else if (t.cs() == "prettyref")
+                                       preamble.registerAutomaticallyLoadedPackage("prettyref");
                        } else {
-                               // LyX does not support optional arguments of ref commands
-                               handle_ert(os, t.asInput() + '[' + opt + "]{" +
-                                              p.verbatim_item() + "}", context);
+                               // LyX does not yet support optional arguments of ref commands
+                               output_ert_inset(os, t.asInput() + '[' + opt + "]{" +
+                                      p.verbatim_item() + '}', context);
                        }
                }
 
@@ -3299,6 +3536,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                           << convert_command_inset_arg(p.verbatim_item())
                           << "\"\n";
                        end_inset(os);
+                       // Need to set the cite engine if natbib is loaded by
+                       // the document class directly
+                       if (preamble.citeEngine() == "basic")
+                               preamble.citeEngine("natbib");
                }
 
                else if (use_jurabib &&
@@ -3349,6 +3590,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        os << "before " << '"' << before << '"' << "\n";
                        os << "key " << '"' << citation << '"' << "\n";
                        end_inset(os);
+                       // Need to set the cite engine if jurabib is loaded by
+                       // the document class directly
+                       if (preamble.citeEngine() == "basic")
+                               preamble.citeEngine("jurabib");
                }
 
                else if (t.cs() == "cite"
@@ -3405,10 +3650,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        end_inset(os);
                }
 
-               else if (t.cs() == "printindex") {
+               else if (t.cs() == "printindex" || t.cs() == "printsubindex") {
                        context.check_layout(os);
-                       begin_command_inset(os, "index_print", "printindex");
-                       os << "type \"idx\"\n";
+                       string commandname = t.cs();
+                       bool star = false;
+                       if (p.next_token().asInput() == "*") {
+                               commandname += "*";
+                               star = true;
+                               p.get_token();
+                       }
+                       begin_command_inset(os, "index_print", commandname);
+                       string const indexname = p.getArg('[', ']');
+                       if (!star) {
+                               if (indexname.empty())
+                                       os << "type \"idx\"\n";
+                               else
+                                       os << "type \"" << indexname << "\"\n";
+                       }
                        end_inset(os);
                        skip_spaces_braces(p);
                        preamble.registerAutomaticallyLoadedPackage("makeidx");
@@ -3553,8 +3811,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                              context, "\\lang",
                                              context.font.language, lang);
                }
-               
-               else if (is_known(t.cs().substr(4, string::npos), polyglossia_languages)) {
+
+               else if (prefixIs(t.cs(), "text")
+                        && is_known(t.cs().substr(4), preamble.polyglossia_languages)) {
                        // scheme is \textLANGUAGE{text} where LANGUAGE is in polyglossia_languages[]
                        string lang;
                        // We have to output the whole command if it has an option
@@ -3565,21 +3824,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                // check if the option contains a variant, if yes, extract it
                                string::size_type pos_var = langopts.find("variant");
                                string::size_type i = langopts.find(',');
-                               if (pos_var != string::npos){
+                               string::size_type k = langopts.find('=', pos_var);
+                               if (pos_var != string::npos && i == string::npos) {
                                        string variant;
-                                       if (i == string::npos) {
-                                               variant = langopts.substr(pos_var + 8, langopts.length() - pos_var - 9);
-                                               lang = polyglossia2lyx(variant);
-                                               parse_text_attributes(p, os, FLAG_ITEM, outer,
-                                                                         context, "\\lang",
-                                                                         context.font.language, lang);
-                                       }
-                                       else
-                                               handle_ert(os, t.asInput() + langopts, context);
+                                       variant = langopts.substr(k + 1, langopts.length() - k - 2);
+                                       lang = preamble.polyglossia2lyx(variant);
+                                       parse_text_attributes(p, os, FLAG_ITEM, outer,
+                                                                 context, "\\lang",
+                                                                 context.font.language, lang);
                                } else
-                                       handle_ert(os, t.asInput() + langopts, context);
+                                       output_ert_inset(os, t.asInput() + langopts, context);
                        } else {
-                               lang = polyglossia2lyx(t.cs().substr(4, string::npos));
+                               lang = preamble.polyglossia2lyx(t.cs().substr(4, string::npos));
                                parse_text_attributes(p, os, FLAG_ITEM, outer,
                                                          context, "\\lang",
                                                          context.font.language, lang);
@@ -3589,21 +3845,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                else if (t.cs() == "inputencoding") {
                        // nothing to write here
                        string const enc = subst(p.verbatim_item(), "\n", " ");
-                       p.setEncoding(enc);
+                       p.setEncoding(enc, Encoding::inputenc);
                }
 
                else if ((where = is_known(t.cs(), known_special_chars))) {
                        context.check_layout(os);
-                       os << "\\SpecialChar \\"
-                          << known_coded_special_chars[where - known_special_chars]
-                          << '\n';
+                       os << known_coded_special_chars[where - known_special_chars];
                        skip_spaces_braces(p);
                }
 
-               else if (t.cs() == "nobreakdash" && p.next_token().asInput() == "-") {
+               else if ((t.cs() == "nobreakdash" && p.next_token().asInput() == "-") ||
+                        (t.cs() == "@" && p.next_token().asInput() == ".")) {
                        context.check_layout(os);
-                       os << "\\SpecialChar \\nobreakdash-\n";
-                       p.get_token();
+                       os << "\\SpecialChar \\" << t.cs()
+                          << p.get_token().asInput() << '\n';
                }
 
                else if (t.cs() == "textquotedbl") {
@@ -3612,40 +3867,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        skip_braces(p);
                }
 
-               else if (t.cs() == "@" && p.next_token().asInput() == ".") {
-                       context.check_layout(os);
-                       os << "\\SpecialChar \\@.\n";
-                       p.get_token();
-               }
-
-               else if (t.cs() == "-") {
-                       context.check_layout(os);
-                       os << "\\SpecialChar \\-\n";
-               }
-
-               else if (t.cs() == "textasciitilde") {
-                       context.check_layout(os);
-                       os << '~';
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "textasciicircum") {
-                       context.check_layout(os);
-                       os << '^';
-                       skip_spaces_braces(p);
-               }
-
-               else if (t.cs() == "textbackslash") {
-                       context.check_layout(os);
-                       os << "\n\\backslash\n";
-                       skip_spaces_braces(p);
-               }
-
                else if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#"
                            || t.cs() == "$" || t.cs() == "{" || t.cs() == "}"
-                           || t.cs() == "%") {
+                           || t.cs() == "%" || t.cs() == "-") {
                        context.check_layout(os);
-                       os << t.cs();
+                       if (t.cs() == "-")
+                               os << "\\SpecialChar \\-\n";
+                       else
+                               os << t.cs();
                }
 
                else if (t.cs() == "char") {
@@ -3657,65 +3886,42 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        os << '"';
                                        skip_braces(p);
                                } else {
-                                       handle_ert(os, "\\char`", context);
+                                       output_ert_inset(os, "\\char`", context);
                                }
                        } else {
-                               handle_ert(os, "\\char", context);
+                               output_ert_inset(os, "\\char", context);
                        }
                }
 
                else if (t.cs() == "verb") {
                        context.check_layout(os);
-                       char const delimiter = p.next_token().character();
-                       string const arg = p.getArg(delimiter, delimiter);
-                       ostringstream oss;
-                       oss << "\\verb" << delimiter << arg << delimiter;
-                       handle_ert(os, oss.str(), context);
+                       // set catcodes to verbatim early, just in case.
+                       p.setCatcodes(VERBATIM_CATCODES);
+                       string delim = p.get_token().asInput();
+                       Parser::Arg arg = p.verbatimStuff(delim);
+                       if (arg.first)
+                               output_ert_inset(os, "\\verb" + delim 
+                                                + arg.second + delim, context);
+                       else
+                               cerr << "invalid \\verb command. Skipping" << endl;
                }
 
                // Problem: \= creates a tabstop inside the tabbing environment
                // and else an accent. In the latter case we really would want
                // \={o} instead of \= o.
                else if (t.cs() == "=" && (flags & FLAG_TABBING))
-                       handle_ert(os, t.asInput(), context);
-
-               // accents (see Table 6 in Comprehensive LaTeX Symbol List)
-               else if (t.cs().size() == 1
-                        && contains("\"'.=^`bcdHkrtuv~", t.cs())) {
-                       context.check_layout(os);
-                       // try to see whether the string is in unicodesymbols
-                       bool termination;
-                       docstring rem;
-                       string command = t.asInput() + "{"
-                               + trimSpaceAndEol(p.verbatim_item())
-                               + "}";
-                       set<string> req;
-                       docstring s = encodings.fromLaTeXCommand(from_utf8(command),
-                               Encodings::TEXT_CMD | Encodings::MATH_CMD,
-                               termination, rem, &req);
-                       if (!s.empty()) {
-                               if (!rem.empty())
-                                       cerr << "When parsing " << command
-                                            << ", result is " << to_utf8(s)
-                                            << "+" << to_utf8(rem) << endl;
-                               os << to_utf8(s);
-                               for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
-                                       preamble.registerAutomaticallyLoadedPackage(*it);
-                       } else
-                               // we did not find a non-ert version
-                               handle_ert(os, command, context);
-               }
+                       output_ert_inset(os, t.asInput(), context);
 
                else if (t.cs() == "\\") {
                        context.check_layout(os);
                        if (p.hasOpt())
-                               handle_ert(os, "\\\\" + p.getOpt(), context);
+                               output_ert_inset(os, "\\\\" + p.getOpt(), context);
                        else if (p.next_token().asInput() == "*") {
                                p.get_token();
                                // getOpt() eats the following space if there
                                // is no optional argument, but that is OK
                                // here since it has no effect in the output.
-                               handle_ert(os, "\\\\*" + p.getOpt(), context);
+                               output_ert_inset(os, "\\\\*" + p.getOpt(), context);
                        }
                        else {
                                begin_inset(os, "Newline newline");
@@ -3740,7 +3946,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                name += p.get_token().asInput();
                        context.check_layout(os);
                        string filename(normalize_filename(p.getArg('{', '}')));
-                       string const path = getMasterFilePath();
+                       string const path = getMasterFilePath(true);
                        // We want to preserve relative / absolute filenames,
                        // therefore path is only used for testing
                        if ((t.cs() == "include" || t.cs() == "input") &&
@@ -3758,16 +3964,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        if (makeAbsPath(filename, path).exists()) {
                                string const abstexname =
                                        makeAbsPath(filename, path).absFileName();
-                               string const abslyxname =
-                                       changeExtension(abstexname, ".lyx");
                                string const absfigname =
                                        changeExtension(abstexname, ".fig");
-                               fix_relative_filename(filename);
-                               string const lyxname =
-                                       changeExtension(filename, ".lyx");
+                               fix_child_filename(filename);
+                               string const lyxname = changeExtension(filename,
+                                       roundtripMode() ? ".lyx.lyx" : ".lyx");
+                               string const abslyxname = makeAbsPath(
+                                       lyxname, getParentFilePath(false)).absFileName();
                                bool xfig = false;
-                               external = FileName(absfigname).exists();
-                               if (t.cs() == "input") {
+                               if (!skipChildren())
+                                       external = FileName(absfigname).exists();
+                               if (t.cs() == "input" && !skipChildren()) {
                                        string const ext = getExtension(abstexname);
 
                                        // Combined PS/LaTeX:
@@ -3810,16 +4017,25 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                }
                                if (external) {
                                        outname = changeExtension(filename, ".fig");
+                                       FileName abssrc(changeExtension(abstexname, ".fig"));
+                                       copy_file(abssrc, outname);
                                } else if (xfig) {
                                        // Don't try to convert, the result
                                        // would be full of ERT.
                                        outname = filename;
+                                       FileName abssrc(abstexname);
+                                       copy_file(abssrc, outname);
                                } else if (t.cs() != "verbatiminput" &&
+                                          !skipChildren() &&
                                    tex2lyx(abstexname, FileName(abslyxname),
                                            p.getEncoding())) {
                                        outname = lyxname;
+                                       // no need to call copy_file
+                                       // tex2lyx creates the file
                                } else {
                                        outname = filename;
+                                       FileName abssrc(abstexname);
+                                       copy_file(abssrc, outname);
                                }
                        } else {
                                cerr << "Warning: Could not find included file '"
@@ -3833,6 +4049,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                registerExternalTemplatePackages("XFig");
                        } else {
                                begin_command_inset(os, "include", name);
+                               outname = subst(outname, "\"", "\\\"");
                                os << "preview false\n"
                                      "filename \"" << outname << "\"\n";
                                if (t.cs() == "verbatiminput")
@@ -3844,8 +4061,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                else if (t.cs() == "bibliographystyle") {
                        // store new bibliographystyle
                        bibliographystyle = p.verbatim_item();
-                       // If any other command than \bibliography and
-                       // \nocite{*} follows, we need to output the style
+                       // If any other command than \bibliography, \addcontentsline
+                       // and \nocite{*} follows, we need to output the style
                        // (because it might be used by that command).
                        // Otherwise, it will automatically be output by LyX.
                        p.pushPosition();
@@ -3860,18 +4077,53 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                                continue;
                                } else if (t2.cs() == "bibliography")
                                        output = false;
+                               else if (t2.cs() == "phantomsection") {
+                                       output = false;
+                                       continue;
+                               }
+                               else if (t2.cs() == "addcontentsline") {
+                                       // get the 3 arguments of \addcontentsline
+                                       p.getArg('{', '}');
+                                       p.getArg('{', '}');
+                                       contentslineContent = p.getArg('{', '}');
+                                       // if the last argument is not \refname we must output
+                                       if (contentslineContent == "\\refname")
+                                               output = false;
+                               }
                                break;
                        }
                        p.popPosition();
                        if (output) {
-                               handle_ert(os,
+                               output_ert_inset(os,
                                        "\\bibliographystyle{" + bibliographystyle + '}',
                                        context);
                        }
                }
 
+               else if (t.cs() == "phantomsection") {
+                       // we only support this if it occurs between
+                       // \bibliographystyle and \bibliography
+                       if (bibliographystyle.empty())
+                               output_ert_inset(os, "\\phantomsection", context);
+               }
+
+               else if (t.cs() == "addcontentsline") {
+                       context.check_layout(os);
+                       // get the 3 arguments of \addcontentsline
+                       string const one = p.getArg('{', '}');
+                       string const two = p.getArg('{', '}');
+                       string const three = p.getArg('{', '}');
+                       // only if it is a \refname, we support if for the bibtex inset
+                       if (contentslineContent != "\\refname") {
+                               output_ert_inset(os,
+                                       "\\addcontentsline{" + one + "}{" + two + "}{"+ three + '}',
+                                       context);
+                       }
+               }
+
                else if (t.cs() == "bibliography") {
                        context.check_layout(os);
+                       string BibOpts;
                        begin_command_inset(os, "bibtex", "bibtex");
                        if (!btprint.empty()) {
                                os << "btprint " << '"' << "btPrintAll" << '"' << "\n";
@@ -3880,9 +4132,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                btprint.clear();
                        }
                        os << "bibfiles " << '"' << p.verbatim_item() << '"' << "\n";
+                       // Do we have addcontentsline?
+                       if (contentslineContent == "\\refname") {
+                               BibOpts = "bibtotoc";
+                               // clear string because next BibTeX inset can be without addcontentsline
+                               contentslineContent.clear();
+                       }
                        // Do we have a bibliographystyle set?
-                       if (!bibliographystyle.empty())
-                               os << "options " << '"' << bibliographystyle << '"' << "\n";
+                       if (!bibliographystyle.empty()) {
+                               if (BibOpts.empty())
+                                       BibOpts = bibliographystyle;
+                               else
+                                       BibOpts = BibOpts + ',' + bibliographystyle;
+                               // clear it because each bibtex entry has its style
+                               // and we need an empty string to handle \phantomsection
+                               bibliographystyle.clear();
+                       }
+                       os << "options " << '"' << BibOpts << '"' << "\n";
                        end_inset(os);
                }
 
@@ -3916,7 +4182,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                          "", "", t.cs());
                }
 
-               else if (t.cs() == "ovalbox" || t.cs() == "Ovalbox" ||
+               else if (t.cs() == "fbox" || t.cs() == "mbox" ||
+                            t.cs() == "ovalbox" || t.cs() == "Ovalbox" ||
                         t.cs() == "shadowbox" || t.cs() == "doublebox")
                        parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), "");
 
@@ -3927,15 +4194,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                arg += p.getFullParentheseArg();
                                arg += p.getFullOpt();
                                eat_whitespace(p, os, context, false);
-                               handle_ert(os, arg + '{', context);
-                               eat_whitespace(p, os, context, false);
+                               output_ert_inset(os, arg + '{', context);
                                parse_text(p, os, FLAG_ITEM, outer, context);
-                               handle_ert(os, "}", context);
+                               output_ert_inset(os, "}", context);
                        } else {
+                               //the syntax is: \framebox[width][position]{content}
                                string special = p.getFullOpt();
                                special += p.getOpt();
                                parse_outer_box(p, os, FLAG_ITEM, outer,
-                                               context, t.cs(), special);
+                                                   context, t.cs(), special);
                        }
                }
 
@@ -3948,10 +4215,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                arg += p.getFullParentheseArg();
                                arg += p.getFullOpt();
                                eat_whitespace(p, os, context, false);
-                               handle_ert(os, arg + '{', context);
-                               eat_whitespace(p, os, context, false);
+                               output_ert_inset(os, arg + '{', context);
                                parse_text(p, os, FLAG_ITEM, outer, context);
-                               handle_ert(os, "}", context);
+                               output_ert_inset(os, "}", context);
                        } else
                                //the syntax is: \makebox[width][position]{content}
                                parse_box(p, os, 0, FLAG_ITEM, outer, context,
@@ -4030,7 +4296,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                            t.cs() == "providecommand" ||
                            t.cs() == "providecommandx" ||
                            name[name.length()-1] == '*')
-                               handle_ert(os, ert, context);
+                               output_ert_inset(os, ert, context);
                        else {
                                context.check_layout(os);
                                begin_inset(os, "FormulaMacro");
@@ -4067,7 +4333,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        CommandMap::iterator it = known_commands.find(command);
                        if (it != known_commands.end())
                                known_commands[t.asInput()] = it->second;
-                       handle_ert(os, ert, context);
+                       output_ert_inset(os, ert, context);
                }
 
                else if (t.cs() == "hspace" || t.cs() == "vspace") {
@@ -4166,13 +4432,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        name += '*';
                                if (valid) {
                                        if (value == 1.0)
-                                               handle_ert(os, name + '{' + unit + '}', context);
+                                               output_ert_inset(os, name + '{' + unit + '}', context);
                                        else if (value == -1.0)
-                                               handle_ert(os, name + "{-" + unit + '}', context);
+                                               output_ert_inset(os, name + "{-" + unit + '}', context);
                                        else
-                                               handle_ert(os, name + '{' + valstring + unit + '}', context);
+                                               output_ert_inset(os, name + '{' + valstring + unit + '}', context);
                                } else
-                                       handle_ert(os, name + '{' + length + '}', context);
+                                       output_ert_inset(os, name + '{' + length + '}', context);
                        }
                }
 
@@ -4183,7 +4449,21 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        begin_inset(os, "Flex ");
                        os << to_utf8(newinsetlayout->name()) << '\n'
                           << "status collapsed\n";
-                       parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout);
+                       if (newinsetlayout->isPassThru()) {
+                               // set catcodes to verbatim early, just in case.
+                               p.setCatcodes(VERBATIM_CATCODES);
+                               string delim = p.get_token().asInput();
+                               if (delim != "{")
+                                       cerr << "Warning: bad delimiter for command " << t.asInput() << endl;
+                               //FIXME: handle error condition
+                               string const arg = p.verbatimStuff("}").second;
+                               Context newcontext(true, context.textclass);
+                               if (newinsetlayout->forcePlainLayout())
+                                       newcontext.layout = &context.textclass.plainLayout();
+                               output_ert(os, arg, newcontext);
+                       } else
+                               
+                               parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout);
                        end_inset(os);
                }
 
@@ -4194,7 +4474,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        vector<string> keys;
                        split_map(arg, opts, keys);
                        string name = normalize_filename(p.verbatim_item());
-                       string const path = getMasterFilePath();
+                       string const path = getMasterFilePath(true);
                        // We want to preserve relative / absolute filenames,
                        // therefore path is only used for testing
                        if (!makeAbsPath(name, path).exists()) {
@@ -4208,9 +4488,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                        pdflatex = true;
                                }
                        }
-                       if (makeAbsPath(name, path).exists())
-                               fix_relative_filename(name);
-                       else
+                       FileName const absname = makeAbsPath(name, path);
+                       if (absname.exists())
+                       {
+                               fix_child_filename(name);
+                               copy_file(absname, name);
+                       } else
                                cerr << "Warning: Could not find file '"
                                     << name << "'." << endl;
                        // write output
@@ -4259,7 +4542,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                else if (t.cs() == "loadgame") {
                        p.skip_spaces();
                        string name = normalize_filename(p.verbatim_item());
-                       string const path = getMasterFilePath();
+                       string const path = getMasterFilePath(true);
                        // We want to preserve relative / absolute filenames,
                        // therefore path is only used for testing
                        if (!makeAbsPath(name, path).exists()) {
@@ -4271,9 +4554,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                if (!lyxskak_name.empty())
                                        name = lyxskak_name;
                        }
-                       if (makeAbsPath(name, path).exists())
-                               fix_relative_filename(name);
-                       else
+                       FileName const absname = makeAbsPath(name, path);
+                       if (absname.exists())
+                       {
+                               fix_child_filename(name);
+                               copy_file(absname, name);
+                       } else
                                cerr << "Warning: Could not find file '"
                                     << name << "'." << endl;
                        context.check_layout(os);
@@ -4292,18 +4578,112 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        // try to see whether the string is in unicodesymbols
                        // Only use text mode commands, since we are in text mode here,
                        // and math commands may be invalid (bug 6797)
+                       string name = t.asInput();
+                       // handle the dingbats and Cyrillic
+                       if (name == "\\ding" || name == "\\textcyr")
+                               name = name + '{' + p.getArg('{', '}') + '}';
+                       // handle the ifsym characters
+                       else if (name == "\\textifsymbol") {
+                               string const optif = p.getFullOpt();
+                               string const argif = p.getArg('{', '}');
+                               name = name + optif + '{' + argif + '}';
+                       }
+                       // handle the \ascii characters
+                       // the case of \ascii within braces, as LyX outputs it, is already
+                       // handled for t.cat() == catBegin
+                       else if (name == "\\ascii") {
+                               // the code is "\asci\xxx"
+                               name = "{" + name + p.get_token().asInput() + "}";
+                               skip_braces(p);
+                       }
+                       // handle some TIPA special characters
+                       else if (preamble.isPackageUsed("tipa")) {
+                               if (name == "\\textglobfall") {
+                                       name = "End";
+                                       skip_braces(p);
+                               } else if (name == "\\s") {
+                                       // fromLaTeXCommand() does not yet
+                                       // recognize tipa short cuts
+                                       name = "\\textsyllabic";
+                               } else if (name == "\\=" &&
+                                          p.next_token().asInput() == "*") {
+                                       // fromLaTeXCommand() does not yet
+                                       // recognize tipa short cuts
+                                       p.get_token();
+                                       name = "\\b";
+                               } else if (name == "\\textdoublevertline") {
+                                       // FIXME: This is not correct,
+                                       // \textvertline is higher than \textbardbl
+                                       name = "\\textbardbl";
+                                       skip_braces(p);
+                               } else if (name == "\\!" ) {
+                                       if (p.next_token().asInput() == "b") {
+                                               p.get_token();  // eat 'b'
+                                               name = "\\texthtb";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "d") {
+                                               p.get_token();
+                                               name = "\\texthtd";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "g") {
+                                               p.get_token();
+                                               name = "\\texthtg";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "G") {
+                                               p.get_token();
+                                               name = "\\texthtscg";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "j") {
+                                               p.get_token();
+                                               name = "\\texthtbardotlessj";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "o") {
+                                               p.get_token();
+                                               name = "\\textbullseye";
+                                               skip_braces(p);
+                                       }
+                               } else if (name == "\\*" ) {
+                                       if (p.next_token().asInput() == "k") {
+                                               p.get_token();
+                                               name = "\\textturnk";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "r") {
+                                               p.get_token();  // eat 'b'
+                                               name = "\\textturnr";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "t") {
+                                               p.get_token();
+                                               name = "\\textturnt";
+                                               skip_braces(p);
+                                       } else if (p.next_token().asInput() == "w") {
+                                               p.get_token();
+                                               name = "\\textturnw";
+                                               skip_braces(p);
+                                       }
+                               }
+                       }
+                       if ((name.size() == 2 &&
+                            contains("\"'.=^`bcdHkrtuv~", name[1]) &&
+                            p.next_token().asInput() != "*") ||
+                           is_known(name.substr(1), known_tipa_marks)) {
+                               // name is a command that corresponds to a
+                               // combining character in unicodesymbols.
+                               // Append the argument, fromLaTeXCommand()
+                               // will either convert it to a single
+                               // character or a combining sequence.
+                               name += '{' + p.verbatim_item() + '}';
+                       }
+                       // now get the character from unicodesymbols
                        bool termination;
                        docstring rem;
                        set<string> req;
-                       docstring s = encodings.fromLaTeXCommand(from_utf8(t.asInput()),
+                       docstring s = encodings.fromLaTeXCommand(from_utf8(name),
                                        Encodings::TEXT_CMD, termination, rem, &req);
                        if (!s.empty()) {
-                               if (!rem.empty())
-                                       cerr << "When parsing " << t.cs()
-                                            << ", result is " << to_utf8(s)
-                                            << "+" << to_utf8(rem) << endl;
                                context.check_layout(os);
                                os << to_utf8(s);
+                               if (!rem.empty())
+                                       output_ert_inset(os, to_utf8(rem), context);
                                if (termination)
                                        skip_spaces_braces(p);
                                for (set<string>::const_iterator it = req.begin(); it != req.end(); ++it)
@@ -4314,23 +4694,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        /*
                        string s = t.asInput();
                        string z = p.verbatim_item();
-                       while (p.good() && z != " " && z.size()) {
+                       while (p.good() && z != " " && !z.empty()) {
                                //cerr << "read: " << z << endl;
                                s += z;
                                z = p.verbatim_item();
                        }
                        cerr << "found ERT: " << s << endl;
-                       handle_ert(os, s + ' ', context);
+                       output_ert_inset(os, s + ' ', context);
                        */
                        else {
-                               string name = t.asInput();
-                               if (p.next_token().asInput() == "*") {
+                               if (t.asInput() == name &&
+                                   p.next_token().asInput() == "*") {
                                        // Starred commands like \vspace*{}
                                        p.get_token();  // Eat '*'
                                        name += '*';
                                }
                                if (!parse_command(name, p, os, outer, context))
-                                       handle_ert(os, name, context);
+                                       output_ert_inset(os, name, context);
                        }
                }
 
@@ -4341,6 +4721,79 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        }
 }
 
+
+string guessLanguage(Parser & p, string const & lang)
+{
+       typedef std::map<std::string, size_t> LangMap;
+       // map from language names to number of characters
+       LangMap used;
+       used[lang] = 0;
+       for (char const * const * i = supported_CJK_languages; *i; i++)
+               used[string(*i)] = 0;
+
+       while (p.good()) {
+               Token const t = p.get_token();
+               // comments are not counted for any language
+               if (t.cat() == catComment)
+                       continue;
+               // commands are not counted as well, but we need to detect
+               // \begin{CJK} and switch encoding if needed
+               if (t.cat() == catEscape) {
+                       if (t.cs() == "inputencoding") {
+                               string const enc = subst(p.verbatim_item(), "\n", " ");
+                               p.setEncoding(enc, Encoding::inputenc);
+                               continue;
+                       }
+                       if (t.cs() != "begin")
+                               continue;
+               } else {
+                       // Non-CJK content is counted for lang.
+                       // We do not care about the real language here:
+                       // If we have more non-CJK contents than CJK contents,
+                       // we simply use the language that was specified as
+                       // babel main language.
+                       used[lang] += t.asInput().length();
+                       continue;
+               }
+               // Now we are starting an environment
+               p.pushPosition();
+               string const name = p.getArg('{', '}');
+               if (name != "CJK") {
+                       p.popPosition();
+                       continue;
+               }
+               // It is a CJK environment
+               p.popPosition();
+               /* name = */ p.getArg('{', '}');
+               string const encoding = p.getArg('{', '}');
+               /* mapping = */ p.getArg('{', '}');
+               string const encoding_old = p.getEncoding();
+               char const * const * const where =
+                       is_known(encoding, supported_CJK_encodings);
+               if (where)
+                       p.setEncoding(encoding, Encoding::CJK);
+               else
+                       p.setEncoding("UTF-8");
+               string const text = p.ertEnvironment("CJK");
+               p.setEncoding(encoding_old);
+               p.skip_spaces();
+               if (!where) {
+                       // ignore contents in unknown CJK encoding
+                       continue;
+               }
+               // the language of the text
+               string const cjk =
+                       supported_CJK_languages[where - supported_CJK_encodings];
+               used[cjk] += text.length();
+       }
+       LangMap::const_iterator use = used.begin();
+       for (LangMap::const_iterator it = used.begin(); it != used.end(); ++it) {
+               if (it->second > use->second)
+                       use = it;
+       }
+       return use->first;
+}
+
 // }])