// This file is part of The New Aspell // Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license // version 2.0 or 2.1. You should have received a copy of the LGPL // license along with this library if you did not you can find // it at http://www.gnu.org/. #include #include "asc_ctype.hpp" #include "config.hpp" #include "indiv_filter.hpp" #include "string_map.hpp" #include "mutable_container.hpp" #include "copy_ptr-t.hpp" #include "clone_ptr-t.hpp" #include "filter_char_vector.hpp" namespace acommon { class ToLowerMap : public StringMap { public: PosibErr add(ParmString to_add) { String new_key; for (const char * i = to_add; *i; ++i) new_key += asc_tolower(*i); return StringMap::add(new_key); } PosibErr remove(ParmString to_rem) { String new_key; for (const char * i = to_rem; *i; ++i) new_key += asc_tolower(*i); return StringMap::remove(new_key); } }; class SgmlFilter : public IndividualFilter { bool in_markup; FilterChar::Chr in_quote; bool new_token; String tag_name; String parm_name; enum InWhat {InKey, InValue, InValueNoSkip, InOther}; InWhat in_what; StringMap noskip_tags; inline bool process_char(FilterChar::Chr c); public: PosibErr setup(Config *); void reset(); void process(FilterChar * &, FilterChar * &); }; PosibErr SgmlFilter::setup(Config * opts) { name_ = "sgml"; order_num_ = 0.35; noskip_tags.clear(); RET_ON_ERR(opts->retrieve_list("sgml-check", &noskip_tags)); reset(); return true; } void SgmlFilter::reset() { in_markup = false; in_quote = false; new_token = false; in_what = InOther; } // yes this should be inlines, it is only called once inline bool SgmlFilter::process_char(FilterChar::Chr c) { if (!in_quote) if (c == '<') { in_markup = true; in_what = InKey; new_token = true; tag_name = ""; return true; } else if (c == '>') { in_markup = false; return true; } if (!in_markup) return false; if (c == '"' || c == '\'') { new_token = false; if (!in_quote) in_quote = c; else if (in_quote == c) in_quote = 0; } else if (!in_quote && asc_isspace(c)) { if (!new_token) { in_what = InKey; new_token = true; } } else if (!in_quote && c == '=') { if (noskip_tags.have(parm_name.c_str())) in_what = InValueNoSkip; else in_what = InValue; new_token = true; return true; } else if (!in_quote && c == '/') { in_what = InOther; } else if (in_what == InKey) { if (new_token) { if (tag_name.empty()) tag_name = parm_name; parm_name = ""; new_token = false; } parm_name += asc_tolower(c); } else if (in_what == InValue || in_what == InValueNoSkip) { new_token = false; } return in_what != InValueNoSkip; } void SgmlFilter::process(FilterChar * & str, FilterChar * & stop) { FilterChar * cur = str; while (cur != stop) { if (process_char(*cur)) *cur = ' '; ++cur; } } // // // class SgmlDecoder : public IndividualFilter { FilterCharVector buf; public: PosibErr setup(Config *); void reset() {} void process(FilterChar * &, FilterChar * &); }; PosibErr SgmlDecoder::setup(Config *) { name_ = "sgml-decoder"; order_num_ = 0.65; return true; } void SgmlDecoder::process(FilterChar * & start, FilterChar * & stop) { buf.clear(); FilterChar * i = start; while (i != stop) { if (*i == '&') { FilterChar * i0 = i; FilterChar::Chr chr; ++i; if (*i == '#') { chr = 0; ++i; while (asc_isdigit(*i)) { chr *= 10; chr += *i - '0'; ++i; } } else { while (asc_isalpha(*i) || asc_isdigit(*i)) { ++i; } chr = '?'; } if (*i == ';') ++i; buf.append(FilterChar(chr, i0, i)); } else { buf.append(*i); ++i; } } buf.append('\0'); start = buf.pbegin(); stop = buf.pend() - 1; } // // // class SgmlEncoder : public IndividualFilter { FilterCharVector buf; public: PosibErr setup(Config *); void reset() {} void process(FilterChar * &, FilterChar * &); }; PosibErr SgmlEncoder::setup(Config *) { name_ = "sgml-encoder"; order_num_ = 0.99; return true; } void SgmlEncoder::process(FilterChar * & start, FilterChar * & stop) { buf.clear(); FilterChar * i = start; while (i != stop) { if (*i > 127) { buf.append("&#", i->width); char b[10]; sprintf(b, "%d", i->chr); buf.append(b, 0); buf.append(';', 0); } else { buf.append(*i); } ++i; } buf.append('\0'); start = buf.pbegin(); stop = buf.pend() - 1; } // // // IndividualFilter * new_sgml_decoder() { return new SgmlDecoder(); } IndividualFilter * new_sgml_filter() { return new SgmlFilter(); } IndividualFilter * new_sgml_encoder() { return 0; //return new SgmlEncoder(); } static const KeyInfo sgml_options[] = { {"sgml-check", KeyInfoList, "alt", "sgml attributes to always check."}, {"sgml-extension", KeyInfoList, "html,htm,php,sgml", "sgml file extensions"} }; const KeyInfo * sgml_options_begin = sgml_options; const KeyInfo * sgml_options_end = sgml_options + 2; }