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", "breton", "british",
59 "bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish",
60 "dutch", "english", "esperanto", "estonian", "finnish", "francais", "french",
61 "frenchb", "frenchle", "frenchpro", "galician", "german", "germanb", "greek",
62 "hebrew", "icelandic", "irish", "italian", "lsorbian", "magyar", "naustrian",
63 "ngerman", "ngermanb", "norsk", "nynorsk", "polish", "portuges", "romanian",
64 "russian", "russianb", "scottish", "serbian", "slovak", "slovene", "spanish",
65 "swedish", "thai", "turkish", "ukraineb", "ukrainian", "usorbian", "welsh", 0};
67 //note this when updating to lyxformat 305:
68 //bahasai, indonesian, and indon = equal to bahasa
69 //malay, and meyalu = equal to bahasam
71 const char * const known_french_languages[] = {"french", "frenchb", "francais",
72 "frenchle", "frenchpro", 0};
73 const char * const known_german_languages[] = {"german", "germanb", 0};
74 const char * const known_ngerman_languages[] = {"ngerman", "ngermanb", 0};
75 const char * const known_russian_languages[] = {"russian", "russianb", 0};
76 const char * const known_ukrainian_languages[] = {"ukrainian", "ukraineb", 0};
78 char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
80 const char * const known_roman_fonts[] = { "ae", "bookman", "charter",
81 "cmr", "fourier", "lmodern", "mathpazo", "mathptmx", "newcent", 0};
83 const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss",
86 const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
87 "courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx",
90 const char * const known_paper_sizes[] = { "a3paper", "b3paper", "a4paper",
91 "b4paper", "a5paper", "b5paper", "executivepaper", "legalpaper",
94 const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
95 "executivepaper", "legalpaper", "letterpaper", 0};
97 const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
98 "bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
100 const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
101 "rightmargin", "bottommargin", "headheight", "headsep", "footskip",
104 const char * const known_lyx_commands[] = { "binom", "cedilla", "cyrtext",
105 "dacute", "dgrave", "docedilla", "doogonek", "dosubhat", "dosubring",
106 "dosubtilde", "greektext", "guillemotleft", "guillemotright", "guilsinglleft",
107 "guilsinglright", "LyX", "lyxadded", "lyxarrow", "lyxdeleted", "lyxdot",
108 "lyxgreyedout", "lyxline", "lyxmathsym", "LyXParagraphLeftIndent",
109 "lyxrightaddress", "makenomenclature", "mathcircumflex", "noun", "ogonek",
110 "printnomenclature", "quotedblbase", "quotesinglbase", "rcap", "subhat",
111 "subring", "subtilde", "tabularnewline", "textcyr", "textgreek", 0};
113 const char * const known_lyx_comments[] = {
114 "%% Binom macro for standard LaTeX users\n",
115 "%% For printing a cirumflex inside a formula\n",
116 "%% Because html converters don't know tabularnewline\n",
117 "%% The greyedout annotation environment\n",
118 "%% A simple dot to overcome graphicx limitations\n",
119 "%% Change tracking with ulem\n",
120 "% the following is useful when we have the old nomencl.sty package\n",
121 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.\n",
122 "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.\n",
126 ostringstream h_preamble;
127 string h_textclass = "article";
128 string h_options = string();
129 string h_language = "english";
130 string h_inputencoding = "auto";
131 string h_font_roman = "default";
132 string h_font_sans = "default";
133 string h_font_typewriter = "default";
134 string h_font_default_family = "default";
135 string h_font_sc = "false";
136 string h_font_osf = "false";
137 string h_font_sf_scale = "100";
138 string h_font_tt_scale = "100";
139 string h_graphics = "default";
140 string h_paperfontsize = "default";
141 string h_spacing = "single";
142 string h_papersize = "default";
143 string h_use_geometry = "false";
144 string h_use_amsmath = "1";
145 string h_use_esint = "1";
146 string h_cite_engine = "basic";
147 string h_use_bibtopic = "false";
148 string h_paperorientation = "portrait";
149 string h_secnumdepth = "3";
150 string h_tocdepth = "3";
151 string h_paragraph_separation = "indent";
152 string h_defskip = "medskip";
153 string h_quotes_language = "english";
154 string h_papercolumns = "1";
155 string h_papersides = string();
156 string h_paperpagestyle = "default";
157 string h_tracking_changes = "false";
158 string h_output_changes = "false";
159 string h_margins = "";
162 void handle_opt(vector<string> & opts, char const * const * what, string & target)
167 // the last language option is the document language (for babel and LyX)
168 // the last size option is the document font size
169 vector<string>::iterator it;
170 vector<string>::iterator position = opts.begin();
171 for (; *what; ++what) {
172 it = find(opts.begin(), opts.end(), *what);
173 if (it != opts.end()) {
174 documentclass_language = true;
175 if (it >= position) {
184 void delete_opt(vector<string> & opts, char const * const * what)
189 // remove found options from the list
190 // do this after handle_opt to avoid potential memory leaks and to be able
191 // to find in every case the last language option
192 vector<string>::iterator it;
193 for (; *what; ++what) {
194 it = find(opts.begin(), opts.end(), *what);
195 if (it != opts.end())
202 * Split a package options string (keyval format) into a vector.
204 * authorformat=smallcaps,
206 * titleformat=colonsep,
207 * bibformat={tabular,ibidem,numbered}
209 vector<string> split_options(string const & input)
211 vector<string> options;
215 Token const & t = p.get_token();
216 if (t.asInput() == ",") {
217 options.push_back(trim(option));
219 } else if (t.asInput() == "=") {
222 if (p.next_token().asInput() == "{")
223 option += '{' + p.getArg('{', '}') + '}';
224 } else if (t.cat() != catSpace)
225 option += t.asInput();
229 options.push_back(trim(option));
236 * Add package \p name with options \p options to used_packages.
237 * Remove options from \p options that we don't want to output.
239 void add_package(string const & name, vector<string> & options)
241 // every package inherits the global options
242 if (used_packages.find(name) == used_packages.end())
243 used_packages[name] = split_options(h_options);
245 vector<string> & v = used_packages[name];
246 v.insert(v.end(), options.begin(), options.end());
247 if (name == "jurabib") {
248 // Don't output the order argument (see the cite command
249 // handling code in text.cpp).
250 vector<string>::iterator end =
251 remove(options.begin(), options.end(), "natbiborder");
252 end = remove(options.begin(), end, "jurabiborder");
253 options.erase(end, options.end());
258 // Given is a string like "scaled=0.9", return 0.9 * 100
259 string const scale_as_percentage(string const & scale)
261 string::size_type pos = scale.find('=');
262 if (pos != string::npos) {
263 string value = scale.substr(pos + 1);
265 return convert<string>(100 * convert<double>(value));
267 // If the input string didn't match our expectations.
268 // return the default value "100"
273 void handle_package(Parser &p, string const & name, string const & opts)
275 vector<string> options = split_options(opts);
276 add_package(name, options);
280 if (is_known(name, known_roman_fonts)) {
285 if (name == "fourier") {
286 h_font_roman = "utopia";
287 // when font uses real small capitals
288 if (opts == "expert")
292 if (name == "mathpazo")
293 h_font_roman = "palatino";
295 if (name == "mathptmx")
296 h_font_roman = "times";
299 if (is_known(name, known_sans_fonts)) {
303 h_font_sf_scale = scale_as_percentage(scale);
308 if (is_known(name, known_typewriter_fonts)) {
309 h_font_typewriter = name;
312 h_font_tt_scale = scale_as_percentage(scale);
316 // font uses old-style figure
320 else if (name == "amsmath" || name == "amssymb")
323 else if (name == "esint")
326 else if (name == "babel" && !opts.empty()) {
327 // check if more than one option was used - used later for inputenc
328 // in case inputenc is parsed before babel, set the encoding to auto
329 if (options.begin() != options.end() - 1) {
330 one_language = false;
331 h_inputencoding = "auto";
333 // only set the document language when there was not already one set
334 // via the documentclass options
335 // babel takes the the last language given in the documentclass options
336 // as document language. If there is no such language option, the last
337 // option of its \usepackage call is used.
338 if (documentclass_language == false) {
339 handle_opt(options, known_languages, h_language);
340 delete_opt(options, known_languages);
341 if (is_known(h_language, known_french_languages))
342 h_language = "french";
343 else if (is_known(h_language, known_german_languages))
344 h_language = "german";
345 else if (is_known(h_language, known_ngerman_languages))
346 h_language = "ngerman";
347 else if (is_known(h_language, known_russian_languages))
348 h_language = "russian";
349 else if (is_known(h_language, known_ukrainian_languages))
350 h_language = "ukrainian";
351 h_quotes_language = h_language;
355 else if (name == "fontenc")
358 else if (name == "inputenc") {
359 // only set when there is not more than one inputenc
360 // option therefore check for the "," character also
361 // only set when there is not more then one babel
363 if (opts.find(",") == string::npos && one_language == true) {
365 //change ascii to auto to be in the unicode range, see
366 //http://bugzilla.lyx.org/show_bug.cgi?id=4719
367 h_inputencoding = "auto";
368 else if (!opts.empty())
369 h_inputencoding = opts;
371 if (!options.empty())
372 p.setEncoding(options.back());
376 else if (name == "makeidx")
379 else if (name == "prettyref")
382 else if (name == "varioref")
385 else if (name == "verbatim")
388 else if (name == "nomencl")
391 else if (name == "textcomp")
394 else if (name == "url")
397 else if (name == "color") {
398 // with the following command this package is only loaded when needed for
399 // undefined colors, since we only support the predefined colors
400 h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n";
403 else if (name == "graphicx")
406 else if (name == "setspace")
409 else if (name == "geometry")
410 ; // Ignore this, the geometry settings are made by the \geometry
411 // command. This command is handled below.
413 else if (is_known(name, known_languages)) {
414 if (is_known(name, known_french_languages))
415 h_language = "french";
416 else if (is_known(name, known_german_languages))
417 h_language = "german";
418 else if (is_known(name, known_ngerman_languages))
419 h_language = "ngerman";
420 else if (is_known(name, known_russian_languages))
421 h_language = "russian";
422 else if (is_known(name, known_ukrainian_languages))
423 h_language = "ukrainian";
426 h_quotes_language = h_language;
429 else if (name == "natbib") {
430 h_cite_engine = "natbib_authoryear";
431 vector<string>::iterator it =
432 find(options.begin(), options.end(), "authoryear");
433 if (it != options.end())
436 it = find(options.begin(), options.end(), "numbers");
437 if (it != options.end()) {
438 h_cite_engine = "natbib_numerical";
444 else if (name == "jurabib")
445 h_cite_engine = "jurabib";
447 else if (name == "babel")
452 h_preamble << "\\usepackage{" << name << "}";
454 h_preamble << "\\usepackage[" << opts << "]{"
460 // We need to do something with the options...
461 if (!options.empty())
462 cerr << "Ignoring options '" << join(options, ",")
463 << "' of package " << name << '.' << endl;
465 // remove the whitespace
471 void end_preamble(ostream & os, TextClass const & /*textclass*/)
473 os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
474 << "\\lyxformat 258\n"
475 << "\\begin_document\n"
476 << "\\begin_header\n"
477 << "\\textclass " << h_textclass << "\n";
478 if (!h_preamble.str().empty())
479 os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
480 if (!h_options.empty())
481 os << "\\options " << h_options << "\n";
482 os << "\\language " << h_language << "\n"
483 << "\\inputencoding " << h_inputencoding << "\n"
484 << "\\font_roman " << h_font_roman << "\n"
485 << "\\font_sans " << h_font_sans << "\n"
486 << "\\font_typewriter " << h_font_typewriter << "\n"
487 << "\\font_default_family " << h_font_default_family << "\n"
488 << "\\font_sc " << h_font_sc << "\n"
489 << "\\font_osf " << h_font_osf << "\n"
490 << "\\font_sf_scale " << h_font_sf_scale << "\n"
491 << "\\font_tt_scale " << h_font_tt_scale << "\n"
492 << "\\graphics " << h_graphics << "\n"
493 << "\\paperfontsize " << h_paperfontsize << "\n"
494 << "\\spacing " << h_spacing << "\n"
495 << "\\papersize " << h_papersize << "\n"
496 << "\\use_geometry " << h_use_geometry << "\n"
497 << "\\use_amsmath " << h_use_amsmath << "\n"
498 << "\\use_esint " << h_use_esint << "\n"
499 << "\\cite_engine " << h_cite_engine << "\n"
500 << "\\use_bibtopic " << h_use_bibtopic << "\n"
501 << "\\paperorientation " << h_paperorientation << "\n"
503 << "\\secnumdepth " << h_secnumdepth << "\n"
504 << "\\tocdepth " << h_tocdepth << "\n"
505 << "\\paragraph_separation " << h_paragraph_separation << "\n"
506 << "\\defskip " << h_defskip << "\n"
507 << "\\quotes_language " << h_quotes_language << "\n"
508 << "\\papercolumns " << h_papercolumns << "\n"
509 << "\\papersides " << h_papersides << "\n"
510 << "\\paperpagestyle " << h_paperpagestyle << "\n"
511 << "\\tracking_changes " << h_tracking_changes << "\n"
512 << "\\output_changes " << h_output_changes << "\n"
513 << "\\end_header\n\n"
515 // clear preamble for subdocuments
519 } // anonymous namespace
521 void parse_preamble(Parser & p, ostream & os,
522 string const & forceclass, TeX2LyXDocClass & tc)
524 // initialize fixed types
525 special_columns['D'] = 3;
526 bool is_full_document = false;
527 bool is_lyx_file = false;
528 bool lyx_specific_preamble = false;
530 // determine whether this is a full document or a fragment for inclusion
532 Token const & t = p.get_token();
534 if (t.cat() == catEscape && t.cs() == "documentclass") {
535 is_full_document = true;
541 while (is_full_document && p.good()) {
542 Token const & t = p.get_token();
545 cerr << "t: " << t << "\n";
551 if ((t.cat() == catLetter ||
552 t.cat() == catSuper ||
554 t.cat() == catOther ||
555 t.cat() == catMath ||
556 t.cat() == catActive ||
557 t.cat() == catBegin ||
559 t.cat() == catAlign ||
560 t.cat() == catParameter))
561 h_preamble << t.character();
563 else if (t.cat() == catSpace || t.cat() == catNewline)
564 h_preamble << t.asInput();
566 else if (t.cat() == catComment) {
567 // regex to parse comments
568 static regex const islyxfile("%% LyX .* created this file");
569 static regex const usercommands("User specified LaTeX commands");
571 string const comment = t.asInput();
573 // magically switch encoding default if it looks like XeLaTeX
574 static string const magicXeLaTeX =
575 "% This document must be compiled with XeLaTeX ";
576 if (comment.size() > magicXeLaTeX.size()
577 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
578 && h_inputencoding == "auto") {
579 cerr << "XeLaTeX comment found, switching to UTF8\n";
580 h_inputencoding = "utf8";
584 if (regex_search(comment, sub, islyxfile))
586 // don't output LyX specific comments
587 if (!is_known(comment, known_lyx_comments))
588 h_preamble << t.asInput();
591 else if (t.cs() == "pagestyle")
592 h_paperpagestyle = p.verbatim_item();
594 else if (t.cs() == "makeatletter") {
595 // LyX takes care of this
596 p.setCatCode('@', catLetter);
599 else if (t.cs() == "makeatother") {
600 // LyX takes care of this
601 p.setCatCode('@', catOther);
604 else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
605 || t.cs() == "providecommand"
606 || t.cs() == "DeclareRobustCommand"
607 || t.cs() == "ProvideTextCommandDefault"
608 || t.cs() == "DeclareMathAccent") {
610 if (p.next_token().character() == '*') {
614 string const name = p.verbatim_item();
615 string const opt1 = p.getOpt();
616 string const opt2 = p.getFullOpt();
617 string const body = p.verbatim_item();
619 if (name == "\\rmdefault")
620 if (is_known(body, known_roman_fonts))
622 if (name == "\\sfdefault")
623 if (is_known(body, known_sans_fonts))
625 if (name == "\\ttdefault")
626 if (is_known(body, known_typewriter_fonts))
627 h_font_typewriter = body;
628 if (name == "\\familydefault") {
629 string family = body;
630 // remove leading "\"
631 h_font_default_family = family.erase(0,1);
633 // LyX specific commands that will automatically be set by LyX
634 string lyx_command = name;
635 // remove the leading "\"
636 lyx_command.erase(0,1);
637 lyx_specific_preamble = false;
638 // allow redefinitions of LyX specific commands
639 if (is_known(lyx_command, known_lyx_commands)
640 && (t.cs() != "renewcommand"))
641 lyx_specific_preamble = true;
642 // only non-lyxspecific stuff
643 if (!lyx_specific_preamble) {
645 ss << '\\' << t.cs();
648 ss << '{' << name << '}' << opt1 << opt2
649 << '{' << body << "}";
650 h_preamble << ss.str();
652 // Add the command to the known commands
653 add_known_command(name, opt1, !opt2.empty());
655 ostream & out = in_preamble ? h_preamble : os;
656 out << "\\" << t.cs() << "{" << name << "}"
657 << opts << "{" << body << "}";
662 else if (t.cs() == "documentclass") {
663 vector<string>::iterator it;
664 vector<string> opts = split_options(p.getArg('[', ']'));
665 handle_opt(opts, known_fontsizes, h_paperfontsize);
666 delete_opt(opts, known_fontsizes);
667 // delete "pt" at the end
668 string::size_type i = h_paperfontsize.find("pt");
669 if (i != string::npos)
670 h_paperfontsize.erase(i);
671 // to avoid that the babel options overwrite the documentclass options
672 documentclass_language = false;
673 handle_opt(opts, known_languages, h_language);
674 delete_opt(opts, known_languages);
675 if (is_known(h_language, known_french_languages))
676 h_language = "french";
677 else if (is_known(h_language, known_german_languages))
678 h_language = "german";
679 else if (is_known(h_language, known_ngerman_languages))
680 h_language = "ngerman";
681 else if (is_known(h_language, known_russian_languages))
682 h_language = "russian";
683 else if (is_known(h_language, known_ukrainian_languages))
684 h_language = "ukrainian";
685 h_quotes_language = h_language;
687 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
688 h_paperorientation = "landscape";
692 if ((it = find(opts.begin(), opts.end(), "oneside"))
697 if ((it = find(opts.begin(), opts.end(), "twoside"))
703 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
705 h_papercolumns = "1";
708 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
710 h_papercolumns = "2";
714 // some size options are know to any document classes, other sizes
715 // are handled by the \geometry command of the geometry package
716 handle_opt(opts, known_class_paper_sizes, h_papersize);
717 delete_opt(opts, known_class_paper_sizes);
718 // the remaining options
719 h_options = join(opts, ",");
720 h_textclass = p.getArg('{', '}');
723 else if (t.cs() == "usepackage") {
724 string const options = p.getArg('[', ']');
725 string const name = p.getArg('{', '}');
726 vector<string> vecnames;
727 split(name, vecnames, ',');
728 vector<string>::const_iterator it = vecnames.begin();
729 vector<string>::const_iterator end = vecnames.end();
730 for (; it != end; ++it)
731 handle_package(p, trim(*it), options);
734 else if (t.cs() == "inputencoding") {
735 string const encoding = p.getArg('{','}');
736 h_inputencoding = encoding;
737 p.setEncoding(encoding);
740 else if (t.cs() == "newenvironment") {
741 string const name = p.getArg('{', '}');
743 // only non LyX specific stuff is output
744 ss << "\\newenvironment{" << name << "}";
747 ss << '{' << p.verbatim_item() << '}';
748 ss << '{' << p.verbatim_item() << '}';
749 if (!is_known(name, known_lyx_commands))
750 h_preamble << ss.str();
753 else if (t.cs() == "def") {
754 string name = p.get_token().cs();
755 while (p.next_token().cat() != catBegin)
756 name += p.get_token().asString();
757 if (!is_known(name, known_lyx_commands))
758 h_preamble << "\\def\\" << name << '{'
759 << p.verbatim_item() << "}";
762 else if (t.cs() == "newcolumntype") {
763 string const name = p.getArg('{', '}');
766 string opts = p.getOpt();
768 istringstream is(string(opts, 1));
771 special_columns[name[0]] = nargs;
772 h_preamble << "\\newcolumntype{" << name << "}";
774 h_preamble << "[" << nargs << "]";
775 h_preamble << "{" << p.verbatim_item() << "}";
778 else if (t.cs() == "setcounter") {
779 string const name = p.getArg('{', '}');
780 string const content = p.getArg('{', '}');
781 if (name == "secnumdepth")
782 h_secnumdepth = content;
783 else if (name == "tocdepth")
784 h_tocdepth = content;
786 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
789 else if (t.cs() == "setlength") {
790 string const name = p.verbatim_item();
791 string const content = p.verbatim_item();
792 // the paragraphs are only not indented when \parindent is set to zero
793 if (name == "\\parindent" && content != "") {
794 if (content[0] == '0')
795 h_paragraph_separation = "skip";
796 } else if (name == "\\parskip") {
797 if (content == "\\smallskipamount")
798 h_defskip = "smallskip";
799 else if (content == "\\medskipamount")
800 h_defskip = "medskip";
801 else if (content == "\\bigskipamount")
802 h_defskip = "bigskip";
806 h_preamble << "\\setlength{" << name << "}{" << content << "}";
809 else if (t.cs() == "onehalfspacing")
810 h_spacing = "onehalf";
812 else if (t.cs() == "doublespacing")
813 h_spacing = "double";
815 else if (t.cs() == "setstretch")
816 h_spacing = "other " + p.verbatim_item();
818 else if (t.cs() == "begin") {
819 string const name = p.getArg('{', '}');
820 if (name == "document")
822 h_preamble << "\\begin{" << name << "}";
825 else if (t.cs() == "geometry") {
826 h_use_geometry = "true";
827 vector<string> opts = split_options(p.getArg('{', '}'));
828 vector<string>::iterator it;
830 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
831 h_paperorientation = "landscape";
835 handle_opt(opts, known_paper_sizes, h_papersize);
836 delete_opt(opts, known_paper_sizes);
838 char const * const * margin = known_paper_margins;
840 for (; *margin; ++margin) {
842 // search for the "=" in e.g. "lmargin=2cm" to get the value
843 for(size_t i = 0; i != opts.size(); i++) {
844 if (opts.at(i).find(*margin) != string::npos) {
845 string::size_type pos = opts.at(i).find("=");
846 string value = opts.at(i).substr(pos + 1);
847 string name = known_coded_paper_margins[k];
848 h_margins += "\\" + name + " " + value + "\n";
854 else if (t.cs() == "jurabibsetup") {
855 vector<string> jurabibsetup =
856 split_options(p.getArg('{', '}'));
857 // add jurabibsetup to the jurabib package options
858 add_package("jurabib", jurabibsetup);
859 if (!jurabibsetup.empty()) {
860 h_preamble << "\\jurabibsetup{"
861 << join(jurabibsetup, ",") << '}';
865 else if (!t.cs().empty())
866 h_preamble << '\\' << t.cs();
868 // remove the whitespace
872 // remove the whitespace
875 // Force textclass if the user wanted it
876 if (!forceclass.empty())
877 h_textclass = forceclass;
878 if (noweb_mode && !prefixIs(h_textclass, "literate-"))
879 h_textclass.insert(0, "literate-");
880 FileName layoutfilename = libFileSearch("layouts", h_textclass, "layout");
881 if (layoutfilename.empty()) {
882 cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
885 tc.read(layoutfilename);
886 if (h_papersides.empty()) {
889 h_papersides = ss.str();
891 end_preamble(os, tc);