xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/search/context/WildCardMatcher.java (revision 0e4c55544f8ea0a68e8bae37b0e502097e008ec1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
22  *
23  * Portions Apache software license, see below
24  *
25  */
26 package org.opengrok.indexer.search.context;
27 
28 public class WildCardMatcher extends LineMatcher {
29 
30     final String pattern;
31 
WildCardMatcher(String pattern, boolean caseInsensitive)32     public WildCardMatcher(String pattern, boolean caseInsensitive) {
33         super(caseInsensitive);
34         this.pattern = normalizeString(pattern);
35     }
36 
37     @Override
match(String token)38     public int match(String token) {
39         String tokenToMatch = normalizeString(token);
40         return wildcardEquals(pattern, 0, tokenToMatch, 0)
41                 ? MATCHED
42                 : NOT_MATCHED;
43     }
44     //TODO below might be buggy, we might need to rewrite this anyways
45     // so far keep it for the sake of 4.0 port
46     /*
47      * Licensed to the Apache Software Foundation (ASF) under one or more
48      * contributor license agreements. See the NOTICE file distributed with this
49      * work for additional information regarding copyright ownership. The ASF
50      * licenses this file to You under the Apache License, Version 2.0 (the
51      * "License"); you may not use this file except in compliance with the
52      * License. You may obtain a copy of the License at
53      *
54      * http://www.apache.org/licenses/LICENSE-2.0
55      *
56      * Unless required by applicable law or agreed to in writing, software
57      * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
58      * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
59      * License for the specific language governing permissions and limitations
60      * under the License.
61      */
62 
63     public static final char WILDCARD_STRING = '*';
64     public static final char WILDCARD_CHAR = '?';
65 
66     /**
67      * Determines if a word matches a wildcard pattern. <small>Work released by
68      * Granta Design Ltd after originally being done on company time.</small>
69      * @param pattern pattern
70      * @param patternIdx index
71      * @param string word
72      * @param stringIdx index
73      * @return true if word matches the pattern
74      */
wildcardEquals(String pattern, int patternIdx, String string, int stringIdx)75     public static boolean wildcardEquals(String pattern, int patternIdx,
76             String string, int stringIdx) {
77         int p = patternIdx;
78 
79         for (int s = stringIdx;; ++p, ++s) {
80             // End of string yet?
81             boolean sEnd = (s >= string.length());
82             // End of pattern yet?
83             boolean pEnd = (p >= pattern.length());
84 
85             // If we're looking at the end of the string...
86             if (sEnd) {
87                 // Assume the only thing left on the pattern is/are wildcards
88                 boolean justWildcardsLeft = true;
89 
90                 // Current wildcard position
91                 int wildcardSearchPos = p;
92                 // While we haven't found the end of the pattern,
93                 // and haven't encountered any non-wildcard characters
94                 while (wildcardSearchPos < pattern.length() && justWildcardsLeft) {
95                     // Check the character at the current position
96                     char wildchar = pattern.charAt(wildcardSearchPos);
97 
98                     // If it's not a wildcard character, then there is more
99                     // pattern information after this/these wildcards.
100                     if (wildchar != WILDCARD_CHAR && wildchar != WILDCARD_STRING) {
101                         justWildcardsLeft = false;
102                     } else {
103                         // to prevent "cat" matches "ca??"
104                         if (wildchar == WILDCARD_CHAR) {
105                             return false;
106                         }
107 
108                         // Look at the next character
109                         wildcardSearchPos++;
110                     }
111                 }
112 
113                 // This was a prefix wildcard search, and we've matched, so
114                 // return true.
115                 if (justWildcardsLeft) {
116                     return true;
117                 }
118             }
119 
120             // If we've gone past the end of the string, or the pattern,
121             // return false.
122             if (sEnd || pEnd) {
123                 break;
124             }
125 
126             // Match a single character, so continue.
127             if (pattern.charAt(p) == WILDCARD_CHAR) {
128                 continue;
129             }
130 
131             //
132             if (pattern.charAt(p) == WILDCARD_STRING) {
133                 // Look at the character beyond the '*' characters.
134                 while (p < pattern.length() && pattern.charAt(p) == WILDCARD_STRING) {
135                     ++p;
136                 }
137                 // Examine the string, starting at the last character.
138                 for (int i = string.length(); i >= s; --i) {
139                     if (wildcardEquals(pattern, p, string, i)) {
140                         return true;
141                     }
142                 }
143                 break;
144             }
145             if (pattern.charAt(p) != string.charAt(s)) {
146                 break;
147             }
148         }
149         return false;
150     }
151 }
152