3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
17 #include "TextClass.h"
19 #include "LayoutFile.h"
20 #include "CiteEnginesList.h"
24 #include "FloatList.h"
28 #include "ModuleList.h"
30 #include "frontends/alert.h"
32 #include "support/lassert.h"
33 #include "support/debug.h"
34 #include "support/ExceptionMessage.h"
35 #include "support/FileName.h"
36 #include "support/filetools.h"
37 #include "support/gettext.h"
38 #include "support/lstrings.h"
39 #include "support/os.h"
40 #include "support/TempFile.h"
51 using namespace lyx::support;
55 // Keep the changes documented in the Customization manual.
57 // If you change this format, then you MUST also make sure that
58 // your changes do not invalidate the hardcoded layout file in
59 // LayoutFile.cpp. Additions will never do so, but syntax changes
60 // could. See LayoutFileList::addEmptyClass() and, especially, the
61 // definition of the layoutpost string.
62 // You should also run the development/tools/updatelayouts.py script,
63 // to update the format of all of our layout files.
65 int const LAYOUT_FORMAT = 75; // spitz: FreeSpacing (Argument)
68 // Layout format for the current lyx file format. Controls which format is
69 // targeted by Local Layout > Convert. In master, equal to LAYOUT_FORMAT.
70 int const LYXFILE_LAYOUT_FORMAT = LAYOUT_FORMAT;
75 class LayoutNamesEqual : public unary_function<Layout, bool> {
77 LayoutNamesEqual(docstring const & name)
80 bool operator()(Layout const & c) const
82 return c.name() == name_;
89 bool layout2layout(FileName const & filename, FileName const & tempfile,
90 int const format = LAYOUT_FORMAT)
92 FileName const script = libFileSearch("scripts", "layout2layout.py");
94 LYXERR0("Could not find layout conversion "
95 "script layout2layout.py.");
99 ostringstream command;
100 command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
102 << ' ' << quoteName(filename.toFilesystemEncoding())
103 << ' ' << quoteName(tempfile.toFilesystemEncoding());
104 string const command_str = command.str();
106 LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
108 cmd_ret const ret = runCommand(command_str);
109 if (ret.first != 0) {
110 if (format == LAYOUT_FORMAT)
111 LYXERR0("Conversion of layout with layout2layout.py has failed.");
118 string translateReadType(TextClass::ReadType rt)
121 case TextClass::BASECLASS:
123 case TextClass::MERGE:
125 case TextClass::MODULE:
126 return "module file";
127 case TextClass::CITE_ENGINE:
128 return "cite engine";
129 case TextClass::VALIDATION:
139 // This string should not be translated here,
140 // because it is a layout identifier.
141 docstring const TextClass::plain_layout_ = from_ascii(N_("Plain Layout"));
144 /////////////////////////////////////////////////////////////////////////
148 /////////////////////////////////////////////////////////////////////////
150 TextClass::TextClass()
151 : loaded_(false), tex_class_avail_(false),
152 opt_enginetype_("authoryear|numerical"), opt_fontsize_("10|11|12"),
153 opt_pagestyle_("empty|plain|headings|fancy"), pagestyle_("default"),
154 tablestyle_("default"), columns_(1), sides_(OneSide), secnumdepth_(3),
155 tocdepth_(3), outputType_(LATEX), outputFormat_("latex"),
156 has_output_format_(false), defaultfont_(sane_font),
157 titletype_(TITLE_COMMAND_AFTER), titlename_("maketitle"),
158 min_toclevel_(0), max_toclevel_(0), maxcitenames_(2),
159 cite_full_author_list_(true)
164 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
166 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
167 if (!lay.read(lexrc, *this)) {
168 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
172 lay.resfont = lay.font;
173 lay.resfont.realize(defaultfont_);
174 lay.reslabelfont = lay.labelfont;
175 lay.reslabelfont.realize(defaultfont_);
176 return true; // no errors
215 TC_ADDTOHTMLPREAMBLE,
236 LexerKeyword textClassTags[] = {
237 { "addtociteengine", TC_ADDTOCITEENGINE },
238 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
239 { "addtohtmlstyles", TC_ADDTOHTMLSTYLES },
240 { "addtopreamble", TC_ADDTOPREAMBLE },
241 { "citeengine", TC_CITEENGINE },
242 { "citeenginetype", TC_CITEENGINETYPE },
243 { "citeformat", TC_CITEFORMAT },
244 { "citeframework", TC_CITEFRAMEWORK },
245 { "classoptions", TC_CLASSOPTIONS },
246 { "columns", TC_COLUMNS },
247 { "counter", TC_COUNTER },
248 { "defaultbiblio", TC_DEFAULTBIBLIO },
249 { "defaultfont", TC_DEFAULTFONT },
250 { "defaultmodule", TC_DEFAULTMODULE },
251 { "defaultstyle", TC_DEFAULTSTYLE },
252 { "excludesmodule", TC_EXCLUDESMODULE },
253 { "float", TC_FLOAT },
254 { "format", TC_FORMAT },
255 { "fullauthorlist", TC_FULLAUTHORLIST },
256 { "htmlpreamble", TC_HTMLPREAMBLE },
257 { "htmlstyles", TC_HTMLSTYLES },
258 { "htmltocsection", TC_HTMLTOCSECTION },
259 { "ifcounter", TC_IFCOUNTER },
260 { "input", TC_INPUT },
261 { "insetlayout", TC_INSETLAYOUT },
262 { "leftmargin", TC_LEFTMARGIN },
263 { "maxcitenames", TC_MAXCITENAMES },
264 { "modifystyle", TC_MODIFYSTYLE },
265 { "nocounter", TC_NOCOUNTER },
266 { "nofloat", TC_NOFLOAT },
267 { "noinsetlayout", TC_NOINSETLAYOUT },
268 { "nostyle", TC_NOSTYLE },
269 { "outlinername", TC_OUTLINERNAME },
270 { "outputformat", TC_OUTPUTFORMAT },
271 { "outputtype", TC_OUTPUTTYPE },
272 { "packageoptions", TC_PKGOPTS },
273 { "pagestyle", TC_PAGESTYLE },
274 { "preamble", TC_PREAMBLE },
275 { "provides", TC_PROVIDES },
276 { "providesmodule", TC_PROVIDESMODULE },
277 { "providestyle", TC_PROVIDESTYLE },
278 { "requires", TC_REQUIRES },
279 { "rightmargin", TC_RIGHTMARGIN },
280 { "secnumdepth", TC_SECNUMDEPTH },
281 { "sides", TC_SIDES },
282 { "style", TC_STYLE },
283 { "tablestyle", TC_TABLESTYLE },
284 { "titlelatexname", TC_TITLELATEXNAME },
285 { "titlelatextype", TC_TITLELATEXTYPE },
286 { "tocdepth", TC_TOCDEPTH }
292 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
294 LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
295 TempFile tmp("convertXXXXXX.layout");
296 FileName const tempfile = tmp.name();
297 bool success = layout2layout(filename, tempfile);
299 success = readWithoutConv(tempfile, rt) == OK;
304 std::string TextClass::convert(std::string const & str)
306 TempFile tmp1("localXXXXXX.layout");
307 FileName const fn = tmp1.name();
308 ofstream os(fn.toFilesystemEncoding().c_str());
311 TempFile tmp2("convert_localXXXXXX.layout");
312 FileName const tempfile = tmp2.name();
313 bool success = layout2layout(fn, tempfile, LYXFILE_LAYOUT_FORMAT);
316 ifstream is(tempfile.toFilesystemEncoding().c_str());
328 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
330 if (!filename.isReadableFile()) {
331 lyxerr << "Cannot read layout file `" << filename << "'."
336 LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
337 to_utf8(makeDisplayPath(filename.absFileName())));
339 // Define the plain layout used in table cells, ert, etc. Note that
340 // we do this before loading any layout file, so that classes can
341 // override features of this layout if they should choose to do so.
342 if (rt == BASECLASS && !hasLayout(plain_layout_))
343 layoutlist_.push_back(createBasicLayout(plain_layout_));
345 Lexer lexrc(textClassTags);
346 lexrc.setFile(filename);
347 ReturnValues retval = read(lexrc, rt);
349 LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
350 to_utf8(makeDisplayPath(filename.absFileName())));
356 bool TextClass::read(FileName const & filename, ReadType rt)
358 ReturnValues const retval = readWithoutConv(filename, rt);
359 if (retval != FORMAT_MISMATCH)
362 bool const worx = convertLayoutFormat(filename, rt);
364 LYXERR0 ("Unable to convert " << filename <<
365 " to format " << LAYOUT_FORMAT);
370 TextClass::ReturnValues TextClass::validate(std::string const & str)
373 return tc.read(str, VALIDATION);
377 TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
379 Lexer lexrc(textClassTags);
380 istringstream is(str);
382 ReturnValues retval = read(lexrc, rt);
384 if (retval != FORMAT_MISMATCH)
387 // write the layout string to a temporary file
388 TempFile tmp("TextClass_read");
389 FileName const tempfile = tmp.name();
390 ofstream os(tempfile.toFilesystemEncoding().c_str());
392 LYXERR0("Unable to create temporary file");
398 // now try to convert it to LAYOUT_FORMAT
399 if (!convertLayoutFormat(tempfile, rt)) {
400 LYXERR0("Unable to convert internal layout information to format "
409 // Reads a textclass structure from file.
410 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
415 // The first usable line should be
416 // Format LAYOUT_FORMAT
417 if (lexrc.lex() != TC_FORMAT || !lexrc.next()
418 || lexrc.getInteger() != LAYOUT_FORMAT)
419 return FORMAT_MISMATCH;
423 while (lexrc.isOK() && !error) {
424 int le = lexrc.lex();
427 case Lexer::LEX_FEOF:
430 case Lexer::LEX_UNDEF:
431 lexrc.printError("Unknown TextClass tag `$$Token'");
439 // used below to track whether we are in an IfStyle or IfCounter tag.
440 bool modifystyle = false;
441 bool providestyle = false;
442 bool ifcounter = false;
444 switch (static_cast<TextClassTags>(le)) {
448 lexrc.printError("Duplicate Format directive");
451 case TC_OUTPUTFORMAT:
453 outputFormat_ = lexrc.getString();
454 has_output_format_ = true;
459 readOutputType(lexrc);
460 switch(outputType_) {
462 outputFormat_ = "latex";
465 outputFormat_ = "docbook";
468 outputFormat_ = "literate";
473 case TC_INPUT: // Include file
476 string const inc = lexrc.getString();
477 if (!path().empty() && (prefixIs(inc, "./") ||
478 prefixIs(inc, "../")))
479 tmp = fileSearch(path(), inc, "layout");
481 tmp = libFileSearch("layouts", inc,
485 lexrc.printError("Could not find input file: " + inc);
487 } else if (!read(tmp, MERGE)) {
488 lexrc.printError("Error reading input file: " + tmp.absFileName());
494 case TC_DEFAULTSTYLE:
496 docstring const name = from_utf8(subst(lexrc.getString(),
498 defaultlayout_ = name;
505 case TC_PROVIDESTYLE:
506 // if modifystyle is true, then we got here by falling through
507 // so we are not in an ProvideStyle block
513 lexrc.printError("No name given for style: `$$Token'.");
517 docstring const name = from_utf8(subst(lexrc.getString(),
520 string s = "Could not read name for style: `$$Token' "
521 + lexrc.getString() + " is probably not valid UTF-8!";
524 // Since we couldn't read the name, we just scan the rest
525 // of the style and discard it.
526 error = !readStyle(lexrc, lay);
530 bool const have_layout = hasLayout(name);
532 // If the layout already exists, then we want to add it to
533 // the existing layout, as long as we are not in an ProvideStyle
535 if (have_layout && !providestyle) {
536 Layout & lay = operator[](name);
537 error = !readStyle(lexrc, lay);
539 // If the layout does not exist, then we want to create a new
540 // one, but not if we are in a ModifyStyle block.
541 else if (!have_layout && !modifystyle) {
543 layout.setName(name);
544 error = !readStyle(lexrc, layout);
546 layoutlist_.push_back(layout);
548 if (defaultlayout_.empty()) {
549 // We do not have a default layout yet, so we choose
550 // the first layout we encounter.
551 defaultlayout_ = name;
554 // There are two ways to get here:
555 // (i) The layout exists but we are in an ProvideStyle block
556 // (ii) The layout doesn't exist, but we are in an ModifyStyle
558 // Either way, we just scan the rest and discard it
561 // signal to coverity that we do not care about the result
562 (void)readStyle(lexrc, lay);
569 docstring const style = from_utf8(subst(lexrc.getString(),
571 if (!deleteLayout(style))
572 lyxerr << "Cannot delete style `"
573 << to_utf8(style) << '\'' << endl;
577 case TC_NOINSETLAYOUT:
579 docstring const style = from_utf8(subst(lexrc.getString(),
581 if (!deleteInsetLayout(style))
582 LYXERR0("Style `" << style << "' cannot be removed\n"
583 "because it was not found!");
589 columns_ = lexrc.getInteger();
594 switch (lexrc.getInteger()) {
595 case 1: sides_ = OneSide; break;
596 case 2: sides_ = TwoSides; break;
598 lyxerr << "Impossible number of page"
599 " sides, setting to one."
609 pagestyle_ = rtrim(lexrc.getString());
613 defaultfont_ = lyxRead(lexrc);
614 if (!defaultfont_.resolved()) {
615 lexrc.printError("Warning: defaultfont should "
616 "be fully instantiated!");
617 defaultfont_.realize(sane_font);
623 secnumdepth_ = lexrc.getInteger();
628 tocdepth_ = lexrc.getInteger();
631 // First step to support options
632 case TC_CLASSOPTIONS:
633 readClassOptions(lexrc);
637 preamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
640 case TC_HTMLPREAMBLE:
641 htmlpreamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
645 htmlstyles_ = lexrc.getLongString(from_ascii("EndStyles"));
648 case TC_HTMLTOCSECTION:
649 html_toc_section_ = from_utf8(trim(lexrc.getString()));
652 case TC_ADDTOPREAMBLE:
653 preamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
656 case TC_ADDTOHTMLPREAMBLE:
657 htmlpreamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
660 case TC_ADDTOHTMLSTYLES:
661 htmlstyles_ += lexrc.getLongString(from_ascii("EndStyles"));
666 string const feature = lexrc.getString();
668 if (lexrc.getInteger())
669 provides_.insert(feature);
671 provides_.erase(feature);
677 vector<string> const req
678 = getVectorFromString(lexrc.getString());
679 requires_.insert(req.begin(), req.end());
685 string const pkg = lexrc.getString();
687 string const options = lexrc.getString();
688 package_options_[pkg] = options;
692 case TC_DEFAULTMODULE: {
694 string const module = lexrc.getString();
695 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
696 default_modules_.push_back(module);
700 case TC_PROVIDESMODULE: {
702 string const module = lexrc.getString();
703 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
704 provided_modules_.push_back(module);
708 case TC_EXCLUDESMODULE: {
710 string const module = lexrc.getString();
711 // modules already have their own way to exclude other modules
713 LYXERR0("ExcludesModule tag cannot be used in a module!");
716 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
717 excluded_modules_.push_back(module);
721 case TC_LEFTMARGIN: // left margin type
723 leftmargin_ = lexrc.getDocString();
726 case TC_RIGHTMARGIN: // right margin type
728 rightmargin_ = lexrc.getDocString();
731 case TC_INSETLAYOUT: {
733 lexrc.printError("No name given for InsetLayout: `$$Token'.");
737 docstring const name = subst(lexrc.getDocString(), '_', ' ');
739 string s = "Could not read name for InsetLayout: `$$Token' "
740 + lexrc.getString() + " is probably not valid UTF-8!";
743 // Since we couldn't read the name, we just scan the rest
744 // of the style and discard it.
745 il.read(lexrc, *this);
746 // Let's try to continue rather than abort.
748 } else if (hasInsetLayout(name)) {
749 InsetLayout & il = insetlayoutlist_[name];
750 error = !il.read(lexrc, *this);
754 error = !il.read(lexrc, *this);
756 insetlayoutlist_[name] = il;
762 error = !readFloat(lexrc);
766 error = !readCiteEngine(lexrc, rt);
769 case TC_ADDTOCITEENGINE:
770 error = !readCiteEngine(lexrc, rt, true);
773 case TC_CITEENGINETYPE:
775 opt_enginetype_ = rtrim(lexrc.getString());
779 error = !readCiteFormat(lexrc, rt);
782 case TC_CITEFRAMEWORK:
784 citeframework_ = rtrim(lexrc.getString());
787 case TC_MAXCITENAMES:
789 maxcitenames_ = size_t(lexrc.getInteger());
792 case TC_DEFAULTBIBLIO:
794 vector<string> const dbs =
795 getVectorFromString(rtrim(lexrc.getString()), "|");
796 vector<string>::const_iterator it = dbs.begin();
797 vector<string>::const_iterator end = dbs.end();
798 for (; it != end; ++it) {
799 if (!contains(*it, ':')) {
800 vector<string> const enginetypes =
801 getVectorFromString(opt_enginetype_, "|");
802 for (string const &s: enginetypes)
803 cite_default_biblio_style_[s] = *it;
806 string const db = split(*it, eng, ':');
807 cite_default_biblio_style_[eng] = db;
813 case TC_FULLAUTHORLIST:
815 cite_full_author_list_ &= lexrc.getBool();
820 docstring const cnt = lexrc.getDocString();
821 if (!counters_.remove(cnt))
822 LYXERR0("Unable to remove counter: " + to_utf8(cnt));
831 docstring const name = lexrc.getDocString();
833 string s = "Could not read name for counter: `$$Token' "
834 + lexrc.getString() + " is probably not valid UTF-8!";
835 lexrc.printError(s.c_str());
837 // Since we couldn't read the name, we just scan the rest
841 error = !counters_.read(lexrc, name, !ifcounter);
844 lexrc.printError("No name given for style: `$$Token'.");
849 case TC_TITLELATEXTYPE:
850 readTitleType(lexrc);
853 case TC_TITLELATEXNAME:
855 titlename_ = lexrc.getString();
860 string const nofloat = lexrc.getString();
861 floatlist_.erase(nofloat);
865 case TC_OUTLINERNAME:
866 error = !readOutlinerName(lexrc);
871 tablestyle_ = rtrim(lexrc.getString());
876 // at present, we abort if we encounter an error,
877 // so there is no point continuing.
884 if (defaultlayout_.empty()) {
885 LYXERR0("Error: Textclass '" << name_
886 << "' is missing a defaultstyle.");
890 // Try to erase "stdinsets" from the provides_ set.
892 // Provides stdinsets 1
893 // declaration simply tells us that the standard insets have been
894 // defined. (It's found in stdinsets.inc but could also be used in
895 // user-defined files.) There isn't really any such package. So we
896 // might as well go ahead and erase it.
897 // If we do not succeed, then it was not there, which means that
898 // the textclass did not provide the definitions of the standard
899 // insets. So we need to try to load them.
900 int erased = provides_.erase("stdinsets");
902 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
905 frontend::Alert::warning(_("Missing File"),
906 _("Could not find stdinsets.inc! This may lead to data loss!"));
908 } else if (!read(tmp, MERGE)) {
909 frontend::Alert::warning(_("Corrupt File"),
910 _("Could not read stdinsets.inc! This may lead to data loss!"));
915 min_toclevel_ = Layout::NOT_IN_TOC;
916 max_toclevel_ = Layout::NOT_IN_TOC;
917 const_iterator lit = begin();
918 const_iterator len = end();
919 for (; lit != len; ++lit) {
920 int const toclevel = lit->toclevel;
921 if (toclevel != Layout::NOT_IN_TOC) {
922 if (min_toclevel_ == Layout::NOT_IN_TOC)
923 min_toclevel_ = toclevel;
925 min_toclevel_ = min(min_toclevel_, toclevel);
926 max_toclevel_ = max(max_toclevel_, toclevel);
929 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
930 << ", maximum is " << max_toclevel_);
932 return (error ? ERROR : OK);
936 void TextClass::readTitleType(Lexer & lexrc)
938 LexerKeyword titleTypeTags[] = {
939 { "commandafter", TITLE_COMMAND_AFTER },
940 { "environment", TITLE_ENVIRONMENT }
943 PushPopHelper pph(lexrc, titleTypeTags);
945 int le = lexrc.lex();
947 case Lexer::LEX_UNDEF:
948 lexrc.printError("Unknown output type `$$Token'");
950 case TITLE_COMMAND_AFTER:
951 case TITLE_ENVIRONMENT:
952 titletype_ = static_cast<TitleLatexType>(le);
955 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
961 void TextClass::readOutputType(Lexer & lexrc)
963 LexerKeyword outputTypeTags[] = {
964 { "docbook", DOCBOOK },
966 { "literate", LITERATE }
969 PushPopHelper pph(lexrc, outputTypeTags);
971 int le = lexrc.lex();
973 case Lexer::LEX_UNDEF:
974 lexrc.printError("Unknown output type `$$Token'");
979 outputType_ = static_cast<OutputType>(le);
982 LYXERR0("Unhandled value " << le);
988 void TextClass::readClassOptions(Lexer & lexrc)
998 LexerKeyword classOptionsTags[] = {
1000 {"fontsize", CO_FONTSIZE },
1001 {"header", CO_HEADER },
1002 {"other", CO_OTHER },
1003 {"pagestyle", CO_PAGESTYLE }
1006 lexrc.pushTable(classOptionsTags);
1007 bool getout = false;
1008 while (!getout && lexrc.isOK()) {
1009 int le = lexrc.lex();
1011 case Lexer::LEX_UNDEF:
1012 lexrc.printError("Unknown ClassOption tag `$$Token'");
1020 opt_fontsize_ = rtrim(lexrc.getString());
1024 opt_pagestyle_ = rtrim(lexrc.getString());
1028 if (options_.empty())
1029 options_ = lexrc.getString();
1031 options_ += ',' + lexrc.getString();
1035 class_header_ = subst(lexrc.getString(), """, "\"");
1046 vector<CitationStyle> const & TextClass::getCiteStyles(
1047 CiteEngineType const & type) const
1049 static vector<CitationStyle> empty;
1050 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1051 if (it == cite_styles_.end())
1057 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1059 int const type = readCiteEngineType(lexrc);
1060 bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1061 bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1062 bool defce = (type & ENGINE_TYPE_DEFAULT);
1064 if (rt == CITE_ENGINE) {
1065 // The cite engines are not supposed to overwrite
1066 // CiteStyle defined by the class or a module.
1068 authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1070 numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1072 defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1075 if (rt != CITE_ENGINE && !add) {
1076 // Reset if we defined CiteStyle
1077 // from the class or a module
1079 cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1081 cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1083 cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1087 bool getout = false;
1088 while (!getout && lexrc.isOK()) {
1090 def = lexrc.getString();
1091 def = subst(def, " ", "");
1092 def = subst(def, "\t", "");
1093 if (compare_ascii_no_case(def, "end") == 0) {
1098 char ichar = def[0];
1101 if (isUpperCase(ichar)) {
1102 cs.forceUpperCase = true;
1103 def[0] = lowercase(ichar);
1106 /** For portability reasons (between different
1107 * cite engines such as natbib and biblatex),
1108 * we distinguish between:
1109 * 1. The LyX name as output in the LyX file
1110 * 2. Possible aliases that might fall back to
1111 * the given LyX name in the current engine
1112 * 3. The actual LaTeX command that is output
1113 * (2) and (3) are optional.
1114 * Also, the GUI string for the starred version can
1117 * LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1126 ScanMode mode = LyXName;
1127 ScanMode oldmode = LyXName;
1132 size_t const n = def.size();
1133 for (size_t i = 0; i != n; ++i) {
1137 else if (ichar == '=')
1139 else if (ichar == '<') {
1142 } else if (ichar == '>')
1144 else if (mode == LaTeXCmd)
1146 else if (mode == StarDesc)
1148 else if (ichar == '$')
1149 cs.hasQualifiedList = true;
1150 else if (ichar == '*')
1151 cs.hasStarredVersion = true;
1152 else if (ichar == '[' && cs.textAfter)
1153 cs.textBefore = true;
1154 else if (ichar == '[')
1155 cs.textAfter = true;
1156 else if (ichar != ']') {
1164 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1165 if (!alias.empty()) {
1166 vector<string> const aliases = getVectorFromString(alias);
1167 for (string const &s: aliases)
1168 cite_command_aliases_[s] = lyx_cmd;
1170 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1171 int size = int(stardesc.size());
1173 cs.stardesc = stardescs[0];
1175 cs.startooltip = stardescs[1];
1178 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1180 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1182 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1185 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1187 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1189 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1192 // If we do AddToCiteEngine, do not apply yet,
1193 // except if we have already a style to add something to
1194 bool apply_ay = !add;
1195 bool apply_num = !add;
1196 bool apply_def = !add;
1198 if (type & ENGINE_TYPE_AUTHORYEAR)
1199 apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1200 if (type & ENGINE_TYPE_NUMERICAL)
1201 apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1202 if (type & ENGINE_TYPE_DEFAULT)
1203 apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1206 // Add the styles from AddToCiteEngine to the class' styles
1207 // (but only if they are not yet defined)
1208 for (auto const & cis : class_cite_styles_) {
1209 // Only consider the current CiteEngineType
1210 if (!(type & cis.first))
1212 for (auto const & ciss : cis.second) {
1213 bool defined = false;
1214 // Check if the style "name" is already def'ed
1215 for (auto const & av : getCiteStyles(cis.first))
1216 if (av.name == ciss.name)
1219 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1220 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1221 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1222 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1223 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1224 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1228 if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1229 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1230 if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1231 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1232 if (type & ENGINE_TYPE_DEFAULT && apply_def)
1233 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1238 int TextClass::readCiteEngineType(Lexer & lexrc) const
1240 static_assert(ENGINE_TYPE_DEFAULT ==
1241 (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1242 "Incorrect default engine type");
1243 if (!lexrc.next()) {
1244 lexrc.printError("No cite engine type given for token: `$$Token'.");
1245 return ENGINE_TYPE_DEFAULT;
1247 string const type = rtrim(lexrc.getString());
1248 if (compare_ascii_no_case(type, "authoryear") == 0)
1249 return ENGINE_TYPE_AUTHORYEAR;
1250 else if (compare_ascii_no_case(type, "numerical") == 0)
1251 return ENGINE_TYPE_NUMERICAL;
1252 else if (compare_ascii_no_case(type, "default") != 0) {
1253 string const s = "Unknown cite engine type `" + type
1254 + "' given for token: `$$Token',";
1255 lexrc.printError(s);
1257 return ENGINE_TYPE_DEFAULT;
1261 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1263 int const type = readCiteEngineType(lexrc);
1266 // Cite engine definitions do not overwrite existing
1267 // definitions from the class or a module
1268 bool const overwrite = rt != CITE_ENGINE;
1269 while (lexrc.isOK()) {
1271 etype = lexrc.getString();
1272 if (compare_ascii_no_case(etype, "end") == 0)
1277 definition = lexrc.getString();
1278 char initchar = etype[0];
1279 if (initchar == '#')
1281 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1282 bool defined = false;
1283 bool aydefined = false;
1284 bool numdefined = false;
1285 // Check if the macro is already def'ed
1286 for (auto const & cm : cite_macros_) {
1287 if (!(type & cm.first))
1289 if (cm.second.find(etype) != cm.second.end()) {
1290 if (type == cm.first)
1291 // defined as default or specific type
1293 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1294 // defined for author-year
1296 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1297 // defined for numerical
1301 if (!defined || overwrite) {
1302 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1303 cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1304 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1305 cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1306 if (type == ENGINE_TYPE_DEFAULT)
1307 cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1310 bool defined = false;
1311 bool aydefined = false;
1312 bool numdefined = false;
1313 // Check if the format is already def'ed
1314 for (auto const & cm : cite_formats_) {
1315 if (!(type & cm.first))
1317 if (cm.second.find(etype) != cm.second.end()) {
1318 if (type == cm.first)
1319 // defined as default or specific type
1321 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1322 // defined for author-year
1324 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1325 // defined for numerical
1329 if (!defined || overwrite){
1330 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1331 cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1332 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1333 cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1334 if (type == ENGINE_TYPE_DEFAULT)
1335 cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1343 bool TextClass::readFloat(Lexer & lexrc)
1360 FT_ALLOWED_PLACEMENT,
1366 LexerKeyword floatTags[] = {
1367 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1368 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1369 { "allowswide", FT_ALLOWS_WIDE },
1371 { "extension", FT_EXT },
1372 { "guiname", FT_NAME },
1373 { "htmlattr", FT_HTMLATTR },
1374 { "htmlstyle", FT_HTMLSTYLE },
1375 { "htmltag", FT_HTMLTAG },
1376 { "ispredefined", FT_PREDEFINED },
1377 { "listcommand", FT_LISTCOMMAND },
1378 { "listname", FT_LISTNAME },
1379 { "numberwithin", FT_WITHIN },
1380 { "placement", FT_PLACEMENT },
1381 { "refprefix", FT_REFPREFIX },
1382 { "style", FT_STYLE },
1383 { "type", FT_TYPE },
1384 { "usesfloatpkg", FT_USESFLOAT }
1387 lexrc.pushTable(floatTags);
1391 docstring htmlstyle;
1397 string allowed_placement = "!htbpH";
1402 bool usesfloat = true;
1403 bool ispredefined = false;
1404 bool allowswide = true;
1405 bool allowssideways = true;
1407 bool getout = false;
1408 while (!getout && lexrc.isOK()) {
1409 int le = lexrc.lex();
1411 case Lexer::LEX_UNDEF:
1412 lexrc.printError("Unknown float tag `$$Token'");
1420 type = lexrc.getString();
1421 if (floatlist_.typeExist(type)) {
1422 Floating const & fl = floatlist_.getType(type);
1423 placement = fl.placement();
1425 within = fl.within();
1428 listname = fl.listName();
1429 usesfloat = fl.usesFloatPkg();
1430 ispredefined = fl.isPredefined();
1431 listcommand = fl.listCommand();
1432 refprefix = fl.refPrefix();
1437 name = lexrc.getString();
1441 placement = lexrc.getString();
1443 case FT_ALLOWED_PLACEMENT:
1445 allowed_placement = lexrc.getString();
1449 ext = lexrc.getString();
1453 within = lexrc.getString();
1454 if (within == "none")
1459 style = lexrc.getString();
1461 case FT_LISTCOMMAND:
1463 listcommand = lexrc.getString();
1467 refprefix = lexrc.getString();
1471 listname = lexrc.getString();
1475 usesfloat = lexrc.getBool();
1479 ispredefined = lexrc.getBool();
1481 case FT_ALLOWS_SIDEWAYS:
1483 allowssideways = lexrc.getBool();
1485 case FT_ALLOWS_WIDE:
1487 allowswide = lexrc.getBool();
1491 htmlattr = lexrc.getString();
1495 htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1499 htmltag = lexrc.getString();
1509 // Here we have a full float if getout == true
1511 if (!usesfloat && listcommand.empty()) {
1512 // if this float uses the same auxfile as an existing one,
1513 // there is no need for it to provide a list command.
1514 FloatList::const_iterator it = floatlist_.begin();
1515 FloatList::const_iterator en = floatlist_.end();
1516 bool found_ext = false;
1517 for (; it != en; ++it) {
1518 if (it->second.ext() == ext) {
1524 LYXERR0("The layout does not provide a list command " <<
1525 "for the float `" << type << "'. LyX will " <<
1526 "not be able to produce a float list.");
1528 Floating fl(type, placement, ext, within, style, name,
1529 listname, listcommand, refprefix, allowed_placement,
1530 htmltag, htmlattr, htmlstyle, usesfloat, ispredefined,
1531 allowswide, allowssideways);
1532 floatlist_.newFloat(fl);
1533 // each float has its own counter
1534 counters_.newCounter(from_ascii(type), from_ascii(within),
1535 docstring(), docstring());
1536 // also define sub-float counters
1537 docstring const subtype = "sub-" + from_ascii(type);
1538 counters_.newCounter(subtype, from_ascii(type),
1539 "\\alph{" + subtype + "}", docstring());
1545 bool TextClass::readOutlinerName(Lexer & lexrc)
1550 type = lexrc.getString();
1552 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1556 name = lexrc.getDocString();
1558 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1561 outliner_names_[type] = name;
1566 string const & TextClass::prerequisites(string const & sep) const
1568 if (contains(prerequisites_, ',')) {
1569 vector<string> const pres = getVectorFromString(prerequisites_);
1570 prerequisites_ = getStringFromVector(pres, sep);
1572 return prerequisites_;
1576 bool TextClass::hasLayout(docstring const & n) const
1578 docstring const name = n.empty() ? defaultLayoutName() : n;
1580 return find_if(layoutlist_.begin(), layoutlist_.end(),
1581 LayoutNamesEqual(name))
1582 != layoutlist_.end();
1586 bool TextClass::hasInsetLayout(docstring const & n) const
1590 InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1591 return it != insetlayoutlist_.end();
1595 Layout const & TextClass::operator[](docstring const & name) const
1597 LATTEST(!name.empty());
1600 find_if(begin(), end(), LayoutNamesEqual(name));
1603 LYXERR0("We failed to find the layout '" << name
1604 << "' in the layout list. You MUST investigate!");
1605 for (const_iterator cit = begin(); cit != end(); ++cit)
1606 lyxerr << " " << to_utf8(cit->name()) << endl;
1608 // We require the name to exist
1609 static const Layout dummy;
1610 LASSERT(false, return dummy);
1617 Layout & TextClass::operator[](docstring const & name)
1619 LATTEST(!name.empty());
1620 // Safe to continue, given what we do below.
1622 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1625 LYXERR0("We failed to find the layout '" << to_utf8(name)
1626 << "' in the layout list. You MUST investigate!");
1627 for (const_iterator cit = begin(); cit != end(); ++cit)
1628 LYXERR0(" " << to_utf8(cit->name()));
1630 // we require the name to exist
1632 // we are here only in release mode
1633 layoutlist_.push_back(createBasicLayout(name, true));
1634 it = find_if(begin(), end(), LayoutNamesEqual(name));
1641 bool TextClass::deleteLayout(docstring const & name)
1643 if (name == defaultLayoutName() || name == plainLayoutName())
1646 LayoutList::iterator it =
1647 remove_if(layoutlist_.begin(), layoutlist_.end(),
1648 LayoutNamesEqual(name));
1650 LayoutList::iterator end = layoutlist_.end();
1651 bool const ret = (it != end);
1652 layoutlist_.erase(it, end);
1657 bool TextClass::deleteInsetLayout(docstring const & name)
1659 return insetlayoutlist_.erase(name);
1663 // Load textclass info if not loaded yet
1664 bool TextClass::load(string const & path) const
1669 // Read style-file, provided path is searched before the system ones
1670 // If path is a file, it is loaded directly.
1671 FileName layout_file(path);
1672 if (!path.empty() && !layout_file.isReadableFile())
1673 layout_file = FileName(addName(path, name_ + ".layout"));
1674 if (layout_file.empty() || !layout_file.exists())
1675 layout_file = libFileSearch("layouts", name_, "layout");
1676 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1679 lyxerr << "Error reading `"
1680 << to_utf8(makeDisplayPath(layout_file.absFileName()))
1681 << "'\n(Check `" << name_
1682 << "')\nCheck your installation and "
1683 "try Options/Reconfigure..."
1691 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1696 layoutlist_.push_back(createBasicLayout(n, true));
1701 string DocumentClass::forcedLayouts() const
1705 const_iterator const e = end();
1706 for (const_iterator i = begin(); i != e; ++i) {
1707 if (i->forcelocal > 0) {
1709 os << "Format " << LAYOUT_FORMAT << '\n';
1719 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1721 // FIXME The fix for the InsetLayout part of 4812 would be here:
1722 // Add the InsetLayout to the document class if it is not found.
1724 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1725 while (!n.empty()) {
1726 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1727 if (cit != cen && cit->first == n) {
1728 if (cit->second.obsoleted_by().empty())
1730 n = cit->second.obsoleted_by();
1731 return insetLayout(n);
1733 // If we have a generic prefix (e.g., "Note:"),
1734 // try if this one alone is found.
1735 size_t i = n.find(':');
1736 if (i == string::npos)
1740 // Layout "name" not found.
1741 return plainInsetLayout();
1745 InsetLayout const & DocumentClass::plainInsetLayout() {
1746 static const InsetLayout plain_insetlayout_;
1747 return plain_insetlayout_;
1751 docstring const & TextClass::defaultLayoutName() const
1753 return defaultlayout_;
1757 Layout const & TextClass::defaultLayout() const
1759 return operator[](defaultLayoutName());
1763 bool TextClass::isDefaultLayout(Layout const & layout) const
1765 return layout.name() == defaultLayoutName();
1769 bool TextClass::isPlainLayout(Layout const & layout) const
1771 return layout.name() == plainLayoutName();
1775 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1777 static Layout * defaultLayout = NULL;
1779 if (defaultLayout) {
1780 defaultLayout->setUnknown(unknown);
1781 defaultLayout->setName(name);
1782 return *defaultLayout;
1785 static char const * s = "Margin Static\n"
1786 "LatexType Paragraph\n"
1789 "AlignPossible Left, Right, Center\n"
1790 "LabelType No_Label\n"
1792 istringstream ss(s);
1793 Lexer lex(textClassTags);
1795 defaultLayout = new Layout;
1796 defaultLayout->setUnknown(unknown);
1797 defaultLayout->setName(name);
1798 if (!readStyle(lex, *defaultLayout)) {
1799 // The only way this happens is because the hardcoded layout above
1803 return *defaultLayout;
1807 DocumentClassPtr getDocumentClass(
1808 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1809 string const & cengine, bool const clone)
1811 DocumentClassPtr doc_class =
1812 DocumentClassPtr(new DocumentClass(baseClass));
1813 LayoutModuleList::const_iterator it = modlist.begin();
1814 LayoutModuleList::const_iterator en = modlist.end();
1815 for (; it != en; ++it) {
1816 string const modName = *it;
1817 LyXModule * lm = theModuleList[modName];
1819 docstring const msg =
1820 bformat(_("The module %1$s has been requested by\n"
1821 "this document but has not been found in the list of\n"
1822 "available modules. If you recently installed it, you\n"
1823 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1825 frontend::Alert::warning(_("Module not available"), msg);
1828 if (!lm->isAvailable() && !clone) {
1829 docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1830 docstring const msg =
1831 bformat(_("The module %1$s requires a package that is not\n"
1832 "available in your LaTeX installation, or a converter that\n"
1833 "you have not installed. LaTeX output may not be possible.\n"
1834 "Missing prerequisites:\n"
1836 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1837 from_utf8(modName), prereqs);
1838 frontend::Alert::warning(_("Package not available"), msg, true);
1840 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1841 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1842 docstring const msg =
1843 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1844 frontend::Alert::warning(_("Read Error"), msg);
1848 if (cengine.empty())
1851 LyXCiteEngine * ce = theCiteEnginesList[cengine];
1853 docstring const msg =
1854 bformat(_("The cite engine %1$s has been requested by\n"
1855 "this document but has not been found in the list of\n"
1856 "available engines. If you recently installed it, you\n"
1857 "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1859 frontend::Alert::warning(_("Cite Engine not available"), msg);
1860 } else if (!ce->isAvailable() && !clone) {
1861 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1862 docstring const msg =
1863 bformat(_("The cite engine %1$s requires a package that is not\n"
1864 "available in your LaTeX installation, or a converter that\n"
1865 "you have not installed. LaTeX output may not be possible.\n"
1866 "Missing prerequisites:\n"
1868 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1869 from_utf8(cengine), prereqs);
1870 frontend::Alert::warning(_("Package not available"), msg, true);
1872 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1873 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1874 docstring const msg =
1875 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1876 frontend::Alert::warning(_("Read Error"), msg);
1884 /////////////////////////////////////////////////////////////////////////
1888 /////////////////////////////////////////////////////////////////////////
1890 DocumentClass::DocumentClass(LayoutFile const & tc)
1895 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1897 LayoutList::const_iterator it = layoutlist_.begin();
1898 LayoutList::const_iterator end = layoutlist_.end();
1899 for (; it != end; ++it)
1900 if (it->latexname() == lay)
1906 bool DocumentClass::provides(string const & p) const
1908 return provides_.find(p) != provides_.end();
1912 bool DocumentClass::hasTocLevels() const
1914 return min_toclevel_ != Layout::NOT_IN_TOC;
1918 Layout const & DocumentClass::getTOCLayout() const
1920 // we're going to look for the layout with the minimum toclevel
1921 TextClass::LayoutList::const_iterator lit = begin();
1922 TextClass::LayoutList::const_iterator const len = end();
1923 int minlevel = 1000;
1924 Layout const * lay = NULL;
1925 for (; lit != len; ++lit) {
1926 int const level = lit->toclevel;
1927 // we don't want Part or unnumbered sections
1928 if (level == Layout::NOT_IN_TOC || level < 0
1929 || level >= minlevel || lit->counter.empty())
1936 // hmm. that is very odd, so we'll do our best.
1937 return operator[](defaultLayoutName());
1941 Layout const & DocumentClass::htmlTOCLayout() const
1943 if (html_toc_section_.empty())
1944 html_toc_section_ = getTOCLayout().name();
1945 return operator[](html_toc_section_);
1949 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1950 string const & entry, bool const punct, string const & fallback) const
1952 string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}"
1953 "\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]]"
1954 "[[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1956 default_format += ".";
1958 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
1959 if (itype == cite_formats_.end())
1960 return default_format;
1961 map<string, string>::const_iterator it = itype->second.find(entry);
1962 if (it == itype->second.end() && !fallback.empty())
1963 it = itype->second.find(fallback);
1964 if (it == itype->second.end())
1965 return default_format;
1967 return it->second + ".";
1972 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
1973 string const & macro) const
1975 static string empty;
1976 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
1977 if (itype == cite_macros_.end())
1979 map<string, string>::const_iterator it = itype->second.find(macro);
1980 if (it == itype->second.end())
1986 vector<string> const DocumentClass::citeCommands(
1987 CiteEngineType const & type) const
1989 vector<CitationStyle> const styles = citeStyles(type);
1990 vector<CitationStyle>::const_iterator it = styles.begin();
1991 vector<CitationStyle>::const_iterator end = styles.end();
1992 vector<string> cmds;
1993 for (; it != end; ++it) {
1994 CitationStyle const cite = *it;
1995 cmds.push_back(cite.name);
2001 vector<CitationStyle> const & DocumentClass::citeStyles(
2002 CiteEngineType const & type) const
2004 static vector<CitationStyle> empty;
2005 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
2006 if (it == cite_styles_.end())
2012 /////////////////////////////////////////////////////////////////////////
2016 /////////////////////////////////////////////////////////////////////////
2018 ostream & operator<<(ostream & os, PageSides p)