]> git.lyx.org Git - lyx.git/blob - src/TextClass.cpp
Use unsigned values for enum
[lyx.git] / src / TextClass.cpp
1 /**
2  * \file TextClass.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author Angus Leeming
9  * \author John Levon
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "TextClass.h"
18
19 #include "LayoutFile.h"
20 #include "CiteEnginesList.h"
21 #include "Color.h"
22 #include "Counters.h"
23 #include "Floating.h"
24 #include "FloatList.h"
25 #include "Layout.h"
26 #include "Lexer.h"
27 #include "Font.h"
28 #include "ModuleList.h"
29
30 #include "frontends/alert.h"
31
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"
41
42 #include <algorithm>
43 #include <fstream>
44 #include <sstream>
45
46 #ifdef ERROR
47 #undef ERROR
48 #endif
49
50 using namespace std;
51 using namespace lyx::support;
52
53 namespace lyx {
54
55 // Keep the changes documented in the Customization manual.
56 //
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.
64 //
65 int const LAYOUT_FORMAT = 80; // spitz: Requires for floats
66
67
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;
71
72
73 namespace {
74
75 class LayoutNamesEqual : public unary_function<Layout, bool> {
76 public:
77         LayoutNamesEqual(docstring const & name)
78                 : name_(name)
79         {}
80         bool operator()(Layout const & c) const
81         {
82                 return c.name() == name_;
83         }
84 private:
85         docstring name_;
86 };
87
88
89 bool layout2layout(FileName const & filename, FileName const & tempfile,
90                    int const format = LAYOUT_FORMAT)
91 {
92         FileName const script = libFileSearch("scripts", "layout2layout.py");
93         if (script.empty()) {
94                 LYXERR0("Could not find layout conversion "
95                         "script layout2layout.py.");
96                 return false;
97         }
98
99         ostringstream command;
100         command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
101                 << " -t " << format
102                 << ' ' << quoteName(filename.toFilesystemEncoding())
103                 << ' ' << quoteName(tempfile.toFilesystemEncoding());
104         string const command_str = command.str();
105
106         LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
107
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.");
112                 return false;
113         }
114         return true;
115 }
116
117
118 string translateReadType(TextClass::ReadType rt)
119 {
120         switch (rt) {
121         case TextClass::BASECLASS:
122                 return "textclass";
123         case TextClass::MERGE:
124                 return "input file";
125         case TextClass::MODULE:
126                 return "module file";
127         case TextClass::CITE_ENGINE:
128                 return "cite engine";
129         case TextClass::VALIDATION:
130                 return "validation";
131         }
132         // shutup warning
133         return string();
134 }
135
136 } // namespace
137
138
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"));
142
143
144 /////////////////////////////////////////////////////////////////////////
145 //
146 // TextClass
147 //
148 /////////////////////////////////////////////////////////////////////////
149
150 TextClass::TextClass()
151         : loaded_(false), tex_class_avail_(false),
152           opt_enginetype_("authoryear|numerical"), opt_fontsize_("10|11|12"),
153           opt_pagesize_("default|a4|a5|b5|letter|legal|executive"),
154           opt_pagestyle_("empty|plain|headings|fancy"), fontsize_format_("$$spt"), pagesize_("default"),
155           pagesize_format_("$$spaper"), pagestyle_("default"), tablestyle_("default"),
156           columns_(1), sides_(OneSide), secnumdepth_(3), tocdepth_(3), outputType_(LATEX),
157           outputFormat_("latex"), has_output_format_(false), defaultfont_(sane_font), 
158           titletype_(TITLE_COMMAND_AFTER), titlename_("maketitle"),
159           min_toclevel_(0), max_toclevel_(0), maxcitenames_(2),
160           cite_full_author_list_(true), bibintoc_(false)
161 {
162 }
163
164
165 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
166 {
167         LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
168         if (!lay.read(lexrc, *this)) {
169                 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
170                 return false;
171         }
172         // Resolve fonts
173         lay.resfont = lay.font;
174         lay.resfont.realize(defaultfont_);
175         lay.reslabelfont = lay.labelfont;
176         lay.reslabelfont.realize(defaultfont_);
177         return true; // no errors
178 }
179
180
181 enum TextClassTags {
182         TC_OUTPUTTYPE = 1,
183         TC_OUTPUTFORMAT,
184         TC_INPUT,
185         TC_STYLE,
186         TC_MODIFYSTYLE,
187         TC_PROVIDESTYLE,
188         TC_DEFAULTSTYLE,
189         TC_INSETLAYOUT,
190         TC_NOINSETLAYOUT,
191         TC_NOSTYLE,
192         TC_COLUMNS,
193         TC_SIDES,
194         TC_PAGESTYLE,
195         TC_PAGESIZE,
196         TC_DEFAULTFONT,
197         TC_SECNUMDEPTH,
198         TC_TOCDEPTH,
199         TC_CLASSOPTIONS,
200         TC_PREAMBLE,
201         TC_HTMLPREAMBLE,
202         TC_HTMLSTYLES,
203         TC_PROVIDES,
204         TC_REQUIRES,
205         TC_PKGOPTS,
206         TC_LEFTMARGIN,
207         TC_RIGHTMARGIN,
208         TC_FLOAT,
209         TC_COUNTER,
210         TC_NOCOUNTER,
211         TC_IFCOUNTER,
212         TC_NOFLOAT,
213         TC_TITLELATEXNAME,
214         TC_TITLELATEXTYPE,
215         TC_FORMAT,
216         TC_ADDTOPREAMBLE,
217         TC_ADDTOHTMLPREAMBLE,
218         TC_ADDTOHTMLSTYLES,
219         TC_DEFAULTMODULE,
220         TC_PROVIDESMODULE,
221         TC_EXCLUDESMODULE,
222         TC_HTMLTOCSECTION,
223         TC_CITEENGINE,
224         TC_ADDTOCITEENGINE,
225         TC_CITEENGINETYPE,
226         TC_CITEFORMAT,
227         TC_CITEFRAMEWORK,
228         TC_MAXCITENAMES,
229         TC_DEFAULTBIBLIO,
230         TC_FULLAUTHORLIST,
231         TC_OUTLINERNAME,
232         TC_TABLESTYLE,
233         TC_BIBINTOC
234 };
235
236
237 namespace {
238
239 LexerKeyword textClassTags[] = {
240         { "addtociteengine",   TC_ADDTOCITEENGINE },
241         { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
242         { "addtohtmlstyles",   TC_ADDTOHTMLSTYLES },
243         { "addtopreamble",     TC_ADDTOPREAMBLE },
244         { "bibintoc",          TC_BIBINTOC },
245         { "citeengine",        TC_CITEENGINE },
246         { "citeenginetype",    TC_CITEENGINETYPE },
247         { "citeformat",        TC_CITEFORMAT },
248         { "citeframework",     TC_CITEFRAMEWORK },
249         { "classoptions",      TC_CLASSOPTIONS },
250         { "columns",           TC_COLUMNS },
251         { "counter",           TC_COUNTER },
252         { "defaultbiblio",     TC_DEFAULTBIBLIO },
253         { "defaultfont",       TC_DEFAULTFONT },
254         { "defaultmodule",     TC_DEFAULTMODULE },
255         { "defaultstyle",      TC_DEFAULTSTYLE },
256         { "excludesmodule",    TC_EXCLUDESMODULE },
257         { "float",             TC_FLOAT },
258         { "format",            TC_FORMAT },
259         { "fullauthorlist",    TC_FULLAUTHORLIST },
260         { "htmlpreamble",      TC_HTMLPREAMBLE },
261         { "htmlstyles",        TC_HTMLSTYLES },
262         { "htmltocsection",    TC_HTMLTOCSECTION },
263         { "ifcounter",         TC_IFCOUNTER },
264         { "input",             TC_INPUT },
265         { "insetlayout",       TC_INSETLAYOUT },
266         { "leftmargin",        TC_LEFTMARGIN },
267         { "maxcitenames",      TC_MAXCITENAMES },
268         { "modifystyle",       TC_MODIFYSTYLE },
269         { "nocounter",         TC_NOCOUNTER },
270         { "nofloat",           TC_NOFLOAT },
271         { "noinsetlayout",     TC_NOINSETLAYOUT },
272         { "nostyle",           TC_NOSTYLE },
273         { "outlinername",      TC_OUTLINERNAME },
274         { "outputformat",      TC_OUTPUTFORMAT },
275         { "outputtype",        TC_OUTPUTTYPE },
276         { "packageoptions",    TC_PKGOPTS },
277         { "pagesize",          TC_PAGESIZE },
278         { "pagestyle",         TC_PAGESTYLE },
279         { "preamble",          TC_PREAMBLE },
280         { "provides",          TC_PROVIDES },
281         { "providesmodule",    TC_PROVIDESMODULE },
282         { "providestyle",      TC_PROVIDESTYLE },
283         { "requires",          TC_REQUIRES },
284         { "rightmargin",       TC_RIGHTMARGIN },
285         { "secnumdepth",       TC_SECNUMDEPTH },
286         { "sides",             TC_SIDES },
287         { "style",             TC_STYLE },
288         { "tablestyle",        TC_TABLESTYLE },
289         { "titlelatexname",    TC_TITLELATEXNAME },
290         { "titlelatextype",    TC_TITLELATEXTYPE },
291         { "tocdepth",          TC_TOCDEPTH }
292 };
293
294 } // namespace
295
296
297 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
298 {
299         LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
300         TempFile tmp("convertXXXXXX.layout");
301         FileName const tempfile = tmp.name();
302         bool success = layout2layout(filename, tempfile);
303         if (success)
304                 success = readWithoutConv(tempfile, rt) == OK;
305         return success;
306 }
307
308
309 std::string TextClass::convert(std::string const & str)
310 {
311         TempFile tmp1("localXXXXXX.layout");
312         FileName const fn = tmp1.name();
313         ofstream os(fn.toFilesystemEncoding().c_str());
314         os << str;
315         os.close();
316         TempFile tmp2("convert_localXXXXXX.layout");
317         FileName const tempfile = tmp2.name();
318         bool success = layout2layout(fn, tempfile, LYXFILE_LAYOUT_FORMAT);
319         if (!success)
320                 return "";
321         ifstream is(tempfile.toFilesystemEncoding().c_str());
322         string ret;
323         string tmp;
324         while (!is.eof()) {
325                 getline(is, tmp);
326                 ret += tmp + '\n';
327         }
328         is.close();
329         return ret;
330 }
331
332
333 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
334 {
335         if (!filename.isReadableFile()) {
336                 lyxerr << "Cannot read layout file `" << filename << "'."
337                        << endl;
338                 return ERROR;
339         }
340
341         LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
342                 to_utf8(makeDisplayPath(filename.absFileName())));
343
344         // Define the plain layout used in table cells, ert, etc. Note that
345         // we do this before loading any layout file, so that classes can
346         // override features of this layout if they should choose to do so.
347         if (rt == BASECLASS && !hasLayout(plain_layout_))
348                 layoutlist_.push_back(createBasicLayout(plain_layout_));
349
350         Lexer lexrc(textClassTags);
351         lexrc.setFile(filename);
352         ReturnValues retval = read(lexrc, rt);
353
354         LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
355                         to_utf8(makeDisplayPath(filename.absFileName())));
356
357         return retval;
358 }
359
360
361 bool TextClass::read(FileName const & filename, ReadType rt)
362 {
363         ReturnValues const retval = readWithoutConv(filename, rt);
364         if (retval != FORMAT_MISMATCH)
365                 return retval == OK;
366
367         bool const worx = convertLayoutFormat(filename, rt);
368         if (!worx)
369                 LYXERR0 ("Unable to convert " << filename <<
370                         " to format " << LAYOUT_FORMAT);
371         return worx;
372 }
373
374
375 TextClass::ReturnValues TextClass::validate(std::string const & str)
376 {
377         TextClass tc;
378         return tc.read(str, VALIDATION);
379 }
380
381
382 TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
383 {
384         Lexer lexrc(textClassTags);
385         istringstream is(str);
386         lexrc.setStream(is);
387         ReturnValues retval = read(lexrc, rt);
388
389         if (retval != FORMAT_MISMATCH)
390                 return retval;
391
392         // write the layout string to a temporary file
393         TempFile tmp("TextClass_read");
394         FileName const tempfile = tmp.name();
395         ofstream os(tempfile.toFilesystemEncoding().c_str());
396         if (!os) {
397                 LYXERR0("Unable to create temporary file");
398                 return ERROR;
399         }
400         os << str;
401         os.close();
402
403         // now try to convert it to LAYOUT_FORMAT
404         if (!convertLayoutFormat(tempfile, rt)) {
405                 LYXERR0("Unable to convert internal layout information to format "
406                         << LAYOUT_FORMAT);
407                 return ERROR;
408         }
409
410         return OK_OLDFORMAT;
411 }
412
413
414 // Reads a textclass structure from file.
415 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
416 {
417         if (!lexrc.isOK())
418                 return ERROR;
419
420         // The first usable line should be
421         // Format LAYOUT_FORMAT
422         if (lexrc.lex() != TC_FORMAT || !lexrc.next()
423             || lexrc.getInteger() != LAYOUT_FORMAT)
424                 return FORMAT_MISMATCH;
425
426         // parsing
427         bool error = false;
428         while (lexrc.isOK() && !error) {
429                 int le = lexrc.lex();
430
431                 switch (le) {
432                 case Lexer::LEX_FEOF:
433                         continue;
434
435                 case Lexer::LEX_UNDEF:
436                         lexrc.printError("Unknown TextClass tag `$$Token'");
437                         error = true;
438                         continue;
439
440                 default:
441                         break;
442                 }
443
444                 // used below to track whether we are in an IfStyle or IfCounter tag.
445                 bool modifystyle  = false;
446                 bool providestyle = false;
447                 bool ifcounter    = false;
448
449                 switch (static_cast<TextClassTags>(le)) {
450
451                 case TC_FORMAT:
452                         lexrc.next();
453                         lexrc.printError("Duplicate Format directive");
454                         break;
455
456                 case TC_OUTPUTFORMAT:
457                         if (lexrc.next()) {
458                                 outputFormat_ = lexrc.getString();
459                                 has_output_format_ = true;
460                         }
461                         break;
462
463                 case TC_OUTPUTTYPE:
464                         readOutputType(lexrc);
465                         switch(outputType_) {
466                         case LATEX:
467                                 outputFormat_ = "latex";
468                                 break;
469                         case DOCBOOK:
470                                 outputFormat_ = "docbook";
471                                 break;
472                         case LITERATE:
473                                 outputFormat_ = "literate";
474                                 break;
475                         }
476                         break;
477
478                 case TC_INPUT: // Include file
479                         if (lexrc.next()) {
480                                 FileName tmp;
481                                 string const inc = lexrc.getString();
482                                 if (!path().empty() && (prefixIs(inc, "./") ||
483                                                         prefixIs(inc, "../")))
484                                         tmp = fileSearch(path(), inc, "layout");
485                                 else
486                                         tmp = libFileSearch("layouts", inc,
487                                                             "layout");
488
489                                 if (tmp.empty()) {
490                                         lexrc.printError("Could not find input file: " + inc);
491                                         error = true;
492                                 } else if (!read(tmp, MERGE)) {
493                                         lexrc.printError("Error reading input file: " + tmp.absFileName());
494                                         error = true;
495                                 }
496                         }
497                         break;
498
499                 case TC_DEFAULTSTYLE:
500                         if (lexrc.next()) {
501                                 docstring const name = from_utf8(subst(lexrc.getString(),
502                                                           '_', ' '));
503                                 defaultlayout_ = name;
504                         }
505                         break;
506
507                 case TC_MODIFYSTYLE:
508                         modifystyle = true;
509                 // fall through
510                 case TC_PROVIDESTYLE:
511                         // if modifystyle is true, then we got here by falling through
512                         // so we are not in an ProvideStyle block
513                         if (!modifystyle)
514                                 providestyle = true;
515                 // fall through
516                 case TC_STYLE: {
517                         if (!lexrc.next()) {
518                                 lexrc.printError("No name given for style: `$$Token'.");
519                                 error = true;
520                                 break;
521                         }
522                         docstring const name = from_utf8(subst(lexrc.getString(),
523                                                         '_', ' '));
524                         if (name.empty()) {
525                                 string s = "Could not read name for style: `$$Token' "
526                                         + lexrc.getString() + " is probably not valid UTF-8!";
527                                 lexrc.printError(s);
528                                 Layout lay;
529                                 // Since we couldn't read the name, we just scan the rest
530                                 // of the style and discard it.
531                                 error = !readStyle(lexrc, lay);
532                                 break;
533                         }
534
535                         bool const have_layout = hasLayout(name);
536
537                         // If the layout already exists, then we want to add it to
538                         // the existing layout, as long as we are not in an ProvideStyle
539                         // block.
540                         if (have_layout && !providestyle) {
541                                 Layout & lay = operator[](name);
542                                 error = !readStyle(lexrc, lay);
543                         }
544                         // If the layout does not exist, then we want to create a new
545                         // one, but not if we are in a ModifyStyle block.
546                         else if (!have_layout && !modifystyle) {
547                                 Layout layout;
548                                 layout.setName(name);
549                                 error = !readStyle(lexrc, layout);
550                                 if (!error)
551                                         layoutlist_.push_back(layout);
552
553                                 if (defaultlayout_.empty()) {
554                                         // We do not have a default layout yet, so we choose
555                                         // the first layout we encounter.
556                                         defaultlayout_ = name;
557                                 }
558                         }
559                         // There are two ways to get here:
560                         //  (i)  The layout exists but we are in an ProvideStyle block
561                         //  (ii) The layout doesn't exist, but we are in an ModifyStyle
562                         //       block.
563                         // Either way, we just scan the rest and discard it
564                         else {
565                                 Layout lay;
566                                 // signal to coverity that we do not care about the result
567                                 (void)readStyle(lexrc, lay);
568                         }
569                         break;
570                 }
571
572                 case TC_NOSTYLE:
573                         if (lexrc.next()) {
574                                 docstring const style = from_utf8(subst(lexrc.getString(),
575                                                      '_', ' '));
576                                 if (!deleteLayout(style))
577                                         lyxerr << "Cannot delete style `"
578                                                << to_utf8(style) << '\'' << endl;
579                         }
580                         break;
581
582                 case TC_NOINSETLAYOUT:
583                         if (lexrc.next()) {
584                                 docstring const style = from_utf8(subst(lexrc.getString(),
585                                                                  '_', ' '));
586                                 if (!deleteInsetLayout(style))
587                                         LYXERR0("Style `" << style << "' cannot be removed\n"
588                                                 "because it was not found!");
589                         }
590                         break;
591
592                 case TC_COLUMNS:
593                         if (lexrc.next())
594                                 columns_ = lexrc.getInteger();
595                         break;
596
597                 case TC_SIDES:
598                         if (lexrc.next()) {
599                                 switch (lexrc.getInteger()) {
600                                 case 1: sides_ = OneSide; break;
601                                 case 2: sides_ = TwoSides; break;
602                                 default:
603                                         lyxerr << "Impossible number of page"
604                                                 " sides, setting to one."
605                                                << endl;
606                                         sides_ = OneSide;
607                                         break;
608                                 }
609                         }
610                         break;
611
612                 case TC_PAGESIZE:
613                         lexrc.next();
614                         pagesize_ = rtrim(lexrc.getString());
615                         break;
616
617                 case TC_PAGESTYLE:
618                         lexrc.next();
619                         pagestyle_ = rtrim(lexrc.getString());
620                         break;
621
622                 case TC_DEFAULTFONT:
623                         defaultfont_ = lyxRead(lexrc);
624                         if (!defaultfont_.resolved()) {
625                                 lexrc.printError("Warning: defaultfont should "
626                                                  "be fully instantiated!");
627                                 defaultfont_.realize(sane_font);
628                         }
629                         break;
630
631                 case TC_SECNUMDEPTH:
632                         lexrc.next();
633                         secnumdepth_ = lexrc.getInteger();
634                         break;
635
636                 case TC_TOCDEPTH:
637                         lexrc.next();
638                         tocdepth_ = lexrc.getInteger();
639                         break;
640
641                 // First step to support options
642                 case TC_CLASSOPTIONS:
643                         readClassOptions(lexrc);
644                         break;
645
646                 case TC_PREAMBLE:
647                         preamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
648                         break;
649
650                 case TC_HTMLPREAMBLE:
651                         htmlpreamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
652                         break;
653
654                 case TC_HTMLSTYLES:
655                         htmlstyles_ = lexrc.getLongString(from_ascii("EndStyles"));
656                         break;
657
658                 case TC_HTMLTOCSECTION:
659                         html_toc_section_ = from_utf8(trim(lexrc.getString()));
660                         break;
661
662                 case TC_ADDTOPREAMBLE:
663                         preamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
664                         break;
665
666                 case TC_ADDTOHTMLPREAMBLE:
667                         htmlpreamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
668                         break;
669
670                 case TC_ADDTOHTMLSTYLES:
671                         htmlstyles_ += lexrc.getLongString(from_ascii("EndStyles"));
672                         break;
673
674                 case TC_PROVIDES: {
675                         lexrc.next();
676                         string const feature = lexrc.getString();
677                         lexrc.next();
678                         if (lexrc.getInteger())
679                                 provides_.insert(feature);
680                         else
681                                 provides_.erase(feature);
682                         break;
683                 }
684
685                 case TC_REQUIRES: {
686                         lexrc.eatLine();
687                         vector<string> const req
688                                 = getVectorFromString(lexrc.getString());
689                         requires_.insert(req.begin(), req.end());
690                         break;
691                 }
692
693                 case TC_PKGOPTS : {
694                         lexrc.next();
695                         string const pkg = lexrc.getString();
696                         lexrc.next();
697                         string const options = lexrc.getString();
698                         package_options_[pkg] = options;
699                         break;
700                 }
701
702                 case TC_DEFAULTMODULE: {
703                         lexrc.next();
704                         string const module = lexrc.getString();
705                         if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
706                                 default_modules_.push_back(module);
707                         break;
708                 }
709
710                 case TC_PROVIDESMODULE: {
711                         lexrc.next();
712                         string const module = lexrc.getString();
713                         if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
714                                 provided_modules_.push_back(module);
715                         break;
716                 }
717
718                 case TC_EXCLUDESMODULE: {
719                         lexrc.next();
720                         string const module = lexrc.getString();
721                         // modules already have their own way to exclude other modules
722                         if (rt == MODULE) {
723                                 LYXERR0("ExcludesModule tag cannot be used in a module!");
724                                 break;
725                         }
726                         if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
727                                 excluded_modules_.push_back(module);
728                         break;
729                 }
730
731                 case TC_LEFTMARGIN:     // left margin type
732                         if (lexrc.next())
733                                 leftmargin_ = lexrc.getDocString();
734                         break;
735
736                 case TC_RIGHTMARGIN:    // right margin type
737                         if (lexrc.next())
738                                 rightmargin_ = lexrc.getDocString();
739                         break;
740
741                 case TC_INSETLAYOUT: {
742                         if (!lexrc.next()) {
743                                 lexrc.printError("No name given for InsetLayout: `$$Token'.");
744                                 error = true;
745                                 break;
746                         }
747                         docstring const name = subst(lexrc.getDocString(), '_', ' ');
748                         if (name.empty()) {
749                                 string s = "Could not read name for InsetLayout: `$$Token' "
750                                         + lexrc.getString() + " is probably not valid UTF-8!";
751                                 lexrc.printError(s);
752                                 InsetLayout il;
753                                 // Since we couldn't read the name, we just scan the rest
754                                 // of the style and discard it.
755                                 il.read(lexrc, *this);
756                                 // Let's try to continue rather than abort.
757                                 // error = true;
758                         } else if (hasInsetLayout(name)) {
759                                 InsetLayout & il = insetlayoutlist_[name];
760                                 error = !il.read(lexrc, *this);
761                         } else {
762                                 InsetLayout il;
763                                 il.setName(name);
764                                 error = !il.read(lexrc, *this);
765                                 if (!error)
766                                         insetlayoutlist_[name] = il;
767                         }
768                         break;
769                 }
770
771                 case TC_FLOAT:
772                         error = !readFloat(lexrc);
773                         break;
774
775                 case TC_CITEENGINE:
776                         error = !readCiteEngine(lexrc, rt);
777                         break;
778
779                 case TC_ADDTOCITEENGINE:
780                         error = !readCiteEngine(lexrc, rt, true);
781                         break;
782
783                 case TC_CITEENGINETYPE:
784                         if (lexrc.next())
785                                 opt_enginetype_ = rtrim(lexrc.getString());
786                         break;
787
788                 case TC_CITEFORMAT:
789                         error = !readCiteFormat(lexrc, rt);
790                         break;
791
792                 case TC_CITEFRAMEWORK:
793                         lexrc.next();
794                         citeframework_ = rtrim(lexrc.getString());
795                         break;
796
797                 case TC_MAXCITENAMES:
798                         lexrc.next();
799                         maxcitenames_ = size_t(lexrc.getInteger());
800                         break;
801
802                 case TC_DEFAULTBIBLIO:
803                         if (lexrc.next()) {
804                                 vector<string> const dbs =
805                                         getVectorFromString(rtrim(lexrc.getString()), "|");
806                                 vector<string>::const_iterator it  = dbs.begin();
807                                 vector<string>::const_iterator end = dbs.end();
808                                 for (; it != end; ++it) {
809                                         if (!contains(*it, ':')) {
810                                                 vector<string> const enginetypes =
811                                                         getVectorFromString(opt_enginetype_, "|");
812                                                 for (string const &s: enginetypes)
813                                                         cite_default_biblio_style_[s] = *it;
814                                         } else {
815                                                 string eng;
816                                                 string const db = split(*it, eng, ':');
817                                                 cite_default_biblio_style_[eng] = db;
818                                         }
819                                 }
820                         }
821                         break;
822
823                 case TC_BIBINTOC:
824                         if (lexrc.next())
825                                 bibintoc_ = lexrc.getBool();
826                         break;
827
828                 case TC_FULLAUTHORLIST:
829                         if (lexrc.next())
830                                 cite_full_author_list_ &= lexrc.getBool();
831                         break;
832
833                 case TC_NOCOUNTER:
834                         if (lexrc.next()) {
835                                 docstring const cnt = lexrc.getDocString();
836                                 if (!counters_.remove(cnt))
837                                         LYXERR0("Unable to remove counter: " + to_utf8(cnt));
838                         }
839                         break;
840
841                 case TC_IFCOUNTER:
842                         ifcounter = true;
843                         // fall through
844                 case TC_COUNTER:
845                         if (lexrc.next()) {
846                                 docstring const name = lexrc.getDocString();
847                                 if (name.empty()) {
848                                         string s = "Could not read name for counter: `$$Token' "
849                                                         + lexrc.getString() + " is probably not valid UTF-8!";
850                                         lexrc.printError(s.c_str());
851                                         Counter c;
852                                         // Since we couldn't read the name, we just scan the rest
853                                         // and discard it.
854                                         c.read(lexrc);
855                                 } else
856                                         error = !counters_.read(lexrc, name, !ifcounter);
857                         }
858                         else {
859                                 lexrc.printError("No name given for style: `$$Token'.");
860                                 error = true;
861                         }
862                         break;
863
864                 case TC_TITLELATEXTYPE:
865                         readTitleType(lexrc);
866                         break;
867
868                 case TC_TITLELATEXNAME:
869                         if (lexrc.next())
870                                 titlename_ = lexrc.getString();
871                         break;
872
873                 case TC_NOFLOAT:
874                         if (lexrc.next()) {
875                                 string const nofloat = lexrc.getString();
876                                 floatlist_.erase(nofloat);
877                         }
878                         break;
879
880                 case TC_OUTLINERNAME:
881                         error = !readOutlinerName(lexrc);
882                         break;
883
884                 case TC_TABLESTYLE:
885                         lexrc.next();
886                         tablestyle_ = rtrim(lexrc.getString());
887                         break;
888                 } // end of switch
889         }
890
891         // at present, we abort if we encounter an error,
892         // so there is no point continuing.
893         if (error)
894                 return ERROR;
895
896         if (rt != BASECLASS)
897                 return OK;
898
899         if (defaultlayout_.empty()) {
900                 LYXERR0("Error: Textclass '" << name_
901                                                 << "' is missing a defaultstyle.");
902                 return ERROR;
903         }
904
905         // Try to erase "stdinsets" from the provides_ set.
906         // The
907         //   Provides stdinsets 1
908         // declaration simply tells us that the standard insets have been
909         // defined. (It's found in stdinsets.inc but could also be used in
910         // user-defined files.) There isn't really any such package. So we
911         // might as well go ahead and erase it.
912         // If we do not succeed, then it was not there, which means that
913         // the textclass did not provide the definitions of the standard
914         // insets. So we need to try to load them.
915         int erased = provides_.erase("stdinsets");
916         if (!erased) {
917                 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
918
919                 if (tmp.empty()) {
920                         frontend::Alert::warning(_("Missing File"),
921                                 _("Could not find stdinsets.inc! This may lead to data loss!"));
922                         error = true;
923                 } else if (!read(tmp, MERGE)) {
924                         frontend::Alert::warning(_("Corrupt File"),
925                                 _("Could not read stdinsets.inc! This may lead to data loss!"));
926                         error = true;
927                 }
928         }
929
930         min_toclevel_ = Layout::NOT_IN_TOC;
931         max_toclevel_ = Layout::NOT_IN_TOC;
932         const_iterator lit = begin();
933         const_iterator len = end();
934         for (; lit != len; ++lit) {
935                 int const toclevel = lit->toclevel;
936                 if (toclevel != Layout::NOT_IN_TOC) {
937                         if (min_toclevel_ == Layout::NOT_IN_TOC)
938                                 min_toclevel_ = toclevel;
939                         else
940                                 min_toclevel_ = min(min_toclevel_, toclevel);
941                         max_toclevel_ = max(max_toclevel_, toclevel);
942                 }
943         }
944         LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
945                 << ", maximum is " << max_toclevel_);
946
947         return (error ? ERROR : OK);
948 }
949
950
951 void TextClass::readTitleType(Lexer & lexrc)
952 {
953         LexerKeyword titleTypeTags[] = {
954                 { "commandafter", TITLE_COMMAND_AFTER },
955                 { "environment",  TITLE_ENVIRONMENT }
956         };
957
958         PushPopHelper pph(lexrc, titleTypeTags);
959
960         int le = lexrc.lex();
961         switch (le) {
962         case Lexer::LEX_UNDEF:
963                 lexrc.printError("Unknown output type `$$Token'");
964                 break;
965         case TITLE_COMMAND_AFTER:
966         case TITLE_ENVIRONMENT:
967                 titletype_ = static_cast<TitleLatexType>(le);
968                 break;
969         default:
970                 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
971                 break;
972         }
973 }
974
975
976 void TextClass::readOutputType(Lexer & lexrc)
977 {
978         LexerKeyword outputTypeTags[] = {
979                 { "docbook",  DOCBOOK },
980                 { "latex",    LATEX },
981                 { "literate", LITERATE }
982         };
983
984         PushPopHelper pph(lexrc, outputTypeTags);
985
986         int le = lexrc.lex();
987         switch (le) {
988         case Lexer::LEX_UNDEF:
989                 lexrc.printError("Unknown output type `$$Token'");
990                 return;
991         case LATEX:
992         case DOCBOOK:
993         case LITERATE:
994                 outputType_ = static_cast<OutputType>(le);
995                 break;
996         default:
997                 LYXERR0("Unhandled value " << le);
998                 break;
999         }
1000 }
1001
1002
1003 void TextClass::readClassOptions(Lexer & lexrc)
1004 {
1005         enum {
1006                 CO_FONTSIZE = 1,
1007                 CO_FONTSIZE_FORMAT,
1008                 CO_PAGESIZE,
1009                 CO_PAGESIZE_FORMAT,
1010                 CO_PAGESTYLE,
1011                 CO_OTHER,
1012                 CO_HEADER,
1013                 CO_END
1014         };
1015
1016         LexerKeyword classOptionsTags[] = {
1017                 {"end",       CO_END },
1018                 {"fontsize",  CO_FONTSIZE },
1019                 {"fontsizeformat", CO_FONTSIZE_FORMAT },
1020                 {"header",    CO_HEADER },
1021                 {"other",     CO_OTHER },
1022                 {"pagesize",  CO_PAGESIZE },
1023                 {"pagesizeformat", CO_PAGESIZE_FORMAT },
1024                 {"pagestyle", CO_PAGESTYLE }
1025         };
1026
1027         lexrc.pushTable(classOptionsTags);
1028         bool getout = false;
1029         while (!getout && lexrc.isOK()) {
1030                 int le = lexrc.lex();
1031                 switch (le) {
1032                 case Lexer::LEX_UNDEF:
1033                         lexrc.printError("Unknown ClassOption tag `$$Token'");
1034                         continue;
1035                 default:
1036                         break;
1037                 }
1038                 switch (le) {
1039                 case CO_FONTSIZE:
1040                         lexrc.next();
1041                         opt_fontsize_ = rtrim(lexrc.getString());
1042                         break;
1043                 case CO_FONTSIZE_FORMAT:
1044                         lexrc.next();
1045                         fontsize_format_ = rtrim(lexrc.getString());
1046                         break;
1047                 case CO_PAGESIZE:
1048                         lexrc.next();
1049                         opt_pagesize_ = rtrim(lexrc.getString());
1050                         break;
1051                 case CO_PAGESIZE_FORMAT:
1052                         lexrc.next();
1053                         pagesize_format_ = rtrim(lexrc.getString());
1054                         break;
1055                 case CO_PAGESTYLE:
1056                         lexrc.next();
1057                         opt_pagestyle_ = rtrim(lexrc.getString());
1058                         break;
1059                 case CO_OTHER:
1060                         lexrc.next();
1061                         if (options_.empty())
1062                                 options_ = lexrc.getString();
1063                         else
1064                                 options_ += ',' + lexrc.getString();
1065                         break;
1066                 case CO_HEADER:
1067                         lexrc.next();
1068                         class_header_ = subst(lexrc.getString(), "&quot;", "\"");
1069                         break;
1070                 case CO_END:
1071                         getout = true;
1072                         break;
1073                 }
1074         }
1075         lexrc.popTable();
1076 }
1077
1078
1079 vector<CitationStyle> const & TextClass::getCiteStyles(
1080         CiteEngineType const & type) const
1081 {
1082         static vector<CitationStyle> empty;
1083         map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1084         if (it == cite_styles_.end())
1085                 return empty;
1086         return it->second;
1087 }
1088
1089
1090 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1091 {
1092         int const type = readCiteEngineType(lexrc);
1093         bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1094         bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1095         bool defce = (type & ENGINE_TYPE_DEFAULT);
1096
1097         if (rt == CITE_ENGINE) {
1098                 // The cite engines are not supposed to overwrite
1099                 // CiteStyle defined by the class or a module.
1100                 if (authoryear)
1101                         authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1102                 if (numerical)
1103                         numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1104                 if (defce)
1105                         defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1106         }
1107
1108         if (rt != CITE_ENGINE && !add) {
1109                 // Reset if we defined CiteStyle
1110                 // from the class or a module
1111                 if (authoryear)
1112                         cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1113                 if (numerical)
1114                         cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1115                 if (defce)
1116                         cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1117         }
1118
1119         string def;
1120         bool getout = false;
1121         while (!getout && lexrc.isOK()) {
1122                 lexrc.eatLine();
1123                 def = lexrc.getString();
1124                 def = subst(def, " ", "");
1125                 def = subst(def, "\t", "");
1126                 if (compare_ascii_no_case(def, "end") == 0) {
1127                         getout = true;
1128                         continue;
1129                 }
1130                 CitationStyle cs;
1131                 char ichar = def[0];
1132                 if (ichar == '#')
1133                         continue;
1134                 if (isUpperCase(ichar)) {
1135                         cs.forceUpperCase = true;
1136                         def[0] = lowercase(ichar);
1137                 }
1138
1139                 /** For portability reasons (between different
1140                  *  cite engines such as natbib and biblatex),
1141                  *  we distinguish between:
1142                  *  1. The LyX name as output in the LyX file
1143                  *  2. Possible aliases that might fall back to
1144                  *     the given LyX name in the current engine
1145                  *  3. The actual LaTeX command that is output
1146                  *  (2) and (3) are optional.
1147                  *  Also, the GUI string for the starred version can
1148                  *  be changed
1149                  *  The syntax is:
1150                  *  LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1151                  */
1152                 enum ScanMode {
1153                         LyXName,
1154                         Alias,
1155                         LaTeXCmd,
1156                         StarDesc
1157                 };
1158
1159                 ScanMode mode = LyXName;
1160                 ScanMode oldmode = LyXName;
1161                 string lyx_cmd;
1162                 string alias;
1163                 string latex_cmd;
1164                 string stardesc;
1165                 size_t const n = def.size();
1166                 for (size_t i = 0; i != n; ++i) {
1167                         ichar = def[i];
1168                         if (ichar == '|')
1169                                 mode = Alias;
1170                         else if (ichar == '=')
1171                                 mode = LaTeXCmd;
1172                         else if (ichar == '<') {
1173                                 oldmode = mode;
1174                                 mode = StarDesc;
1175                         } else if (ichar == '>')
1176                                 mode = oldmode;
1177                         else if (mode == LaTeXCmd)
1178                                 latex_cmd += ichar;
1179                         else if (mode == StarDesc)
1180                                 stardesc += ichar;
1181                         else if (ichar == '$')
1182                                 cs.hasQualifiedList = true;
1183                         else if (ichar == '*')
1184                                 cs.hasStarredVersion = true;
1185                         else if (ichar == '[' && cs.textAfter)
1186                                 cs.textBefore = true;
1187                         else if (ichar == '[')
1188                                 cs.textAfter = true;
1189                         else if (ichar != ']') {
1190                                 if (mode == Alias)
1191                                         alias += ichar;
1192                                 else
1193                                         lyx_cmd += ichar;
1194                         }
1195                 }
1196                 cs.name = lyx_cmd;
1197                 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1198                 if (!alias.empty()) {
1199                         vector<string> const aliases = getVectorFromString(alias);
1200                         for (string const &s: aliases)
1201                                 cite_command_aliases_[s] = lyx_cmd;
1202                 }
1203                 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1204                 int size = int(stardesc.size());
1205                 if (size > 0)
1206                         cs.stardesc = stardescs[0];
1207                 if (size > 1)
1208                         cs.startooltip = stardescs[1];
1209                 if (add) {
1210                         if (authoryear)
1211                                 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1212                         if (numerical)
1213                                 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1214                         if (defce)
1215                                 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1216                 } else {
1217                         if (authoryear)
1218                                 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1219                         if (numerical)
1220                                 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1221                         if (defce)
1222                                 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1223                 }
1224         }
1225         // If we do AddToCiteEngine, do not apply yet,
1226         // except if we have already a style to add something to
1227         bool apply_ay = !add;
1228         bool apply_num = !add;
1229         bool apply_def = !add;
1230         if (add) {
1231                 if (type & ENGINE_TYPE_AUTHORYEAR)
1232                         apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1233                 if (type & ENGINE_TYPE_NUMERICAL)
1234                         apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1235                 if (type & ENGINE_TYPE_DEFAULT)
1236                         apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1237         }
1238
1239         // Add the styles from AddToCiteEngine to the class' styles
1240         // (but only if they are not yet defined)
1241         for (auto const & cis : class_cite_styles_) {
1242                 // Only consider the current CiteEngineType
1243                 if (!(type & cis.first))
1244                         continue;
1245                 for (auto const & ciss : cis.second) {
1246                         bool defined = false;
1247                         // Check if the style "name" is already def'ed
1248                         for (auto const & av : getCiteStyles(cis.first))
1249                                 if (av.name == ciss.name)
1250                                         defined = true;
1251                         if (!defined) {
1252                                 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1253                                         cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1254                                 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1255                                         cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1256                                 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1257                                         cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1258                         }
1259                 }
1260         }
1261         if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1262                 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1263         if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1264                 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1265         if (type & ENGINE_TYPE_DEFAULT && apply_def)
1266                 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1267         return getout;
1268 }
1269
1270
1271 int TextClass::readCiteEngineType(Lexer & lexrc) const
1272 {
1273         static_assert(ENGINE_TYPE_DEFAULT ==
1274                                   (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1275                                   "Incorrect default engine type");
1276         if (!lexrc.next()) {
1277                 lexrc.printError("No cite engine type given for token: `$$Token'.");
1278                 return ENGINE_TYPE_DEFAULT;
1279         }
1280         string const type = rtrim(lexrc.getString());
1281         if (compare_ascii_no_case(type, "authoryear") == 0)
1282                 return ENGINE_TYPE_AUTHORYEAR;
1283         else if (compare_ascii_no_case(type, "numerical") == 0)
1284                 return ENGINE_TYPE_NUMERICAL;
1285         else if (compare_ascii_no_case(type, "default") != 0) {
1286                 string const s = "Unknown cite engine type `" + type
1287                         + "' given for token: `$$Token',";
1288                 lexrc.printError(s);
1289         }
1290         return ENGINE_TYPE_DEFAULT;
1291 }
1292
1293
1294 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1295 {
1296         int const type = readCiteEngineType(lexrc);
1297         string etype;
1298         string definition;
1299         // Cite engine definitions do not overwrite existing
1300         // definitions from the class or a module
1301         bool const overwrite = rt != CITE_ENGINE;
1302         while (lexrc.isOK()) {
1303                 lexrc.next();
1304                 etype = lexrc.getString();
1305                 if (compare_ascii_no_case(etype, "end") == 0)
1306                         break;
1307                 if (!lexrc.isOK())
1308                         return false;
1309                 lexrc.eatLine();
1310                 definition = lexrc.getString();
1311                 char initchar = etype[0];
1312                 if (initchar == '#')
1313                         continue;
1314                 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1315                         bool defined = false;
1316                         bool aydefined = false;
1317                         bool numdefined = false;
1318                         // Check if the macro is already def'ed
1319                         for (auto const & cm : cite_macros_) {
1320                                 if (!(type & cm.first))
1321                                         continue;
1322                                 if (cm.second.find(etype) != cm.second.end()) {
1323                                         if (type == cm.first)
1324                                                 // defined as default or specific type
1325                                                 defined = true;
1326                                         if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1327                                                 // defined for author-year
1328                                                 aydefined = true;
1329                                         else if (cm.first == ENGINE_TYPE_NUMERICAL)
1330                                                 // defined for numerical
1331                                                 numdefined = true;
1332                                 }
1333                         }
1334                         if (!defined || overwrite) {
1335                                 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1336                                         cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1337                                 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1338                                         cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1339                                 if (type == ENGINE_TYPE_DEFAULT)
1340                                         cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1341                         }
1342                 } else {
1343                         bool defined = false;
1344                         bool aydefined = false;
1345                         bool numdefined = false;
1346                         // Check if the format is already def'ed
1347                         for (auto const & cm : cite_formats_) {
1348                                 if (!(type & cm.first))
1349                                         continue;
1350                                 if (cm.second.find(etype) != cm.second.end()) {
1351                                         if (type == cm.first)
1352                                                 // defined as default or specific type
1353                                                 defined = true;
1354                                         if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1355                                                 // defined for author-year
1356                                                 aydefined = true;
1357                                         else if (cm.first == ENGINE_TYPE_NUMERICAL)
1358                                                 // defined for numerical
1359                                                 numdefined = true;
1360                                 }
1361                         }
1362                         if (!defined || overwrite){
1363                                 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1364                                         cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1365                                 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1366                                         cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1367                                 if (type == ENGINE_TYPE_DEFAULT)
1368                                         cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1369                         }
1370                 }
1371         }
1372         return true;
1373 }
1374
1375
1376 bool TextClass::readFloat(Lexer & lexrc)
1377 {
1378         enum {
1379                 FT_TYPE = 1,
1380                 FT_NAME,
1381                 FT_PLACEMENT,
1382                 FT_EXT,
1383                 FT_WITHIN,
1384                 FT_STYLE,
1385                 FT_LISTNAME,
1386                 FT_USESFLOAT,
1387                 FT_PREDEFINED,
1388                 FT_HTMLSTYLE,
1389                 FT_HTMLATTR,
1390                 FT_HTMLTAG,
1391                 FT_LISTCOMMAND,
1392                 FT_REFPREFIX,
1393                 FT_ALLOWED_PLACEMENT,
1394                 FT_ALLOWS_SIDEWAYS,
1395                 FT_ALLOWS_WIDE,
1396                 FT_REQUIRES,
1397                 FT_END
1398         };
1399
1400         LexerKeyword floatTags[] = {
1401                 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1402                 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1403                 { "allowswide", FT_ALLOWS_WIDE },
1404                 { "end", FT_END },
1405                 { "extension", FT_EXT },
1406                 { "guiname", FT_NAME },
1407                 { "htmlattr", FT_HTMLATTR },
1408                 { "htmlstyle", FT_HTMLSTYLE },
1409                 { "htmltag", FT_HTMLTAG },
1410                 { "ispredefined", FT_PREDEFINED },
1411                 { "listcommand", FT_LISTCOMMAND },
1412                 { "listname", FT_LISTNAME },
1413                 { "numberwithin", FT_WITHIN },
1414                 { "placement", FT_PLACEMENT },
1415                 { "refprefix", FT_REFPREFIX },
1416                 { "requires", FT_REQUIRES },
1417                 { "style", FT_STYLE },
1418                 { "type", FT_TYPE },
1419                 { "usesfloatpkg", FT_USESFLOAT }
1420         };
1421
1422         lexrc.pushTable(floatTags);
1423
1424         string ext;
1425         string htmlattr;
1426         docstring htmlstyle;
1427         string htmltag;
1428         string listname;
1429         string listcommand;
1430         string name;
1431         string placement;
1432         string allowed_placement = "!htbpH";
1433         string refprefix;
1434         string style;
1435         string type;
1436         string within;
1437         string requires;
1438         bool usesfloat = true;
1439         bool ispredefined = false;
1440         bool allowswide = true;
1441         bool allowssideways = true;
1442
1443         bool getout = false;
1444         while (!getout && lexrc.isOK()) {
1445                 int le = lexrc.lex();
1446                 switch (le) {
1447                 case Lexer::LEX_UNDEF:
1448                         lexrc.printError("Unknown float tag `$$Token'");
1449                         continue;
1450                 default:
1451                         break;
1452                 }
1453                 switch (le) {
1454                 case FT_TYPE:
1455                         lexrc.next();
1456                         type = lexrc.getString();
1457                         if (floatlist_.typeExist(type)) {
1458                                 Floating const & fl = floatlist_.getType(type);
1459                                 placement = fl.placement();
1460                                 ext = fl.ext();
1461                                 within = fl.within();
1462                                 style = fl.style();
1463                                 name = fl.name();
1464                                 listname = fl.listName();
1465                                 usesfloat = fl.usesFloatPkg();
1466                                 ispredefined = fl.isPredefined();
1467                                 listcommand = fl.listCommand();
1468                                 refprefix = fl.refPrefix();
1469                         }
1470                         break;
1471                 case FT_NAME:
1472                         lexrc.next();
1473                         name = lexrc.getString();
1474                         break;
1475                 case FT_PLACEMENT:
1476                         lexrc.next();
1477                         placement = lexrc.getString();
1478                         break;
1479                 case FT_ALLOWED_PLACEMENT:
1480                         lexrc.next();
1481                         allowed_placement = lexrc.getString();
1482                         break;
1483                 case FT_EXT:
1484                         lexrc.next();
1485                         ext = lexrc.getString();
1486                         break;
1487                 case FT_WITHIN:
1488                         lexrc.next();
1489                         within = lexrc.getString();
1490                         if (within == "none")
1491                                 within.erase();
1492                         break;
1493                 case FT_STYLE:
1494                         lexrc.next();
1495                         style = lexrc.getString();
1496                         break;
1497                 case FT_LISTCOMMAND:
1498                         lexrc.next();
1499                         listcommand = lexrc.getString();
1500                         break;
1501                 case FT_REFPREFIX:
1502                         lexrc.next();
1503                         refprefix = lexrc.getString();
1504                         break;
1505                 case FT_LISTNAME:
1506                         lexrc.next();
1507                         listname = lexrc.getString();
1508                         break;
1509                 case FT_USESFLOAT:
1510                         lexrc.next();
1511                         usesfloat = lexrc.getBool();
1512                         break;
1513                 case FT_REQUIRES:
1514                         lexrc.next();
1515                         requires = lexrc.getString();
1516                         break;
1517                 case FT_PREDEFINED:
1518                         lexrc.next();
1519                         ispredefined = lexrc.getBool();
1520                         break;
1521                 case FT_ALLOWS_SIDEWAYS:
1522                         lexrc.next();
1523                         allowssideways = lexrc.getBool();
1524                         break;
1525                 case FT_ALLOWS_WIDE:
1526                         lexrc.next();
1527                         allowswide = lexrc.getBool();
1528                         break;
1529                 case FT_HTMLATTR:
1530                         lexrc.next();
1531                         htmlattr = lexrc.getString();
1532                         break;
1533                 case FT_HTMLSTYLE:
1534                         lexrc.next();
1535                         htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1536                         break;
1537                 case FT_HTMLTAG:
1538                         lexrc.next();
1539                         htmltag = lexrc.getString();
1540                         break;
1541                 case FT_END:
1542                         getout = true;
1543                         break;
1544                 }
1545         }
1546
1547         lexrc.popTable();
1548
1549         // Here we have a full float if getout == true
1550         if (getout) {
1551                 if (!usesfloat && listcommand.empty()) {
1552                         // if this float uses the same auxfile as an existing one,
1553                         // there is no need for it to provide a list command.
1554                         FloatList::const_iterator it = floatlist_.begin();
1555                         FloatList::const_iterator en = floatlist_.end();
1556                         bool found_ext = false;
1557                         for (; it != en; ++it) {
1558                                 if (it->second.ext() == ext) {
1559                                         found_ext = true;
1560                                         break;
1561                                 }
1562                         }
1563                         if (!found_ext)
1564                                 LYXERR0("The layout does not provide a list command " <<
1565                                   "for the float `" << type << "'. LyX will " <<
1566                                   "not be able to produce a float list.");
1567                 }
1568                 Floating fl(type, placement, ext, within, style, name,
1569                             listname, listcommand, refprefix, allowed_placement,
1570                             htmltag, htmlattr, htmlstyle, requires, usesfloat,
1571                             ispredefined, allowswide, allowssideways);
1572                 floatlist_.newFloat(fl);
1573                 // each float has its own counter
1574                 counters_.newCounter(from_ascii(type), from_ascii(within),
1575                                       docstring(), docstring());
1576                 // also define sub-float counters
1577                 docstring const subtype = "sub-" + from_ascii(type);
1578                 counters_.newCounter(subtype, from_ascii(type),
1579                                       "\\alph{" + subtype + "}", docstring());
1580         }
1581         return getout;
1582 }
1583
1584
1585 bool TextClass::readOutlinerName(Lexer & lexrc)
1586 {
1587         std::string type;
1588         docstring name;
1589         if (lexrc.next())
1590                 type = lexrc.getString();
1591         else {
1592                 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1593                 return false;
1594         }
1595         if (lexrc.next())
1596                 name = lexrc.getDocString();
1597         else {
1598                 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1599                 return false;
1600         }
1601         outliner_names_[type] = name;
1602     return true;
1603 }
1604
1605
1606 string const & TextClass::prerequisites(string const & sep) const
1607 {
1608         if (contains(prerequisites_, ',')) {
1609                 vector<string> const pres = getVectorFromString(prerequisites_);
1610                 prerequisites_ = getStringFromVector(pres, sep);
1611         }
1612         return prerequisites_;
1613 }
1614
1615
1616 bool TextClass::hasLayout(docstring const & n) const
1617 {
1618         docstring const name = n.empty() ? defaultLayoutName() : n;
1619
1620         return find_if(layoutlist_.begin(), layoutlist_.end(),
1621                        LayoutNamesEqual(name))
1622                 != layoutlist_.end();
1623 }
1624
1625
1626 bool TextClass::hasInsetLayout(docstring const & n) const
1627 {
1628         if (n.empty())
1629                 return false;
1630         InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1631         return it != insetlayoutlist_.end();
1632 }
1633
1634
1635 Layout const & TextClass::operator[](docstring const & name) const
1636 {
1637         LATTEST(!name.empty());
1638
1639         const_iterator it =
1640                 find_if(begin(), end(), LayoutNamesEqual(name));
1641
1642         if (it == end()) {
1643                 LYXERR0("We failed to find the layout '" << name
1644                        << "' in the layout list. You MUST investigate!");
1645                 for (const_iterator cit = begin(); cit != end(); ++cit)
1646                         lyxerr  << " " << to_utf8(cit->name()) << endl;
1647
1648                 // We require the name to exist
1649                 static const Layout dummy;
1650                 LASSERT(false, return dummy);
1651         }
1652
1653         return *it;
1654 }
1655
1656
1657 Layout & TextClass::operator[](docstring const & name)
1658 {
1659         LATTEST(!name.empty());
1660         // Safe to continue, given what we do below.
1661
1662         iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1663
1664         if (it == end()) {
1665                 LYXERR0("We failed to find the layout '" << to_utf8(name)
1666                        << "' in the layout list. You MUST investigate!");
1667                 for (const_iterator cit = begin(); cit != end(); ++cit)
1668                         LYXERR0(" " << to_utf8(cit->name()));
1669
1670                 // we require the name to exist
1671                 LATTEST(false);
1672                 // we are here only in release mode
1673                 layoutlist_.push_back(createBasicLayout(name, true));
1674                 it = find_if(begin(), end(), LayoutNamesEqual(name));
1675         }
1676
1677         return *it;
1678 }
1679
1680
1681 bool TextClass::deleteLayout(docstring const & name)
1682 {
1683         if (name == defaultLayoutName() || name == plainLayoutName())
1684                 return false;
1685
1686         LayoutList::iterator it =
1687                 remove_if(layoutlist_.begin(), layoutlist_.end(),
1688                           LayoutNamesEqual(name));
1689
1690         LayoutList::iterator end = layoutlist_.end();
1691         bool const ret = (it != end);
1692         layoutlist_.erase(it, end);
1693         return ret;
1694 }
1695
1696
1697 bool TextClass::deleteInsetLayout(docstring const & name)
1698 {
1699         return insetlayoutlist_.erase(name);
1700 }
1701
1702
1703 // Load textclass info if not loaded yet
1704 bool TextClass::load(string const & path) const
1705 {
1706         if (loaded_)
1707                 return true;
1708
1709         // Read style-file, provided path is searched before the system ones
1710         // If path is a file, it is loaded directly.
1711         FileName layout_file(path);
1712         if (!path.empty() && !layout_file.isReadableFile())
1713                 layout_file = FileName(addName(path, name_ + ".layout"));
1714         if (layout_file.empty() || !layout_file.exists())
1715                 layout_file = libFileSearch("layouts", name_, "layout");
1716         loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1717
1718         if (!loaded_) {
1719                 lyxerr << "Error reading `"
1720                        << to_utf8(makeDisplayPath(layout_file.absFileName()))
1721                        << "'\n(Check `" << name_
1722                        << "')\nCheck your installation and "
1723                           "try Options/Reconfigure..."
1724                        << endl;
1725         }
1726
1727         return loaded_;
1728 }
1729
1730
1731 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1732 {
1733         if (hasLayout(n))
1734                 return false;
1735
1736         layoutlist_.push_back(createBasicLayout(n, true));
1737         return true;
1738 }
1739
1740
1741 string DocumentClass::forcedLayouts() const
1742 {
1743         ostringstream os;
1744         bool first = true;
1745         const_iterator const e = end();
1746         for (const_iterator i = begin(); i != e; ++i) {
1747                 if (i->forcelocal > 0) {
1748                         if (first) {
1749                                 os << "Format " << LAYOUT_FORMAT << '\n';
1750                                 first = false;
1751                         }
1752                         i->write(os);
1753                 }
1754         }
1755         return os.str();
1756 }
1757
1758
1759 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1760 {
1761         // FIXME The fix for the InsetLayout part of 4812 would be here:
1762         // Add the InsetLayout to the document class if it is not found.
1763         docstring n = name;
1764         InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1765         while (!n.empty()) {
1766                 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1767                 if (cit != cen && cit->first == n) {
1768                         if (cit->second.obsoleted_by().empty())
1769                                 return cit->second;
1770                         n = cit->second.obsoleted_by();
1771                         return insetLayout(n);
1772                 }
1773                 // If we have a generic prefix (e.g., "Note:"),
1774                 // try if this one alone is found.
1775                 size_t i = n.find(':');
1776                 if (i == string::npos)
1777                         break;
1778                 n = n.substr(0, i);
1779         }
1780         // Layout "name" not found.
1781         return plainInsetLayout();
1782 }
1783
1784
1785 InsetLayout const & DocumentClass::plainInsetLayout() {
1786         static const InsetLayout plain_insetlayout_;
1787         return plain_insetlayout_;
1788 }
1789
1790
1791 docstring const & TextClass::defaultLayoutName() const
1792 {
1793         return defaultlayout_;
1794 }
1795
1796
1797 Layout const & TextClass::defaultLayout() const
1798 {
1799         return operator[](defaultLayoutName());
1800 }
1801
1802
1803 bool TextClass::isDefaultLayout(Layout const & layout) const
1804 {
1805         return layout.name() == defaultLayoutName();
1806 }
1807
1808
1809 bool TextClass::isPlainLayout(Layout const & layout) const
1810 {
1811         return layout.name() == plainLayoutName();
1812 }
1813
1814
1815 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1816 {
1817         static Layout * defaultLayout = NULL;
1818
1819         if (defaultLayout) {
1820                 defaultLayout->setUnknown(unknown);
1821                 defaultLayout->setName(name);
1822                 return *defaultLayout;
1823         }
1824
1825         static char const * s = "Margin Static\n"
1826                         "LatexType Paragraph\n"
1827                         "LatexName dummy\n"
1828                         "Align Block\n"
1829                         "AlignPossible Left, Right, Center\n"
1830                         "LabelType No_Label\n"
1831                         "End";
1832         istringstream ss(s);
1833         Lexer lex(textClassTags);
1834         lex.setStream(ss);
1835         defaultLayout = new Layout;
1836         defaultLayout->setUnknown(unknown);
1837         defaultLayout->setName(name);
1838         if (!readStyle(lex, *defaultLayout)) {
1839                 // The only way this happens is because the hardcoded layout above
1840                 // is wrong.
1841                 LATTEST(false);
1842         };
1843         return *defaultLayout;
1844 }
1845
1846
1847 DocumentClassPtr getDocumentClass(
1848                 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1849                 string const & cengine, bool const clone)
1850 {
1851         DocumentClassPtr doc_class =
1852             DocumentClassPtr(new DocumentClass(baseClass));
1853         LayoutModuleList::const_iterator it = modlist.begin();
1854         LayoutModuleList::const_iterator en = modlist.end();
1855         for (; it != en; ++it) {
1856                 string const modName = *it;
1857                 LyXModule * lm = theModuleList[modName];
1858                 if (!lm) {
1859                         docstring const msg =
1860                                                 bformat(_("The module %1$s has been requested by\n"
1861                                                 "this document but has not been found in the list of\n"
1862                                                 "available modules. If you recently installed it, you\n"
1863                                                 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1864                         if (!clone)
1865                                 frontend::Alert::warning(_("Module not available"), msg);
1866                         continue;
1867                 }
1868                 if (!lm->isAvailable() && !clone) {
1869                         docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1870                         docstring const msg =
1871                                 bformat(_("The module %1$s requires a package that is not\n"
1872                                         "available in your LaTeX installation, or a converter that\n"
1873                                         "you have not installed. LaTeX output may not be possible.\n"
1874                                         "Missing prerequisites:\n"
1875                                                 "\t%2$s\n"
1876                                         "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1877                                 from_utf8(modName), prereqs);
1878                         frontend::Alert::warning(_("Package not available"), msg, true);
1879                 }
1880                 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1881                 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1882                         docstring const msg =
1883                                                 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1884                         frontend::Alert::warning(_("Read Error"), msg);
1885                 }
1886         }
1887
1888         if (cengine.empty())
1889                 return doc_class;
1890
1891         LyXCiteEngine * ce = theCiteEnginesList[cengine];
1892         if (!ce) {
1893                 docstring const msg =
1894                                         bformat(_("The cite engine %1$s has been requested by\n"
1895                                         "this document but has not been found in the list of\n"
1896                                         "available engines. If you recently installed it, you\n"
1897                                         "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1898                 if (!clone)
1899                         frontend::Alert::warning(_("Cite Engine not available"), msg);
1900         } else if (!ce->isAvailable() && !clone) {
1901                 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1902                 docstring const msg =
1903                         bformat(_("The cite engine %1$s requires a package that is not\n"
1904                                 "available in your LaTeX installation, or a converter that\n"
1905                                 "you have not installed. LaTeX output may not be possible.\n"
1906                                 "Missing prerequisites:\n"
1907                                         "\t%2$s\n"
1908                                 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1909                         from_utf8(cengine), prereqs);
1910                 frontend::Alert::warning(_("Package not available"), msg, true);
1911         } else {
1912                 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1913                 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1914                         docstring const msg =
1915                                                 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1916                         frontend::Alert::warning(_("Read Error"), msg);
1917                 }
1918         }
1919
1920         return doc_class;
1921 }
1922
1923
1924 /////////////////////////////////////////////////////////////////////////
1925 //
1926 // DocumentClass
1927 //
1928 /////////////////////////////////////////////////////////////////////////
1929
1930 DocumentClass::DocumentClass(LayoutFile const & tc)
1931         : TextClass(tc)
1932 {}
1933
1934
1935 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1936 {
1937         LayoutList::const_iterator it  = layoutlist_.begin();
1938         LayoutList::const_iterator end = layoutlist_.end();
1939         for (; it != end; ++it)
1940                 if (it->latexname() == lay)
1941                         return true;
1942         return false;
1943 }
1944
1945
1946 bool DocumentClass::provides(string const & p) const
1947 {
1948         return provides_.find(p) != provides_.end();
1949 }
1950
1951
1952 bool DocumentClass::hasTocLevels() const
1953 {
1954         return min_toclevel_ != Layout::NOT_IN_TOC;
1955 }
1956
1957
1958 Layout const & DocumentClass::getTOCLayout() const
1959 {
1960         // we're going to look for the layout with the minimum toclevel
1961         TextClass::LayoutList::const_iterator lit = begin();
1962         TextClass::LayoutList::const_iterator const len = end();
1963         int minlevel = 1000;
1964         Layout const * lay = NULL;
1965         for (; lit != len; ++lit) {
1966                 int const level = lit->toclevel;
1967                 // we don't want Part or unnumbered sections
1968                 if (level == Layout::NOT_IN_TOC || level < 0
1969                     || level >= minlevel || lit->counter.empty())
1970                         continue;
1971                 lay = &*lit;
1972                 minlevel = level;
1973         }
1974         if (lay)
1975                 return *lay;
1976         // hmm. that is very odd, so we'll do our best.
1977         return operator[](defaultLayoutName());
1978 }
1979
1980
1981 Layout const & DocumentClass::htmlTOCLayout() const
1982 {
1983         if (html_toc_section_.empty())
1984                 html_toc_section_ = getTOCLayout().name();
1985         return operator[](html_toc_section_);
1986 }
1987
1988
1989 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1990         string const & entry, bool const punct, string const & fallback) const
1991 {
1992         string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}"
1993                                 "\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]]"
1994                                 "[[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1995         if (punct)
1996                 default_format += ".";
1997
1998         map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
1999         if (itype == cite_formats_.end())
2000                 return default_format;
2001         map<string, string>::const_iterator it = itype->second.find(entry);
2002         if (it == itype->second.end() && !fallback.empty())
2003                 it = itype->second.find(fallback);
2004         if (it == itype->second.end())
2005                 return default_format;
2006         if (punct)
2007                 return it->second + ".";
2008         return it->second;
2009 }
2010
2011
2012 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
2013         string const & macro) const
2014 {
2015         static string empty;
2016         map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
2017         if (itype == cite_macros_.end())
2018                 return empty;
2019         map<string, string>::const_iterator it = itype->second.find(macro);
2020         if (it == itype->second.end())
2021                 return empty;
2022         return it->second;
2023 }
2024
2025
2026 vector<string> const DocumentClass::citeCommands(
2027         CiteEngineType const & type) const
2028 {
2029         vector<CitationStyle> const styles = citeStyles(type);
2030         vector<CitationStyle>::const_iterator it = styles.begin();
2031         vector<CitationStyle>::const_iterator end = styles.end();
2032         vector<string> cmds;
2033         for (; it != end; ++it) {
2034                 CitationStyle const cite = *it;
2035                 cmds.push_back(cite.name);
2036         }
2037         return cmds;
2038 }
2039
2040
2041 vector<CitationStyle> const & DocumentClass::citeStyles(
2042         CiteEngineType const & type) const
2043 {
2044         static vector<CitationStyle> empty;
2045         map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
2046         if (it == cite_styles_.end())
2047                 return empty;
2048         return it->second;
2049 }
2050
2051
2052 /////////////////////////////////////////////////////////////////////////
2053 //
2054 // PageSides
2055 //
2056 /////////////////////////////////////////////////////////////////////////
2057
2058 ostream & operator<<(ostream & os, PageSides p)
2059 {
2060         switch (p) {
2061         case OneSide:
2062                 os << '1';
2063                 break;
2064         case TwoSides:
2065                 os << '2';
2066                 break;
2067         }
2068         return os;
2069 }
2070
2071
2072 } // namespace lyx