// This file is part of The New Aspell // Copyright (C) 2002 by Christoph Hintermüller 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/. // // Example for a filter implementation usable via extended filter library // interface. // This was added to Aspell by Christoph Hintermüller #include "settings.h" #include "can_have_error.hpp" #include "config.hpp" #include "filter_char.hpp" #include "indiv_filter.hpp" #include "iostream.hpp" #include "posib_err.hpp" #include "string.hpp" #include "string_enumeration.hpp" #include "string_list.hpp" #include "vector.hpp" using namespace acommon; namespace { enum filterstate {hidden=0, visible=1}; class ContextFilter : public IndividualFilter { filterstate state; Vector opening; Vector closing; int correspond; String filterversion; PosibErr hidecode(FilterChar * begin,FilterChar * end); public: ContextFilter(void); virtual void reset(void); void process(FilterChar *& start,FilterChar *& stop); virtual PosibErr setup(Config * config); virtual ~ContextFilter(); }; ContextFilter::ContextFilter(void) : opening(), closing() { state=hidden; correspond=-1; opening.resize(3); opening[0]="\""; opening[1]="/*"; opening[2]="//"; closing.resize(3); closing[0]="\""; closing[1]="*/"; closing[2]=""; filterversion=VERSION; } PosibErr ContextFilter::setup(Config * config){ name_ = "context-filter"; StringList delimiters; StringEnumeration * delimiterpairs; const char * delimiterpair=NULL; char * repair=NULL; char * begin=NULL; char * end=NULL; String delimiter; unsigned int countdelim=0; if (config == NULL) { fprintf(stderr,"Nothing to be configured\n"); return true; } if (config->retrieve_bool("f-context-visible-first")) { state=visible; } config->retrieve_list("f-context-delimiters", &delimiters); delimiterpairs=delimiters.elements(); opening.resize(0); closing.resize(0); while ((delimiterpair=delimiterpairs->next())) { if ((begin=repair=strdup(delimiterpair)) == NULL) { //fprintf(stderr,"ifailed to initialise %s filter\n",filter_name()); return false; } end=repair+strlen(repair); while ((*begin != ' ') && (*begin != '\t') && (begin != end)) { begin++; } if (begin == repair) { fprintf(stderr,"no delimiter pair: `%s'\n",repair); free(repair); //FIXME replace someday by make_err //fprintf(stderr,"ifailed to initialise %s filter\n",filter_name()); return false; } if (((*begin == ' ') || (*begin == '\t')) && (begin != end)) { *begin='\0'; opening.resize(opening.size()+1); opening[opening.size()-1]=repair; begin++; } while (((*begin == ' ') || (*begin == '\t')) && (begin != end)) { begin++; } if ((*begin != ' ') && (*begin != '\t') && (begin != end)) { closing.resize(closing.size()+1); if (strcmp(begin,"\\0") != 0) { closing[closing.size()-1]=begin; } else { closing[closing.size()-1]=""; } } else { closing.resize(closing.size()+1); closing[closing.size()-1]=""; } free(repair); } if (state == visible) { for (countdelim=0;(countdelim < opening.size()) && (countdelim < closing.size());countdelim++) { delimiter=opening[countdelim]; opening[countdelim]=closing[countdelim]; closing[countdelim]=delimiter; } } //fprintf(stderr,"%s filter initialised\n",filter_name()); return true; } void ContextFilter::process(FilterChar *& start,FilterChar *& stop) { FilterChar * current=start-1; FilterChar * beginblind=start; FilterChar * endblind=stop; FilterChar * localstop=stop; int countmasking=0; int countdelimit=0; int matchdelim=0; if ((localstop > start+1) && (*(localstop-1) == '\0')) { localstop--; endblind=localstop; } if (state == visible) { beginblind=endblind; } while (( ++current < localstop) && (*current != '\0')) { if (*current == '\\') { countmasking++; continue; } if (state == visible) { if ((countmasking % 2 == 0) && (correspond < 0)) { for (countdelimit=0; countdelimit < (signed)closing.size();countdelimit++) { for (matchdelim=0; (current+closing[countdelimit].size() < localstop) && (matchdelim < (signed)closing[countdelimit].size()); matchdelim++){ //FIXME Warning about comparison of signed and unsigned in following line if (current[matchdelim] != closing[countdelimit][matchdelim]) { break; } } if ((matchdelim == (signed) closing[countdelimit].size()) && closing[countdelimit].size()) { correspond=countdelimit; break; } } } if ((countmasking % 2 == 0) && (correspond >= 0) && (correspond < (signed)closing.size()) && (closing[correspond].size() > 0) && (current+closing[correspond].size() < localstop)) { for (matchdelim=0;matchdelim < (signed)closing[correspond].size(); matchdelim++) { //FIXME Warning about comparison of signed and unsigned in following line if (current[matchdelim] != closing[correspond][matchdelim]) { break; } } if ((matchdelim == (signed) closing[correspond].size()) && closing[correspond].size()) { beginblind=current; endblind=localstop; state=hidden; correspond=-1; } } countmasking=0; continue; } if (countmasking % 2) { countmasking=0; continue; } countmasking=0; for (countdelimit=0;countdelimit < (signed)opening.size();countdelimit++) { for (matchdelim=0;(current+opening[countdelimit].size() < localstop) && (matchdelim < (signed)opening[countdelimit].size()); matchdelim++) { //FIXME Warning about comparison of signed and unsigned in following line if (current[matchdelim] != opening[countdelimit][matchdelim]) { break; } } if ((matchdelim == (signed) opening[countdelimit].size()) && opening[countdelimit].size()) { endblind=current+opening[countdelimit].size(); state=visible; hidecode(beginblind,endblind); current=endblind-1; beginblind=endblind=localstop; correspond=countdelimit; break; } } } if ((state == visible) && (correspond >= 0) && (correspond < (signed)closing.size()) && (closing[correspond] == "") && (countmasking % 2 == 0)) { state=hidden; correspond=-1; } if (beginblind < endblind) { hidecode(beginblind,endblind); } } PosibErr ContextFilter::hidecode(FilterChar * begin,FilterChar * end) { //FIXME here we go, a more efficient context hiding blinding might be used :) FilterChar * current=begin; while (current < end) { if ((*current != '\t') && (*current != '\n') && (*current != '\r')) { *current=' '; } current++; } return true; } void ContextFilter::reset(void) { opening.resize(0); closing.resize(0); state=hidden; } ContextFilter::~ContextFilter() { reset(); } } C_EXPORT IndividualFilter * new_aspell_context_filter() { return new ContextFilter; }