]> git.lyx.org Git - lyx.git/blob - src/sgml.C
bc8704c01b9502bb88fd9233e39f1475eb5b3090
[lyx.git] / src / sgml.C
1 /**
2  * \file sgml.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author John Levon
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "sgml.h"
15
16 #include "buffer.h"
17 #include "bufferparams.h"
18 #include "counters.h"
19 #include "lyxtext.h"
20 #include "outputparams.h"
21 #include "paragraph.h"
22
23 #include "support/lstrings.h"
24 #include "support/std_ostream.h"
25 #include "support/convert.h"
26
27 #include <boost/tuple/tuple.hpp>
28
29 #include <map>
30 #include <sstream>
31
32
33 namespace lyx {
34
35 using support::subst;
36
37 using std::make_pair;
38 using std::map;
39 using std::ostream;
40 using std::ostringstream;
41 using std::pair;
42 using std::string;
43
44 pair<bool, string> sgml::escapeChar(char c)
45 {
46         string str;
47
48         switch (c) {
49         case ' ':
50                 return make_pair(true, string(" "));
51                 break;
52         case '\0': // Ignore :-)
53                 str.erase();
54                 break;
55         case '&':
56                 str = "&amp;";
57                 break;
58         case '<':
59                 str = "&lt;";
60                 break;
61         case '>':
62                 str = "&gt;";
63                 break;
64 #if 0
65         case '$':
66                 str = "&dollar;";
67                 break;
68         case '#':
69                 str = "&num;";
70                 break;
71         case '%':
72                 str = "&percnt;";
73                 break;
74         case '[':
75                 str = "&lsqb;";
76                 break;
77         case ']':
78                 str = "&rsqb;";
79                 break;
80         case '{':
81                 str = "&lcub;";
82                 break;
83         case '}':
84                 str = "&rcub;";
85                 break;
86         case '~':
87                 str = "&tilde;";
88                 break;
89         case '"':
90                 str = "&quot;";
91                 break;
92         case '\\':
93                 str = "&bsol;";
94                 break;
95 #endif
96         default:
97                 str = c;
98                 break;
99         }
100         return make_pair(false, str);
101 }
102
103
104 string sgml::escapeString(string const & raw)
105 {
106         ostringstream bin;
107
108         for(string::size_type i = 0; i < raw.size(); ++i) {
109                 bool ws;
110                 string str;
111                 boost::tie(ws, str) = sgml::escapeChar(raw[i]);
112                 bin << str;
113         }
114         return bin.str();
115 }
116
117
118 string const sgml::uniqueID(string const label)
119 {
120         static unsigned int seed = 1000;
121         return label + convert<string>(++seed);
122 }
123
124
125 string sgml::cleanID(Buffer const & buf, OutputParams const & runparams, std::string const & orig)
126 {
127         // The standard DocBook SGML declaration only allows letters,
128         // digits, '-' and '.' in a name.
129         // Since users might change that declaration one has to cater
130         // for additional allowed characters.
131         // This routine replaces illegal characters by '-' or '.'
132         // and adds a number for uniqueness.
133         // If you know what you are doing, you can set allowed==""
134         // to disable this mangling.
135         LyXTextClass const & tclass = buf.params().getLyXTextClass();
136         string const allowed = runparams.flavor == OutputParams::XML? ".-_:":tclass.options();
137
138         if (allowed.empty())
139                 return orig;
140
141         string::const_iterator it  = orig.begin();
142         string::const_iterator end = orig.end();
143
144         string content;
145
146         typedef map<string, string> MangledMap;
147         static MangledMap mangledNames;
148         static int mangleID = 1;
149
150         MangledMap::const_iterator const known = mangledNames.find(orig);
151         if (known != mangledNames.end())
152                 return (*known).second;
153
154         // make sure it starts with a letter
155         if (!isalpha(*it) && allowed.find(*it) >= allowed.size())
156                 content += "x";
157
158         bool mangle = false;
159         for (; it != end; ++it) {
160                 char c = *it;
161                 if (isalpha(c) || isdigit(c) || c == '-' || c == '.' || allowed.find(c) < allowed.size())
162                         content += c;
163                 else if (c == '_' || c == ' ') {
164                         mangle = true;
165                         content += "-";
166                 }
167                 else if (c == ':' || c == ',' || c == ';' || c == '!') {
168                         mangle = true;
169                         content += ".";
170                 }
171                 else {
172                         mangle = true;
173                 }
174         }
175         if (mangle) {
176                 content += "-" + convert<string>(mangleID++);
177         }
178         else if (isdigit(content[content.size() - 1])) {
179                 content += ".";
180         }
181
182         mangledNames[orig] = content;
183
184         return content;
185 }
186
187
188 void sgml::openTag(odocstream & os, string const & name, string const & attribute)
189 {
190         // FIXME UNICODE
191         // This should be fixed in layout files later.
192         string param = subst(attribute, "<", "\"");
193         param = subst(param, ">", "\"");
194
195         if (!name.empty() && name != "!-- --") {
196                 os << '<' << from_ascii(name);
197                 if (!param.empty())
198                     os << ' ' << from_ascii(param);
199                 os << '>';
200         }
201 }
202
203
204 void sgml::closeTag(odocstream & os, string const & name)
205 {
206         // FIXME UNICODE
207         if (!name.empty() && name != "!-- --")
208                 os << "</" << from_ascii(name) << '>';
209 }
210
211
212 void sgml::openTag(Buffer const & buf, odocstream & os, OutputParams const & runparams, Paragraph const & par)
213 {
214         LyXLayout_ptr const & style = par.layout();
215         string const & name = style->latexname();
216         string param = style->latexparam();
217         Counters & counters = buf.params().getLyXTextClass().counters();
218
219         string id = par.getID(buf, runparams);
220
221         string attribute;
222         if(!id.empty()) {
223                 if (param.find('#') != string::npos) {
224                         string::size_type pos = param.find("id=<");
225                         string::size_type end = param.find(">");
226                         if( pos != string::npos && end != string::npos)
227                                 param.erase(pos, end-pos + 1);
228                 }
229                 attribute = id + ' ' + param;
230         } else {
231                 if (param.find('#') != string::npos) {
232                         // FIXME UNICODE
233                         if(!style->counter.empty())
234                                 counters.step(style->counter);
235                         else
236                                 counters.step(from_ascii(name));
237                         int i = counters.value(from_ascii(name));
238                         attribute = subst(param, "#", convert<string>(i));
239                 } else {
240                         attribute = param;
241                 }
242         }
243         openTag(os, name, attribute);
244 }
245
246
247 void sgml::closeTag(odocstream & os, Paragraph const & par)
248 {
249         LyXLayout_ptr const & style = par.layout();
250         closeTag(os, style->latexname());
251 }
252
253
254 } // namespace lyx