]> git.lyx.org Git - lyx.git/blob - src/output_latex.cpp
use FileName::isDirectory()
[lyx.git] / src / output_latex.cpp
1 /**
2  * \file output_latex.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "output_latex.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "debug.h"
18 #include "Encoding.h"
19 #include "InsetList.h"
20 #include "Language.h"
21 #include "Layout.h"
22 #include "LyXRC.h"
23 #include "OutputParams.h"
24 #include "Paragraph.h"
25 #include "paragraph_funcs.h"
26 #include "ParagraphParameters.h"
27 #include "TexRow.h"
28 #include "VSpace.h"
29
30 #include "insets/InsetBibitem.h"
31 #include "insets/InsetOptArg.h"
32
33 #include "support/lstrings.h"
34
35 #include <boost/next_prior.hpp>
36
37 namespace lyx {
38
39 using support::subst;
40
41 using std::endl;
42 using std::string;
43 using std::pair;
44 using std::make_pair;
45
46
47 namespace {
48
49 ParagraphList::const_iterator
50 TeXEnvironment(Buffer const & buf,
51                ParagraphList const & paragraphs,
52                ParagraphList::const_iterator pit,
53                odocstream & os, TexRow & texrow,
54                OutputParams const & runparams);
55
56 ParagraphList::const_iterator
57 TeXOnePar(Buffer const & buf,
58           ParagraphList const & paragraphs,
59           ParagraphList::const_iterator pit,
60           odocstream & os, TexRow & texrow,
61           OutputParams const & runparams,
62           string const & everypar = string());
63
64
65 ParagraphList::const_iterator
66 TeXDeeper(Buffer const & buf,
67           ParagraphList const & paragraphs,
68           ParagraphList::const_iterator pit,
69           odocstream & os, TexRow & texrow,
70           OutputParams const & runparams)
71 {
72         LYXERR(Debug::LATEX) << "TeXDeeper...     " << &*pit << endl;
73         ParagraphList::const_iterator par = pit;
74
75         while (par != paragraphs.end() &&
76                      par->params().depth() == pit->params().depth()) {
77                 if (par->layout()->isEnvironment()) {
78                         par = TeXEnvironment(buf, paragraphs, par,
79                                              os, texrow, runparams);
80                 } else {
81                         par = TeXOnePar(buf, paragraphs, par,
82                                              os, texrow, runparams);
83                 }
84         }
85         LYXERR(Debug::LATEX) << "TeXDeeper...done " << endl;
86
87         return par;
88 }
89
90
91 ParagraphList::const_iterator
92 TeXEnvironment(Buffer const & buf,
93                ParagraphList const & paragraphs,
94                ParagraphList::const_iterator pit,
95                odocstream & os, TexRow & texrow,
96                OutputParams const & runparams)
97 {
98         LYXERR(Debug::LATEX) << "TeXEnvironment...     " << &*pit << endl;
99
100         BufferParams const & bparams = buf.params();
101
102         LayoutPtr const & style = pit->layout();
103
104         Language const * const par_language = pit->getParLanguage(bparams);
105         Language const * const doc_language = bparams.language;
106         Language const * const prev_par_language =
107                 (pit != paragraphs.begin())
108                 ? boost::prior(pit)->getParLanguage(bparams)
109                 : doc_language;
110         if (par_language->babel() != prev_par_language->babel()) {
111
112                 if (!lyxrc.language_command_end.empty() &&
113                     prev_par_language->babel() != doc_language->babel() &&
114                     !prev_par_language->babel().empty()) {
115                         os << from_ascii(subst(
116                                 lyxrc.language_command_end,
117                                 "$$lang",
118                                 prev_par_language->babel()))
119                            << '\n';
120                         texrow.newline();
121                 }
122
123                 if ((lyxrc.language_command_end.empty() ||
124                      par_language->babel() != doc_language->babel()) &&
125                     !par_language->babel().empty()) {
126                         os << from_ascii(subst(
127                                 lyxrc.language_command_begin,
128                                 "$$lang",
129                                 par_language->babel()))
130                            << '\n';
131                         texrow.newline();
132                 }
133         }
134
135         bool leftindent_open = false;
136         if (!pit->params().leftIndent().zero()) {
137                 os << "\\begin{LyXParagraphLeftIndent}{"
138                    << from_ascii(pit->params().leftIndent().asLatexString())
139                    << "}\n";
140                 texrow.newline();
141                 leftindent_open = true;
142         }
143
144         if (style->isEnvironment()) {
145                 os << "\\begin{" << from_ascii(style->latexname()) << '}';
146                 if (style->optionalargs > 0) {
147                         int ret = latexOptArgInsets(buf, *pit, os, runparams,
148                                                     style->optionalargs);
149                         while (ret > 0) {
150                                 texrow.newline();
151                                 --ret;
152                         }
153                 }
154                 if (style->latextype == LATEX_LIST_ENVIRONMENT) {
155                         os << '{'
156                            << pit->params().labelWidthString()
157                            << "}\n";
158                 } else if (style->labeltype == LABEL_BIBLIO) {
159                         // ale970405
160                         os << '{' << bibitemWidest(buf) << "}\n";
161                 } else
162                         os << from_ascii(style->latexparam()) << '\n';
163                 texrow.newline();
164         }
165         ParagraphList::const_iterator par = pit;
166         do {
167                 par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams);
168
169                 if (par == paragraphs.end()) {
170                         // Make sure that the last paragraph is
171                         // correctly terminated (because TeXOnePar does
172                         // not add a \n in this case)
173                         os << '\n';
174                         texrow.newline();
175                 } else if (par->params().depth() > pit->params().depth()) {
176                         if (par->layout()->isParagraph()) {
177                           // Thinko!
178                           // How to handle this? (Lgb)
179                           //&& !suffixIs(os, "\n\n")
180                                   //) {
181
182                                 // There should be at least one '\n' already
183                                 // but we need there to be two for Standard
184                                 // paragraphs that are depth-increment'ed to be
185                                 // output correctly.  However, tables can
186                                 // also be paragraphs so don't adjust them.
187                                 // ARRae
188                                 // Thinkee:
189                                 // Will it ever harm to have one '\n' too
190                                 // many? i.e. that we sometimes will have
191                                 // three in a row. (Lgb)
192                                 os << '\n';
193                                 texrow.newline();
194                         }
195                         par = TeXDeeper(buf, paragraphs, par, os, texrow,
196                                         runparams);
197                 }
198         } while (par != paragraphs.end()
199                  && par->layout() == pit->layout()
200                  && par->params().depth() == pit->params().depth()
201                  && par->params().leftIndent() == pit->params().leftIndent());
202
203         if (style->isEnvironment()) {
204                 os << "\\end{" << from_ascii(style->latexname()) << "}\n";
205                 texrow.newline();
206         }
207
208         if (leftindent_open) {
209                 os << "\\end{LyXParagraphLeftIndent}\n";
210                 texrow.newline();
211         }
212
213         if (par != paragraphs.end()) {
214                 LYXERR(Debug::LATEX) << "TeXEnvironment...done " << &*par << endl;
215         }
216         return par;
217 }
218
219 }
220
221
222 int latexOptArgInsets(Buffer const & buf, Paragraph const & par,
223                       odocstream & os, OutputParams const & runparams, int number)
224 {
225         int lines = 0;
226
227         InsetList::const_iterator it = par.insetList().begin();
228         InsetList::const_iterator end = par.insetList().end();
229         for (; it != end && number > 0 ; ++it) {
230                 if (it->inset->lyxCode() == OPTARG_CODE) {
231                         InsetOptArg * ins =
232                                 static_cast<InsetOptArg *>(it->inset);
233                         lines += ins->latexOptional(buf, os, runparams);
234                         --number;
235                 }
236         }
237         return lines;
238 }
239
240
241 namespace {
242
243 ParagraphList::const_iterator
244 TeXOnePar(Buffer const & buf,
245           ParagraphList const & paragraphs,
246           ParagraphList::const_iterator pit,
247           odocstream & os, TexRow & texrow,
248           OutputParams const & runparams_in,
249           string const & everypar)
250 {
251         LYXERR(Debug::LATEX) << "TeXOnePar...     " << &*pit << " '"
252                 << everypar << "'" << endl;
253         BufferParams const & bparams = buf.params();
254         LayoutPtr style;
255
256         // In an inset with unlimited length (all in one row),
257         // force layout to default
258         if (!pit->forceDefaultParagraphs())
259                 style = pit->layout();
260         else
261                 style = bparams.getTextClass().defaultLayout();
262
263         OutputParams runparams = runparams_in;
264         runparams.moving_arg |= style->needprotect;
265
266         // This paragraph's language
267         Language const * const par_language = pit->getParLanguage(bparams);
268         // The document's language
269         Language const * const doc_language = bparams.language;
270         // The language that was in effect when the environemnt this paragraph is 
271         // inside of was opened
272         Language const * const outer_language = 
273                 (runparams.local_font != 0) ?
274                         runparams.local_font->language() : doc_language;
275         // The previous language that was in effect is either the language of
276         // the previous paragraph, if there is one, or else the outer language
277         // if there is no previous paragraph
278         Language const * const prev_language =
279                 (pit != paragraphs.begin()) ?
280                         boost::prior(pit)->getParLanguage(bparams) : outer_language;
281
282         if (par_language->babel() != prev_language->babel()
283             // check if we already put language command in TeXEnvironment()
284             && !(style->isEnvironment()
285                  && (pit == paragraphs.begin() ||
286                      (boost::prior(pit)->layout() != pit->layout() &&
287                       boost::prior(pit)->getDepth() <= pit->getDepth())
288                      || boost::prior(pit)->getDepth() < pit->getDepth())))
289         {
290                 if (!lyxrc.language_command_end.empty() &&
291                     prev_language->babel() != outer_language->babel() &&
292                     !prev_language->babel().empty())
293                 {
294                         os << from_ascii(subst(lyxrc.language_command_end,
295                                 "$$lang",
296                                 prev_language->babel()))
297                            << '\n';
298                         texrow.newline();
299                 }
300
301                 // We need to open a new language if we couldn't close the previous 
302                 // one (because there's no language_command_end); and even if we closed
303                 // the previous one, if the current language is different than the
304                 // outer_language (which is currently in effect once the previous one
305                 // is closed).
306                 if ((lyxrc.language_command_end.empty() ||
307                      par_language->babel() != outer_language->babel()) &&
308                     !par_language->babel().empty()) {
309                         // If we're inside an inset, and that inset is within an \L or \R
310                         // (or equivalents), then within the inset, too, any opposite
311                         // language paragraph should appear within an \L or \R (in addition
312                         // to, outside of, the normal language switch commands).
313                         // This behavior is not correct for ArabTeX, though.
314                         if (    // not for ArabTeX
315                                         (par_language->lang() != "arabic_arabtex" &&
316                                          outer_language->lang() != "arabic_arabtex") &&
317                                         // are we in an inset?
318                                         runparams.local_font != 0 &&
319                                         // is the inset within an \L or \R?
320                                         // 
321                                         // FIXME: currently, we don't check this; this means that
322                                         // we'll have unnnecessary \L and \R commands, but that 
323                                         // doesn't seem to hurt (though latex will complain)
324                                         // 
325                                         // is this paragraph in the opposite direction?
326                                         runparams.local_font->isRightToLeft() !=
327                                                 par_language->rightToLeft()
328                                 ) {
329                                 // FIXME: I don't have a working copy of the Arabi package, so
330                                 // I'm not sure if the farsi and arabic_arabi stuff is correct
331                                 // or not...
332                                 if (par_language->lang() == "farsi")
333                                         os << "\\textFR{";
334                                 else if (outer_language->lang() == "farsi")
335                                         os << "\\textLR{";
336                                 else if (par_language->lang() == "arabic_arabi")
337                                         os << "\\textAR{";
338                                 else if (outer_language->lang() == "arabic_arabi")
339                                         os << "\\textLR{";
340                                 // remaining RTL languages currently is hebrew
341                                 else if (par_language->rightToLeft())
342                                         os << "\\R{";
343                                 else
344                                         os << "\\L{";
345                         }
346                         os << from_ascii(subst(
347                                 lyxrc.language_command_begin,
348                                 "$$lang",
349                                 par_language->babel()))
350                            << '\n';
351                         texrow.newline();
352                 }
353         }
354
355         // Switch file encoding if necessary; no need to do this for "default"
356         // encoding, since this only affects the position of the outputted
357         // \inputencoding command; the encoding switch will occur when necessary
358         if (bparams.inputenc == "auto" &&
359             runparams.encoding->package() == Encoding::inputenc) {
360                 // Look ahead for future encoding changes.
361                 // We try to output them at the beginning of the paragraph,
362                 // since the \inputencoding command is not allowed e.g. in
363                 // sections.
364                 for (pos_type i = 0; i < pit->size(); ++i) {
365                         char_type const c = pit->getChar(i);
366                         if (c < 0x80)
367                                 continue;
368                         if (pit->isInset(i))
369                                 break;
370                         // All characters before c are in the ASCII range, and
371                         // c is non-ASCII (but no inset), so change the
372                         // encoding to that required by the language of c.
373                         Encoding const * const encoding =
374                                 pit->getFontSettings(bparams, i).language()->encoding();
375                         pair<bool, int> enc_switch = switchEncoding(os, bparams, false,
376                                         *(runparams.encoding), *encoding);
377                         if (encoding->package() == Encoding::inputenc && enc_switch.first) {
378                                 runparams.encoding = encoding;
379                                 if (enc_switch.second > 0) {
380                                         os << '\n';
381                                         texrow.newline();
382                                 }
383                         }
384                         break;
385                 }
386         }
387
388         // In an inset with unlimited length (all in one row),
389         // don't allow any special options in the paragraph
390         if (!pit->forceDefaultParagraphs()) {
391                 if (pit->params().startOfAppendix()) {
392                         os << "\\appendix\n";
393                         texrow.newline();
394                 }
395
396                 if (!pit->params().spacing().isDefault()
397                         && (pit == paragraphs.begin()
398                             || !boost::prior(pit)->hasSameLayout(*pit)))
399                 {
400                         os << from_ascii(pit->params().spacing().writeEnvirBegin())
401                             << '\n';
402                         texrow.newline();
403                 }
404
405                 if (style->isCommand()) {
406                         os << '\n';
407                         texrow.newline();
408                 }
409         }
410
411         switch (style->latextype) {
412         case LATEX_COMMAND:
413                 os << '\\' << from_ascii(style->latexname());
414
415                 // Separate handling of optional argument inset.
416                 if (style->optionalargs > 0) {
417                         int ret = latexOptArgInsets(buf, *pit, os, runparams,
418                                                     style->optionalargs);
419                         while (ret > 0) {
420                                 texrow.newline();
421                                 --ret;
422                         }
423                 }
424                 else
425                         os << from_ascii(style->latexparam());
426                 break;
427         case LATEX_ITEM_ENVIRONMENT:
428         case LATEX_LIST_ENVIRONMENT:
429                 os << "\\item ";
430                 break;
431         case LATEX_BIB_ENVIRONMENT:
432                 // ignore this, the inset will write itself
433                 break;
434         default:
435                 break;
436         }
437
438         Font const outerfont =
439                 outerFont(std::distance(paragraphs.begin(), pit),
440                           paragraphs);
441
442         // FIXME UNICODE
443         os << from_utf8(everypar);
444         bool need_par = pit->simpleTeXOnePar(buf, bparams, outerfont,
445                                              os, texrow, runparams);
446
447         // Make sure that \\par is done with the font of the last
448         // character if this has another size as the default.
449         // This is necessary because LaTeX (and LyX on the screen)
450         // calculates the space between the baselines according
451         // to this font. (Matthias)
452         //
453         // Is this really needed ? (Dekel)
454         // We do not need to use to change the font for the last paragraph
455         // or for a command.
456
457         Font const font =
458                 (pit->empty()
459                  ? pit->getLayoutFont(bparams, outerfont)
460                  : pit->getFont(bparams, pit->size() - 1, outerfont));
461
462         bool is_command = style->isCommand();
463
464         if (style->resfont.size() != font.size()
465             && boost::next(pit) != paragraphs.end()
466             && !is_command) {
467                 if (!need_par)
468                         os << '{';
469                 os << "\\" << from_ascii(font.latexSize()) << " \\par}";
470         } else if (need_par) {
471                 os << "\\par}";
472         } else if (is_command)
473                 os << '}';
474
475         bool pending_newline = false;
476         switch (style->latextype) {
477         case LATEX_ITEM_ENVIRONMENT:
478         case LATEX_LIST_ENVIRONMENT:
479                 if (boost::next(pit) != paragraphs.end()
480                     && (pit->params().depth() < boost::next(pit)->params().depth()))
481                         pending_newline = true;
482                 break;
483         case LATEX_ENVIRONMENT: {
484                 // if its the last paragraph of the current environment
485                 // skip it otherwise fall through
486                 ParagraphList::const_iterator next = boost::next(pit);
487
488                 if (next != paragraphs.end()
489                     && (next->layout() != pit->layout()
490                         || next->params().depth() != pit->params().depth()))
491                         break;
492         }
493
494                 // fall through possible
495         default:
496                 // we don't need it for the last paragraph!!!
497                 if (boost::next(pit) != paragraphs.end())
498                         pending_newline = true;
499         }
500
501         if (!pit->forceDefaultParagraphs()) {
502                 if (!pit->params().spacing().isDefault()
503                         && (boost::next(pit) == paragraphs.end()
504                             || !boost::next(pit)->hasSameLayout(*pit)))
505                 {
506                         if (pending_newline) {
507                                 os << '\n';
508                                 texrow.newline();
509                         }
510                         os << from_ascii(pit->params().spacing().writeEnvirEnd());
511                         pending_newline = true;
512                 }
513         }
514
515         // Closing the language is needed for the last paragraph; it is also
516         // needed if we're within an \L or \R that we may have opened above (not
517         // necessarily in this paragraph) and are about to close.
518         bool closing_rtl_ltr_environment = 
519                 // not for ArabTeX
520                 (par_language->lang() != "arabic_arabtex" &&
521                  outer_language->lang() != "arabic_arabtex") &&
522                 // have we opened and \L or \R environment?
523                 runparams.local_font != 0 &&
524                 runparams.local_font->isRightToLeft() != par_language->rightToLeft() &&
525                 // are we about to close the language?
526                 ((boost::next(pit) != paragraphs.end() &&
527                   par_language->babel() != 
528                         (boost::next(pit)->getParLanguage(bparams))->babel()) ||
529                  (boost::next(pit) == paragraphs.end() &&
530                   par_language->babel() != outer_language->babel()));
531
532         if (closing_rtl_ltr_environment || (boost::next(pit) == paragraphs.end()
533             && par_language->babel() != outer_language->babel())) {
534                 // Since \selectlanguage write the language to the aux file,
535                 // we need to reset the language at the end of footnote or
536                 // float.
537
538                 if (pending_newline) {
539                         os << '\n';
540                         texrow.newline();
541                 }
542                 if (lyxrc.language_command_end.empty()) {
543                         if (!prev_language->babel().empty()) {
544                                 os << from_ascii(subst(
545                                         lyxrc.language_command_begin,
546                                         "$$lang",
547                                         prev_language->babel()));
548                                 pending_newline = true;
549                         }
550                 } else if (!par_language->babel().empty()) {
551                         os << from_ascii(subst(
552                                 lyxrc.language_command_end,
553                                 "$$lang",
554                                 par_language->babel()));
555                         pending_newline = true;
556                 }
557         }
558         if (closing_rtl_ltr_environment)
559                 os << "}";
560
561         if (pending_newline) {
562                 os << '\n';
563                 texrow.newline();
564         }
565
566         // If this is the last paragraph, and a local_font was set upon entering
567         // the inset, the encoding should be set back to that local_font's 
568         // encoding. We don't use switchEncoding(), because no explicit encoding
569         // switch command is needed, since latex will automatically revert to it
570         // when this inset closes.
571         // This switch is only necessary if we're using "auto" or "default" 
572         // encoding. 
573         if (boost::next(pit) == paragraphs.end() && runparams_in.local_font != 0) {
574                 runparams_in.encoding = runparams_in.local_font->language()->encoding();
575                 if (bparams.inputenc == "auto" || bparams.inputenc == "default")
576                         os << setEncoding(runparams_in.encoding->iconvName());
577
578         }
579         // Otherwise, the current encoding should be set for the next paragraph.
580         else
581                 runparams_in.encoding = runparams.encoding;
582
583
584         // we don't need it for the last paragraph!!!
585         // Note from JMarc: we will re-add a \n explicitely in
586         // TeXEnvironment, because it is needed in this case
587         if (boost::next(pit) != paragraphs.end()) {
588                 os << '\n';
589                 texrow.newline();
590         }
591
592         if (boost::next(pit) != paragraphs.end()) {
593                 LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*boost::next(pit) << endl;
594         }
595
596         return ++pit;
597 }
598
599 } // anon namespace
600
601
602 // LaTeX all paragraphs
603 void latexParagraphs(Buffer const & buf,
604                      ParagraphList const & paragraphs,
605                      odocstream & os,
606                      TexRow & texrow,
607                      OutputParams const & runparams,
608                      string const & everypar)
609 {
610         bool was_title = false;
611         bool already_title = false;
612         TextClass const & tclass = buf.params().getTextClass();
613         ParagraphList::const_iterator par = paragraphs.begin();
614         ParagraphList::const_iterator endpar = paragraphs.end();
615
616         BOOST_ASSERT(runparams.par_begin <= runparams.par_end);
617         // if only part of the paragraphs will be outputed
618         if (runparams.par_begin !=  runparams.par_end) {
619                 par = boost::next(paragraphs.begin(), runparams.par_begin);
620                 endpar = boost::next(paragraphs.begin(), runparams.par_end);
621                 // runparams will be passed to nested paragraphs, so
622                 // we have to reset the range parameters.
623                 const_cast<OutputParams&>(runparams).par_begin = 0;
624                 const_cast<OutputParams&>(runparams).par_end = 0;
625         }
626
627         // if only_body
628         while (par != endpar) {
629                 ParagraphList::const_iterator lastpar = par;
630                 // well we have to check if we are in an inset with unlimited
631                 // length (all in one row) if that is true then we don't allow
632                 // any special options in the paragraph and also we don't allow
633                 // any environment other than the default layout of the
634                 // text class to be valid!
635                 if (!par->forceDefaultParagraphs()) {
636                         LayoutPtr const & layout = par->layout();
637
638                         if (layout->intitle) {
639                                 if (already_title) {
640                                         lyxerr << "Error in latexParagraphs: You"
641                                                 " should not mix title layouts"
642                                                 " with normal ones." << endl;
643                                 } else if (!was_title) {
644                                         was_title = true;
645                                         if (tclass.titletype() == TITLE_ENVIRONMENT) {
646                                                 os << "\\begin{"
647                                                     << from_ascii(tclass.titlename())
648                                                     << "}\n";
649                                                 texrow.newline();
650                                         }
651                                 }
652                         } else if (was_title && !already_title) {
653                                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
654                                         os << "\\end{" << from_ascii(tclass.titlename())
655                                             << "}\n";
656                                 }
657                                 else {
658                                         os << "\\" << from_ascii(tclass.titlename())
659                                             << "\n";
660                                 }
661                                 texrow.newline();
662                                 already_title = true;
663                                 was_title = false;
664                         }
665
666                         if (layout->is_environment) {
667                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
668                                                 runparams, everypar);
669                         } else if (layout->isEnvironment() ||
670                                    !par->params().leftIndent().zero()) {
671                                 par = TeXEnvironment(buf, paragraphs, par, os,
672                                                      texrow, runparams);
673                         } else {
674                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
675                                                 runparams, everypar);
676                         }
677                 } else {
678                         par = TeXOnePar(buf, paragraphs, par, os, texrow,
679                                         runparams, everypar);
680                 }
681                 if (std::distance(lastpar, par) >= std::distance(lastpar, endpar))
682                         break;
683         }
684         // It might be that we only have a title in this document
685         if (was_title && !already_title) {
686                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
687                         os << "\\end{" << from_ascii(tclass.titlename())
688                             << "}\n";
689                 }
690                 else {
691                         os << "\\" << from_ascii(tclass.titlename())
692                             << "\n";
693                                 }
694                 texrow.newline();
695         }
696 }
697
698
699 pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
700                    bool moving_arg, Encoding const & oldEnc,
701                    Encoding const & newEnc)
702 {
703         if ((bparams.inputenc != "auto" && bparams.inputenc != "default")
704                 || moving_arg)
705                 return make_pair(false, 0);
706
707         // Do nothing if the encoding is unchanged.
708         if (oldEnc.name() == newEnc.name())
709                 return make_pair(false, 0);
710
711         // FIXME We ignore encoding switches from/to encodings that do
712         // neither support the inputenc package nor the CJK package here.
713         // This does of course only work in special cases (e.g. switch from
714         // tis620-0 to latin1, but the text in latin1 contains ASCII only),
715         // but it is the best we can do
716         if (oldEnc.package() == Encoding::none
717                 || newEnc.package() == Encoding::none)
718                 return make_pair(false, 0);
719
720         LYXERR(Debug::LATEX) << "Changing LaTeX encoding from "
721                 << oldEnc.name() << " to "
722                 << newEnc.name() << endl;
723         os << setEncoding(newEnc.iconvName());
724         if (bparams.inputenc == "default")
725                 return make_pair(true, 0);
726
727         docstring const inputenc(from_ascii(newEnc.latexName()));
728         switch (newEnc.package()) {
729                 case Encoding::none:
730                         // shouldn't ever reach here, see above
731                         return make_pair(true, 0);
732                 case Encoding::inputenc: {
733                         int count = inputenc.length();
734                         if (oldEnc.package() == Encoding::CJK) {
735                                 os << "\\end{CJK}";
736                                 count += 9;
737                         }
738                         os << "\\inputencoding{" << inputenc << '}';
739                         return make_pair(true, count + 16);
740                  }
741                 case Encoding::CJK: {
742                         int count = inputenc.length();
743                         if (oldEnc.package() == Encoding::CJK) {
744                                 os << "\\end{CJK}";
745                                 count += 9;
746                         }
747                         os << "\\begin{CJK}{" << inputenc << "}{}";
748                         return make_pair(true, count + 15);
749                 }
750         }
751         // Dead code to avoid a warning:
752         return make_pair(true, 0);
753 }
754
755 } // namespace lyx