Introduce TDEStringMatcher, a general purpose iterative string
matching class. Additional information about the class can be found in tdecore/README.tdestringmatcher. Introduce concept of a "hidden file matcher" instance of the TDEStringMatcher class that can be used to extend the definition "hidden" files beyond traditional "dotfiles". Create a global default instance of a "hidden file matcher" for use in applications that don't need their own. Modify KFileItem class to utilize a hidden file matcher when evaluating whether or not a filesystem object is hidden. This commit partially addresses issue # 273. Additional changes to tdelibs, tdebase/libkonq, and tdebase/konqueror will be required to resolve that issue. Signed-off-by: Vincent Reher <tde@4reher.org>pull/179/head
parent
682b8acae4
commit
78905ffa6a
@ -0,0 +1,63 @@
|
|||||||
|
The TDEStringMatcher class provides string matching against a list of
|
||||||
|
one or more TQRegExp objects. The matching functions currently provided
|
||||||
|
are:
|
||||||
|
|
||||||
|
matchAny(): strings match if they match any TQRegExp object in list.
|
||||||
|
matchAll(): strings match only if the match all TQRegExp objects in list.
|
||||||
|
|
||||||
|
The list of TQRegExp objects is constructed using a specially formatted string
|
||||||
|
that is passed by applications via the generatePatternList() function. This
|
||||||
|
string is referred to as the "patternString" and is formatted as follows:
|
||||||
|
|
||||||
|
* The first character of the patternString defines the character that
|
||||||
|
is used to split the remainder of the string into match specification
|
||||||
|
strings. It is recommended (but not required) that this be a character
|
||||||
|
that does not occur in a match pattern (see below).
|
||||||
|
|
||||||
|
* Each match specification string consists of an initial character that
|
||||||
|
designates the match specification type followed by the corresponding
|
||||||
|
match specification itself.
|
||||||
|
|
||||||
|
* Match specification strings starting with 'o' are followed by zero or
|
||||||
|
or more letters, each of which are interpreted as setting or unsetting
|
||||||
|
a match option. Match options remain in effect until explicitly overridden
|
||||||
|
by subsequent match options. The match option letters that are currently
|
||||||
|
recognized and processed are:
|
||||||
|
|
||||||
|
'w' - Match patterns are to be interpreted as "wildcards"
|
||||||
|
'r' - Match patterns are to be interpreted as "regexes" (TQRegExp default)
|
||||||
|
'c' - Matching will be case-sensitive (TQRegExp default)
|
||||||
|
'c' - Matching will be case-INsensitive
|
||||||
|
'm' - Regex matching will be "minimal" versus "greedy"
|
||||||
|
'g' - Regex matching will be "greedy" (TQRegExp default)
|
||||||
|
|
||||||
|
* Match specification strings starting with 'p' are followed by one or
|
||||||
|
more characters that constitute a match pattern. Each match pattern
|
||||||
|
together with the match options in effect are used to construct
|
||||||
|
a single TQRegExp object to be used for string matching. This object
|
||||||
|
will be validated before acceptance.
|
||||||
|
|
||||||
|
* Match specification strings starting with any other character are ignored.
|
||||||
|
|
||||||
|
Some examples of patternString:
|
||||||
|
|
||||||
|
* |ow|p.*|p*~
|
||||||
|
Dotfiles and kwrite backup files will be matched via wildcards
|
||||||
|
|
||||||
|
* /or/p[.][0-9]+$/ow/p.*
|
||||||
|
Files with a version number suffix will be matched via regex
|
||||||
|
and dotfiles will be matched via wildcard
|
||||||
|
|
||||||
|
Current and potential use of the TDEStringMatcher class include:
|
||||||
|
|
||||||
|
* Expansion of definition of "hidden" files, addressing issue # 270.
|
||||||
|
|
||||||
|
* Creation of a subclass that provides string parsing functions.
|
||||||
|
|
||||||
|
Miscellaneous implementation notes:
|
||||||
|
|
||||||
|
* It is the responsibility of applications that use this class to provide
|
||||||
|
patternString editing (perhaps via UI), storage, and retrieval.
|
||||||
|
|
||||||
|
* Regex patterns use TQRegExp::search for matching but wildcard patterns
|
||||||
|
must use TQRegExp::exactMatch in order for matching to work correctly.
|
@ -0,0 +1,169 @@
|
|||||||
|
#include "tdestringmatcher.h"
|
||||||
|
|
||||||
|
#include <tqregexp.h>
|
||||||
|
#include <kdebug.h>
|
||||||
|
|
||||||
|
class TDEStringMatcher::TDEStringMatcherPrivate {
|
||||||
|
public:
|
||||||
|
TQString patternString;
|
||||||
|
}; // FIXME: This may be too small to warrant a private class :\
|
||||||
|
|
||||||
|
TDEStringMatcher::TDEStringMatcher()
|
||||||
|
{
|
||||||
|
p = new TDEStringMatcherPrivate;
|
||||||
|
TSMTRACE << "TDEStringMatcher::TDEStringMatcher: New instance created: " << this << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TDEStringMatcher::~TDEStringMatcher()
|
||||||
|
{
|
||||||
|
patternList.setAutoDelete( true );
|
||||||
|
patternList.clear();
|
||||||
|
delete p;
|
||||||
|
TSMTRACE << "TDEStringMatcher::TDEStringMatcher: Instance destroyed: " << this << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TQString TDEStringMatcher::getPatternString()
|
||||||
|
{
|
||||||
|
return p->patternString;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TDEStringMatcher::generatePatternList( TQString newPatternString )
|
||||||
|
{
|
||||||
|
if ( newPatternString == p->patternString )
|
||||||
|
return true;
|
||||||
|
TSMTRACE << "TDEStringMatcher::generatePatternList: Proposed pattern string: <" << newPatternString << ">" << endl;
|
||||||
|
if ( newPatternString.length() < 2 ) {
|
||||||
|
TSMTRACE << " Input string too short to be interpreted, patterns will be cleared" << endl;
|
||||||
|
patternList.clear();
|
||||||
|
p->patternString = "" ;
|
||||||
|
#ifdef TSMSIGNALS
|
||||||
|
emit patternsChanged();
|
||||||
|
#endif // TSMSIGNALS
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
TQChar patternStringDivider = newPatternString[0];
|
||||||
|
TSMTRACE << " patternStringDivider = '" << patternStringDivider << "'" << endl;
|
||||||
|
TQStringList specList = TQStringList::split( patternStringDivider, newPatternString.mid(1), true );
|
||||||
|
|
||||||
|
TQRegExp rxWork;
|
||||||
|
TQPtrList<TQRegExp> rxPatternList;
|
||||||
|
|
||||||
|
for ( const TQString &specification : specList ) {
|
||||||
|
TSMTRACE << " Processing specification string: '" << specification << "'" << endl;
|
||||||
|
TQChar specificationType = specification[0].lower();
|
||||||
|
switch ( specificationType ) {
|
||||||
|
case 'o' : {
|
||||||
|
TQString optionString = specification.mid(1).lower();
|
||||||
|
TSMTRACE << " Processing match option string: '" << optionString << "'" << endl;
|
||||||
|
for ( int i = 0 ; i < optionString.length() ; i++ ) {
|
||||||
|
TQChar optionChar = optionString[i];
|
||||||
|
TSMTRACE << " Option character: '" << optionChar << "'" << endl;
|
||||||
|
switch ( optionChar ) {
|
||||||
|
case 'w' : rxWork.setWildcard( true ); break;
|
||||||
|
case 'r' : rxWork.setWildcard( false ); break;
|
||||||
|
case 'c' : rxWork.setCaseSensitive( true ); break;
|
||||||
|
case 'i' : rxWork.setCaseSensitive( false ); break;
|
||||||
|
case 'm' : rxWork.setMinimal( true ); break;
|
||||||
|
case 'g' : rxWork.setMinimal( false ); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TSMTRACE << " Wildcard/CaseSensitive settings: " << rxWork.wildcard() << "/" << rxWork.caseSensitive() << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p' : {
|
||||||
|
TQString pattern = specification.mid(1);
|
||||||
|
TSMTRACE << " Processing match pattern: '" << pattern << "'" << endl;
|
||||||
|
if ( pattern.isEmpty() ) {
|
||||||
|
TSMTRACE << " Empty patterns are not allowed" << endl;
|
||||||
|
rxPatternList.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rxWork.setPattern( pattern );
|
||||||
|
if (! rxWork.isValid() ) {
|
||||||
|
TSMTRACE << " Invalid pattern" << endl;
|
||||||
|
rxPatternList.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TQRegExp *rxPattern = new TQRegExp( rxWork );
|
||||||
|
rxPatternList.append( rxPattern );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
TSMTRACE << " Ignoring unknown specification type '" << specificationType << "'" << endl;
|
||||||
|
//-Relax, don't overreact: rxPatternList.clear();
|
||||||
|
//-Relax, don't overreact: return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// patternList.clear(); // no need to do this?
|
||||||
|
patternList.setAutoDelete( true );
|
||||||
|
patternList = rxPatternList;
|
||||||
|
p->patternString = newPatternString;
|
||||||
|
// rxPatternList.clear(); // no need to do this?
|
||||||
|
|
||||||
|
TSMTRACE << " Final patternString: '" << p->patternString << "'" << endl;
|
||||||
|
TSMTRACE << " Number of regex match patterns in list: '" << patternList.count() << "'" << endl;
|
||||||
|
|
||||||
|
#ifdef TSMSIGNALS
|
||||||
|
TSMTRACE << " Notifying slots of pattern change" << endl;
|
||||||
|
emit patternsChanged();
|
||||||
|
TSMTRACE << " All slots have been notified" << endl;
|
||||||
|
#endif // TSMSIGNALS
|
||||||
|
TSMTRACE << "TDEStringMatcher::generatePatternList: Patterns were successfully regenerated" << endl << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TDEStringMatcher::matchAny( const TQString& stringToMatch )
|
||||||
|
{
|
||||||
|
//-Debug: TSMTRACE << "Attempting to match string '" << stringToMatch << "' against stored patterns" << endl;
|
||||||
|
for ( const TQRegExp *rxPattern : patternList ) {
|
||||||
|
if (
|
||||||
|
( rxPattern->wildcard() && rxPattern->exactMatch( stringToMatch ) ) ||
|
||||||
|
( ! rxPattern->wildcard() && rxPattern->search( stringToMatch ) >= 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//-Debug: TSMTRACE << "String matched pattern: '" << rxPattern->pattern() << "'" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( patternList.isEmpty() ) {
|
||||||
|
//-Debug: TSMTRACE << "Match failed on empty pattern list!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//-Debug: TSMTRACE << "Match failed, no pattern matched!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TDEStringMatcher::matchAll( const TQString& stringToMatch )
|
||||||
|
{
|
||||||
|
//-Debug: TSMTRACE << "Attempting to match string '" << stringToMatch << "' against ALL stored patterns" << endl;
|
||||||
|
for ( const TQRegExp *rxPattern : patternList ) {
|
||||||
|
if ( !
|
||||||
|
( rxPattern->wildcard() && rxPattern->exactMatch( stringToMatch ) ) ||
|
||||||
|
( ! rxPattern->wildcard() && rxPattern->search( stringToMatch ) >= 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//-Debug: TSMTRACE << "String failed to match pattern: '" << rxPattern->pattern() << "'" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( patternList.isEmpty() ) {
|
||||||
|
//-Debug: TSMTRACE << "Match failed on empty pattern list!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//-Debug: TSMTRACE << "Match succeeded, all patterns matched!" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "tdestringmatcher.moc"
|
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef TDESTRINGMATCHER_H
|
||||||
|
#define TDESTRINGMATCHER_H
|
||||||
|
|
||||||
|
#include "tdelibs_export.h"
|
||||||
|
|
||||||
|
#include <tqstring.h>
|
||||||
|
#include <tqptrlist.h>
|
||||||
|
#include <tqobject.h>
|
||||||
|
|
||||||
|
#define TSMTRACE kdDebug() << "<TSMTRACE> "
|
||||||
|
#define TSMSIGNALS
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Generic string matcher class.
|
||||||
|
*/
|
||||||
|
class TDECORE_EXPORT TDEStringMatcher : public TQObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
TDEStringMatcher();
|
||||||
|
~TDEStringMatcher();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Use @param newPatternString to generate @property patternList. Refer to
|
||||||
|
file README.tdestringmatcher for more information on how the input
|
||||||
|
string should be formatted.
|
||||||
|
*/
|
||||||
|
bool generatePatternList( TQString newPatternString );
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return pattern string from which @property patternList was created.
|
||||||
|
String is stored in @property TDEStringMatcherPrivate::patternString.
|
||||||
|
*/
|
||||||
|
TQString getPatternString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Methods that determine whether or not @param stringToMatch match
|
||||||
|
any/all of the TQRegExp objects contained in @property patternList.
|
||||||
|
*/
|
||||||
|
bool matchAny( const TQString& stringToMatch );
|
||||||
|
bool matchAll( const TQString& stringToMatch );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void patternsChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
TQPtrList<TQRegExp> patternList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class TDEStringMatcherPrivate;
|
||||||
|
TDEStringMatcherPrivate *p;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue