]> git.lyx.org Git - features.git/blobdiff - src/xml.cpp
Improved character count statistics for letter based insets (e.g. the LyX logo).
[features.git] / src / xml.cpp
index 7733bf0260d7d944be9b012dd6cd266edc097b27..e16a7840b6db099e1a8048da629bad979bff6b1c 100644 (file)
@@ -44,43 +44,50 @@ docstring escapeChar(char_type c, XMLStream::EscapeSettings e)
 {
        docstring str;
        switch (e) { // For HTML: always ESCAPE_NONE. For XML: it depends, hence the parameter.
-               case XMLStream::ESCAPE_NONE:
-                       str += c;
+       case XMLStream::ESCAPE_NONE:
+       case XMLStream::ESCAPE_COMMENTS:
+               str += c;
+               break;
+       case XMLStream::ESCAPE_ALL:
+               if (c == '<') {
+                       str += "&lt;";
                        break;
-               case XMLStream::ESCAPE_ALL:
-                       if (c == '<') {
-                               str += "&lt;";
-                               break;
-                       } else if (c == '>') {
-                               str += "&gt;";
-                               break;
-                       }
-                       // fall through
-               case XMLStream::ESCAPE_AND:
-                       if (c == '&')
-                               str += "&amp;";
-                       else
-                               str     +=c ;
+               } else if (c == '>') {
+                       str += "&gt;";
                        break;
+               }
+               // fall through
+       case XMLStream::ESCAPE_AND:
+               if (c == '&')
+                       str += "&amp;";
+               else
+                       str     +=c ;
+               break;
        }
        return str;
 }
 
 
