View | Details | Raw Unified | Return to bug 23037
Collapse All | Expand All

(-)ContainsRegexpSelector.java (-126 / +308 lines)
Lines 54-193 Link Here
54
54
55
package org.apache.tools.ant.types.selectors;
55
package org.apache.tools.ant.types.selectors;
56
56
57
import java.io.BufferedReader;
58
import java.io.File;
57
import java.io.File;
59
import java.io.FileInputStream;
58
import java.io.BufferedReader;
59
import java.io.FileReader;
60
import java.io.IOException;
60
import java.io.IOException;
61
import java.io.InputStreamReader;
62
61
63
import org.apache.tools.ant.BuildException;
64
import org.apache.tools.ant.types.Parameter;
62
import org.apache.tools.ant.types.Parameter;
65
import org.apache.tools.ant.types.RegularExpression;
63
import org.apache.tools.ant.util.FileUtils;
66
import org.apache.tools.ant.util.regexp.Regexp;
64
import org.apache.tools.ant.util.regexp.Regexp;
65
import org.apache.tools.ant.util.regexp.RegexpFactory;
66
import org.apache.tools.ant.BuildException;
67
import org.apache.tools.ant.Project;
67
68
68
/**
69
/**
69
 * Selector that filters files based on a regular expression.
70
 * Selector that filters files based on whether they contain a
71
 * particular pattern expressed with a regular expression.
72
 * The input file(s) must be able to be properly processed by
73
 * a Reader instance. That is, it must be text only, no binary.
74
 *
75
 * The syntax of the regular expression depends on the implemtation that
76
 * you choose to use. The system property <code>ant.regexp.regexpimpl</code>
77
 * will be the classname of the implementation that will be used (the default
78
 * is <code>org.apache.tools.ant.util.regexp.JakartaOroRegexp</code> and
79
 * requires the Jakarta Oro Package).
80
 *
81
 * <pre>
82
 * For jdk  &lt;= 1.3, there are two available implementations:
83
 *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
84
 *        Requires  the jakarta-oro package
85
 *
86
 *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
87
 *        Requires the jakarta-regexp package
70
 *
88
 *
71
 * @author <a href="mailto:jvandermeer2@comcast.net">Jay van der Meer</a>
89
 * For jdk &gt;= 1.4 an additional implementation is available:
72
 * @since Ant 1.6
90
 *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
91
 *        Requires the jdk 1.4 built in regular expression package.
92
 *
93
 *   Attributes:
94
 *
95
 *     pattern --&gt; The Regular expression to search for
96
 *     flags   --&gt; The options to give to the search. For more information, consult the Perl5 syntax.
97
 *                 i = Case insensitive match
98
 *                 m = Multiline.  Treat the string as multiple lines of input, using
99
 *                     "^" and "$" as the start or end of any line, respectively, rather
100
 *                     than start or end of string.
101
 *                 m = Singleline.  Treat the string as a single line of input, using
102
 *                     "." to match any character, including a newline, which normally,
103
 *                     it would not match.
104
 *
105
 *     byline  --&gt; Should files be processed a single line at a time (default is false)
106
 *                 "true" indicates to perform search on a line by line basis
107
 *                 "false" indicates to perform search on the whole file at once.
108
 *
109
 *
110
 * @author Thorsten Möller - Thorsten.Moeller@jexam.de
111
 * 
112
 * $Revision: $; $Author: $; $Date: $
73
 */
113
 */
