4 * This file is part of LyX, the document processor.
5 * License details can be found in the file COPYING.
10 * Full author contact details are available in file CREDITS.
16 #include "support/docstring.h"
27 // Inspiration for the *Tag structs and for XMLStream
28 // came from MathMLStream and its cousins.
43 explicit XMLStream(odocstream & os): os_(os), escape_(ESCAPE_ALL), is_last_tag_cr_(true) {}
45 odocstream & os() { return os_; }
47 // int & tab() { return tab_; }
48 /// closes any font tags that are eligible to be closed,
49 /// i.e., last on the tag_stack_.
50 /// \return false if there are open font tags we could not close.
51 /// because they are "blocked" by open non-font tags on the stack.
53 /// sets a mark so we know what tags to close at the end.
54 /// normally called at the start of a paragraph.
55 void startDivision(bool keep_empty);
56 /// clears the mark set by previous method.
57 /// there should not be any other tags open before it on the stack,
58 /// but if there are, we will close them.
61 XMLStream & operator<<(docstring const &);
63 XMLStream & operator<<(const char *);
65 XMLStream & operator<<(char_type);
67 XMLStream & operator<<(int);
69 XMLStream & operator<<(char);
71 XMLStream & operator<<(xml::NullTag const &);
73 XMLStream & operator<<(xml::StartTag const &);
75 XMLStream & operator<<(xml::EndTag const &);
77 XMLStream & operator<<(xml::CompTag const &);
79 XMLStream & operator<<(xml::ParTag const &);
81 XMLStream & operator<<(xml::FontTag const &);
83 XMLStream & operator<<(xml::CR const &);
87 ESCAPE_AND, // meaning &
88 ESCAPE_ALL, // meaning <, >, &, at present, except things that are forbidden in comments
89 ESCAPE_COMMENTS // Anything that is forbidden within comments
91 /// Sets what we are going to escape on the NEXT write.
92 /// Everything is reset for the next time.
93 XMLStream & operator<<(EscapeSettings);
94 /// This routine is for debugging the tag stack, etc. Code
95 /// for it is disabled by default, however, so you will need
96 /// to enable it if you want to use it.
97 void dumpTagStack(std::string const & msg);
99 bool isTagOpen(xml::StartTag const &, int maxdepth = -1) const;
101 bool isTagOpen(xml::EndTag const &, int maxdepth = -1) const;
103 bool isTagPending(xml::StartTag const &, int maxdepth = -1) const;
104 /// Is the last tag that was added to the stream a new line (CR)? This is mostly to known
105 /// whether a new line must be added. Therefore, consider that an empty stream just had a CR,
106 /// that simplifies the logic using this code.
107 bool isLastTagCR() const { return is_last_tag_cr_; }
109 void writeError(std::string const &);
111 void writeError(docstring const &);
113 typedef std::shared_ptr<xml::StartTag> TagPtr;
114 /// Returns the last element on the tag stack. XMLStream keeps ownership of the item.
115 TagPtr getLastStackTag();
118 void clearTagDeque();
122 EscapeSettings escape_;
123 // What we would really like to do here is simply use a
124 // deque<StartTag>. But we want to store both StartTags and
125 // sub-classes thereof on this stack, which means we run into the
126 // so-called polymorphic class problem with the STL. We therefore have
127 // to use a deque<StartTag *>, which leads to the question who will
128 // own these pointers and how they will be deleted, so we use shared
131 typedef std::deque<TagPtr> TagDeque;
133 template <typename T>
134 TagPtr makeTagPtr(T const & tag) { return std::make_shared<T>(tag); }
136 TagDeque pending_tags_;
140 bool is_last_tag_cr_;
145 /// Escape the given character, if necessary, to an entity.
146 docstring escapeChar(char_type c, XMLStream::EscapeSettings e);
148 /// Escape the given character, if necessary, to an entity.
149 /// \param c must be ASCII
150 docstring escapeChar(char c, XMLStream::EscapeSettings e);
152 /// Escape a word instead of a single character
153 docstring escapeString(docstring const & raw, XMLStream::EscapeSettings e=XMLStream::ESCAPE_ALL);
155 /// cleans \param str for use as an attribute by replacing all non-altnum by "_"
156 docstring cleanAttr(docstring const & str);
158 /// replaces illegal characters from ID attributes
159 docstring cleanID(docstring const &orig);
161 /// returns a unique numeric ID
162 docstring uniqueID(docstring const & label);
164 /// determines whether a string only contains space characters
165 bool isNotOnlySpace(docstring const & str);
167 /// trims the string to the left, i.e. remove any space-like character at the beginning of the string
168 docstring trimLeft(docstring const & str);
173 /// Attributes will be escaped automatically and so should NOT
174 /// be escaped before being passed to the constructor.
178 explicit StartTag(std::string const & tag) : tag_(from_ascii(tag)), keepempty_(false), tagtype_("none") {}
180 explicit StartTag(docstring const & tag) : tag_(tag), keepempty_(false), tagtype_("none") {}
182 explicit StartTag(docstring const & tag, docstring const & attr,
183 bool keepempty = false, std::string const & tagtype = "none")
184 : tag_(tag), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
186 explicit StartTag(std::string const & tag, std::string const & attr,
187 bool keepempty = false, std::string const & tagtype = "none")
188 : tag_(from_ascii(tag)), attr_(from_utf8(attr)), keepempty_(keepempty), tagtype_(tagtype) {}
190 explicit StartTag(std::string const & tag, docstring const & attr,
191 bool keepempty = false, std::string const & tagtype = "none")
192 : tag_(from_ascii(tag)), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
194 virtual ~StartTag() = default;
196 virtual docstring writeTag() const;
198 virtual docstring writeEndTag() const;
200 virtual FontTag const * asFontTag() const { return nullptr; }
205 /// whether to keep things like "<tag></tag>" or discard them
206 /// you would want this for td, e.g, but maybe not for a div
208 /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
209 std::string tagtype_;
217 explicit EndTag(std::string const & tag, std::string const & tagtype = "none")
218 : tag_(from_ascii(tag)), tagtype_(tagtype) {}
220 explicit EndTag(docstring const & tag, std::string const & tagtype = "none")
221 : tag_(tag), tagtype_(tagtype) {}
223 virtual ~EndTag() = default;
225 virtual docstring writeEndTag() const;
227 virtual EndFontTag const * asFontTag() const { return nullptr; }
230 /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
231 /// The value should match that of the corresponding xml::StartTag.
232 std::string tagtype_;
236 /// Tags like <img />
237 /// Attributes will be escaped automatically and so should NOT
238 /// be escaped before being passed to the constructor.
242 explicit CompTag(std::string const & tag)
243 : tag_(from_utf8(tag)), tagtype_("none") {}
245 explicit CompTag(docstring const & tag)
246 : tag_(tag), tagtype_("none") {}
248 explicit CompTag(std::string const & tag, std::string const & attr, std::string const & tagtype = "none")
249 : tag_(from_utf8(tag)), attr_(from_utf8(attr)), tagtype_(tagtype) {}
251 explicit CompTag(std::string const & tag, docstring const & attr, std::string const & tagtype = "none")
252 : tag_(from_utf8(tag)), attr_(attr), tagtype_(tagtype) {}
254 explicit CompTag(docstring const & tag, std::string const & attr, std::string const & tagtype = "none")
255 : tag_(tag), attr_(from_utf8(attr)), tagtype_(tagtype) {}
257 explicit CompTag(docstring const & tag, docstring const & attr, std::string const & tagtype = "none")
258 : tag_(tag), attr_(attr), tagtype_(tagtype) {}
260 docstring writeTag() const;
265 /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
266 std::string tagtype_;
270 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
271 struct ParTag : public StartTag
274 explicit ParTag(std::string const & tag, const std::string & attr): StartTag(tag, from_utf8(attr)) {}
276 ~ParTag() override = default;
280 /// A special tag that doesn't produce any XML output, but makes the XMLStream behave as it it output some text.
281 struct NullTag : public StartTag
284 NullTag(): StartTag("NULLTAG", from_utf8(""), true) {}
286 ~NullTag() override = default;
325 // When updating this list, also update fontToTag in both output_docbook.cpp and output_xhtml.cpp,
326 // fontToRole in output_docbook.cpp, and fontToAttribute in output_xhtml.cpp.
331 struct FontTag : public StartTag
334 FontTag(docstring const & tag, FontTypes type): StartTag(tag), font_type_(type) {}
336 FontTag(std::string const & tag, FontTypes type): StartTag(from_utf8(tag)), font_type_(type) {}
338 FontTag(docstring const & tag, docstring const & attr, FontTypes type): StartTag(tag, attr), font_type_(type) {}
340 FontTag(std::string const & tag, std::string const & attr, FontTypes type): StartTag(from_utf8(tag), from_utf8(attr)), font_type_(type) {}
342 FontTag const * asFontTag() const override { return this; }
344 FontTypes font_type_;
349 struct EndFontTag : public EndTag
352 EndFontTag(docstring const & tag, FontTypes type): EndTag(tag), font_type_(type) {}
354 EndFontTag(std::string const & tag, FontTypes type): EndTag(from_utf8(tag)), font_type_(type) {}
356 EndFontTag const * asFontTag() const override { return this; }
358 FontTypes font_type_;
362 // trivial struct for output of newlines
365 // an illegal tag for internal use
366 xml::StartTag const parsep_tag("&LyX_parsep_tag&");
369 void openTag(odocstream & os, std::string const & name,
370 std::string const & attribute = std::string());
373 void openTag(Buffer const & buf, odocstream & os,
374 OutputParams const & runparams, Paragraph const & par);
377 void closeTag(odocstream & os, std::string const & name);
380 void closeTag(odocstream & os, Paragraph const & par);
382 // Convenience functions to open and close tags. First, very low-level ones to ensure a consistent new-line behaviour.
386 // Contents of the block.
391 // <paratag>Contents of the paragraph.</paratag>
394 // Content before<inlinetag>Contents of the paragraph.</inlinetag>Content after
397 void openTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
399 void openTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
401 void openTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
403 void openTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
405 void closeTag(XMLStream & xs, const docstring & tag, const std::string & tagtype);
407 void closeTag(XMLStream & xs, const std::string & tag, const std::string & tagtype);
409 void compTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
411 void compTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
413 void compTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
415 void compTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
420 /// Comparison operators for tags. They are defined as free functions, otherwise comparison of casts does not work.
421 /// For font tags, do not only compare the XML tag, but also the font type: several fonts can be using the same tag.
422 /// In XHTML, <span>; in DocBook, <emphasis>.
423 bool operator==(xml::StartTag const & lhs, xml::StartTag const & rhs);
424 bool operator==(xml::EndTag const & lhs, xml::StartTag const & rhs);
425 bool operator!=(xml::EndTag const & lhs, xml::StartTag const & rhs);
426 bool operator!=(xml::StartTag const & lhs, xml::StartTag const & rhs);