3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
18 #include "LayoutFile.h"
21 #include "TextClass.h"
23 #include "support/convert.h"
24 #include "support/FileName.h"
25 #include "support/filetools.h"
26 #include "support/lstrings.h"
28 #include <boost/regex.hpp>
38 using namespace lyx::support;
44 // special columntypes
45 extern map<char, int> special_columns;
47 map<string, vector<string> > used_packages;
49 // needed to handle encodings with babel
50 bool one_language = true;
52 // to avoid that the babel options overwrite the documentclass options
53 bool documentclass_language;
57 const char * const known_languages[] = { "afrikaans", "american", "arabic",
58 "austrian", "bahasa", "basque", "belarusian", "brazil", "brazilian", "breton",
59 "british", "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech",
60 "danish", "dutch", "english", "esperanto", "estonian", "finnish", "francais",
61 "french", "frenchb", "frenchle", "frenchpro", "galician", "german", "germanb",
62 "greek", "hebrew", "icelandic", "irish", "italian", "lsorbian", "magyar",
63 "naustrian", "ngerman", "ngermanb", "norsk", "nynorsk", "polish", "portuges",
64 "portuguese", "romanian", "russian", "russianb", "scottish", "serbian", "slovak",
65 "slovene", "spanish", "swedish", "thai", "turkish", "ukraineb", "ukrainian",
66 "usorbian", "welsh", 0};
68 //note this when updating to lyxformat 305:
69 //bahasai, indonesian, and indon = equal to bahasa
70 //malay and meyalu = equal to bahasam
72 const char * const known_brazilian_languages[] = {"brazil", "brazilian", 0};
73 const char * const known_french_languages[] = {"french", "frenchb", "francais",
74 "frenchle", "frenchpro", 0};
75 const char * const known_german_languages[] = {"german", "germanb", 0};
76 const char * const known_ngerman_languages[] = {"ngerman", "ngermanb", 0};
77 const char * const known_portuguese_languages[] = {"portuges", "portuguese", 0};
78 const char * const known_russian_languages[] = {"russian", "russianb", 0};
79 const char * const known_ukrainian_languages[] = {"ukrainian", "ukraineb", 0};
81 char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
83 const char * const known_roman_fonts[] = { "ae", "bookman", "charter",
84 "cmr", "fourier", "lmodern", "mathpazo", "mathptmx", "newcent", 0};
86 const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss",
89 const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
90 "courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx",
93 const char * const known_paper_sizes[] = { "a3paper", "b3paper", "a4paper",
94 "b4paper", "a5paper", "b5paper", "executivepaper", "legalpaper",
97 const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
98 "executivepaper", "legalpaper", "letterpaper", 0};
100 const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
101 "bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
103 const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
104 "rightmargin", "bottommargin", "headheight", "headsep", "footskip",
107 const char * const known_lyx_commands[] = { "binom", "cedilla", "cyrtext",
108 "dacute", "dgrave", "docedilla", "doogonek", "dosubhat", "dosubring",
109 "dosubtilde", "greektext", "guillemotleft", "guillemotright", "guilsinglleft",
110 "guilsinglright", "LyX", "lyxadded", "lyxarrow", "lyxdeleted", "lyxdot",
111 "lyxgreyedout", "lyxline", "lyxmathsym", "LyXParagraphLeftIndent",
112 "lyxrightaddress", "makenomenclature", "mathcircumflex", "noun", "ogonek",
113 "printnomenclature", "quotedblbase", "quotesinglbase", "rcap", "subhat",
114 "subring", "subtilde", "tabularnewline", "textcyr", "textgreek", 0};
116 const char * const known_lyx_comments[] = {
117 "%% Binom macro for standard LaTeX users\n",
118 "%% For printing a cirumflex inside a formula\n",
119 "%% Because html converters don't know tabularnewline\n",
120 "%% The greyedout annotation environment\n",
121 "%% A simple dot to overcome graphicx limitations\n",
122 "%% Change tracking with ulem\n",
123 "% the following is useful when we have the old nomencl.sty package\n",
124 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.\n",
125 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.\n",
129 ostringstream h_preamble;
130 string h_textclass = "article";
131 string h_options = string();
132 string h_language = "english";
133 string h_inputencoding = "auto";
134 string h_font_roman = "default";
135 string h_font_sans = "default";
136 string h_font_typewriter = "default";
137 string h_font_default_family = "default";
138 string h_font_sc = "false";
139 string h_font_osf = "false";
140 string h_font_sf_scale = "100";
141 string h_font_tt_scale = "100";
142 string h_graphics = "default";
143 string h_paperfontsize = "default";
144 string h_spacing = "single";
145 string h_papersize = "default";
146 string h_use_geometry = "false";
147 string h_use_amsmath = "1";
148 string h_use_esint = "1";
149 string h_cite_engine = "basic";
150 string h_use_bibtopic = "false";
151 string h_paperorientation = "portrait";
152 string h_secnumdepth = "3";
153 string h_tocdepth = "3";
154 string h_paragraph_separation = "indent";
155 string h_defskip = "medskip";
156 string h_quotes_language = "english";
157 string h_papercolumns = "1";
158 string h_papersides = string();
159 string h_paperpagestyle = "default";
160 string h_tracking_changes = "false";
161 string h_output_changes = "false";
162 string h_margins = "";
165 void handle_opt(vector<string> & opts, char const * const * what, string & target)
170 // the last language option is the document language (for babel and LyX)
171 // the last size option is the document font size
172 vector<string>::iterator it;
173 vector<string>::iterator position = opts.begin();
174 for (; *what; ++what) {
175 it = find(opts.begin(), opts.end(), *what);
176 if (it != opts.end()) {
177 documentclass_language = true;
178 if (it >= position) {
187 void delete_opt(vector<string> & opts, char const * const * what)
192 // remove found options from the list
193 // do this after handle_opt to avoid potential memory leaks and to be able
194 // to find in every case the last language option
195 vector<string>::iterator it;
196 for (; *what; ++what) {
197 it = find(opts.begin(), opts.end(), *what);
198 if (it != opts.end())
205 * Split a package options string (keyval format) into a vector.
207 * authorformat=smallcaps,
209 * titleformat=colonsep,
210 * bibformat={tabular,ibidem,numbered}
212 vector<string> split_options(string const & input)
214 vector<string> options;
218 Token const & t = p.get_token();
219 if (t.asInput() == ",") {
220 options.push_back(trim(option));
222 } else if (t.asInput() == "=") {
225 if (p.next_token().asInput() == "{")
226 option += '{' + p.getArg('{', '}') + '}';
227 } else if (t.cat() != catSpace)
228 option += t.asInput();
232 options.push_back(trim(option));
239 * Add package \p name with options \p options to used_packages.
240 * Remove options from \p options that we don't want to output.
242 void add_package(string const & name, vector<string> & options)
244 // every package inherits the global options
245 if (used_packages.find(name) == used_packages.end())
246 used_packages[name] = split_options(h_options);
248 vector<string> & v = used_packages[name];
249 v.insert(v.end(), options.begin(), options.end());
250 if (name == "jurabib") {
251 // Don't output the order argument (see the cite command
252 // handling code in text.cpp).
253 vector<string>::iterator end =
254 remove(options.begin(), options.end(), "natbiborder");
255 end = remove(options.begin(), end, "jurabiborder");
256 options.erase(end, options.end());
261 // Given is a string like "scaled=0.9", return 0.9 * 100
262 string const scale_as_percentage(string const & scale)
264 string::size_type pos = scale.find('=');
265 if (pos != string::npos) {
266 string value = scale.substr(pos + 1);
268 return convert<string>(100 * convert<double>(value));
270 // If the input string didn't match our expectations.
271 // return the default value "100"
276 void handle_package(Parser &p, string const & name, string const & opts)
278 vector<string> options = split_options(opts);
279 add_package(name, options);
283 if (is_known(name, known_roman_fonts)) {
288 if (name == "fourier") {
289 h_font_roman = "utopia";
290 // when font uses real small capitals
291 if (opts == "expert")
295 if (name == "mathpazo")
296 h_font_roman = "palatino";
298 if (name == "mathptmx")
299 h_font_roman = "times";
302 if (is_known(name, known_sans_fonts)) {
306 h_font_sf_scale = scale_as_percentage(scale);
311 if (is_known(name, known_typewriter_fonts)) {
312 h_font_typewriter = name;
315 h_font_tt_scale = scale_as_percentage(scale);
319 // font uses old-style figure
323 else if (name == "amsmath" || name == "amssymb")
326 else if (name == "esint")
329 else if (name == "babel" && !opts.empty()) {
330 // check if more than one option was used - used later for inputenc
331 // in case inputenc is parsed before babel, set the encoding to auto
332 if (options.begin() != options.end() - 1) {
333 one_language = false;
334 h_inputencoding = "auto";
336 // only set the document language when there was not already one set
337 // via the documentclass options
338 // babel takes the the last language given in the documentclass options
339 // as document language. If there is no such language option, the last
340 // option of its \usepackage call is used.
341 if (documentclass_language == false) {
342 handle_opt(options, known_languages, h_language);
343 delete_opt(options, known_languages);
344 if (is_known(h_language, known_brazilian_languages))
345 h_language = "brazilian";
346 else if (is_known(h_language, known_french_languages))
347 h_language = "french";
348 else if (is_known(h_language, known_german_languages))
349 h_language = "german";
350 else if (is_known(h_language, known_ngerman_languages))
351 h_language = "ngerman";
352 else if (is_known(h_language, known_portuguese_languages))
353 h_language = "portuguese";
354 else if (is_known(h_language, known_russian_languages))
355 h_language = "russian";
356 else if (is_known(h_language, known_ukrainian_languages))
357 h_language = "ukrainian";
358 h_quotes_language = h_language;
362 else if (name == "fontenc")
365 else if (name == "inputenc") {
366 // only set when there is not more than one inputenc
367 // option therefore check for the "," character also
368 // only set when there is not more then one babel
370 if (opts.find(",") == string::npos && one_language == true) {
372 //change ascii to auto to be in the unicode range, see
373 //http://bugzilla.lyx.org/show_bug.cgi?id=4719
374 h_inputencoding = "auto";
375 else if (!opts.empty())
376 h_inputencoding = opts;
378 if (!options.empty())
379 p.setEncoding(options.back());
383 else if (name == "makeidx")
386 else if (name == "prettyref")
389 else if (name == "varioref")
392 else if (name == "verbatim")
395 else if (name == "nomencl")
398 else if (name == "textcomp")
401 else if (name == "url")
404 else if (name == "color") {
405 // with the following command this package is only loaded when needed for
406 // undefined colors, since we only support the predefined colors
407 h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n";
410 else if (name == "graphicx")
413 else if (name == "setspace")
416 else if (name == "geometry")
417 ; // Ignore this, the geometry settings are made by the \geometry
418 // command. This command is handled below.
420 else if (is_known(name, known_languages)) {
421 if (is_known(h_language, known_brazilian_languages))
422 h_language = "brazilian";
423 else if (is_known(name, known_french_languages))
424 h_language = "french";
425 else if (is_known(name, known_german_languages))
426 h_language = "german";
427 else if (is_known(name, known_ngerman_languages))
428 h_language = "ngerman";
429 else if (is_known(h_language, known_portuguese_languages))
430 h_language = "portuguese";
431 else if (is_known(name, known_russian_languages))
432 h_language = "russian";
433 else if (is_known(name, known_ukrainian_languages))
434 h_language = "ukrainian";
437 h_quotes_language = h_language;
440 else if (name == "natbib") {
441 h_cite_engine = "natbib_authoryear";
442 vector<string>::iterator it =
443 find(options.begin(), options.end(), "authoryear");
444 if (it != options.end())
447 it = find(options.begin(), options.end(), "numbers");
448 if (it != options.end()) {
449 h_cite_engine = "natbib_numerical";
455 else if (name == "jurabib")
456 h_cite_engine = "jurabib";
458 else if (name == "babel")
463 h_preamble << "\\usepackage{" << name << "}";
465 h_preamble << "\\usepackage[" << opts << "]{"
471 // We need to do something with the options...
472 if (!options.empty())
473 cerr << "Ignoring options '" << join(options, ",")
474 << "' of package " << name << '.' << endl;
476 // remove the whitespace
482 void end_preamble(ostream & os, TextClass const & /*textclass*/)
484 os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
485 << "\\lyxformat 264\n"
486 << "\\begin_document\n"
487 << "\\begin_header\n"
488 << "\\textclass " << h_textclass << "\n";
489 if (!h_preamble.str().empty())
490 os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
491 if (!h_options.empty())
492 os << "\\options " << h_options << "\n";
493 os << "\\language " << h_language << "\n"
494 << "\\inputencoding " << h_inputencoding << "\n"
495 << "\\font_roman " << h_font_roman << "\n"
496 << "\\font_sans " << h_font_sans << "\n"
497 << "\\font_typewriter " << h_font_typewriter << "\n"
498 << "\\font_default_family " << h_font_default_family << "\n"
499 << "\\font_sc " << h_font_sc << "\n"
500 << "\\font_osf " << h_font_osf << "\n"
501 << "\\font_sf_scale " << h_font_sf_scale << "\n"
502 << "\\font_tt_scale " << h_font_tt_scale << "\n"
503 << "\\graphics " << h_graphics << "\n"
504 << "\\paperfontsize " << h_paperfontsize << "\n"
505 << "\\spacing " << h_spacing << "\n"
506 << "\\papersize " << h_papersize << "\n"
507 << "\\use_geometry " << h_use_geometry << "\n"
508 << "\\use_amsmath " << h_use_amsmath << "\n"
509 << "\\use_esint " << h_use_esint << "\n"
510 << "\\cite_engine " << h_cite_engine << "\n"
511 << "\\use_bibtopic " << h_use_bibtopic << "\n"
512 << "\\paperorientation " << h_paperorientation << "\n"
514 << "\\secnumdepth " << h_secnumdepth << "\n"
515 << "\\tocdepth " << h_tocdepth << "\n"
516 << "\\paragraph_separation " << h_paragraph_separation << "\n"
517 << "\\defskip " << h_defskip << "\n"
518 << "\\quotes_language " << h_quotes_language << "\n"
519 << "\\papercolumns " << h_papercolumns << "\n"
520 << "\\papersides " << h_papersides << "\n"
521 << "\\paperpagestyle " << h_paperpagestyle << "\n"
522 << "\\tracking_changes " << h_tracking_changes << "\n"
523 << "\\output_changes " << h_output_changes << "\n"
524 << "\\end_header\n\n"
526 // clear preamble for subdocuments
530 } // anonymous namespace
532 void parse_preamble(Parser & p, ostream & os,
533 string const & forceclass, TeX2LyXDocClass & tc)
535 // initialize fixed types
536 special_columns['D'] = 3;
537 bool is_full_document = false;
538 bool lyx_specific_preamble = false;
540 // determine whether this is a full document or a fragment for inclusion
542 Token const & t = p.get_token();
544 if (t.cat() == catEscape && t.cs() == "documentclass") {
545 is_full_document = true;
551 while (is_full_document && p.good()) {
552 Token const & t = p.get_token();
555 cerr << "t: " << t << "\n";
561 if ((t.cat() == catLetter ||
562 t.cat() == catSuper ||
564 t.cat() == catOther ||
565 t.cat() == catMath ||
566 t.cat() == catActive ||
567 t.cat() == catBegin ||
569 t.cat() == catAlign ||
570 t.cat() == catParameter))
571 h_preamble << t.character();
573 else if (t.cat() == catSpace || t.cat() == catNewline)
574 h_preamble << t.asInput();
576 else if (t.cat() == catComment) {
577 // regex to parse comments (currently not used)
578 //static regex const islyxfile("%% LyX .* created this file");
579 string const comment = t.asInput();
580 // magically switch encoding default if it looks like XeLaTeX
581 static string const magicXeLaTeX =
582 "% This document must be compiled with XeLaTeX ";
583 if (comment.size() > magicXeLaTeX.size()
584 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
585 && h_inputencoding == "auto") {
586 cerr << "XeLaTeX comment found, switching to UTF8\n";
587 h_inputencoding = "utf8";
590 // don't output LyX specific comments
591 if (!is_known(comment, known_lyx_comments))
592 h_preamble << t.asInput();
595 else if (t.cs() == "pagestyle")
596 h_paperpagestyle = p.verbatim_item();
598 else if (t.cs() == "makeatletter") {
599 // LyX takes care of this
600 p.setCatCode('@', catLetter);
603 else if (t.cs() == "makeatother") {
604 // LyX takes care of this
605 p.setCatCode('@', catOther);
608 else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
609 || t.cs() == "providecommand"
610 || t.cs() == "DeclareRobustCommand"
611 || t.cs() == "ProvideTextCommandDefault"
612 || t.cs() == "DeclareMathAccent") {
614 if (p.next_token().character() == '*') {
618 string const name = p.verbatim_item();
619 string const opt1 = p.getOpt();
620 string const opt2 = p.getFullOpt();
621 string const body = p.verbatim_item();
623 if (name == "\\rmdefault")
624 if (is_known(body, known_roman_fonts))
626 if (name == "\\sfdefault")
627 if (is_known(body, known_sans_fonts))
629 if (name == "\\ttdefault")
630 if (is_known(body, known_typewriter_fonts))
631 h_font_typewriter = body;
632 if (name == "\\familydefault") {
633 string family = body;
634 // remove leading "\"
635 h_font_default_family = family.erase(0,1);
637 // LyX specific commands that will automatically be set by LyX
638 string lyx_command = name;
639 // remove the leading "\"
640 lyx_command.erase(0,1);
641 lyx_specific_preamble = false;
642 // allow redefinitions of LyX specific commands
643 if (is_known(lyx_command, known_lyx_commands)
644 && (t.cs() != "renewcommand"))
645 lyx_specific_preamble = true;
646 // only non-lyxspecific stuff
647 if (!lyx_specific_preamble) {
649 ss << '\\' << t.cs();
652 ss << '{' << name << '}' << opt1 << opt2
653 << '{' << body << "}";
654 h_preamble << ss.str();
656 // Add the command to the known commands
657 add_known_command(name, opt1, !opt2.empty());
659 ostream & out = in_preamble ? h_preamble : os;
660 out << "\\" << t.cs() << "{" << name << "}"
661 << opts << "{" << body << "}";
666 else if (t.cs() == "documentclass") {
667 vector<string>::iterator it;
668 vector<string> opts = split_options(p.getArg('[', ']'));
669 handle_opt(opts, known_fontsizes, h_paperfontsize);
670 delete_opt(opts, known_fontsizes);
671 // delete "pt" at the end
672 string::size_type i = h_paperfontsize.find("pt");
673 if (i != string::npos)
674 h_paperfontsize.erase(i);
675 // to avoid that the babel options overwrite the documentclass options
676 documentclass_language = false;
677 handle_opt(opts, known_languages, h_language);
678 delete_opt(opts, known_languages);
679 if (is_known(h_language, known_brazilian_languages))
680 h_language = "brazilian";
681 else if (is_known(h_language, known_french_languages))
682 h_language = "french";
683 else if (is_known(h_language, known_german_languages))
684 h_language = "german";
685 else if (is_known(h_language, known_ngerman_languages))
686 h_language = "ngerman";
687 else if (is_known(h_language, known_portuguese_languages))
688 h_language = "portuguese";
689 else if (is_known(h_language, known_russian_languages))
690 h_language = "russian";
691 else if (is_known(h_language, known_ukrainian_languages))
692 h_language = "ukrainian";
693 h_quotes_language = h_language;
695 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
696 h_paperorientation = "landscape";
700 if ((it = find(opts.begin(), opts.end(), "oneside"))
705 if ((it = find(opts.begin(), opts.end(), "twoside"))
711 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
713 h_papercolumns = "1";
716 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
718 h_papercolumns = "2";
722 // some size options are know to any document classes, other sizes
723 // are handled by the \geometry command of the geometry package
724 handle_opt(opts, known_class_paper_sizes, h_papersize);
725 delete_opt(opts, known_class_paper_sizes);
726 // the remaining options
727 h_options = join(opts, ",");
728 h_textclass = p.getArg('{', '}');
731 else if (t.cs() == "usepackage") {
732 string const options = p.getArg('[', ']');
733 string const name = p.getArg('{', '}');
734 vector<string> vecnames;
735 split(name, vecnames, ',');
736 vector<string>::const_iterator it = vecnames.begin();
737 vector<string>::const_iterator end = vecnames.end();
738 for (; it != end; ++it)
739 handle_package(p, trim(*it), options);
742 else if (t.cs() == "inputencoding") {
743 string const encoding = p.getArg('{','}');
744 h_inputencoding = encoding;
745 p.setEncoding(encoding);
748 else if (t.cs() == "newenvironment") {
749 string const name = p.getArg('{', '}');
751 // only non LyX specific stuff is output
752 ss << "\\newenvironment{" << name << "}";
755 ss << '{' << p.verbatim_item() << '}';
756 ss << '{' << p.verbatim_item() << '}';
757 if (!is_known(name, known_lyx_commands))
758 h_preamble << ss.str();
761 else if (t.cs() == "def") {
762 string name = p.get_token().cs();
763 while (p.next_token().cat() != catBegin)
764 name += p.get_token().asString();
765 if (!is_known(name, known_lyx_commands))
766 h_preamble << "\\def\\" << name << '{'
767 << p.verbatim_item() << "}";
770 else if (t.cs() == "newcolumntype") {
771 string const name = p.getArg('{', '}');
774 string opts = p.getOpt();
776 istringstream is(string(opts, 1));
779 special_columns[name[0]] = nargs;
780 h_preamble << "\\newcolumntype{" << name << "}";
782 h_preamble << "[" << nargs << "]";
783 h_preamble << "{" << p.verbatim_item() << "}";
786 else if (t.cs() == "setcounter") {
787 string const name = p.getArg('{', '}');
788 string const content = p.getArg('{', '}');
789 if (name == "secnumdepth")
790 h_secnumdepth = content;
791 else if (name == "tocdepth")
792 h_tocdepth = content;
794 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
797 else if (t.cs() == "setlength") {
798 string const name = p.verbatim_item();
799 string const content = p.verbatim_item();
800 // the paragraphs are only not indented when \parindent is set to zero
801 if (name == "\\parindent" && content != "") {
802 if (content[0] == '0')
803 h_paragraph_separation = "skip";
804 } else if (name == "\\parskip") {
805 if (content == "\\smallskipamount")
806 h_defskip = "smallskip";
807 else if (content == "\\medskipamount")
808 h_defskip = "medskip";
809 else if (content == "\\bigskipamount")
810 h_defskip = "bigskip";
814 h_preamble << "\\setlength{" << name << "}{" << content << "}";
817 else if (t.cs() == "onehalfspacing")
818 h_spacing = "onehalf";
820 else if (t.cs() == "doublespacing")
821 h_spacing = "double";
823 else if (t.cs() == "setstretch")
824 h_spacing = "other " + p.verbatim_item();
826 else if (t.cs() == "begin") {
827 string const name = p.getArg('{', '}');
828 if (name == "document")
830 h_preamble << "\\begin{" << name << "}";
833 else if (t.cs() == "geometry") {
834 h_use_geometry = "true";
835 vector<string> opts = split_options(p.getArg('{', '}'));
836 vector<string>::iterator it;
838 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
839 h_paperorientation = "landscape";
843 handle_opt(opts, known_paper_sizes, h_papersize);
844 delete_opt(opts, known_paper_sizes);
846 char const * const * margin = known_paper_margins;
848 for (; *margin; ++margin) {
850 // search for the "=" in e.g. "lmargin=2cm" to get the value
851 for(size_t i = 0; i != opts.size(); i++) {
852 if (opts.at(i).find(*margin) != string::npos) {
853 string::size_type pos = opts.at(i).find("=");
854 string value = opts.at(i).substr(pos + 1);
855 string name = known_coded_paper_margins[k];
856 h_margins += "\\" + name + " " + value + "\n";
862 else if (t.cs() == "jurabibsetup") {
863 vector<string> jurabibsetup =
864 split_options(p.getArg('{', '}'));
865 // add jurabibsetup to the jurabib package options
866 add_package("jurabib", jurabibsetup);
867 if (!jurabibsetup.empty()) {
868 h_preamble << "\\jurabibsetup{"
869 << join(jurabibsetup, ",") << '}';
873 else if (!t.cs().empty())
874 h_preamble << '\\' << t.cs();
876 // remove the whitespace
880 // remove the whitespace
883 // Force textclass if the user wanted it
884 if (!forceclass.empty())
885 h_textclass = forceclass;
886 if (noweb_mode && !prefixIs(h_textclass, "literate-"))
887 h_textclass.insert(0, "literate-");
888 FileName layoutfilename = libFileSearch("layouts", h_textclass, "layout");
889 if (layoutfilename.empty()) {
890 cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
893 tc.read(layoutfilename);
894 if (h_papersides.empty()) {
897 h_papersides = ss.str();
899 end_preamble(os, tc);