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 = 76; // spitz: BibInToc
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), bibintoc_(false)
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,
237 LexerKeyword textClassTags[] = {
238 { "addtociteengine", TC_ADDTOCITEENGINE },
239 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
240 { "addtohtmlstyles", TC_ADDTOHTMLSTYLES },
241 { "addtopreamble", TC_ADDTOPREAMBLE },
242 { "bibintoc", TC_BIBINTOC },
243 { "citeengine", TC_CITEENGINE },
244 { "citeenginetype", TC_CITEENGINETYPE },
245 { "citeformat", TC_CITEFORMAT },
246 { "citeframework", TC_CITEFRAMEWORK },
247 { "classoptions", TC_CLASSOPTIONS },
248 { "columns", TC_COLUMNS },
249 { "counter", TC_COUNTER },
250 { "defaultbiblio", TC_DEFAULTBIBLIO },
251 { "defaultfont", TC_DEFAULTFONT },
252 { "defaultmodule", TC_DEFAULTMODULE },
253 { "defaultstyle", TC_DEFAULTSTYLE },
254 { "excludesmodule", TC_EXCLUDESMODULE },
255 { "float", TC_FLOAT },
256 { "format", TC_FORMAT },
257 { "fullauthorlist", TC_FULLAUTHORLIST },
258 { "htmlpreamble", TC_HTMLPREAMBLE },
259 { "htmlstyles", TC_HTMLSTYLES },
260 { "htmltocsection", TC_HTMLTOCSECTION },
261 { "ifcounter", TC_IFCOUNTER },
262 { "input", TC_INPUT },
263 { "insetlayout", TC_INSETLAYOUT },
264 { "leftmargin", TC_LEFTMARGIN },
265 { "maxcitenames", TC_MAXCITENAMES },
266 { "modifystyle", TC_MODIFYSTYLE },
267 { "nocounter", TC_NOCOUNTER },
268 { "nofloat", TC_NOFLOAT },
269 { "noinsetlayout", TC_NOINSETLAYOUT },
270 { "nostyle", TC_NOSTYLE },
271 { "outlinername", TC_OUTLINERNAME },
272 { "outputformat", TC_OUTPUTFORMAT },
273 { "outputtype", TC_OUTPUTTYPE },
274 { "packageoptions", TC_PKGOPTS },
275 { "pagestyle", TC_PAGESTYLE },
276 { "preamble", TC_PREAMBLE },
277 { "provides", TC_PROVIDES },
278 { "providesmodule", TC_PROVIDESMODULE },
279 { "providestyle", TC_PROVIDESTYLE },
280 { "requires", TC_REQUIRES },
281 { "rightmargin", TC_RIGHTMARGIN },
282 { "secnumdepth", TC_SECNUMDEPTH },
283 { "sides", TC_SIDES },
284 { "style", TC_STYLE },
285 { "tablestyle", TC_TABLESTYLE },
286 { "titlelatexname", TC_TITLELATEXNAME },
287 { "titlelatextype", TC_TITLELATEXTYPE },
288 { "tocdepth", TC_TOCDEPTH }
294 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
296 LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
297 TempFile tmp("convertXXXXXX.layout");
298 FileName const tempfile = tmp.name();
299 bool success = layout2layout(filename, tempfile);
301 success = readWithoutConv(tempfile, rt) == OK;
306 std::string TextClass::convert(std::string const & str)
308 TempFile tmp1("localXXXXXX.layout");
309 FileName const fn = tmp1.name();
310 ofstream os(fn.toFilesystemEncoding().c_str());
313 TempFile tmp2("convert_localXXXXXX.layout");
314 FileName const tempfile = tmp2.name();
315 bool success = layout2layout(fn, tempfile, LYXFILE_LAYOUT_FORMAT);
318 ifstream is(tempfile.toFilesystemEncoding().c_str());
330 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
332 if (!filename.isReadableFile()) {
333 lyxerr << "Cannot read layout file `" << filename << "'."
338 LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
339 to_utf8(makeDisplayPath(filename.absFileName())));
341 // Define the plain layout used in table cells, ert, etc. Note that
342 // we do this before loading any layout file, so that classes can
343 // override features of this layout if they should choose to do so.
344 if (rt == BASECLASS && !hasLayout(plain_layout_))
345 layoutlist_.push_back(createBasicLayout(plain_layout_));
347 Lexer lexrc(textClassTags);
348 lexrc.setFile(filename);
349 ReturnValues retval = read(lexrc, rt);
351 LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
352 to_utf8(makeDisplayPath(filename.absFileName())));
358 bool TextClass::read(FileName const & filename, ReadType rt)
360 ReturnValues const retval = readWithoutConv(filename, rt);
361 if (retval != FORMAT_MISMATCH)
364 bool const worx = convertLayoutFormat(filename, rt);
366 LYXERR0 ("Unable to convert " << filename <<
367 " to format " << LAYOUT_FORMAT);
372 TextClass::ReturnValues TextClass::validate(std::string const & str)
375 return tc.read(str, VALIDATION);
379 TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
381 Lexer lexrc(textClassTags);
382 istringstream is(str);
384 ReturnValues retval = read(lexrc, rt);
386 if (retval != FORMAT_MISMATCH)
389 // write the layout string to a temporary file
390 TempFile tmp("TextClass_read");
391 FileName const tempfile = tmp.name();
392 ofstream os(tempfile.toFilesystemEncoding().c_str());
394 LYXERR0("Unable to create temporary file");
400 // now try to convert it to LAYOUT_FORMAT
401 if (!convertLayoutFormat(tempfile, rt)) {
402 LYXERR0("Unable to convert internal layout information to format "
411 // Reads a textclass structure from file.
412 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
417 // The first usable line should be
418 // Format LAYOUT_FORMAT
419 if (lexrc.lex() != TC_FORMAT || !lexrc.next()
420 || lexrc.getInteger() != LAYOUT_FORMAT)
421 return FORMAT_MISMATCH;
425 while (lexrc.isOK() && !error) {
426 int le = lexrc.lex();
429 case Lexer::LEX_FEOF:
432 case Lexer::LEX_UNDEF:
433 lexrc.printError("Unknown TextClass tag `$$Token'");
441 // used below to track whether we are in an IfStyle or IfCounter tag.
442 bool modifystyle = false;
443 bool providestyle = false;
444 bool ifcounter = false;
446 switch (static_cast<TextClassTags>(le)) {
450 lexrc.printError("Duplicate Format directive");
453 case TC_OUTPUTFORMAT:
455 outputFormat_ = lexrc.getString();
456 has_output_format_ = true;
461 readOutputType(lexrc);
462 switch(outputType_) {
464 outputFormat_ = "latex";
467 outputFormat_ = "docbook";
470 outputFormat_ = "literate";
475 case TC_INPUT: // Include file
478 string const inc = lexrc.getString();
479 if (!path().empty() && (prefixIs(inc, "./") ||
480 prefixIs(inc, "../")))
481 tmp = fileSearch(path(), inc, "layout");
483 tmp = libFileSearch("layouts", inc,
487 lexrc.printError("Could not find input file: " + inc);
489 } else if (!read(tmp, MERGE)) {
490 lexrc.printError("Error reading input file: " + tmp.absFileName());
496 case TC_DEFAULTSTYLE:
498 docstring const name = from_utf8(subst(lexrc.getString(),
500 defaultlayout_ = name;
507 case TC_PROVIDESTYLE:
508 // if modifystyle is true, then we got here by falling through
509 // so we are not in an ProvideStyle block
515 lexrc.printError("No name given for style: `$$Token'.");
519 docstring const name = from_utf8(subst(lexrc.getString(),
522 string s = "Could not read name for style: `$$Token' "
523 + lexrc.getString() + " is probably not valid UTF-8!";
526 // Since we couldn't read the name, we just scan the rest
527 // of the style and discard it.
528 error = !readStyle(lexrc, lay);
532 bool const have_layout = hasLayout(name);
534 // If the layout already exists, then we want to add it to
535 // the existing layout, as long as we are not in an ProvideStyle
537 if (have_layout && !providestyle) {
538 Layout & lay = operator[](name);
539 error = !readStyle(lexrc, lay);
541 // If the layout does not exist, then we want to create a new
542 // one, but not if we are in a ModifyStyle block.
543 else if (!have_layout && !modifystyle) {
545 layout.setName(name);
546 error = !readStyle(lexrc, layout);
548 layoutlist_.push_back(layout);
550 if (defaultlayout_.empty()) {
551 // We do not have a default layout yet, so we choose
552 // the first layout we encounter.
553 defaultlayout_ = name;
556 // There are two ways to get here:
557 // (i) The layout exists but we are in an ProvideStyle block
558 // (ii) The layout doesn't exist, but we are in an ModifyStyle
560 // Either way, we just scan the rest and discard it
563 // signal to coverity that we do not care about the result
564 (void)readStyle(lexrc, lay);
571 docstring const style = from_utf8(subst(lexrc.getString(),
573 if (!deleteLayout(style))
574 lyxerr << "Cannot delete style `"
575 << to_utf8(style) << '\'' << endl;
579 case TC_NOINSETLAYOUT:
581 docstring const style = from_utf8(subst(lexrc.getString(),
583 if (!deleteInsetLayout(style))
584 LYXERR0("Style `" << style << "' cannot be removed\n"
585 "because it was not found!");
591 columns_ = lexrc.getInteger();
596 switch (lexrc.getInteger()) {
597 case 1: sides_ = OneSide; break;
598 case 2: sides_ = TwoSides; break;
600 lyxerr << "Impossible number of page"
601 " sides, setting to one."
611 pagestyle_ = rtrim(lexrc.getString());
615 defaultfont_ = lyxRead(lexrc);
616 if (!defaultfont_.resolved()) {
617 lexrc.printError("Warning: defaultfont should "
618 "be fully instantiated!");
619 defaultfont_.realize(sane_font);
625 secnumdepth_ = lexrc.getInteger();
630 tocdepth_ = lexrc.getInteger();
633 // First step to support options
634 case TC_CLASSOPTIONS:
635 readClassOptions(lexrc);
639 preamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
642 case TC_HTMLPREAMBLE:
643 htmlpreamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
647 htmlstyles_ = lexrc.getLongString(from_ascii("EndStyles"));
650 case TC_HTMLTOCSECTION:
651 html_toc_section_ = from_utf8(trim(lexrc.getString()));
654 case TC_ADDTOPREAMBLE:
655 preamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
658 case TC_ADDTOHTMLPREAMBLE:
659 htmlpreamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
662 case TC_ADDTOHTMLSTYLES:
663 htmlstyles_ += lexrc.getLongString(from_ascii("EndStyles"));
668 string const feature = lexrc.getString();
670 if (lexrc.getInteger())
671 provides_.insert(feature);
673 provides_.erase(feature);
679 vector<string> const req
680 = getVectorFromString(lexrc.getString());
681 requires_.insert(req.begin(), req.end());
687 string const pkg = lexrc.getString();
689 string const options = lexrc.getString();
690 package_options_[pkg] = options;
694 case TC_DEFAULTMODULE: {
696 string const module = lexrc.getString();
697 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
698 default_modules_.push_back(module);
702 case TC_PROVIDESMODULE: {
704 string const module = lexrc.getString();
705 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
706 provided_modules_.push_back(module);
710 case TC_EXCLUDESMODULE: {
712 string const module = lexrc.getString();
713 // modules already have their own way to exclude other modules
715 LYXERR0("ExcludesModule tag cannot be used in a module!");
718 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
719 excluded_modules_.push_back(module);
723 case TC_LEFTMARGIN: // left margin type
725 leftmargin_ = lexrc.getDocString();
728 case TC_RIGHTMARGIN: // right margin type
730 rightmargin_ = lexrc.getDocString();
733 case TC_INSETLAYOUT: {
735 lexrc.printError("No name given for InsetLayout: `$$Token'.");
739 docstring const name = subst(lexrc.getDocString(), '_', ' ');
741 string s = "Could not read name for InsetLayout: `$$Token' "
742 + lexrc.getString() + " is probably not valid UTF-8!";
745 // Since we couldn't read the name, we just scan the rest
746 // of the style and discard it.
747 il.read(lexrc, *this);
748 // Let's try to continue rather than abort.
750 } else if (hasInsetLayout(name)) {
751 InsetLayout & il = insetlayoutlist_[name];
752 error = !il.read(lexrc, *this);
756 error = !il.read(lexrc, *this);
758 insetlayoutlist_[name] = il;
764 error = !readFloat(lexrc);
768 error = !readCiteEngine(lexrc, rt);
771 case TC_ADDTOCITEENGINE:
772 error = !readCiteEngine(lexrc, rt, true);
775 case TC_CITEENGINETYPE:
777 opt_enginetype_ = rtrim(lexrc.getString());
781 error = !readCiteFormat(lexrc, rt);
784 case TC_CITEFRAMEWORK:
786 citeframework_ = rtrim(lexrc.getString());
789 case TC_MAXCITENAMES:
791 maxcitenames_ = size_t(lexrc.getInteger());
794 case TC_DEFAULTBIBLIO:
796 vector<string> const dbs =
797 getVectorFromString(rtrim(lexrc.getString()), "|");
798 vector<string>::const_iterator it = dbs.begin();
799 vector<string>::const_iterator end = dbs.end();
800 for (; it != end; ++it) {
801 if (!contains(*it, ':')) {
802 vector<string> const enginetypes =
803 getVectorFromString(opt_enginetype_, "|");
804 for (string const &s: enginetypes)
805 cite_default_biblio_style_[s] = *it;
808 string const db = split(*it, eng, ':');
809 cite_default_biblio_style_[eng] = db;
817 bibintoc_ = lexrc.getBool();
820 case TC_FULLAUTHORLIST:
822 cite_full_author_list_ &= lexrc.getBool();
827 docstring const cnt = lexrc.getDocString();
828 if (!counters_.remove(cnt))
829 LYXERR0("Unable to remove counter: " + to_utf8(cnt));
838 docstring const name = lexrc.getDocString();
840 string s = "Could not read name for counter: `$$Token' "
841 + lexrc.getString() + " is probably not valid UTF-8!";
842 lexrc.printError(s.c_str());
844 // Since we couldn't read the name, we just scan the rest
848 error = !counters_.read(lexrc, name, !ifcounter);
851 lexrc.printError("No name given for style: `$$Token'.");
856 case TC_TITLELATEXTYPE:
857 readTitleType(lexrc);
860 case TC_TITLELATEXNAME:
862 titlename_ = lexrc.getString();
867 string const nofloat = lexrc.getString();
868 floatlist_.erase(nofloat);
872 case TC_OUTLINERNAME:
873 error = !readOutlinerName(lexrc);
878 tablestyle_ = rtrim(lexrc.getString());
883 // at present, we abort if we encounter an error,
884 // so there is no point continuing.
891 if (defaultlayout_.empty()) {
892 LYXERR0("Error: Textclass '" << name_
893 << "' is missing a defaultstyle.");
897 // Try to erase "stdinsets" from the provides_ set.
899 // Provides stdinsets 1
900 // declaration simply tells us that the standard insets have been
901 // defined. (It's found in stdinsets.inc but could also be used in
902 // user-defined files.) There isn't really any such package. So we
903 // might as well go ahead and erase it.
904 // If we do not succeed, then it was not there, which means that
905 // the textclass did not provide the definitions of the standard
906 // insets. So we need to try to load them.
907 int erased = provides_.erase("stdinsets");
909 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
912 frontend::Alert::warning(_("Missing File"),
913 _("Could not find stdinsets.inc! This may lead to data loss!"));
915 } else if (!read(tmp, MERGE)) {
916 frontend::Alert::warning(_("Corrupt File"),
917 _("Could not read stdinsets.inc! This may lead to data loss!"));
922 min_toclevel_ = Layout::NOT_IN_TOC;
923 max_toclevel_ = Layout::NOT_IN_TOC;
924 const_iterator lit = begin();
925 const_iterator len = end();
926 for (; lit != len; ++lit) {
927 int const toclevel = lit->toclevel;
928 if (toclevel != Layout::NOT_IN_TOC) {
929 if (min_toclevel_ == Layout::NOT_IN_TOC)
930 min_toclevel_ = toclevel;
932 min_toclevel_ = min(min_toclevel_, toclevel);
933 max_toclevel_ = max(max_toclevel_, toclevel);
936 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
937 << ", maximum is " << max_toclevel_);
939 return (error ? ERROR : OK);
943 void TextClass::readTitleType(Lexer & lexrc)
945 LexerKeyword titleTypeTags[] = {
946 { "commandafter", TITLE_COMMAND_AFTER },
947 { "environment", TITLE_ENVIRONMENT }
950 PushPopHelper pph(lexrc, titleTypeTags);
952 int le = lexrc.lex();
954 case Lexer::LEX_UNDEF:
955 lexrc.printError("Unknown output type `$$Token'");
957 case TITLE_COMMAND_AFTER:
958 case TITLE_ENVIRONMENT:
959 titletype_ = static_cast<TitleLatexType>(le);
962 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
968 void TextClass::readOutputType(Lexer & lexrc)
970 LexerKeyword outputTypeTags[] = {
971 { "docbook", DOCBOOK },
973 { "literate", LITERATE }
976 PushPopHelper pph(lexrc, outputTypeTags);
978 int le = lexrc.lex();
980 case Lexer::LEX_UNDEF:
981 lexrc.printError("Unknown output type `$$Token'");
986 outputType_ = static_cast<OutputType>(le);
989 LYXERR0("Unhandled value " << le);
995 void TextClass::readClassOptions(Lexer & lexrc)
1005 LexerKeyword classOptionsTags[] = {
1007 {"fontsize", CO_FONTSIZE },
1008 {"header", CO_HEADER },
1009 {"other", CO_OTHER },
1010 {"pagestyle", CO_PAGESTYLE }
1013 lexrc.pushTable(classOptionsTags);
1014 bool getout = false;
1015 while (!getout && lexrc.isOK()) {
1016 int le = lexrc.lex();
1018 case Lexer::LEX_UNDEF:
1019 lexrc.printError("Unknown ClassOption tag `$$Token'");
1027 opt_fontsize_ = rtrim(lexrc.getString());
1031 opt_pagestyle_ = rtrim(lexrc.getString());
1035 if (options_.empty())
1036 options_ = lexrc.getString();
1038 options_ += ',' + lexrc.getString();
1042 class_header_ = subst(lexrc.getString(), """, "\"");
1053 vector<CitationStyle> const & TextClass::getCiteStyles(
1054 CiteEngineType const & type) const
1056 static vector<CitationStyle> empty;
1057 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1058 if (it == cite_styles_.end())
1064 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1066 int const type = readCiteEngineType(lexrc);
1067 bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1068 bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1069 bool defce = (type & ENGINE_TYPE_DEFAULT);
1071 if (rt == CITE_ENGINE) {
1072 // The cite engines are not supposed to overwrite
1073 // CiteStyle defined by the class or a module.
1075 authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1077 numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1079 defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1082 if (rt != CITE_ENGINE && !add) {
1083 // Reset if we defined CiteStyle
1084 // from the class or a module
1086 cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1088 cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1090 cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1094 bool getout = false;
1095 while (!getout && lexrc.isOK()) {
1097 def = lexrc.getString();
1098 def = subst(def, " ", "");
1099 def = subst(def, "\t", "");
1100 if (compare_ascii_no_case(def, "end") == 0) {
1105 char ichar = def[0];
1108 if (isUpperCase(ichar)) {
1109 cs.forceUpperCase = true;
1110 def[0] = lowercase(ichar);
1113 /** For portability reasons (between different
1114 * cite engines such as natbib and biblatex),
1115 * we distinguish between:
1116 * 1. The LyX name as output in the LyX file
1117 * 2. Possible aliases that might fall back to
1118 * the given LyX name in the current engine
1119 * 3. The actual LaTeX command that is output
1120 * (2) and (3) are optional.
1121 * Also, the GUI string for the starred version can
1124 * LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1133 ScanMode mode = LyXName;
1134 ScanMode oldmode = LyXName;
1139 size_t const n = def.size();
1140 for (size_t i = 0; i != n; ++i) {
1144 else if (ichar == '=')
1146 else if (ichar == '<') {
1149 } else if (ichar == '>')
1151 else if (mode == LaTeXCmd)
1153 else if (mode == StarDesc)
1155 else if (ichar == '$')
1156 cs.hasQualifiedList = true;
1157 else if (ichar == '*')
1158 cs.hasStarredVersion = true;
1159 else if (ichar == '[' && cs.textAfter)
1160 cs.textBefore = true;
1161 else if (ichar == '[')
1162 cs.textAfter = true;
1163 else if (ichar != ']') {
1171 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1172 if (!alias.empty()) {
1173 vector<string> const aliases = getVectorFromString(alias);
1174 for (string const &s: aliases)
1175 cite_command_aliases_[s] = lyx_cmd;
1177 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1178 int size = int(stardesc.size());
1180 cs.stardesc = stardescs[0];
1182 cs.startooltip = stardescs[1];
1185 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1187 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1189 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1192 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1194 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1196 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1199 // If we do AddToCiteEngine, do not apply yet,
1200 // except if we have already a style to add something to
1201 bool apply_ay = !add;
1202 bool apply_num = !add;
1203 bool apply_def = !add;
1205 if (type & ENGINE_TYPE_AUTHORYEAR)
1206 apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1207 if (type & ENGINE_TYPE_NUMERICAL)
1208 apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1209 if (type & ENGINE_TYPE_DEFAULT)
1210 apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1213 // Add the styles from AddToCiteEngine to the class' styles
1214 // (but only if they are not yet defined)
1215 for (auto const & cis : class_cite_styles_) {
1216 // Only consider the current CiteEngineType
1217 if (!(type & cis.first))
1219 for (auto const & ciss : cis.second) {
1220 bool defined = false;
1221 // Check if the style "name" is already def'ed
1222 for (auto const & av : getCiteStyles(cis.first))
1223 if (av.name == ciss.name)
1226 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1227 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1228 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1229 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1230 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1231 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1235 if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1236 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1237 if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1238 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1239 if (type & ENGINE_TYPE_DEFAULT && apply_def)
1240 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1245 int TextClass::readCiteEngineType(Lexer & lexrc) const
1247 static_assert(ENGINE_TYPE_DEFAULT ==
1248 (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1249 "Incorrect default engine type");
1250 if (!lexrc.next()) {
1251 lexrc.printError("No cite engine type given for token: `$$Token'.");
1252 return ENGINE_TYPE_DEFAULT;
1254 string const type = rtrim(lexrc.getString());
1255 if (compare_ascii_no_case(type, "authoryear") == 0)
1256 return ENGINE_TYPE_AUTHORYEAR;
1257 else if (compare_ascii_no_case(type, "numerical") == 0)
1258 return ENGINE_TYPE_NUMERICAL;
1259 else if (compare_ascii_no_case(type, "default") != 0) {
1260 string const s = "Unknown cite engine type `" + type
1261 + "' given for token: `$$Token',";
1262 lexrc.printError(s);
1264 return ENGINE_TYPE_DEFAULT;
1268 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1270 int const type = readCiteEngineType(lexrc);
1273 // Cite engine definitions do not overwrite existing
1274 // definitions from the class or a module
1275 bool const overwrite = rt != CITE_ENGINE;
1276 while (lexrc.isOK()) {
1278 etype = lexrc.getString();
1279 if (compare_ascii_no_case(etype, "end") == 0)
1284 definition = lexrc.getString();
1285 char initchar = etype[0];
1286 if (initchar == '#')
1288 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1289 bool defined = false;
1290 bool aydefined = false;
1291 bool numdefined = false;
1292 // Check if the macro is already def'ed
1293 for (auto const & cm : cite_macros_) {
1294 if (!(type & cm.first))
1296 if (cm.second.find(etype) != cm.second.end()) {
1297 if (type == cm.first)
1298 // defined as default or specific type
1300 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1301 // defined for author-year
1303 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1304 // defined for numerical
1308 if (!defined || overwrite) {
1309 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1310 cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1311 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1312 cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1313 if (type == ENGINE_TYPE_DEFAULT)
1314 cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1317 bool defined = false;
1318 bool aydefined = false;
1319 bool numdefined = false;
1320 // Check if the format is already def'ed
1321 for (auto const & cm : cite_formats_) {
1322 if (!(type & cm.first))
1324 if (cm.second.find(etype) != cm.second.end()) {
1325 if (type == cm.first)
1326 // defined as default or specific type
1328 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1329 // defined for author-year
1331 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1332 // defined for numerical
1336 if (!defined || overwrite){
1337 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1338 cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1339 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1340 cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1341 if (type == ENGINE_TYPE_DEFAULT)
1342 cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1350 bool TextClass::readFloat(Lexer & lexrc)
1367 FT_ALLOWED_PLACEMENT,
1373 LexerKeyword floatTags[] = {
1374 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1375 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1376 { "allowswide", FT_ALLOWS_WIDE },
1378 { "extension", FT_EXT },
1379 { "guiname", FT_NAME },
1380 { "htmlattr", FT_HTMLATTR },
1381 { "htmlstyle", FT_HTMLSTYLE },
1382 { "htmltag", FT_HTMLTAG },
1383 { "ispredefined", FT_PREDEFINED },
1384 { "listcommand", FT_LISTCOMMAND },
1385 { "listname", FT_LISTNAME },
1386 { "numberwithin", FT_WITHIN },
1387 { "placement", FT_PLACEMENT },
1388 { "refprefix", FT_REFPREFIX },
1389 { "style", FT_STYLE },
1390 { "type", FT_TYPE },
1391 { "usesfloatpkg", FT_USESFLOAT }
1394 lexrc.pushTable(floatTags);
1398 docstring htmlstyle;
1404 string allowed_placement = "!htbpH";
1409 bool usesfloat = true;
1410 bool ispredefined = false;
1411 bool allowswide = true;
1412 bool allowssideways = true;
1414 bool getout = false;
1415 while (!getout && lexrc.isOK()) {
1416 int le = lexrc.lex();
1418 case Lexer::LEX_UNDEF:
1419 lexrc.printError("Unknown float tag `$$Token'");
1427 type = lexrc.getString();
1428 if (floatlist_.typeExist(type)) {
1429 Floating const & fl = floatlist_.getType(type);
1430 placement = fl.placement();
1432 within = fl.within();
1435 listname = fl.listName();
1436 usesfloat = fl.usesFloatPkg();
1437 ispredefined = fl.isPredefined();
1438 listcommand = fl.listCommand();
1439 refprefix = fl.refPrefix();
1444 name = lexrc.getString();
1448 placement = lexrc.getString();
1450 case FT_ALLOWED_PLACEMENT:
1452 allowed_placement = lexrc.getString();
1456 ext = lexrc.getString();
1460 within = lexrc.getString();
1461 if (within == "none")
1466 style = lexrc.getString();
1468 case FT_LISTCOMMAND:
1470 listcommand = lexrc.getString();
1474 refprefix = lexrc.getString();
1478 listname = lexrc.getString();
1482 usesfloat = lexrc.getBool();
1486 ispredefined = lexrc.getBool();
1488 case FT_ALLOWS_SIDEWAYS:
1490 allowssideways = lexrc.getBool();
1492 case FT_ALLOWS_WIDE:
1494 allowswide = lexrc.getBool();
1498 htmlattr = lexrc.getString();
1502 htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1506 htmltag = lexrc.getString();
1516 // Here we have a full float if getout == true
1518 if (!usesfloat && listcommand.empty()) {
1519 // if this float uses the same auxfile as an existing one,
1520 // there is no need for it to provide a list command.
1521 FloatList::const_iterator it = floatlist_.begin();
1522 FloatList::const_iterator en = floatlist_.end();
1523 bool found_ext = false;
1524 for (; it != en; ++it) {
1525 if (it->second.ext() == ext) {
1531 LYXERR0("The layout does not provide a list command " <<
1532 "for the float `" << type << "'. LyX will " <<
1533 "not be able to produce a float list.");
1535 Floating fl(type, placement, ext, within, style, name,
1536 listname, listcommand, refprefix, allowed_placement,
1537 htmltag, htmlattr, htmlstyle, usesfloat, ispredefined,
1538 allowswide, allowssideways);
1539 floatlist_.newFloat(fl);
1540 // each float has its own counter
1541 counters_.newCounter(from_ascii(type), from_ascii(within),
1542 docstring(), docstring());
1543 // also define sub-float counters
1544 docstring const subtype = "sub-" + from_ascii(type);
1545 counters_.newCounter(subtype, from_ascii(type),
1546 "\\alph{" + subtype + "}", docstring());
1552 bool TextClass::readOutlinerName(Lexer & lexrc)
1557 type = lexrc.getString();
1559 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1563 name = lexrc.getDocString();
1565 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1568 outliner_names_[type] = name;
1573 string const & TextClass::prerequisites(string const & sep) const
1575 if (contains(prerequisites_, ',')) {
1576 vector<string> const pres = getVectorFromString(prerequisites_);
1577 prerequisites_ = getStringFromVector(pres, sep);
1579 return prerequisites_;
1583 bool TextClass::hasLayout(docstring const & n) const
1585 docstring const name = n.empty() ? defaultLayoutName() : n;
1587 return find_if(layoutlist_.begin(), layoutlist_.end(),
1588 LayoutNamesEqual(name))
1589 != layoutlist_.end();
1593 bool TextClass::hasInsetLayout(docstring const & n) const
1597 InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1598 return it != insetlayoutlist_.end();
1602 Layout const & TextClass::operator[](docstring const & name) const
1604 LATTEST(!name.empty());
1607 find_if(begin(), end(), LayoutNamesEqual(name));
1610 LYXERR0("We failed to find the layout '" << name
1611 << "' in the layout list. You MUST investigate!");
1612 for (const_iterator cit = begin(); cit != end(); ++cit)
1613 lyxerr << " " << to_utf8(cit->name()) << endl;
1615 // We require the name to exist
1616 static const Layout dummy;
1617 LASSERT(false, return dummy);
1624 Layout & TextClass::operator[](docstring const & name)
1626 LATTEST(!name.empty());
1627 // Safe to continue, given what we do below.
1629 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1632 LYXERR0("We failed to find the layout '" << to_utf8(name)
1633 << "' in the layout list. You MUST investigate!");
1634 for (const_iterator cit = begin(); cit != end(); ++cit)
1635 LYXERR0(" " << to_utf8(cit->name()));
1637 // we require the name to exist
1639 // we are here only in release mode
1640 layoutlist_.push_back(createBasicLayout(name, true));
1641 it = find_if(begin(), end(), LayoutNamesEqual(name));
1648 bool TextClass::deleteLayout(docstring const & name)
1650 if (name == defaultLayoutName() || name == plainLayoutName())
1653 LayoutList::iterator it =
1654 remove_if(layoutlist_.begin(), layoutlist_.end(),
1655 LayoutNamesEqual(name));
1657 LayoutList::iterator end = layoutlist_.end();
1658 bool const ret = (it != end);
1659 layoutlist_.erase(it, end);
1664 bool TextClass::deleteInsetLayout(docstring const & name)
1666 return insetlayoutlist_.erase(name);
1670 // Load textclass info if not loaded yet
1671 bool TextClass::load(string const & path) const
1676 // Read style-file, provided path is searched before the system ones
1677 // If path is a file, it is loaded directly.
1678 FileName layout_file(path);
1679 if (!path.empty() && !layout_file.isReadableFile())
1680 layout_file = FileName(addName(path, name_ + ".layout"));
1681 if (layout_file.empty() || !layout_file.exists())
1682 layout_file = libFileSearch("layouts", name_, "layout");
1683 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1686 lyxerr << "Error reading `"
1687 << to_utf8(makeDisplayPath(layout_file.absFileName()))
1688 << "'\n(Check `" << name_
1689 << "')\nCheck your installation and "
1690 "try Options/Reconfigure..."
1698 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1703 layoutlist_.push_back(createBasicLayout(n, true));
1708 string DocumentClass::forcedLayouts() const
1712 const_iterator const e = end();
1713 for (const_iterator i = begin(); i != e; ++i) {
1714 if (i->forcelocal > 0) {
1716 os << "Format " << LAYOUT_FORMAT << '\n';
1726 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1728 // FIXME The fix for the InsetLayout part of 4812 would be here:
1729 // Add the InsetLayout to the document class if it is not found.
1731 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1732 while (!n.empty()) {
1733 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1734 if (cit != cen && cit->first == n) {
1735 if (cit->second.obsoleted_by().empty())
1737 n = cit->second.obsoleted_by();
1738 return insetLayout(n);
1740 // If we have a generic prefix (e.g., "Note:"),
1741 // try if this one alone is found.
1742 size_t i = n.find(':');
1743 if (i == string::npos)
1747 // Layout "name" not found.
1748 return plainInsetLayout();
1752 InsetLayout const & DocumentClass::plainInsetLayout() {
1753 static const InsetLayout plain_insetlayout_;
1754 return plain_insetlayout_;
1758 docstring const & TextClass::defaultLayoutName() const
1760 return defaultlayout_;
1764 Layout const & TextClass::defaultLayout() const
1766 return operator[](defaultLayoutName());
1770 bool TextClass::isDefaultLayout(Layout const & layout) const
1772 return layout.name() == defaultLayoutName();
1776 bool TextClass::isPlainLayout(Layout const & layout) const
1778 return layout.name() == plainLayoutName();
1782 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1784 static Layout * defaultLayout = NULL;
1786 if (defaultLayout) {
1787 defaultLayout->setUnknown(unknown);
1788 defaultLayout->setName(name);
1789 return *defaultLayout;
1792 static char const * s = "Margin Static\n"
1793 "LatexType Paragraph\n"
1796 "AlignPossible Left, Right, Center\n"
1797 "LabelType No_Label\n"
1799 istringstream ss(s);
1800 Lexer lex(textClassTags);
1802 defaultLayout = new Layout;
1803 defaultLayout->setUnknown(unknown);
1804 defaultLayout->setName(name);
1805 if (!readStyle(lex, *defaultLayout)) {
1806 // The only way this happens is because the hardcoded layout above
1810 return *defaultLayout;
1814 DocumentClassPtr getDocumentClass(
1815 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1816 string const & cengine, bool const clone)
1818 DocumentClassPtr doc_class =
1819 DocumentClassPtr(new DocumentClass(baseClass));
1820 LayoutModuleList::const_iterator it = modlist.begin();
1821 LayoutModuleList::const_iterator en = modlist.end();
1822 for (; it != en; ++it) {
1823 string const modName = *it;
1824 LyXModule * lm = theModuleList[modName];
1826 docstring const msg =
1827 bformat(_("The module %1$s has been requested by\n"
1828 "this document but has not been found in the list of\n"
1829 "available modules. If you recently installed it, you\n"
1830 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1832 frontend::Alert::warning(_("Module not available"), msg);
1835 if (!lm->isAvailable() && !clone) {
1836 docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1837 docstring const msg =
1838 bformat(_("The module %1$s requires a package that is not\n"
1839 "available in your LaTeX installation, or a converter that\n"
1840 "you have not installed. LaTeX output may not be possible.\n"
1841 "Missing prerequisites:\n"
1843 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1844 from_utf8(modName), prereqs);
1845 frontend::Alert::warning(_("Package not available"), msg, true);
1847 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1848 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1849 docstring const msg =
1850 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1851 frontend::Alert::warning(_("Read Error"), msg);
1855 if (cengine.empty())
1858 LyXCiteEngine * ce = theCiteEnginesList[cengine];
1860 docstring const msg =
1861 bformat(_("The cite engine %1$s has been requested by\n"
1862 "this document but has not been found in the list of\n"
1863 "available engines. If you recently installed it, you\n"
1864 "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1866 frontend::Alert::warning(_("Cite Engine not available"), msg);
1867 } else if (!ce->isAvailable() && !clone) {
1868 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1869 docstring const msg =
1870 bformat(_("The cite engine %1$s requires a package that is not\n"
1871 "available in your LaTeX installation, or a converter that\n"
1872 "you have not installed. LaTeX output may not be possible.\n"
1873 "Missing prerequisites:\n"
1875 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1876 from_utf8(cengine), prereqs);
1877 frontend::Alert::warning(_("Package not available"), msg, true);
1879 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1880 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1881 docstring const msg =
1882 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1883 frontend::Alert::warning(_("Read Error"), msg);
1891 /////////////////////////////////////////////////////////////////////////
1895 /////////////////////////////////////////////////////////////////////////
1897 DocumentClass::DocumentClass(LayoutFile const & tc)
1902 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1904 LayoutList::const_iterator it = layoutlist_.begin();
1905 LayoutList::const_iterator end = layoutlist_.end();
1906 for (; it != end; ++it)
1907 if (it->latexname() == lay)
1913 bool DocumentClass::provides(string const & p) const
1915 return provides_.find(p) != provides_.end();
1919 bool DocumentClass::hasTocLevels() const
1921 return min_toclevel_ != Layout::NOT_IN_TOC;
1925 Layout const & DocumentClass::getTOCLayout() const
1927 // we're going to look for the layout with the minimum toclevel
1928 TextClass::LayoutList::const_iterator lit = begin();
1929 TextClass::LayoutList::const_iterator const len = end();
1930 int minlevel = 1000;
1931 Layout const * lay = NULL;
1932 for (; lit != len; ++lit) {
1933 int const level = lit->toclevel;
1934 // we don't want Part or unnumbered sections
1935 if (level == Layout::NOT_IN_TOC || level < 0
1936 || level >= minlevel || lit->counter.empty())
1943 // hmm. that is very odd, so we'll do our best.
1944 return operator[](defaultLayoutName());
1948 Layout const & DocumentClass::htmlTOCLayout() const
1950 if (html_toc_section_.empty())
1951 html_toc_section_ = getTOCLayout().name();
1952 return operator[](html_toc_section_);
1956 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1957 string const & entry, bool const punct, string const & fallback) const
1959 string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}"
1960 "\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]]"
1961 "[[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1963 default_format += ".";
1965 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
1966 if (itype == cite_formats_.end())
1967 return default_format;
1968 map<string, string>::const_iterator it = itype->second.find(entry);
1969 if (it == itype->second.end() && !fallback.empty())
1970 it = itype->second.find(fallback);
1971 if (it == itype->second.end())
1972 return default_format;
1974 return it->second + ".";
1979 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
1980 string const & macro) const
1982 static string empty;
1983 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
1984 if (itype == cite_macros_.end())
1986 map<string, string>::const_iterator it = itype->second.find(macro);
1987 if (it == itype->second.end())
1993 vector<string> const DocumentClass::citeCommands(
1994 CiteEngineType const & type) const
1996 vector<CitationStyle> const styles = citeStyles(type);
1997 vector<CitationStyle>::const_iterator it = styles.begin();
1998 vector<CitationStyle>::const_iterator end = styles.end();
1999 vector<string> cmds;
2000 for (; it != end; ++it) {
2001 CitationStyle const cite = *it;
2002 cmds.push_back(cite.name);
2008 vector<CitationStyle> const & DocumentClass::citeStyles(
2009 CiteEngineType const & type) const
2011 static vector<CitationStyle> empty;
2012 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
2013 if (it == cite_styles_.end())
2019 /////////////////////////////////////////////////////////////////////////
2023 /////////////////////////////////////////////////////////////////////////
2025 ostream & operator<<(ostream & os, PageSides p)