-// escape what needs escaping
-docstring xmlize(docstring const &str, XMLStream::EscapeSettings e) {
-       odocstringstream d;
-       docstring::const_iterator it = str.begin();
-       docstring::const_iterator en = str.end();
-       for (; it != en; ++it)
-               d << escapeChar(*it, e);
-       return d.str();
+docstring escapeChar(char c, XMLStream::EscapeSettings e)
+{
+       LATTEST(static_cast<unsigned char>(c) < 0x80);
+       return escapeChar(static_cast<char_type>(c), e);
 }
 
 
-docstring escapeChar(char c, XMLStream::EscapeSettings e) {
-       LATTEST(static_cast<unsigned char>(c) < 0x80);
-       return escapeChar(static_cast<char_type>(c), e);
+docstring escapeString(docstring const & raw, XMLStream::EscapeSettings e)
+{
+       docstring bin;
+       bin.reserve(raw.size() * 2); // crude approximation is sufficient
+       for (size_t i = 0; i != raw.size(); ++i) {
+               char_type c = raw[i];
+               if (e == XMLStream::ESCAPE_COMMENTS && c == '-' && i > 0 && raw[i - 1] == '-')
+                       bin += "&#45;";
+               else
+                       bin += xml::escapeChar(c, e);
+       }
+
+       return bin;
 }
 
 
@@ -97,10 +104,11 @@ docstring cleanAttr(docstring const & str)
 }
 
 
-docstring StartTag::writeTag() const {
+docstring StartTag::writeTag() const
+{
        docstring output = '<' + tag_;
        if (!attr_.empty()) {
-               docstring attributes = xml::xmlize(attr_, XMLStream::ESCAPE_NONE);
+               docstring attributes = xml::escapeString(attr_, XMLStream::ESCAPE_NONE);
                attributes.erase(attributes.begin(), std::find_if(attributes.begin(), attributes.end(),
                                                           [](int c) {return !std::isspace(c);}));
                if (!attributes.empty()) {
@@ -112,27 +120,31 @@ docstring StartTag::writeTag() const {
 }
 
 
-docstring StartTag::writeEndTag() const {
+docstring StartTag::writeEndTag() const
+{
        return from_utf8("</") + tag_ + from_utf8(">");
 }
 
 
-bool StartTag::operator==(FontTag const &rhs) const {
+bool StartTag::operator==(FontTag const &rhs) const
+{
        return rhs == *this;
 }
 
 
-docstring EndTag::writeEndTag() const {
+docstring EndTag::writeEndTag() const
+{
        return from_utf8("</") + tag_ + from_utf8(">");
 }
 
 
-docstring CompTag::writeTag() const {
+docstring CompTag::writeTag() const
+{
        docstring output = '<' + from_utf8(tag_);
        if (!attr_.empty()) {
                // Erase the beginning of the attributes if it contains space characters: this function deals with that
                // automatically.
-               docstring attributes = xmlize(from_utf8(attr_), XMLStream::ESCAPE_NONE);
+               docstring attributes = escapeString(from_utf8(attr_), XMLStream::ESCAPE_NONE);
                attributes.erase(attributes.begin(), std::find_if(attributes.begin(), attributes.end(),
                                                           [](int c) {return !std::isspace(c);}));
                if (!attributes.empty()) {
@@ -155,19 +167,22 @@ bool FontTag::operator==(StartTag const & tag) const
 } // namespace xml
 
 
-void XMLStream::writeError(std::string const &s) const {
+void XMLStream::writeError(std::string const &s) const
+{
        LYXERR0(s);
        os_ << from_utf8("<!-- Output Error: " + s + " -->\n");
 }
 
 
-void XMLStream::writeError(docstring const &s) const {
+void XMLStream::writeError(docstring const &s) const
+{
        LYXERR0(s);
        os_ << from_utf8("<!-- Output Error: ") << s << from_utf8(" -->\n");
 }
 
 
-bool XMLStream::closeFontTags() {
+bool XMLStream::closeFontTags()
+{
        if (isTagPending(xml::parsep_tag))
                // we haven't had any content
                return true;
@@ -185,7 +200,9 @@ bool XMLStream::closeFontTags() {
                tag_stack_.pop_back();
                // this shouldn't happen, since then the font tags
                // weren't in any other tag.
-               LASSERT(!tag_stack_.empty(), return true);
+//             LASSERT(!tag_stack_.empty(), return true);
+               if (tag_stack_.empty())
+                       return true;
                curtag = &tag_stack_.back();
        }
 
@@ -206,14 +223,16 @@ bool XMLStream::closeFontTags() {
 }
 
 
-void XMLStream::startDivision(bool keep_empty) {
+void XMLStream::startDivision(bool keep_empty)
+{
        pending_tags_.push_back(makeTagPtr(xml::StartTag(xml::parsep_tag)));
        if (keep_empty)
                clearTagDeque();
 }
 
 
-void XMLStream::endDivision() {
+void XMLStream::endDivision()
+{
        if (isTagPending(xml::parsep_tag)) {
                // this case is normal. it just means we didn't have content,
                // so the parsep_tag never got moved onto the tag stack.
@@ -256,7 +275,8 @@ void XMLStream::endDivision() {
 }
 
 
-void XMLStream::clearTagDeque() {
+void XMLStream::clearTagDeque()
+{
        while (!pending_tags_.empty()) {
                TagPtr const & tag = pending_tags_.front();
                if (*tag != xml::parsep_tag)
@@ -268,24 +288,27 @@ void XMLStream::clearTagDeque() {
 }
 
 
-XMLStream &XMLStream::operator<<(docstring const &d) {
+XMLStream &XMLStream::operator<<(docstring const &d)
+{
        clearTagDeque();
-       os_ << xml::xmlize(d, escape_);
+       os_ << xml::escapeString(d, escape_);
        escape_ = ESCAPE_ALL;
        return *this;
 }
 
 
-XMLStream &XMLStream::operator<<(const char *s) {
+XMLStream &XMLStream::operator<<(const char *s)
+{
        clearTagDeque();
        docstring const d = from_ascii(s);
-       os_ << xml::xmlize(d, escape_);
+       os_ << xml::escapeString(d, escape_);
        escape_ = ESCAPE_ALL;
        return *this;
 }
 
 
-XMLStream &XMLStream::operator<<(char_type c) {
+XMLStream &XMLStream::operator<<(char_type c)
+{
        clearTagDeque();
        os_ << xml::escapeChar(c, escape_);
        escape_ = ESCAPE_ALL;
@@ -293,7 +316,8 @@ XMLStream &XMLStream::operator<<(char_type c) {
 }
 
 
-XMLStream &XMLStream::operator<<(char c) {
+XMLStream &XMLStream::operator<<(char c)
+{
        clearTagDeque();
        os_ << xml::escapeChar(c, escape_);
        escape_ = ESCAPE_ALL;
@@ -301,7 +325,8 @@ XMLStream &XMLStream::operator<<(char c) {
 }
 
 
-XMLStream &XMLStream::operator<<(int i) {
+XMLStream &XMLStream::operator<<(int i)
+{
        clearTagDeque();
        os_ << i;
        escape_ = ESCAPE_ALL;
@@ -309,13 +334,15 @@ XMLStream &XMLStream::operator<<(int i) {
 }
 
 
-XMLStream &XMLStream::operator<<(EscapeSettings e) {
+XMLStream &XMLStream::operator<<(EscapeSettings e)
+{
        escape_ = e;
        return *this;
 }
 
 
-XMLStream &XMLStream::operator<<(xml::StartTag const &tag) {
+XMLStream &XMLStream::operator<<(xml::StartTag const &tag)
+{
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -325,7 +352,8 @@ XMLStream &XMLStream::operator<<(xml::StartTag const &tag) {
 }
 
 
-XMLStream &XMLStream::operator<<(xml::ParTag const &tag) {
+XMLStream &XMLStream::operator<<(xml::ParTag const &tag)
+{
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -333,7 +361,8 @@ XMLStream &XMLStream::operator<<(xml::ParTag const &tag) {
 }
 
 
-XMLStream &XMLStream::operator<<(xml::CompTag const &tag) {
+XMLStream &XMLStream::operator<<(xml::CompTag const &tag)
+{
        if (tag.tag_.empty())
                return *this;
        clearTagDeque();
@@ -342,7 +371,8 @@ XMLStream &XMLStream::operator<<(xml::CompTag const &tag) {
 }
 
 
-XMLStream &XMLStream::operator<<(xml::FontTag const &tag) {
+XMLStream &XMLStream::operator<<(xml::FontTag const &tag)
+{
        if (tag.tag_.empty())
                return *this;
        pending_tags_.push_back(makeTagPtr(tag));
@@ -350,14 +380,16 @@ XMLStream &XMLStream::operator<<(xml::FontTag const &tag) {
 }
 
 
-XMLStream &XMLStream::operator<<(xml::CR const &) {
+XMLStream &XMLStream::operator<<(xml::CR const &)
+{
        clearTagDeque();
        os_ << from_ascii("\n");
        return *this;
 }
 
 
-bool XMLStream::isTagOpen(xml::StartTag const &stag, int maxdepth) const {
+bool XMLStream::isTagOpen(xml::StartTag const &stag, int maxdepth) const
+{
        auto sit = tag_stack_.begin();
        auto sen = tag_stack_.cend();
        for (; sit != sen && maxdepth != 0; ++sit) {
@@ -369,7 +401,8 @@ bool XMLStream::isTagOpen(xml::StartTag const &stag, int maxdepth) const {
 }
 
 
-bool XMLStream::isTagOpen(xml::EndTag const &etag, int maxdepth) const {
+bool XMLStream::isTagOpen(xml::EndTag const &etag, int maxdepth) const
+{
        auto sit = tag_stack_.begin();
        auto sen = tag_stack_.cend();
        for (; sit != sen && maxdepth != 0; ++sit) {
@@ -381,7 +414,8 @@ bool XMLStream::isTagOpen(xml::EndTag const &etag, int maxdepth) const {
 }
 
 
-bool XMLStream::isTagPending(xml::StartTag const &stag, int maxdepth) const {
+bool XMLStream::isTagPending(xml::StartTag const &stag, int maxdepth) const
+{
        auto sit = pending_tags_.begin();
        auto sen = pending_tags_.cend();
        for (; sit != sen && maxdepth != 0; ++sit) {
@@ -398,7 +432,8 @@ bool XMLStream::isTagPending(xml::StartTag const &stag, int maxdepth) const {
 // sure of that, but we won't assert (yet) if we run into
 // a problem. we'll just output error messages and try our
 // best to make things work.
-XMLStream &XMLStream::operator<<(xml::EndTag const &etag) {
+XMLStream &XMLStream::operator<<(xml::EndTag const &etag)
+{
        if (etag.tag_.empty())
                return *this;
 
@@ -441,7 +476,7 @@ XMLStream &XMLStream::operator<<(xml::EndTag const &etag) {
                string estr = "Closing tag `" + to_utf8(etag.tag_)
                                          + "' when other tags are pending. Discarded pending tags:\n";
                for (dit = pending_tags_.begin(); dit != den; ++dit)
-                       estr += to_utf8(xml::xmlize((*dit)->writeTag(), XMLStream::ESCAPE_ALL)) + "\n";
+                       estr += to_utf8(xml::escapeString((*dit)->writeTag(), XMLStream::ESCAPE_ALL)) + "\n";
                writeError(estr);
                // clear the pending tags...
                pending_tags_.clear();
@@ -538,18 +573,7 @@ XMLStream &XMLStream::operator<<(xml::EndTag const &etag) {
 }
 
 
-docstring xml::escapeString(docstring const & raw, XMLStream::EscapeSettings e)
-{
-       docstring bin;
-       bin.reserve(raw.size() * 2); // crude approximation is sufficient
-       for (size_t i = 0; i != raw.size(); ++i)
-               bin += xml::escapeChar(raw[i], e);
-
-       return bin;
-}
-
-
-docstring const xml::uniqueID(docstring const & label)
+docstring xml::uniqueID(docstring const & label)
 {
        // thread-safe
        static atomic_uint seed(1000);
@@ -557,7 +581,7 @@ docstring const xml::uniqueID(docstring const & label)
 }
 
 
-docstring xml::cleanID(docstring const &orig)
+docstring xml::cleanID(docstring const & orig)
 {
        // The standard xml:id only allows letters,
        // digits, '-' and '.' in a name.
@@ -611,8 +635,7 @@ docstring xml::cleanID(docstring const &orig)
        if (mangle) {
                int & mangleID = tMangleID.localData();
                content += "-" + convert<docstring>(mangleID++);
-       } else if (isDigitASCII(content[content.size() - 1]))
-               content += ".";
+       }
 
        mangledNames[orig] = content;