2 * \file LayoutFileList.cpp
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
9 * Full author contact details are available in file CREDITS.
14 #include "LayoutFile.h"
17 #include "FloatList.h"
19 #include "TextClass.h"
21 #include "support/debug.h"
22 #include "support/FileName.h"
23 #include "support/filetools.h"
24 #include "support/gettext.h"
26 #include <boost/bind.hpp>
27 #include <boost/regex.hpp>
32 using namespace lyx::support
;
40 LayoutFile::LayoutFile(string
const & fn
, string
const & cln
,
41 string
const & desc
, bool texClassAvail
)
46 texClassAvail_
= texClassAvail
;
50 LayoutFileList
& LayoutFileList::get()
52 static LayoutFileList baseclasslist
;
57 bool LayoutFileList::haveClass(string
const & classname
) const
59 ClassMap::const_iterator it
= classmap_
.begin();
60 ClassMap::const_iterator en
= classmap_
.end();
61 for (; it
!= en
; ++it
) {
62 if (it
->first
== classname
)
69 LayoutFile
const & LayoutFileList::operator[](string
const & classname
) const
71 BOOST_ASSERT(haveClass(classname
));
72 return *classmap_
[classname
];
77 LayoutFileList::operator[](string
const & classname
)
79 BOOST_ASSERT(haveClass(classname
));
80 return *classmap_
[classname
];
84 // Reads LyX textclass definitions according to textclass config file
85 bool LayoutFileList::read()
88 FileName
const real_file
= libFileSearch("", "textclass.lst");
89 LYXERR(Debug::TCLASS
, "Reading textclasses from `" << real_file
<< '\'');
91 if (real_file
.empty()) {
92 lyxerr
<< "LayoutFileList::Read: unable to find "
94 << to_utf8(makeDisplayPath(real_file
.absFilename(), 1000))
95 << "'. Exiting." << endl
;
97 // This causes LyX to end... Not a desirable behaviour. Lgb
98 // What do you propose? That the user gets a file dialog
99 // and is allowed to hunt for the file? (Asger)
100 // more that we have a layout for minimal.cls statically
101 // compiled in... (Lgb)
104 if (!lex
.setFile(real_file
)) {
105 lyxerr
<< "LayoutFileList::Read: "
106 "lyxlex was not able to set file: "
107 << real_file
<< endl
;
111 lyxerr
<< "LayoutFileList::Read: unable to open "
113 << to_utf8(makeDisplayPath(real_file
.absFilename(), 1000))
114 << "'\nCheck your installation. LyX can't continue."
119 bool finished
= false;
121 LYXERR(Debug::TCLASS
, "Starting parsing of textclass.lst");
122 while (lex
.isOK() && !finished
) {
123 LYXERR(Debug::TCLASS
, "\tline by line");
125 case Lexer::LEX_FEOF
:
129 string
const fname
= lex
.getString();
130 LYXERR(Debug::TCLASS
, "Fname: " << fname
);
132 string
const clname
= lex
.getString();
133 LYXERR(Debug::TCLASS
, "Clname: " << clname
);
135 string
const desc
= lex
.getString();
136 LYXERR(Debug::TCLASS
, "Desc: " << desc
);
138 bool avail
= lex
.getBool();
139 LYXERR(Debug::TCLASS
, "Avail: " << avail
);
140 // This code is run when we have
141 // fname, clname, desc, and avail
142 LayoutFile
* tmpl
= new LayoutFile(fname
, clname
, desc
, avail
);
143 if (lyxerr
.debugging(Debug::TCLASS
)) {
144 // only system layout files are loaded here so no
145 // buffer path is needed.
148 classmap_
[fname
] = tmpl
;
154 LYXERR(Debug::TCLASS
, "End of parsing of textclass.lst");
156 // lyx will start with an empty classmap_, but only reconfigure is allowed
157 // in this case. This gives users a second chance to configure lyx if
158 // initial configuration fails. (c.f. bug 2829)
159 if (classmap_
.empty())
160 lyxerr
<< "LayoutFileList::Read: no textclasses found!"
166 std::vector
<LayoutFileIndex
> LayoutFileList::classList() const
168 std::vector
<LayoutFileIndex
> cl
;
169 ClassMap::const_iterator it
= classmap_
.begin();
170 ClassMap::const_iterator en
= classmap_
.end();
171 for (; it
!= en
; ++it
)
172 cl
.push_back(it
->first
);
177 void LayoutFileList::reset(LayoutFileIndex
const & classname
) {
178 BOOST_ASSERT(haveClass(classname
));
179 LayoutFile
* tc
= classmap_
[classname
];
181 new LayoutFile(tc
->name(), tc
->latexname(), tc
->description(),
182 tc
->isTeXClassAvailable());
183 classmap_
[classname
] = tmpl
;
188 string
const LayoutFileList::localPrefix
= "LOCAL:";
189 string
const LayoutFileList::embeddedPrefix
= "EMBED:";
193 LayoutFileList::addLayoutFile(string
const & textclass
, string
const & path
,
196 // FIXME There is a bug here: 4593
198 // only check for textclass.layout file, .cls can be anywhere in $TEXINPUTS
199 // NOTE: latex class name is defined in textclass.layout, which can be
200 // different from textclass
201 string fullName
= addName(path
, textclass
+ ".layout");
205 localIndex
= localPrefix
+ fullName
;
206 else if (type
== Embedded
)
207 localIndex
= embeddedPrefix
+ textclass
;
209 // if the local file has already been loaded, return it
210 if (haveClass(localIndex
))
213 FileName
const layout_file(fullName
);
214 if (layout_file
.exists()) {
215 LYXERR(Debug::TCLASS
, "Adding class " << textclass
<< " from directory " << path
);
216 // Read .layout file and get description, real latex classname etc
218 // This is a C++ version of function processLayoutFile in configure.py,
219 // which uses the following regex
220 // \Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}
221 ifstream
ifs(layout_file
.toFilesystemEncoding().c_str());
222 static regex
const reg("^#\\s*\\\\Declare(LaTeX|DocBook)Class\\s*"
223 "(?:\\[([^,]*)(?:,.*)*\\])*\\s*\\{(.*)\\}\\s*");
225 while (getline(ifs
, line
)) {
226 // look for the \DeclareXXXClass line
228 if (regex_match(line
, sub
, reg
)) {
229 // returns: whole string, classtype (not used here), class name, description
230 BOOST_ASSERT(sub
.size() == 4);
231 // now, create a TextClass with description containing path information
232 string
className(sub
.str(2) == "" ? textclass
: sub
.str(2));
234 new LayoutFile(textclass
, className
, localIndex
, true);
235 // This textclass is added on request so it will definitely be
236 // used. Load it now because other load() calls may fail if they
237 // are called in a context without buffer path information.
239 classmap_
[localIndex
] = tmpl
;
244 // If .layout is not in local directory, or an invalid layout is found, return null
249 LayoutFileIndex
defaultBaseclass()
251 if (LayoutFileList::get().haveClass("article"))
252 return string("article");
253 if (LayoutFileList::get().empty())
255 return LayoutFileList::get().classList().front();
260 // Reads the style files
263 LYXERR(Debug::TCLASS
, "LyXSetStyle: parsing configuration...");
265 if (!LayoutFileList::get().read()) {
266 LYXERR(Debug::TCLASS
, "LyXSetStyle: an error occured "
267 "during parsing.\n Exiting.");
271 LYXERR(Debug::TCLASS
, "LyXSetStyle: configuration parsed.");