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",
123 "%% LyX 2.0.0svn created this file. For more info, see http://www.lyx.org/.\n",
127 ostringstream h_preamble;
128 string h_textclass = "article";
129 string h_options = string();
130 string h_language = "english";
131 string h_inputencoding = "auto";
132 string h_font_roman = "default";
133 string h_font_sans = "default";
134 string h_font_typewriter = "default";
135 string h_font_default_family = "default";
136 string h_font_sc = "false";
137 string h_font_osf = "false";
138 string h_font_sf_scale = "100";
139 string h_font_tt_scale = "100";
140 string h_graphics = "default";
141 string h_paperfontsize = "default";
142 string h_spacing = "single";
143 string h_papersize = "default";
144 string h_use_geometry = "false";
145 string h_use_amsmath = "1";
146 string h_use_esint = "1";
147 string h_cite_engine = "basic";
148 string h_use_bibtopic = "false";
149 string h_paperorientation = "portrait";
150 string h_secnumdepth = "3";
151 string h_tocdepth = "3";
152 string h_paragraph_separation = "indent";
153 string h_defskip = "medskip";
154 string h_quotes_language = "english";
155 string h_papercolumns = "1";
156 string h_papersides = string();
157 string h_paperpagestyle = "default";
158 string h_tracking_changes = "false";
159 string h_output_changes = "false";
160 string h_margins = "";
163 void handle_opt(vector<string> & opts, char const * const * what, string & target)
168 // the last language option is the document language (for babel and LyX)
169 // the last size option is the document font size
170 vector<string>::iterator it;
171 vector<string>::iterator position = opts.begin();
172 for (; *what; ++what) {
173 it = find(opts.begin(), opts.end(), *what);
174 if (it != opts.end()) {
175 documentclass_language = true;
176 if (it >= position) {
185 void delete_opt(vector<string> & opts, char const * const * what)
190 // remove found options from the list
191 // do this after handle_opt to avoid potential memory leaks and to be able
192 // to find in every case the last language option
193 vector<string>::iterator it;
194 for (; *what; ++what) {
195 it = find(opts.begin(), opts.end(), *what);
196 if (it != opts.end())
203 * Split a package options string (keyval format) into a vector.
205 * authorformat=smallcaps,
207 * titleformat=colonsep,
208 * bibformat={tabular,ibidem,numbered}
210 vector<string> split_options(string const & input)
212 vector<string> options;
216 Token const & t = p.get_token();
217 if (t.asInput() == ",") {
218 options.push_back(trim(option));
220 } else if (t.asInput() == "=") {
223 if (p.next_token().asInput() == "{")
224 option += '{' + p.getArg('{', '}') + '}';
225 } else if (t.cat() != catSpace)
226 option += t.asInput();
230 options.push_back(trim(option));
237 * Add package \p name with options \p options to used_packages.
238 * Remove options from \p options that we don't want to output.
240 void add_package(string const & name, vector<string> & options)
242 // every package inherits the global options
243 if (used_packages.find(name) == used_packages.end())
244 used_packages[name] = split_options(h_options);
246 vector<string> & v = used_packages[name];
247 v.insert(v.end(), options.begin(), options.end());
248 if (name == "jurabib") {
249 // Don't output the order argument (see the cite command
250 // handling code in text.cpp).
251 vector<string>::iterator end =
252 remove(options.begin(), options.end(), "natbiborder");
253 end = remove(options.begin(), end, "jurabiborder");
254 options.erase(end, options.end());
259 // Given is a string like "scaled=0.9", return 0.9 * 100
260 string const scale_as_percentage(string const & scale)
262 string::size_type pos = scale.find('=');
263 if (pos != string::npos) {
264 string value = scale.substr(pos + 1);
266 return convert<string>(100 * convert<double>(value));
268 // If the input string didn't match our expectations.
269 // return the default value "100"
274 void handle_package(Parser &p, string const & name, string const & opts)
276 vector<string> options = split_options(opts);
277 add_package(name, options);
281 if (is_known(name, known_roman_fonts)) {
286 if (name == "fourier") {
287 h_font_roman = "utopia";
288 // when font uses real small capitals
289 if (opts == "expert")
293 if (name == "mathpazo")
294 h_font_roman = "palatino";
296 if (name == "mathptmx")
297 h_font_roman = "times";
300 if (is_known(name, known_sans_fonts)) {
304 h_font_sf_scale = scale_as_percentage(scale);
309 if (is_known(name, known_typewriter_fonts)) {
310 h_font_typewriter = name;
313 h_font_tt_scale = scale_as_percentage(scale);
317 // font uses old-style figure
321 else if (name == "amsmath" || name == "amssymb")
324 else if (name == "esint")
327 else if (name == "babel" && !opts.empty()) {
328 // check if more than one option was used - used later for inputenc
329 // in case inputenc is parsed before babel, set the encoding to auto
330 if (options.begin() != options.end() - 1) {
331 one_language = false;
332 h_inputencoding = "auto";
334 // only set the document language when there was not already one set
335 // via the documentclass options
336 // babel takes the the last language given in the documentclass options
337 // as document language. If there is no such language option, the last
338 // option of its \usepackage call is used.
339 if (documentclass_language == false) {
340 handle_opt(options, known_languages, h_language);
341 delete_opt(options, known_languages);
342 if (is_known(h_language, known_french_languages))
343 h_language = "french";
344 else if (is_known(h_language, known_german_languages))
345 h_language = "german";
346 else if (is_known(h_language, known_ngerman_languages))
347 h_language = "ngerman";
348 else if (is_known(h_language, known_russian_languages))
349 h_language = "russian";
350 else if (is_known(h_language, known_ukrainian_languages))
351 h_language = "ukrainian";
352 h_quotes_language = h_language;
356 else if (name == "fontenc")
359 else if (name == "inputenc") {
360 // only set when there is not more than one inputenc
361 // option therefore check for the "," character also
362 // only set when there is not more then one babel
364 if (opts.find(",") == string::npos && one_language == true) {
366 //change ascii to auto to be in the unicode range, see
367 //http://bugzilla.lyx.org/show_bug.cgi?id=4719
368 h_inputencoding = "auto";
369 else if (!opts.empty())
370 h_inputencoding = opts;
372 if (!options.empty())
373 p.setEncoding(options.back());
377 else if (name == "makeidx")
380 else if (name == "prettyref")
383 else if (name == "varioref")
386 else if (name == "verbatim")
389 else if (name == "nomencl")
392 else if (name == "textcomp")
395 else if (name == "url")
398 else if (name == "color") {
399 // with the following command this package is only loaded when needed for
400 // undefined colors, since we only support the predefined colors
401 h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n";
404 else if (name == "graphicx")
407 else if (name == "setspace")
410 else if (name == "geometry")
411 ; // Ignore this, the geometry settings are made by the \geometry
412 // command. This command is handled below.
414 else if (is_known(name, known_languages)) {
415 if (is_known(name, known_french_languages))
416 h_language = "french";
417 else if (is_known(name, known_german_languages))
418 h_language = "german";
419 else if (is_known(name, known_ngerman_languages))
420 h_language = "ngerman";
421 else if (is_known(name, known_russian_languages))
422 h_language = "russian";
423 else if (is_known(name, known_ukrainian_languages))
424 h_language = "ukrainian";
427 h_quotes_language = h_language;
430 else if (name == "natbib") {
431 h_cite_engine = "natbib_authoryear";
432 vector<string>::iterator it =
433 find(options.begin(), options.end(), "authoryear");
434 if (it != options.end())
437 it = find(options.begin(), options.end(), "numbers");
438 if (it != options.end()) {
439 h_cite_engine = "natbib_numerical";
445 else if (name == "jurabib")
446 h_cite_engine = "jurabib";
448 else if (name == "babel")
453 h_preamble << "\\usepackage{" << name << "}";
455 h_preamble << "\\usepackage[" << opts << "]{"
461 // We need to do something with the options...
462 if (!options.empty())
463 cerr << "Ignoring options '" << join(options, ",")
464 << "' of package " << name << '.' << endl;
466 // remove the whitespace
472 void end_preamble(ostream & os, TextClass const & /*textclass*/)
474 os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
475 << "\\lyxformat 258\n"
476 << "\\begin_document\n"
477 << "\\begin_header\n"
478 << "\\textclass " << h_textclass << "\n";
479 if (!h_preamble.str().empty())
480 os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
481 if (!h_options.empty())
482 os << "\\options " << h_options << "\n";
483 os << "\\language " << h_language << "\n"
484 << "\\inputencoding " << h_inputencoding << "\n"
485 << "\\font_roman " << h_font_roman << "\n"
486 << "\\font_sans " << h_font_sans << "\n"
487 << "\\font_typewriter " << h_font_typewriter << "\n"
488 << "\\font_default_family " << h_font_default_family << "\n"
489 << "\\font_sc " << h_font_sc << "\n"
490 << "\\font_osf " << h_font_osf << "\n"
491 << "\\font_sf_scale " << h_font_sf_scale << "\n"
492 << "\\font_tt_scale " << h_font_tt_scale << "\n"
493 << "\\graphics " << h_graphics << "\n"
494 << "\\paperfontsize " << h_paperfontsize << "\n"
495 << "\\spacing " << h_spacing << "\n"
496 << "\\papersize " << h_papersize << "\n"
497 << "\\use_geometry " << h_use_geometry << "\n"
498 << "\\use_amsmath " << h_use_amsmath << "\n"
499 << "\\use_esint " << h_use_esint << "\n"
500 << "\\cite_engine " << h_cite_engine << "\n"
501 << "\\use_bibtopic " << h_use_bibtopic << "\n"
502 << "\\paperorientation " << h_paperorientation << "\n"
504 << "\\secnumdepth " << h_secnumdepth << "\n"
505 << "\\tocdepth " << h_tocdepth << "\n"
506 << "\\paragraph_separation " << h_paragraph_separation << "\n"
507 << "\\defskip " << h_defskip << "\n"
508 << "\\quotes_language " << h_quotes_language << "\n"
509 << "\\papercolumns " << h_papercolumns << "\n"
510 << "\\papersides " << h_papersides << "\n"
511 << "\\paperpagestyle " << h_paperpagestyle << "\n"
512 << "\\tracking_changes " << h_tracking_changes << "\n"
513 << "\\output_changes " << h_output_changes << "\n"
514 << "\\end_header\n\n"
516 // clear preamble for subdocuments
520 } // anonymous namespace
522 void parse_preamble(Parser & p, ostream & os,
523 string const & forceclass, TeX2LyXDocClass & tc)
525 // initialize fixed types
526 special_columns['D'] = 3;
527 bool is_full_document = false;
528 bool is_lyx_file = false;
529 bool lyx_specific_preamble = false;
531 // determine whether this is a full document or a fragment for inclusion
533 Token const & t = p.get_token();
535 if (t.cat() == catEscape && t.cs() == "documentclass") {
536 is_full_document = true;
542 while (is_full_document && p.good()) {
543 Token const & t = p.get_token();
546 cerr << "t: " << t << "\n";
552 if ((t.cat() == catLetter ||
553 t.cat() == catSuper ||
555 t.cat() == catOther ||
556 t.cat() == catMath ||
557 t.cat() == catActive ||
558 t.cat() == catBegin ||
560 t.cat() == catAlign ||
561 t.cat() == catParameter))
562 h_preamble << t.character();
564 else if (t.cat() == catSpace || t.cat() == catNewline)
565 h_preamble << t.asInput();
567 else if (t.cat() == catComment) {
568 // regex to parse comments
569 static regex const islyxfile("%% LyX .* created this file");
570 static regex const usercommands("User specified LaTeX commands");
572 string const comment = t.asInput();
574 // magically switch encoding default if it looks like XeLaTeX
575 static string const magicXeLaTeX =
576 "% This document must be compiled with XeLaTeX ";
577 if (comment.size() > magicXeLaTeX.size()
578 && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
579 && h_inputencoding == "auto") {
580 cerr << "XeLaTeX comment found, switching to UTF8\n";
581 h_inputencoding = "utf8";
585 if (regex_search(comment, sub, islyxfile))
587 // don't output LyX specific comments
588 if (!is_known(comment, known_lyx_comments))
589 h_preamble << t.asInput();
592 else if (t.cs() == "pagestyle")
593 h_paperpagestyle = p.verbatim_item();
595 else if (t.cs() == "makeatletter") {
596 // LyX takes care of this
597 p.setCatCode('@', catLetter);
600 else if (t.cs() == "makeatother") {
601 // LyX takes care of this
602 p.setCatCode('@', catOther);
605 else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
606 || t.cs() == "providecommand"
607 || t.cs() == "DeclareRobustCommand"
608 || t.cs() == "ProvideTextCommandDefault"
609 || t.cs() == "DeclareMathAccent") {
611 if (p.next_token().character() == '*') {
615 string const name = p.verbatim_item();
616 string const opt1 = p.getOpt();
617 string const opt2 = p.getFullOpt();
618 string const body = p.verbatim_item();
620 if (name == "\\rmdefault")
621 if (is_known(body, known_roman_fonts))
623 if (name == "\\sfdefault")
624 if (is_known(body, known_sans_fonts))
626 if (name == "\\ttdefault")
627 if (is_known(body, known_typewriter_fonts))
628 h_font_typewriter = body;
629 if (name == "\\familydefault") {
630 string family = body;
631 // remove leading "\"
632 h_font_default_family = family.erase(0,1);
634 // LyX specific commands that will automatically be set by LyX
635 string lyx_command = name;
636 // remove the leading "\"
637 lyx_command.erase(0,1);
638 if (is_known(lyx_command, known_lyx_commands))
639 lyx_specific_preamble = true;
640 // only non-lyxspecific stuff
641 if (!lyx_specific_preamble) {
643 ss << '\\' << t.cs();
646 ss << '{' << name << '}' << opt1 << opt2
647 << '{' << body << "}";
648 h_preamble << ss.str();
650 // Add the command to the known commands
651 add_known_command(name, opt1, !opt2.empty());
653 ostream & out = in_preamble ? h_preamble : os;
654 out << "\\" << t.cs() << "{" << name << "}"
655 << opts << "{" << body << "}";
660 else if (t.cs() == "documentclass") {
661 vector<string>::iterator it;
662 vector<string> opts = split_options(p.getArg('[', ']'));
663 handle_opt(opts, known_fontsizes, h_paperfontsize);
664 delete_opt(opts, known_fontsizes);
665 // delete "pt" at the end
666 string::size_type i = h_paperfontsize.find("pt");
667 if (i != string::npos)
668 h_paperfontsize.erase(i);
669 // to avoid that the babel options overwrite the documentclass options
670 documentclass_language = false;
671 handle_opt(opts, known_languages, h_language);
672 delete_opt(opts, known_languages);
673 if (is_known(h_language, known_french_languages))
674 h_language = "french";
675 else if (is_known(h_language, known_german_languages))
676 h_language = "german";
677 else if (is_known(h_language, known_ngerman_languages))
678 h_language = "ngerman";
679 else if (is_known(h_language, known_russian_languages))
680 h_language = "russian";
681 else if (is_known(h_language, known_ukrainian_languages))
682 h_language = "ukrainian";
683 h_quotes_language = h_language;
685 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
686 h_paperorientation = "landscape";
690 if ((it = find(opts.begin(), opts.end(), "oneside"))
695 if ((it = find(opts.begin(), opts.end(), "twoside"))
701 if ((it = find(opts.begin(), opts.end(), "onecolumn"))
703 h_papercolumns = "1";
706 if ((it = find(opts.begin(), opts.end(), "twocolumn"))
708 h_papercolumns = "2";
712 // some size options are know to any document classes, other sizes
713 // are handled by the \geometry command of the geometry package
714 handle_opt(opts, known_class_paper_sizes, h_papersize);
715 delete_opt(opts, known_class_paper_sizes);
716 // the remaining options
717 h_options = join(opts, ",");
718 h_textclass = p.getArg('{', '}');
721 else if (t.cs() == "usepackage") {
722 string const options = p.getArg('[', ']');
723 string const name = p.getArg('{', '}');
724 vector<string> vecnames;
725 split(name, vecnames, ',');
726 vector<string>::const_iterator it = vecnames.begin();
727 vector<string>::const_iterator end = vecnames.end();
728 for (; it != end; ++it)
729 handle_package(p, trim(*it), options);
732 else if (t.cs() == "inputencoding") {
733 string const encoding = p.getArg('{','}');
734 h_inputencoding = encoding;
735 p.setEncoding(encoding);
738 else if (t.cs() == "newenvironment") {
739 string const name = p.getArg('{', '}');
741 // only non LyX specific stuff is output
742 ss << "\\newenvironment{" << name << "}";
745 ss << '{' << p.verbatim_item() << '}';
746 ss << '{' << p.verbatim_item() << '}';
747 if (!is_known(name, known_lyx_commands))
748 h_preamble << ss.str();
751 else if (t.cs() == "def") {
752 string name = p.get_token().cs();
753 while (p.next_token().cat() != catBegin)
754 name += p.get_token().asString();
755 if (!is_known(name, known_lyx_commands))
756 h_preamble << "\\def\\" << name << '{'
757 << p.verbatim_item() << "}";
760 else if (t.cs() == "newcolumntype") {
761 string const name = p.getArg('{', '}');
764 string opts = p.getOpt();
766 istringstream is(string(opts, 1));
769 special_columns[name[0]] = nargs;
770 h_preamble << "\\newcolumntype{" << name << "}";
772 h_preamble << "[" << nargs << "]";
773 h_preamble << "{" << p.verbatim_item() << "}";
776 else if (t.cs() == "setcounter") {
777 string const name = p.getArg('{', '}');
778 string const content = p.getArg('{', '}');
779 if (name == "secnumdepth")
780 h_secnumdepth = content;
781 else if (name == "tocdepth")
782 h_tocdepth = content;
784 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
787 else if (t.cs() == "setlength") {
788 string const name = p.verbatim_item();
789 string const content = p.verbatim_item();
790 // the paragraphs are only not indented when \parindent is set to zero
791 if (name == "\\parindent" && content != "") {
792 if (content[0] == '0')
793 h_paragraph_separation = "skip";
794 } else if (name == "\\parskip") {
795 if (content == "\\smallskipamount")
796 h_defskip = "smallskip";
797 else if (content == "\\medskipamount")
798 h_defskip = "medskip";
799 else if (content == "\\bigskipamount")
800 h_defskip = "bigskip";
804 h_preamble << "\\setlength{" << name << "}{" << content << "}";
807 else if (t.cs() == "onehalfspacing")
808 h_spacing = "onehalf";
810 else if (t.cs() == "doublespacing")
811 h_spacing = "double";
813 else if (t.cs() == "setstretch")
814 h_spacing = "other " + p.verbatim_item();
816 else if (t.cs() == "begin") {
817 string const name = p.getArg('{', '}');
818 if (name == "document")
820 h_preamble << "\\begin{" << name << "}";
823 else if (t.cs() == "geometry") {
824 h_use_geometry = "true";
825 vector<string> opts = split_options(p.getArg('{', '}'));
826 vector<string>::iterator it;
828 if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
829 h_paperorientation = "landscape";
833 handle_opt(opts, known_paper_sizes, h_papersize);
834 delete_opt(opts, known_paper_sizes);
836 char const * const * margin = known_paper_margins;
838 for (; *margin; ++margin) {
840 // search for the "=" in e.g. "lmargin=2cm" to get the value
841 for(size_t i = 0; i != opts.size(); i++) {
842 if (opts.at(i).find(*margin) != string::npos) {
843 string::size_type pos = opts.at(i).find("=");
844 string value = opts.at(i).substr(pos + 1);
845 string name = known_coded_paper_margins[k];
846 h_margins += "\\" + name + " " + value + "\n";
852 else if (t.cs() == "jurabibsetup") {
853 vector<string> jurabibsetup =
854 split_options(p.getArg('{', '}'));
855 // add jurabibsetup to the jurabib package options
856 add_package("jurabib", jurabibsetup);
857 if (!jurabibsetup.empty()) {
858 h_preamble << "\\jurabibsetup{"
859 << join(jurabibsetup, ",") << '}';
863 else if (!t.cs().empty())
864 h_preamble << '\\' << t.cs();
866 // remove the whitespace
870 // remove the whitespace
873 // Force textclass if the user wanted it
874 if (!forceclass.empty())
875 h_textclass = forceclass;
876 if (noweb_mode && !prefixIs(h_textclass, "literate-"))
877 h_textclass.insert(0, "literate-");
878 FileName layoutfilename = libFileSearch("layouts", h_textclass, "layout");
879 if (layoutfilename.empty()) {
880 cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
883 tc.read(layoutfilename);
884 if (h_papersides.empty()) {
887 h_papersides = ss.str();
889 end_preamble(os, tc);