1 | /*
|
---|
2 | * Copyright 2000,2002-2004 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 | package org.apache.tools.ant;
|
---|
18 |
|
---|
19 | import java.io.File;
|
---|
20 | import java.util.NoSuchElementException;
|
---|
21 | import java.util.StringTokenizer;
|
---|
22 | import org.apache.tools.ant.taskdefs.condition.Os;
|
---|
23 |
|
---|
24 | /**
|
---|
25 | * A Path tokenizer takes a path and returns the components that make up
|
---|
26 | * that path.
|
---|
27 | *
|
---|
28 | * The path can use path separators of either ':' or ';' and file separators
|
---|
29 | * of either '/' or '\'.
|
---|
30 | *
|
---|
31 | */
|
---|
32 | public class PathTokenizer {
|
---|
33 | /**
|
---|
34 | * A tokenizer to break the string up based on the ':' or ';' separators.
|
---|
35 | */
|
---|
36 | private StringTokenizer tokenizer;
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * A String which stores any path components which have been read ahead
|
---|
40 | * due to DOS filesystem compensation.
|
---|
41 | */
|
---|
42 | private String lookahead = null;
|
---|
43 |
|
---|
44 | /**
|
---|
45 | * A boolean that determines if we are running on Novell NetWare, which
|
---|
46 | * exhibits slightly different path name characteristics (multi-character
|
---|
47 | * volume / drive names)
|
---|
48 | */
|
---|
49 | private boolean onNetWare = Os.isFamily("netware");
|
---|
50 |
|
---|
51 | /**
|
---|
52 | * Flag to indicate whether or not we are running on a platform with a
|
---|
53 | * DOS style filesystem
|
---|
54 | */
|
---|
55 | private boolean dosStyleFilesystem;
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * Constructs a path tokenizer for the specified path.
|
---|
59 | *
|
---|
60 | * @param path The path to tokenize. Must not be <code>null</code>.
|
---|
61 | */
|
---|
62 | public PathTokenizer(String path) {
|
---|
63 | if (onNetWare) {
|
---|
64 | // For NetWare, use the boolean=true mode, so we can use delimiter
|
---|
65 | // information to make a better decision later.
|
---|
66 | tokenizer = new StringTokenizer(path, ":;", true);
|
---|
67 | } else {
|
---|
68 | // on Windows and Unix, we can ignore delimiters and still have
|
---|
69 | // enough information to tokenize correctly.
|
---|
70 | tokenizer = new StringTokenizer(path, ":;", false);
|
---|
71 | }
|
---|
72 | dosStyleFilesystem = File.pathSeparatorChar == ';';
|
---|
73 | }
|
---|
74 |
|
---|
75 | /**
|
---|
76 | * Tests if there are more path elements available from this tokenizer's
|
---|
77 | * path. If this method returns <code>true</code>, then a subsequent call
|
---|
78 | * to nextToken will successfully return a token.
|
---|
79 | *
|
---|
80 | * @return <code>true</code> if and only if there is at least one token
|
---|
81 | * in the string after the current position; <code>false</code> otherwise.
|
---|
82 | */
|
---|
83 | public boolean hasMoreTokens() {
|
---|
84 | if (lookahead != null) {
|
---|
85 | return true;
|
---|
86 | }
|
---|
87 |
|
---|
88 | return tokenizer.hasMoreTokens();
|
---|
89 | }
|
---|
90 |
|
---|
91 | /**
|
---|
92 | * Returns the next path element from this tokenizer.
|
---|
93 | *
|
---|
94 | * @return the next path element from this tokenizer.
|
---|
95 | *
|
---|
96 | * @exception NoSuchElementException if there are no more elements in this
|
---|
97 | * tokenizer's path.
|
---|
98 | */
|
---|
99 | public String nextToken() throws NoSuchElementException {
|
---|
100 | String token = null;
|
---|
101 | if (lookahead != null) {
|
---|
102 | token = lookahead;
|
---|
103 | lookahead = null;
|
---|
104 | } else {
|
---|
105 | token = tokenizer.nextToken().trim();
|
---|
106 | }
|
---|
107 |
|
---|
108 | if (!onNetWare) {
|
---|
109 | if (token.length() == 1 && Character.isLetter(token.charAt(0))
|
---|
110 | && dosStyleFilesystem
|
---|
111 | && tokenizer.hasMoreTokens()) {
|
---|
112 | // we are on a dos style system so this path could be a drive
|
---|
113 | // spec. We look at the next token
|
---|
114 | String nextToken = tokenizer.nextToken().trim();
|
---|
115 | if (nextToken.startsWith("\\") || nextToken.startsWith("/")) {
|
---|
116 | // we know we are on a DOS style platform and the next path
|
---|
117 | // starts with a slash or backslash, so we know this is a
|
---|
118 | // drive spec
|
---|
119 | token += ":" + nextToken;
|
---|
120 | } else {
|
---|
121 | // store the token just read for next time
|
---|
122 | lookahead = nextToken;
|
---|
123 | }
|
---|
124 | }
|
---|
125 | } else {
|
---|
126 | // we are on NetWare, tokenizing is handled a little differently,
|
---|
127 | // due to the fact that NetWare has multiple-character volume names.
|
---|
128 | if (token.equals(File.pathSeparator) || token.equals(":")) {
|
---|
129 | // ignore ";" and get the next token
|
---|
130 | token = tokenizer.nextToken().trim();
|
---|
131 | }
|
---|
132 |
|
---|
133 | if (tokenizer.hasMoreTokens()) {
|
---|
134 | // this path could be a drive spec, so look at the next token
|
---|
135 | String nextToken = tokenizer.nextToken().trim();
|
---|
136 |
|
---|
137 | // make sure we aren't going to get the path separator next
|
---|
138 | if (!nextToken.equals(File.pathSeparator)) {
|
---|
139 | if (nextToken.equals(":")) {
|
---|
140 | if (!token.startsWith("/") && !token.startsWith("\\")
|
---|
141 | && !token.startsWith(".")
|
---|
142 | && !token.startsWith("..")) {
|
---|
143 | // it indeed is a drive spec, get the next bit
|
---|
144 | String oneMore = tokenizer.nextToken().trim();
|
---|
145 | if (!oneMore.equals(File.pathSeparator)) {
|
---|
146 | token += ":" + oneMore;
|
---|
147 | } else {
|
---|
148 | token += ":";
|
---|
149 | lookahead = oneMore;
|
---|
150 | }
|
---|
151 | }
|
---|
152 | // implicit else: ignore the ':' since we have either a
|
---|
153 | // UNIX or a relative path
|
---|
154 | } else {
|
---|
155 | // store the token just read for next time
|
---|
156 | lookahead = nextToken;
|
---|
157 | }
|
---|
158 | }
|
---|
159 | }
|
---|
160 | }
|
---|
161 | return token;
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|