001: /*
002: ** Java cvs client library package.
003: ** Copyright (c) 1997-2002 by Timothy Gerard Endres
004: **
005: ** This program is free software.
006: **
007: ** You may redistribute it and/or modify it under the terms of the GNU
008: ** Library General Public License (LGPL) as published by the Free Software
009: ** Foundation.
010: **
011: ** Version 2 of the license should be included with this distribution in
012: ** the file LICENSE.txt, as well as License.html. If the license is not
013: ** included with this distribution, you may find a copy at the FSF web
014: ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the Free
015: ** Software Foundation at 59 Temple Place - Suite 330, Boston, MA 02111 USA.
016: **
017: ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
018: ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
019: ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
020: ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
021: ** REDISTRIBUTION OF THIS SOFTWARE.
022: **
023: */
024:
025: package com.ice.cvsc;
026:
027: /**
028: * The CVSIgnore class implements the concept of a '.cvsignore' file.
029: * This is used by CVSProject's to handling CVS's concept of files that
030: * should be ignored during processing. Currently, we only need this for
031: * the 'import' function, since in all other cases we have a list of
032: * entries to work from. In other words, 'import' is the only function
033: * we implement that scans directories, and thus cares about ignoring
034: * certain files.
035: *
036: * @version $Revision: 2.4 $
037: * @author Timothy Gerard Endres, <a href="mailto:time@ice.com">time@ice.com</a>.
038: * @see CVSProject
039: *
040: */
041:
042: import java.lang.*;
043: import java.io.*;
044: import java.util.*;
045:
046: public class CVSIgnore extends Object {
047: static public final String RCS_ID = "$Id: CVSIgnore.java,v 2.4 2003/07/27 01:08:32 time Exp $";
048: static public final String RCS_REV = "$Revision: 2.4 $";
049:
050: static private final String DEFAULT_IGNORE_SPEC = "RCSLOG RCS SCCS CVS cvslog.*"
051: + "tags TAGS *~ #* ,*"
052: + "*.old *.bak *.orig *.rej .del-*"
053: + "*.a *.o *.elc *.ln core" + "*.zip *.tar *.gz *.z *.Z";
054:
055: private Vector specs;
056:
057: /**
058: * Constructs a new CVSIgnore object.
059: */
060: public CVSIgnore() {
061: super ();
062: this .specs = null;
063: this .setIgnoreSpec(DEFAULT_IGNORE_SPEC);
064: }
065:
066: /**
067: * Constructs a new CVSIgnore object, setting the
068: * ignore's list to that specified by the parameter.
069: *
070: * @param default_spec The default ignore specs.
071: */
072: public CVSIgnore(String default_spec) {
073: super ();
074: this .specs = null;
075: this .setIgnoreSpec(default_spec);
076: }
077:
078: public int size() {
079: return this .specs.size();
080: }
081:
082: /**
083: * Adds the cvsignore specifications to the current list
084: * of ignored files.
085: *
086: * @param spec The string listing the specs to add.
087: */
088: public void addIgnoreSpec(String spec) {
089: if (spec == null)
090: return;
091:
092: String toke;
093: int i, count;
094:
095: if (this .specs == null) {
096: this .specs = new Vector();
097: }
098:
099: StringTokenizer toker = new StringTokenizer(spec);
100:
101: count = toker.countTokens();
102:
103: for (i = 0; i < count; ++i) {
104: try {
105: toke = toker.nextToken();
106: } catch (NoSuchElementException ex) {
107: break;
108: }
109:
110: if (toke.equals("!")) {
111: this .specs = new Vector();
112: } else {
113: this .specs.addElement(toke);
114: }
115: }
116: }
117:
118: /**
119: * Adds the cvsignore specifications from the file
120: * provided to the current list of ignored files.
121: *
122: * @param ignoreFile The file containing the ignore specs.
123: */
124: public void addIgnoreFile(File ignoreFile) {
125: if (ignoreFile == null)
126: return;
127:
128: String line;
129: boolean ok = true;
130: BufferedReader in = null;
131:
132: if (this .specs == null) {
133: this .specs = new Vector();
134: }
135:
136: try {
137: in = new BufferedReader(new FileReader(ignoreFile));
138: } catch (IOException ex) {
139: in = null;
140: ok = false;
141: }
142:
143: for (; ok;) {
144: try {
145: line = in.readLine();
146: } catch (IOException ex) {
147: line = null;
148: }
149:
150: if (line == null)
151: break;
152:
153: this .addIgnoreSpec(line);
154: }
155:
156: if (in != null) {
157: try {
158: in.close();
159: } catch (IOException ex) {
160: }
161: }
162: }
163:
164: /**
165: * Replaces all current ignore specs with those passed in.
166: *
167: * @param spec The string listing the specs to replace with.
168: */
169: public void setIgnoreSpec(String spec) {
170: if (this .specs != null) {
171: this .specs.removeAllElements();
172: }
173:
174: this .addIgnoreSpec(spec);
175: }
176:
177: /**
178: * Determines if a file is to be ignored.
179: *
180: * @param name The name of the file to check.
181: * @return If the file is to be ignored, true, else false.
182: */
183: public boolean isFileToBeIgnored(String name) {
184: int i;
185:
186: for (i = 0; i < this .specs.size(); ++i) {
187: String spec = (String) this .specs.elementAt(i);
188: if (fileMatchesExpr(name, spec)) {
189: return true;
190: }
191: }
192:
193: return false;
194: }
195:
196: /**
197: * Determines if a filename matches an expression.
198: *
199: * @param fileName The name of the file to check.
200: * @param matchExpr The expression to check against.
201: * @return If the file name matches the expression, true, else false.
202: */
203: private boolean fileMatchesExpr(String fileName, String matchExpr) {
204: return this .matchExprRecursor(fileName, matchExpr, 0, 0);
205: }
206:
207: /**
208: * An internal routine to implement expression matching.
209: * This routine is based on a self-recursive algorithm.
210: *
211: * @param string The string to be compared.
212: * @param pattern The expression to compare <em>string</em> to.
213: * @param sIdx The index of where we are in <em>string</em>.
214: * @param pIdx The index of where we are in <em>pattern</em>.
215: * @return True if <em>string</em> matched pattern, else false.
216: */
217: private boolean matchExprRecursor(String string, String pattern,
218: int sIdx, int pIdx) {
219: int pLen = pattern.length();
220: int sLen = string.length();
221:
222: for (;;) {
223:
224: if (pIdx >= pLen) {
225: if (sIdx >= sLen)
226: return true;
227: else
228: return false;
229: }
230:
231: if (sIdx >= sLen && pattern.charAt(pIdx) != '*') {
232: return false;
233: }
234:
235: // Check for a '*' as the next pattern char.
236: // This is handled by a recursive call for
237: // each postfix of the name.
238: if (pattern.charAt(pIdx) == '*') {
239: if (++pIdx >= pLen)
240: return true;
241:
242: for (;;) {
243: if (this .matchExprRecursor(string, pattern, sIdx,
244: pIdx))
245: return true;
246:
247: if (sIdx >= sLen)
248: return false;
249:
250: ++sIdx;
251: }
252: }
253:
254: // Check for '?' as the next pattern char.
255: // This matches the current character.
256: if (pattern.charAt(pIdx) == '?') {
257: ++pIdx;
258: ++sIdx;
259: continue;
260: }
261:
262: // Check for '[' as the next pattern char.
263: // This is a list of acceptable characters,
264: // which can include character ranges.
265: if (pattern.charAt(pIdx) == '[') {
266: for (++pIdx;; ++pIdx) {
267: if (pIdx >= pLen || pattern.charAt(pIdx) == ']')
268: return false;
269:
270: if (pattern.charAt(pIdx) == string.charAt(sIdx))
271: break;
272:
273: if (pIdx < (pLen - 1)
274: && pattern.charAt(pIdx + 1) == '-') {
275: if (pIdx >= (pLen - 2))
276: return false;
277:
278: char chStr = string.charAt(sIdx);
279: char chPtn = pattern.charAt(pIdx);
280: char chPtn2 = pattern.charAt(pIdx + 2);
281:
282: if ((chPtn <= chStr) && (chPtn2 >= chStr))
283: break;
284:
285: if ((chPtn >= chStr) && (chPtn2 <= chStr))
286: break;
287:
288: pIdx += 2;
289: }
290: }
291:
292: for (; pattern.charAt(pIdx) != ']'; ++pIdx) {
293: if (pIdx >= pLen) {
294: --pIdx;
295: break;
296: }
297: }
298:
299: ++pIdx;
300: ++sIdx;
301: continue;
302: }
303:
304: // Check for backslash escapes
305: // We just skip over them to match the next char.
306: if (pattern.charAt(pIdx) == '\\') {
307: if (++pIdx >= pLen)
308: return false;
309: }
310:
311: if (pIdx < pLen && sIdx < sLen)
312: if (pattern.charAt(pIdx) != string.charAt(sIdx))
313: return false;
314:
315: ++pIdx;
316: ++sIdx;
317: }
318: }
319:
320: public void dumpIgnoreList(String message) {
321: if (message != null)
322: CVSLog.logMsg(message);
323:
324: for (int i = 0; i < this .specs.size(); ++i) {
325: String spec = (String) this .specs.elementAt(i);
326:
327: CVSLog.logMsg("Ignore[" + i + "] '" + spec + "'");
328: }
329: }
330: }
|