// -*- c++ -*- /* * Jakelib2 - General purpose C++ library * Copyright (C) 2001 Florian Wolff (florian@donuz.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: WildCardFilter.jlc,v 1.17 2006-01-14 14:07:16 florian Exp $ */ #include "jakelib2.h" #include "jakelib2/io/WildCardFilter.h" #include "jakelib2/io/File.h" #include "jakelib2/lang/System.h" #include "jakelib2/util/StringTokenizer.h" #include "jakelib2/util/ArrayList.h" using namespace jakelib::lang; using namespace jakelib::util; using namespace jakelib::io; JAKELIB_IMPLEMENT_CLASS_1("jakelib.io.WildCardFilter", WildCardFilter, Object, FilenameFilter); /*****************************************************************************\ * WildCardFilter | *****************************************************************************/ WildCardFilter::WildCardFilter(String *pattern) { if (pattern == null) this->pattern = String::emptyString; else this->pattern = pattern; // FIXME: Calculate number of tokens!! tokens = (TOKEN*) GC_MALLOC(sizeof(TOKEN) * pattern->length()); // Parse the given pattern string: jchar c; StringBuffer str; for (int x = 0; x < pattern->length(); x++) { c = pattern->charAt(x); if (c == '*' || c == '?' || c == '[' || c == '{') { if (str.length() > 0) { tokens[length].type = STRING; tokens[length++].str = str.toString(); str.setLength(0); } if (c == '*') { // Asterisk "*" tokens[length++].type = ASTERISK; } else if (c == '?') { // Questionmark "?" tokens[length++].type = QUESTIONMARK; } else if (c == '[') { // Alternative Characters "[abcd]" for (x++; x < pattern->length(); x++) { c = pattern->charAt(x); if (c == ']') break; else str.append(c); } if (x >= pattern->length()) throw new Exception(`"Missing ']' in \""` .. pattern .. `"\""` .. JAKELIB_AT2(`"jakelib.io.WildCardFilter.WildCardFilter"`)); tokens[length].type = CHARACTER; tokens[length++].str = str.toString(); str.setLength(0); } else if (c == '{') { // String Alternatives "{abc,def,ghi}" int altEnd = pattern->indexOf('}', x +1); if (altEnd == -1) throw new Exception(`"Missing '}' in \""` .. pattern .. `"\""` .. JAKELIB_AT2(`"jakelib.io.WildCardFilter.WildCardFilter"`)); String *altStrings = pattern->substring(x +1, altEnd); StringTokenizer tokenizer(altStrings, `","`); tokens[length].type = ALTERNATIVES; tokens[length].str = null; tokens[length].alternatives = new ArrayList(); while (tokenizer.hasNext()) { tokens[length].alternatives->add(tokenizer.nextToken()); } length ++; x = altEnd; } } else { str.append(c); } } if (str.length() > 0) { tokens[length].type = STRING; tokens[length++].str = str.toString(); } // printf("'%s'\n", pattern->latin1()); // for (int idx = 0; idx < length; idx++) { // switch (tokens[idx].type) { // case ASTERISK: // printf(" - *\n"); // break; // case STRING: // printf(" - \"%s\"\n", tokens[idx].str->latin1()); // break; // default: // printf(" - %i\n", tokens[idx].type); // } // } } WildCardFilter::~WildCardFilter() { destroy(); } /*****************************************************************************\ * accept | *****************************************************************************/ jboolean WildCardFilter::accept(File *dir, jakelib::lang::String *name) { if (dir != null) { return accept(new File(dir, name)); } else { return matches(name, 0, 0); } } jboolean WildCardFilter::accept(File *file) { if (pattern->length() == 0) { return true; } else { return matches(file->getPath(), 0, 0); } } /*****************************************************************************\ * matches | *****************************************************************************/ jboolean WildCardFilter::matches(String *input, int inputPos, int patternPos) { int suckUntil = 0; int inputLen = input->length(); // All tokens evaluated? if (patternPos == length) { // Matches if input is empty, too: return (inputLen == inputPos); } if (inputPos > inputLen) return false; // JAKELIB_MSG(`"matches(\""` .. input .. `"\", "` .. inputPos .. `", "` .. patternPos .. `")"`); switch (tokens[patternPos].type) { case ASTERISK: // If "*" is the last token, the input always matches: if (patternPos == length -1) { return true; } // "*" is greedy: Try to suck up as many characters as possible: for (suckUntil = inputLen; suckUntil >= inputPos; suckUntil--) { // JAKELIB_MSG(`" - ASTERISK("` .. inputPos..`"-"` ..suckUntil ..`"): \""` // .. input->substring(inputPos, suckUntil) .. `"\""`); if (matches(input, suckUntil, patternPos +1)) return true; } return false; case STRING: { int stringLength = tokens[patternPos].str->length(); // JAKELIB_MSG(`" - STRING(\""` .. tokens[patternPos].str .. `"\"): \""` // .. input->substring(inputPos, inputPos + tokens[patternPos].str->length()) .. `"\""`); // If the remainder of the input is shorter than the string, // match will not be possible: if (stringLength > inputLen - inputPos) return false; else return (input->regionMatches(inputPos, tokens[patternPos].str, 0, stringLength) && matches(input, inputPos + stringLength, patternPos +1)); } case ALTERNATIVES: { for (int idx = 0; idx < tokens[patternPos].alternatives->size(); idx++) { String *alt = (String*) tokens[patternPos].alternatives->get(idx); if (input->regionMatches(inputPos, alt, 0, alt->length()) && matches(input, inputPos + alt->length(), patternPos +1)) return true; } return false; } case CHARACTER: { //JAKELIB_MSG(`" - CHARACTER(\""` .. tokens[patternPos].str .. `"\"): "`->plusChar(input->charAt(inputPos))); return (tokens[patternPos].str->indexOf(input->charAt(inputPos)) != -1 && matches(input, inputPos + 1, patternPos +1)); } case QUESTIONMARK: { //JAKELIB_MSG(`" - QUESTIONMARK: "`->plusChar(input->charAt(inputPos))); return matches(input, inputPos +1, patternPos +1); } default: JAKELIB_MSG(`" - INVALID: "` .. tokens[patternPos].type); } return false; } /*****************************************************************************\ * toString | *****************************************************************************/ String *WildCardFilter::toString() { return `"WildCardFilter: \""` .. pattern .. `"\""`; } /*****************************************************************************\ * destroy | *****************************************************************************/ void WildCardFilter::destroy() { GC_FREE(tokens); tokens = null; }