74
public class ContainsRegexpSelector extends BaseExtendSelector {
114
public class ContainsRegexpSelector extends BaseExtendSelector
115
{
75
116
76
    private String userProvidedExpression = null;
117
	private boolean byline;
77
    private RegularExpression myRegExp = null;
118
	private String flags;
78
    private Regexp myExpression = null;
119
	private Regexp regexp = null;
79
    /** Key to used for parameterized custom selector */
120
	private static final RegexpFactory factory = new RegexpFactory();
80
    public static final String EXPRESSION_KEY = "expression";
121
81
122
	public static final String PATTERN_KEY = "pattern";
82
    /**
123
	public static final String FLAGS_KEY = "flags";
83
     * Creates a new <code>ContainsRegexpSelector</code> instance.
124
	public static final String BYLINE_KEY = "byline";
84
     */
125
85
    public ContainsRegexpSelector() {
126
	public ContainsRegexpSelector()
86
    }
127
	{
87
128
		this.regexp = factory.newRegexp();
88
    /**
129
	}
89
     * @return a string describing this object
130
90
     */
131
	public String toString()
91
    public String toString() {
132
	{
92
        StringBuffer buf = new StringBuffer(
133
		StringBuffer buf = new StringBuffer("{containsRegexpSelector pattern: ");
93
                "{containsregexpselector expression: ");
134
		buf.append(regexp.getPattern());
94
        buf.append(userProvidedExpression);
135
		buf.append(" byline: ");
95
        buf.append("}");
136
		buf.append(Boolean.toString(byline));
96
        return buf.toString();
137
		buf.append(" flags: ");
97
    }
138
		buf.append(flags);
98
139
		buf.append("}");
99
    /**
140
		return buf.toString();
100
     * The regular expression used to search the file.
141
	}
101
     *
142
102
     * @param theexpression this must match a line in the file to be selected.
143
	/**
103
     */
144
	 * Process the file(s) one line at a time.
104
    public void setExpression(String theexpression) {
145
	 * This is useful if you want to only search for the first occurence of a regular expression on
105
        this.userProvidedExpression = theexpression;
146
	 * each line, which is not easy to do when processing the file as a whole.
106
    }
147
	 * Defaults to <i>false</i>.</td>
107
148
	 */
108
    /**
149
	public void setByLine(String byline)
109
     * When using this as a custom selector, this method will be called.
150
	{
110
     * It translates each parameter into the appropriate setXXX() call.
151
		Boolean res = Boolean.valueOf(byline);
111
     *
152
		if (res == null)
112
     * @param parameters the complete set of parameters for this selector
153
		{
113
     */
154
			res = Boolean.FALSE;
114
    public void setParameters(Parameter[] parameters) {
155
		}
115
        super.setParameters(parameters);
156
		this.byline = res.booleanValue();
116
        if (parameters != null) {
157
	}
117
            for (int i = 0; i < parameters.length; i++) {
158
118
                String paramname = parameters[i].getName();
159
	/**
119
                if (EXPRESSION_KEY.equalsIgnoreCase(paramname)) {
160
	 * The flags to use when matching the regular expression.  For more
120
                    setExpression(parameters[i].getValue());
161
	 * information, consult the Perl5 syntax.
121
                } else {
162
	 * <ul>
122
                    setError("Invalid parameter " + paramname);
163
	 *  <li>i : Case Insensitive.  Do not consider case in the match
123
                }
164
	 *  <li>m : Multiline.  Treat the string as multiple lines of input, 
124
            }
165
	 *         using "^" and "$" as the start or end of any line, respectively, rather than start or end of string.
125
        }
166
	 *  <li>s : Singleline.  Treat the string as a single line of input, using
126
    }
167
	 *        "." to match any character, including a newline, which normally, it would not match.
127
168
	 *</ul>
128
    /**
169
	 */
129
     * Checks that an expression was specified.
170
	public void setFlags(String flags)
130
     *
171
	{
131
     */
172
		this.flags = flags;
132
    public void verifySettings() {
173
	}
133
        if (userProvidedExpression == null) {
174
134
            setError("The expression attribute is required");
175
	/**
135
        }
176
	 * The pattern to search for within a file.
136
    }
177
	 *
137
178
	 * @param regexp the string that a file must contain to be selected.
138
    /**
179
	 */
139
     * Tests a regular expression against each line of text in the file.
180
	public void setRegexp(String pattern)
140
     *
181
	{
141
     * @param basedir the base directory the scan is being done from
182
		this.regexp.setPattern(pattern);
142
     * @param filename is the name of the file to check
183
	}
143
     * @param file is a java.io.File object the selector can use
184
144
     * @return whether the file should be selected or not
185
	/**
145
     */
186
	 * When using this as a custom selector, this method will be called.
146
    public boolean isSelected(File basedir, String filename, File file) {
187
	 * It translates each parameter into the appropriate setXXX() call.
147
        String teststr = null;
188
	 *
148
        BufferedReader in = null;
189
	 * @param parameters the complete set of parameters for this selector
149
190
	 */
150
        // throw BuildException on error
191
	public void setParameters(Parameter[] parameters)
151
192
	{
152
        validate();
193
		super.setParameters(parameters);
153
194
		if (parameters != null)
154
        if (file.isDirectory()) {
195
		{
155
            return true;
196
			for (int i = 0; i < parameters.length; i++)
156
        }
197
			{
157
198
				String paramname = parameters[i].getName();
158
        if (myRegExp == null) {
199
				if (PATTERN_KEY.equalsIgnoreCase(paramname))
159
            myRegExp = new RegularExpression();
200
				{
160
            myRegExp.setPattern(userProvidedExpression);
201
					setRegexp(parameters[i].getValue());
161
            myExpression = myRegExp.getRegexp(getProject());
202
				}
162
        }
203
				else if (BYLINE_KEY.equalsIgnoreCase(paramname))
163
204
				{
164
        try {
205
					setByLine(parameters[i].getValue());
165
            in = new BufferedReader(new InputStreamReader(
206
				}
166
                    new FileInputStream(file)));
207
				else if (FLAGS_KEY.equalsIgnoreCase(paramname))
167
208
				{
168
            teststr = in.readLine();
209
					setFlags(parameters[i].getValue());
169
210
				}
170
            while (teststr != null) {
211
				else
171
212
				{
172
                if (myExpression.matches(teststr)) {
213
					setError("Invalid parameter " + paramname);
173
                    return true;
214
				}
174
                }
215
			}
175
                teststr = in.readLine();
216
		}
176
            }
217
	}
177
218
178
            return false;
219
	/**
179
        } catch (IOException ioe) {
220
	 * Checks to make sure all settings are kosher. In this case, it
180
            throw new BuildException("Could not read file " + filename);
221
	 * means that the pattern attribute has been set.
181
        } finally {
222
	 *
182
            if (in != null) {
223
	 */
183
                try {
224
	public void verifySettings()
184
                    in.close();
225
	{
185
                } catch (Exception e) {
226
		if (regexp == null)
186
                    throw new BuildException("Could not close file "
227
		{
187
                                             + filename);
228
			setError("The pattern attribute is required");
188
                }
229
		}
189
            }
230
	}
190
        }
231
191
    }
232
	/**
233
	 * The heart of the matter. This is where the selector gets to decide
234
	 * on the inclusion of a file in a particular fileset.
235
	 *
236
	 * @param basedir the base directory the scan is being done from
237
	 * @param filename is the name of the file to check
238
	 * @param file is a java.io.File object the selector can use
239
	 * @return whether the file should be selected or not
240
	 */
241
	public boolean isSelected(File basedir, String filename, File file)
242
	{
243
244
		// throw BuildException on error
245
		validate();
246
247
		if (file.isDirectory())
248
		{
249
			return true;
250
		}
251
252
		int options = 0;
253
		//		if (flags.indexOf('g') != -1)	options |= Regexp.REPLACE_ALL;
254
		if (flags.indexOf('i') != -1)
255
			options |= Regexp.MATCH_CASE_INSENSITIVE;
256
		if (flags.indexOf('m') != -1)
257
			options |= Regexp.MATCH_MULTILINE;
258
		if (flags.indexOf('s') != -1)
259
			options |= Regexp.MATCH_SINGLELINE;
260
261
		FileReader r = null;
262
		try
263
		{
264
			r = new FileReader(file);
265
			BufferedReader br = new BufferedReader(r);
266
			log(
267
				"Searching pattern '"
268
					+ regexp.getPattern()
269
					+ "' in '"
270
					+ file.getPath()
271
					+ "'"
272
					+ (byline ? " by line" : "")
273
					+ (flags.length() > 0 ? " with flags: '" + flags + "'" : "")
274
					+ ".",
275
				Project.MSG_VERBOSE);
276
277
			if (byline)
278
			{
279
				StringBuffer linebuf = new StringBuffer();
280
				String line = null;
281
				int c;
282
				boolean hasCR = false;
283
284
				do
285
				{
286
					c = br.read();
287
					if (c == '\r')
288
					{
289
						if (hasCR)
290
						{
291
							// second CR -> EOL + possibly empty line
292
							line = linebuf.toString();
293
							if (regexp.matches(line, options))
294
							{
295
								return true;
296
							}
297
							linebuf.setLength(0);
298
							// hasCR is still true (for the second one)
299
						}
300
						else
301
						{
302
							// first CR in this line
303
							hasCR = true;
304
						}
305
					}
306
					else if (c == '\n')
307
					{
308
						// LF -> EOL
309
						line = linebuf.toString();
310
						if (regexp.matches(line, options))
311
						{
312
							return true;
313
						}
314
						if (hasCR)
315
						{
316
							hasCR = false;
317
						}
318
						linebuf.setLength(0);
319
					}
320
					else
321
					{ // any other char
322
						if ((hasCR) || (c < 0))
323
						{
324
							// Mac-style linebreak or EOF (or both)
325
							line = linebuf.toString();
326
							if (regexp.matches(line, options))
327
							{
328
								return true;
329
							}
330
							if (hasCR)
331
							{
332
								hasCR = false;
333
							}
334
							linebuf.setLength(0);
335
						}
336
						if (c >= 0)
337
						{
338
							linebuf.append((char) c);
339
						}
340
					}
341
				}
342
				while (c >= 0);
343
			}
344
			else
345
			{
346
				String buf = FileUtils.readFully(br);
347
				if (regexp.matches(buf, options))
348
				{
349
					return true;
350
				}
351
			}
352
			r.close();
353
			r = null;
354
		}
355
		catch (IOException ioe)
356
		{
357
			throw new BuildException("Could not read file " + filename);
358
		}
359
		finally
360
		{
361
			try
362
			{
363
				if (r != null)
364
				{
365
					r.close();
366
				}
367
			}
368
			catch (Exception e)
369
			{
370
				throw new BuildException("Could not close file " + filename);
371
			}
372
		}
373
		return false;
374
	}
192
}
375
}
193

Return to bug 23037