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", "lyxaddress", "lyxarrow", "lyxcode",
111 "lyxdeleted", "lyxdot", "lyxgreyedout", "lyxline", "lyxlist", "lyxmathsym",
112 "LyXParagraphLeftIndent", "lyxrightaddress", "makenomenclature",
113 "mathcircumflex", "noun", "ogonek", "printnomenclature", "quotedblbase",
114 "quotesinglbase", "rcap", "subhat", "subring", "subtilde", "tabularnewline",
115 "textcyr", "textgreek", 0};
117 const char * const known_lyx_comments[] = {
118 "%% Binom macro for standard LaTeX users\n",
119 "%% For printing a cirumflex inside a formula\n",
120 "%% Because html converters don't know tabularnewline\n",
121 "%% The greyedout annotation environment\n",
122 "%% A simple dot to overcome graphicx limitations\n",
123 "%% Change tracking with ulem\n",
124 "% the following is useful when we have the old nomencl.sty package\n",
125 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.\n",
126 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.\n",
127 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.\n",
131 ostringstream h_preamble;
132 string h_textclass = "article";
133 string h_options = string();
134 string h_language = "english";
135 string h_inputencoding = "auto";
136 string h_font_roman = "default";
137 string h_font_sans = "default";
138 string h_font_typewriter = "default";
139 string h_font_default_family = "default";
140 string h_font_sc = "false";
141 string h_font_osf = "false";
142 string h_font_sf_scale = "100";
143 string h_font_tt_scale = "100";
144 string h_graphics = "default";
145 string h_paperfontsize = "default";
146 string h_spacing = "single";
147 string h_papersize = "default";
148 string h_use_geometry = "false";
149 string h_use_amsmath = "1";
150 string h_use_esint = "1";
151 string h_cite_engine = "basic";
152 string h_use_bibtopic = "false";
153 string h_paperorientation = "portrait";
154 string h_secnumdepth = "3";
155 string h_tocdepth = "3";
156 string h_paragraph_separation = "indent";
157 string h_defskip = "medskip";
158 string h_quotes_language = "english";
159 string h_papercolumns = "1";
160 string h_papersides = string();
161 string h_paperpagestyle = "default";
162 string h_tracking_changes = "false";
163 string h_output_changes = "false";
164 string h_margins = "";
167 void handle_opt(vector<string> & opts, char const * const * what, string & target)
172 // the last language option is the document language (for babel and LyX)
173 // the last size option is the document font size
174 vector<string>::iterator it;
175 vector<string>::iterator position = opts.begin();
176 for (; *what; ++what) {
177 it = find(opts.begin(), opts.end(), *what);
178 if (it != opts.end()) {
179 documentclass_language = true;
180 if (it >= position) {
189 void delete_opt(vector<string> & opts, char const * const * what)
194 // remove found options from the list
195 // do this after handle_opt to avoid potential memory leaks and to be able
196 // to find in every case the last language option
197 vector<string>::iterator it;
198 for (; *what; ++what) {
199 it = find(opts.begin(), opts.end(), *what);
200 if (it != opts.end())
207 * Split a package options string (keyval format) into a vector.
209 * authorformat=smallcaps,
211 * titleformat=colonsep,
212 * bibformat={tabular,ibidem,numbered}
214 vector<string> split_options(string const & input)
216 vector<string> options;
220 Token const & t = p.get_token();
221 if (t.asInput() == ",") {
222 options.push_back(trim(option));
224 } else if (t.asInput() == "=") {
227 if (p.next_token().asInput() == "{")
228 option += '{' + p.getArg('{', '}') + '}';
229 } else if (t.cat() != catSpace)
230 option += t.asInput();
234 options.push_back(trim(option));
241 * Add package \p name with options \p options to used_packages.
242 * Remove options from \p options that we don't want to output.
244 void add_package(string const & name, vector<string> & options)
246 // every package inherits the global options
247 if (used_packages.find(name) == used_packages.end())
248 used_packages[name] = split_options(h_options);
250 vector<string> & v = used_packages[name];
251 v.insert(v.end(), options.begin(), options.end());
252 if (name == "jurabib") {
253 // Don't output the order argument (see the cite command
254 // handling code in text.cpp).
255 vector<string>::iterator end =
256 remove(options.begin(), options.end(), "natbiborder");
257 end = remove(options.begin(), end, "jurabiborder");
258 options.erase(end, options.end());
263 // Given is a string like "scaled=0.9", return 0.9 * 100
264 string const scale_as_percentage(string const & scale)
266 string::size_type pos = scale.find('=');
267 if (pos != string::npos) {
268 string value = scale.substr(pos + 1);
270 return convert<string>(100 * convert<double>(value));
272 // If the input string didn't match our expectations.
273 // return the default value "100"
278 void handle_package(Parser &p, string const & name, string const & opts)
280 vector<string> options = split_options(opts);
281 add_package(name, options);
285 if (is_known(name, known_roman_fonts)) {
290 if (name == "fourier") {
291 h_font_roman = "utopia";
292 // when font uses real small capitals
293 if (opts == "expert")
297 if (name == "mathpazo")
298 h_font_roman = "palatino";
300 if (name == "mathptmx")
301 h_font_roman = "times";
304 if (is_known(name, known_sans_fonts)) {
308 h_font_sf_scale = scale_as_percentage(scale);
313 if (is_known(name, known_typewriter_fonts)) {
314 h_font_typewriter = name;
317 h_font_tt_scale = scale_as_percentage(scale);
321 // font uses old-style figure
325 else if (name == "amsmath" || name == "amssymb")
328 else if (name == "amstext")
331 else if (name == "esint")
334 else if (name == "babel" && !opts.empty()) {
335 // check if more than one option was used - used later for inputenc
336 // in case inputenc is parsed before babel, set the encoding to auto
337 if (options.begin() != options.end() - 1) {
338 one_language = false;
339 h_inputencoding = "auto";
341 // only set the document language when there was not already one set
342 // via the documentclass options
343 // babel takes the the last language given in the documentclass options
344 // as document language. If there is no such language option, the last
345 // option of its \usepackage call is used.
346 if (documentclass_language == false) {
347 handle_opt(options, known_languages, h_language);
348 delete_opt(options, known_languages);
349 if (is_known(h_language, known_brazilian_languages))
350 h_language = "brazilian";
351 else if (is_known(h_language, known_french_languages))
352 h_language = "french";
353 else if (is_known(h_language, known_german_languages))
354 h_language = "german";
355 else if (is_known(h_language, known_ngerman_languages))
356 h_language = "ngerman";
357 else if (is_known(h_language, known_portuguese_languages))
358 h_language = "portuguese";
359 else if (is_known(h_language, known_russian_languages))
360 h_language = "russian";
361 else if (is_known(h_language, known_ukrainian_languages))
362 h_language = "ukrainian";
363 h_quotes_language = h_language;
367 else if (name == "fontenc")
370 else if (name == "inputenc") {
371 // only set when there is not more than one inputenc
372 // option therefore check for the "," character also
373 // only set when there is not more then one babel
375 if (opts.find(",") == string::npos && one_language == true) {
377 //change ascii to auto to be in the unicode range, see
378 //http://bugzilla.lyx.org/show_bug.cgi?id=4719
379 h_inputencoding = "auto";
380 else if (!opts.empty())
381 h_inputencoding = opts;
383 if (!options.empty())
384 p.setEncoding(options.back());
388 else if (name == "makeidx")
391 else if (name == "prettyref")
394 else if (name == "varioref")
397 else if (name == "verbatim")
400 else if (name == "nomencl")
403 else if (name == "textcomp")
406 else if (name == "url")
409 else if (name == "color") {
410 // with the following command this package is only loaded when needed for
411 // undefined colors, since we only support the predefined colors
412 h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n";
415 else if (name == "graphicx")
418 else if (name == "setspace")
421 else if (name == "geometry")
422 ; // Ignore this, the geometry settings are made by the \geometry
423 // command. This command is handled below.
425 else if (is_known(name, known_languages)) {
426 if (is_known(h_language, known_brazilian_languages))
427 h_language = "brazilian";
428 else if (is_known(name, known_french_languages))
429 h_language = "french";
430 else if (is_known(name, known_german_languages))
431 h_language = "german";
432 else if (is_known(name, known_ngerman_languages))
433 h_language = "ngerman";
434 else if (is_known(h_language, known_portuguese_languages))
435 h_language = "portuguese";
436 else if (is_known(name, known_russian_languages))
437 h_language = "russian";
438 else if (is_known(name, known_ukrainian_languages))
439 h_language = "ukrainian";
442 h_quotes_language = h_language;
445 else if (name == "natbib") {
446 h_cite_engine = "natbib_authoryear";
447 vector<string>::iterator it =
448 find(options.begin(), options.end(), "authoryear");
449 if (it != options.end())
452 it = find(options.begin(), options.end(), "numbers");
453 if (it != options.end()) {
454 h_cite_engine = "natbib_numerical";
460 else if (name == "jurabib")
461 h_cite_engine = "jurabib";
463 else if (name == "babel")
468 h_preamble << "\\usepackage{" << name << "}";
470 h_preamble << "\\usepackage[" << opts << "]{"
476 // We need to do something with the options...
477 if (!options.empty())
478 cerr << "Ignoring options '" << join(options, ",")
479 << "' of package " << name << '.' << endl;
481 // remove the whitespace
487 void end_preamble(ostream & os, TextClass const & /*textclass*/)
489 os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
490 << "\\lyxformat 264\n"
491 << "\\begin_document\n"
492 << "\\begin_header\n"
493 << "\\textclass " << h_textclass << "\n";
494 if (!h_preamble.str().empty())
495 os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
496 if (!h_options.empty())
497 os << "\\options " << h_options << "\n";
498 os << "\\language " << h_language << "\n"
499 << "\\inputencoding " << h_inputencoding << "\n"
500 << "\\font_roman " << h_font_roman << "\n"
501 << "\\font_sans " << h_font_sans << "\n"
502 << "\\font_typewriter " << h_font_typewriter << "\n"
503 << "\\font_default_family " << h_font_default_family << "\n"
504 << "\\font_sc " << h_font_sc << "\n"
505 << "\\font_osf " << h_font_osf << "\n"
506 << "\\font_sf_scale " << h_font_sf_scale << "\n"
507 << "\\font_tt_scale " << h_font_tt_scale << "\n"
508 << "\\graphics " << h_graphics << "\n"
509 << "\\paperfontsize " << h_paperfontsize << "\n"
510 << "\\spacing " << h_spacing << "\n"
511 << "\\papersize " << h_papersize << "\n"
512 << "\\use_geometry " << h_use_geometry << "\n"
513 << "\\use_amsmath " << h_use_amsmath << "\n"
514 << "\\use_esint " << h_use_esint << "\n"
515 << "\\cite_engine " << h_cite_engine << "\n"
516 << "\\use_bibtopic " << h_use_bibtopic << "\n"
517 << "\\paperorientation " << h_paperorientation << "\n"
519 << "\\secnumdepth " << h_secnumdepth << "\n"
520 << "\\tocdepth " << h_tocdepth << "\n"
521 << "\\paragraph_separation " << h_paragraph_separation << "\n"
522 << "\\defskip " << h_defskip << "\n"
523 << "\\quotes_language " << h_quotes_language << "\n"
524 << "\\papercolumns " << h_papercolumns << "\n"
525 << "\\papersides " << h_papersides << "\n"
526 << "\\paperpagestyle " << h_paperpagestyle << "\n"
527 << "\\tracking_changes " << h_tracking_changes << "\n"
528 << "\\output_changes " << h_output_changes << "\n"
529 << "\\end_header\n\n"
531 // clear preamble for subdocuments
535 } // anonymous namespace
537 void parse_preamble(Parser & p, ostream & os,
538 string const & forceclass, TeX2LyXDocClass & tc)
540 // initialize fixed types
541 special_columns['D'] = 3;
542 bool is_full_document = false;
543 bool lyx_specific_preamble = false;
545 // determine whether this is a full document or a fragment for inclusion
547 Token const & t = p.get_token();
549 if (t.cat() == catEscape && t.cs() == "documentclass") {
550 is_full_document = true;
556 while (is_full_document && p.good()) {
557 Token const & t = p.get_token();
560 cerr << "t: " << t << "\n";
566 if ((t.cat() == catLetter ||
567 t.cat() == catSuper ||
569 t.cat() == catOther ||
570 t.cat() == catMath ||
571 t.cat() == catActive ||
572 t.cat() == catBegin ||
574 t.cat() == catAlign ||
575 t.cat() == catParameter))
576 h_preamble << t.character();
578 else if (t.cat() == catSpace || t.cat() == catNewline)
579 h_preamble << t.asInput();
581 else if (t.cat() == catComment) {
582 // regex to parse comments (currently not used)
583 //static regex const islyxfile("%% LyX .* created this file");
584 string const comment = t.asInput();
585 // magically switch encoding default if it looks like XeLaTeX
586 static string const magicXeLaTeX =
587 "% This document must be compiled with XeLaTeX ";
588 if (comment.size() > magicXeLaTeX.size()
589 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
590 && h_inputencoding == "auto") {
591 cerr << "XeLaTeX comment found, switching to UTF8\n";
592 h_inputencoding = "utf8";
595 // don't output LyX specific comments
596 if (!is_known(comment, known_lyx_comments))
597 h_preamble << t.asInput();
600 else if (t.cs() == "pagestyle")
601 h_paperpagestyle = p.verbatim_item();
603 else if (t.cs() == "makeatletter") {
604 // LyX takes care of this
605 p.setCatCode('@', catLetter);
608 else if (t.cs() == "makeatother") {
609 // LyX takes care of this
610 p.setCatCode('@', catOther);
613 else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
614 || t.cs() == "providecommand"
615 || t.cs() == "DeclareRobustCommand"
616 || t.cs() == "ProvideTextCommandDefault"
617 || t.cs() == "DeclareMathAccent") {
619 if (p.next_token().character() == '*') {
623 string const name = p.verbatim_item();
624 string const opt1 = p.getOpt();
625 string const opt2 = p.getFullOpt();
626 string const body = p.verbatim_item();
628 if (name == "\\rmdefault")
629 if (is_known(body, known_roman_fonts))
631 if (name == "\\sfdefault")
632 if (is_known(body, known_sans_fonts))
634 if (name == "\\ttdefault")
635 if (is_known(body, known_typewriter_fonts))
636 h_font_typewriter = body;
637 if (name == "\\familydefault") {
638 string family = body;
639 // remove leading "\"
640 h_font_default_family = family.erase(0,1);
642 // LyX specific commands that will automatically be set by LyX
643 string lyx_command = name;
644 // remove the leading "\"
645 lyx_command.erase(0,1);
646 lyx_specific_preamble = false;
647 // allow redefinitions of LyX specific commands
648 if (is_known(lyx_command, known_lyx_commands)
649 && (t.cs() != "renewcommand"))
650 lyx_specific_preamble = true;
651 // only non-lyxspecific stuff
652 if (!lyx_specific_preamble) {
654 ss << '\\' << t.cs();
657 ss << '{' << name << '}' << opt1 << opt2
658 << '{' << body << "}";
659 h_preamble << ss.str();
661 // Add the command to the known commands
662 add_known_command(name, opt1, !opt2.empty());
664 ostream & out = in_preamble ? h_preamble : os;
665 out << "\\" << t.cs() << "{" << name << "}"
666 << opts << "{" << body << "}";
671 else if (t.cs() == "documentclass") {
672 vector<string>::iterator it;
673 vector<string> opts = split_options(p.getArg('[', ']'));
674 handle_opt(opts, known_fontsizes, h_paperfontsize);
675 delete_opt(opts, known_fontsizes);
676 // delete "pt" at the end
677 string::size_type i = h_paperfontsize.find("pt");
678 if (i != string::npos)
679 h_paperfontsize.erase(i);
680 // to avoid that the babel options overwrite the documentclass options
681 documentclass_language = false;
682 handle_opt(opts, known_languages, h_language);
683 delete_opt(opts, known_languages);
684 if (is_known(h_language, known_brazilian_languages))
685 h_language = "brazilian";
686 else if (is_known(h_language, known_french_languages))
687 h_language = "french";
688 else if (is_known(h_language, known_german_languages))
689 h_language = "german";
690 else if (is_known(h_language, known_ngerman_languages))
691 h_language = "ngerman";
692 else if (is_known(h_language, known_portuguese_languages))
693 h_language = "portuguese";
694 else if (is_known(h_language, known_russian_languages))
695 h_language = "russian";
696 else if (is_known(h_language, known_ukrainian_languages))
697 h_language = "ukrainian";
698 h_quotes_language = h_language;
700 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
701 h_paperorientation = "landscape";
705 if ((it = find(opts.begin(), opts.end(), "oneside"))
710 if ((it = find(opts.begin(), opts.end(), "twoside"))
716 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
718 h_papercolumns = "1";
721 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
723 h_papercolumns = "2";
727 // some size options are know to any document classes, other sizes
728 // are handled by the \geometry command of the geometry package
729 handle_opt(opts, known_class_paper_sizes, h_papersize);
730 delete_opt(opts, known_class_paper_sizes);
731 // the remaining options
732 h_options = join(opts, ",");
733 h_textclass = p.getArg('{', '}');
736 else if (t.cs() == "usepackage") {
737 string const options = p.getArg('[', ']');
738 string const name = p.getArg('{', '}');
739 vector<string> vecnames;
740 split(name, vecnames, ',');
741 vector<string>::const_iterator it = vecnames.begin();
742 vector<string>::const_iterator end = vecnames.end();
743 for (; it != end; ++it)
744 handle_package(p, trim(*it), options);
747 else if (t.cs() == "inputencoding") {
748 string const encoding = p.getArg('{','}');
749 h_inputencoding = encoding;
750 p.setEncoding(encoding);
753 else if (t.cs() == "newenvironment") {
754 string const name = p.getArg('{', '}');
756 // only non LyX specific stuff is output
757 ss << "\\newenvironment{" << name << "}";
760 ss << '{' << p.verbatim_item() << '}';
761 ss << '{' << p.verbatim_item() << '}';
762 if (!is_known(name, known_lyx_commands))
763 h_preamble << ss.str();
766 else if (t.cs() == "def") {
767 string name = p.get_token().cs();
768 while (p.next_token().cat() != catBegin)
769 name += p.get_token().asString();
770 if (!is_known(name, known_lyx_commands))
771 h_preamble << "\\def\\" << name << '{'
772 << p.verbatim_item() << "}";
775 else if (t.cs() == "newcolumntype") {
776 string const name = p.getArg('{', '}');
779 string opts = p.getOpt();
781 istringstream is(string(opts, 1));
784 special_columns[name[0]] = nargs;
785 h_preamble << "\\newcolumntype{" << name << "}";
787 h_preamble << "[" << nargs << "]";
788 h_preamble << "{" << p.verbatim_item() << "}";
791 else if (t.cs() == "setcounter") {
792 string const name = p.getArg('{', '}');
793 string const content = p.getArg('{', '}');
794 if (name == "secnumdepth")
795 h_secnumdepth = content;
796 else if (name == "tocdepth")
797 h_tocdepth = content;
799 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
802 else if (t.cs() == "setlength") {
803 string const name = p.verbatim_item();
804 string const content = p.verbatim_item();
805 // the paragraphs are only not indented when \parindent is set to zero
806 if (name == "\\parindent" && content != "") {
807 if (content[0] == '0')
808 h_paragraph_separation = "skip";
809 } else if (name == "\\parskip") {
810 if (content == "\\smallskipamount")
811 h_defskip = "smallskip";
812 else if (content == "\\medskipamount")
813 h_defskip = "medskip";
814 else if (content == "\\bigskipamount")
815 h_defskip = "bigskip";
819 h_preamble << "\\setlength{" << name << "}{" << content << "}";
822 else if (t.cs() == "onehalfspacing")
823 h_spacing = "onehalf";
825 else if (t.cs() == "doublespacing")
826 h_spacing = "double";
828 else if (t.cs() == "setstretch")
829 h_spacing = "other " + p.verbatim_item();
831 else if (t.cs() == "begin") {
832 string const name = p.getArg('{', '}');
833 if (name == "document")
835 h_preamble << "\\begin{" << name << "}";
838 else if (t.cs() == "geometry") {
839 h_use_geometry = "true";
840 vector<string> opts = split_options(p.getArg('{', '}'));
841 vector<string>::iterator it;
843 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
844 h_paperorientation = "landscape";
848 handle_opt(opts, known_paper_sizes, h_papersize);
849 delete_opt(opts, known_paper_sizes);
851 char const * const * margin = known_paper_margins;
853 for (; *margin; ++margin) {
855 // search for the "=" in e.g. "lmargin=2cm" to get the value
856 for(size_t i = 0; i != opts.size(); i++) {
857 if (opts.at(i).find(*margin) != string::npos) {
858 string::size_type pos = opts.at(i).find("=");
859 string value = opts.at(i).substr(pos + 1);
860 string name = known_coded_paper_margins[k];
861 h_margins += "\\" + name + " " + value + "\n";
867 else if (t.cs() == "jurabibsetup") {
868 vector<string> jurabibsetup =
869 split_options(p.getArg('{', '}'));
870 // add jurabibsetup to the jurabib package options
871 add_package("jurabib", jurabibsetup);
872 if (!jurabibsetup.empty()) {
873 h_preamble << "\\jurabibsetup{"
874 << join(jurabibsetup, ",") << '}';
878 else if (!t.cs().empty())
879 h_preamble << '\\' << t.cs();
881 // remove the whitespace
885 // remove the whitespace
888 // Force textclass if the user wanted it
889 if (!forceclass.empty())
890 h_textclass = forceclass;
891 if (noweb_mode && !prefixIs(h_textclass, "literate-"))
892 h_textclass.insert(0, "literate-");
893 FileName layoutfilename = libFileSearch("layouts", h_textclass, "layout");
894 if (layoutfilename.empty()) {
895 cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
898 tc.read(layoutfilename);
899 if (h_papersides.empty()) {
902 h_papersides = ss.str();
904 end_preamble(os, tc);