]> git.lyx.org Git - features.git/blob - src/xml.h
XML: memorise if the last thing that is getting output is a line feed.
[features.git] / src / xml.h
1 // -*- C++ -*-
2 /**
3  * \file xml.h
4  * This file is part of LyX, the document processor.
5  * License details can be found in the file COPYING.
6  *
7  * \author José Matos
8  * \author John Levon
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #ifndef XML_H
14 #define XML_H
15
16 #include "support/docstring.h"
17
18 #include <deque>
19 #include <memory>
20
21 namespace lyx {
22
23 class Buffer;
24 class Paragraph;
25 class OutputParams;
26
27 // Inspiration for the *Tag structs and for XMLStream
28 // came from MathStream and its cousins.
29
30 namespace xml {
31 struct StartTag;
32 struct EndTag;
33 struct CompTag;
34 struct ParTag;
35 struct FontTag;
36 struct CR;
37 }
38
39 class XMLStream {
40 public:
41         ///
42         explicit XMLStream(odocstream & os): os_(os), escape_(ESCAPE_ALL), is_last_tag_cr_(false) {}
43         ///
44         odocstream & os() { return os_; }
45         ///
46         // int & tab() { return tab_; }
47         /// closes any font tags that are eligible to be closed,
48         /// i.e., last on the tag_stack_.
49         /// \return false if there are open font tags we could not close.
50         /// because they are "blocked" by open non-font tags on the stack.
51         bool closeFontTags();
52         /// sets a mark so we know what tags to close at the end.
53         /// normally called at the start of a paragraph.
54         void startDivision(bool keep_empty);
55         /// clears the mark set by previous method.
56         /// there should not be any other tags open before it on the stack,
57         /// but if there are, we will close them.
58         void endDivision();
59         ///
60         XMLStream & operator<<(docstring const &);
61         ///
62         XMLStream & operator<<(const char *);
63         ///
64         XMLStream & operator<<(char_type);
65         ///
66         XMLStream & operator<<(int);
67         ///
68         XMLStream & operator<<(char);
69         ///
70         XMLStream & operator<<(xml::StartTag const &);
71         ///
72         XMLStream & operator<<(xml::EndTag const &);
73         ///
74         XMLStream & operator<<(xml::CompTag const &);
75         ///
76         XMLStream & operator<<(xml::ParTag const &);
77         ///
78         XMLStream & operator<<(xml::FontTag const &);
79         ///
80         XMLStream & operator<<(xml::CR const &);
81         ///
82         enum EscapeSettings {
83                 ESCAPE_NONE,
84                 ESCAPE_AND, // meaning &
85                 ESCAPE_ALL, // meaning <, >, &, at present
86                 ESCAPE_COMMENTS // Anything that is forbidden within comments
87         };
88         /// Sets what we are going to escape on the NEXT write.
89         /// Everything is reset for the next time.
90         XMLStream & operator<<(EscapeSettings);
91         /// This routine is for debugging the tag stack, etc. Code
92         /// for it is disabled by default, however, so you will need
93         /// to enable it if you want to use it.
94         void dumpTagStack(std::string const & msg);
95         ///
96         bool isTagOpen(xml::StartTag const &, int maxdepth = -1) const;
97         ///
98         bool isTagOpen(xml::EndTag const &, int maxdepth = -1) const;
99         ///
100         bool isTagPending(xml::StartTag const &, int maxdepth = -1) const;
101         ///
102         bool isLastTagCR() const { return is_last_tag_cr_; };
103 private:
104         ///
105         void clearTagDeque();
106         ///
107         void writeError(std::string const &) const;
108         ///
109         void writeError(docstring const &) const;
110         ///
111         odocstream & os_;
112         ///
113         EscapeSettings escape_;
114         // What we would really like to do here is simply use a
115         // deque<StartTag>. But we want to store both StartTags and
116         // sub-classes thereof on this stack, which means we run into the
117         // so-called polymorphic class problem with the STL. We therefore have
118         // to use a deque<StartTag *>, which leads to the question who will
119         // own these pointers and how they will be deleted, so we use shared
120         // pointers.
121         ///
122         typedef std::shared_ptr<xml::StartTag> TagPtr;
123         typedef std::deque<TagPtr> TagDeque;
124         ///
125         template <typename T>
126         TagPtr makeTagPtr(T const & tag) { return std::make_shared<T>(tag); }
127         ///
128         TagDeque pending_tags_;
129         ///
130         TagDeque tag_stack_;
131         ///
132         bool is_last_tag_cr_;
133 public:
134         bool pending_tags_empty() { return pending_tags_.empty();};
135 };
136
137 namespace xml {
138
139 /// Escape the given character, if necessary, to an entity.
140 docstring escapeChar(char_type c, XMLStream::EscapeSettings e);
141
142 /// Escape the given character, if necessary, to an entity.
143 docstring escapeChar(char c, XMLStream::EscapeSettings e);
144
145 /// Escape a word instead of a single character
146 docstring escapeString(docstring const & raw, XMLStream::EscapeSettings e=XMLStream::ESCAPE_ALL);
147
148 /// cleans \param str for use as an attribute by replacing all non-altnum by "_"
149 docstring cleanAttr(docstring const & str);
150
151 /// \p c must be ASCII
152 docstring escapeChar(char c, XMLStream::EscapeSettings e);
153
154 /// replaces illegal characters from ID attributes
155 docstring cleanID(docstring const &orig);
156
157 /// returns a unique numeric ID
158 docstring uniqueID(docstring const & label);
159
160 struct FontTag;
161 struct EndFontTag;
162
163 /// Attributes will be escaped automatically and so should NOT
164 /// be escaped before being passed to the constructor.
165 struct StartTag
166 {
167         ///
168         explicit StartTag(std::string const & tag) : tag_(from_ascii(tag)), keepempty_(false) {}
169         ///
170         explicit StartTag(docstring const & tag) : tag_(tag), keepempty_(false) {}
171         ///
172         explicit StartTag(docstring const & tag, docstring const & attr,
173                                           bool keepempty = false)
174                         : tag_(tag), attr_(attr), keepempty_(keepempty) {}
175         ///
176         explicit StartTag(std::string const & tag, std::string const & attr,
177                                           bool keepempty = false)
178                         : tag_(from_ascii(tag)), attr_(from_ascii(attr)), keepempty_(keepempty) {}
179         ///
180         explicit StartTag(std::string const & tag, docstring const & attr,
181                                           bool keepempty = false)
182                         : tag_(from_ascii(tag)), attr_(attr), keepempty_(keepempty) {}
183         ///
184         virtual ~StartTag() {}
185         /// <tag_ attr_>
186         virtual docstring writeTag() const;
187         /// </tag_>
188         virtual docstring writeEndTag() const;
189         ///
190         virtual FontTag const * asFontTag() const { return nullptr; }
191         ///
192         virtual bool operator==(StartTag const & rhs) const
193         { return tag_ == rhs.tag_; }
194         ///
195         virtual bool operator!=(StartTag const & rhs) const
196         { return !(*this == rhs); }
197         ///
198         virtual bool operator==(FontTag const & rhs) const;
199         ///
200         docstring tag_;
201         ///
202         docstring attr_;
203         /// whether to keep things like "<tag></tag>" or discard them
204         /// you would want this for td, e.g, but maybe not for a div
205         bool keepempty_;
206 };
207
208
209 ///
210 struct EndTag
211 {
212         ///
213         explicit EndTag(std::string tag) : tag_(from_ascii(tag)) {}
214         ///
215         explicit EndTag(docstring tag) : tag_(tag) {}
216         ///
217         virtual ~EndTag() {}
218         /// </tag_>
219         virtual docstring writeEndTag() const;
220         ///
221         bool operator==(StartTag const & rhs) const
222         { return tag_ == rhs.tag_; }
223         ///
224         bool operator!=(StartTag const & rhs) const
225         { return !(*this == rhs); }
226         ///
227         virtual EndFontTag const * asFontTag() const { return 0; }
228         ///
229         docstring tag_;
230 };
231
232
233 /// Tags like <img />
234 /// Attributes will be escaped automatically and so should NOT
235 /// be escaped before being passed to the constructor.
236 struct CompTag
237 {
238         ///
239         explicit CompTag(std::string const & tag)
240                         : tag_(tag) {}
241         ///
242         explicit CompTag(std::string const & tag, std::string const & attr)
243                         : tag_(tag), attr_(attr) {}
244         /// <tag_ attr_ />
245         docstring writeTag() const;
246         ///
247         std::string tag_;
248         ///
249         std::string attr_;
250 };
251
252
253 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
254 /// parid is only used for HTML output; XML is supposed to use attr for this.
255 struct ParTag : public StartTag
256 {
257         ///
258         explicit ParTag(std::string const & tag, const std::string & attr): StartTag(tag, from_utf8(attr)) {}
259         ///
260         ~ParTag() {}
261 };
262
263
264 ///
265 enum FontTypes {
266         // ranges
267         FT_EMPH,
268         FT_NOUN,
269         FT_UBAR,
270         FT_DBAR,
271         FT_WAVE,
272         FT_SOUT,
273         FT_XOUT,
274         // bold
275         FT_BOLD,
276         // shapes
277         FT_UPRIGHT,
278         FT_ITALIC,
279         FT_SLANTED,
280         FT_SMALLCAPS,
281         // families
282         FT_ROMAN,
283         FT_SANS,
284         FT_TYPE,
285         // sizes
286         FT_SIZE_TINY,
287         FT_SIZE_SCRIPT,
288         FT_SIZE_FOOTNOTE,
289         FT_SIZE_SMALL,
290         FT_SIZE_NORMAL,
291         FT_SIZE_LARGE,
292         FT_SIZE_LARGER,
293         FT_SIZE_LARGEST,
294         FT_SIZE_HUGE,
295         FT_SIZE_HUGER,
296         FT_SIZE_INCREASE,
297         FT_SIZE_DECREASE
298
299         // When updating this list, also update fontToTag in both output_docbook.cpp and output_xhtml.cpp,
300         // fontToRole in output_docbook.cpp, and fontToAttribute in output_xhtml.cpp.
301 };
302
303
304 ///
305 struct FontTag : public StartTag
306 {
307         ///
308         FontTag(docstring const & tag, FontTypes type): StartTag(tag), font_type_(type) {}
309         ///
310         FontTag(std::string const & tag, FontTypes type): StartTag(from_utf8(tag)), font_type_(type) {}
311         ///
312         FontTag(docstring const & tag, docstring const & attr, FontTypes type): StartTag(tag, attr), font_type_(type) {}
313         ///
314         FontTag(std::string const & tag, std::string const & attr, FontTypes type): StartTag(from_utf8(tag), from_utf8(attr)), font_type_(type) {}
315         ///
316         FontTag const * asFontTag() const override { return this; }
317         ///
318         bool operator==(StartTag const &) const override;
319         ///
320         FontTypes font_type_;
321 };
322
323
324 ///
325 struct EndFontTag : public EndTag
326 {
327         ///
328         EndFontTag(docstring const & tag, FontTypes type): EndTag(tag), font_type_(type) {}
329         ///
330         EndFontTag(std::string const & tag, FontTypes type): EndTag(from_utf8(tag)), font_type_(type) {}
331         ///
332         EndFontTag const * asFontTag() const override { return this; }
333         ///
334         FontTypes font_type_;
335 };
336
337
338 // trivial struct for output of newlines
339 struct CR{};
340
341 // an illegal tag for internal use
342 xml::StartTag const parsep_tag("&LyX_parsep_tag&");
343
344 /// Open tag
345 void openTag(odocstream & os, std::string const & name,
346              std::string const & attribute = std::string());
347
348 /// Open tag
349 void openTag(Buffer const & buf, odocstream & os,
350              OutputParams const & runparams, Paragraph const & par);
351
352 /// Close tag
353 void closeTag(odocstream & os, std::string const & name);
354
355 /// Close tag
356 void closeTag(odocstream & os, Paragraph const & par);
357
358 } // namespace xml
359
360 } // namespace lyx
361
362 #endif // XML_H