001: /*
002: * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
003: * NETSCAPE COMMUNICATIONS CORPORATION
004: *
005: * Copyright (c) 1996 Netscape Communications Corporation.
006: * All Rights Reserved.
007: * Use of this Source Code is subject to the terms of the applicable
008: * license agreement from Netscape Communications Corporation.
009: */
010:
011: package util;
012:
013: import java.util.Enumeration;
014: import java.util.NoSuchElementException;
015:
016: /*
017: ** AltSTokenizer.java
018: **
019: */
020:
021: /**
022: The Sun's StringTokenizer class modified to allow more
023: extensive functionality.
024: <p>
025: <i>
026: @(#)StringTokenizer.java 1.13 95/08/10
027: <p>
028: Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
029: <p>
030: Permission to use, copy, modify, and distribute this software
031: and its documentation for NON-COMMERCIAL purposes and without
032: fee is hereby granted provided that this copyright notice
033: appears in all copies. Please refer to the file "copyright.html"
034: for further important copyright and licensing information.
035: <p>
036: SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
037: THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
038: TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
039: PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
040: ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
041: DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
042: </i>
043: *
044: */
045: public class AltSTokenizer implements Enumeration {
046:
047: /**
048: * Current position in the string.
049: */
050: private int currentPosition;
051:
052: /**
053: * End of string position.
054: */
055: private int maxPosition;
056:
057: /**
058: * The string in question.
059: */
060: private String str;
061:
062: /**
063: * Token delimiters.
064: */
065: private String delimiters;
066:
067: /**
068: * Return delimiters as tokens or skip them.
069: */
070: private boolean retTokens;
071:
072: /**
073: * Respect quoted strings.
074: */
075: private boolean respectQuotedStrings;
076:
077: /**
078: * Constructs an AltSTokenizer instance.
079: * @param str the string
080: * @param delim the delimiters
081: * @param returnTokens returns delimiters as tokens or skips them
082: */
083: public AltSTokenizer(String str, String delim, boolean returnTokens) {
084: currentPosition = 0;
085: this .str = str;
086: maxPosition = str.length();
087: delimiters = delim;
088: retTokens = returnTokens;
089: respectQuotedStrings = false;
090: }
091:
092: /**
093: * Constructs an AltSTokenizer instance.
094: * @param str the string
095: * @param delim the delimiters
096: */
097: public AltSTokenizer(String str, String delim) {
098: this (str, delim, false);
099: }
100:
101: /**
102: * Constructs an AltSTokenizer instance.
103: * @param str the string
104: */
105: public AltSTokenizer(String str) {
106: this (str, " \t\n\r", false);
107: }
108:
109: /**
110: * Return the next character.
111: * @exception NoSuchElementException If no more characters
112: */
113: public String nextChar() throws NoSuchElementException {
114: if (currentPosition >= maxPosition) {
115: throw new NoSuchElementException();
116: }
117:
118: int start = currentPosition;
119:
120: currentPosition++;
121:
122: return str.substring(start, currentPosition);
123: }
124:
125: /**
126: * Return true or false there are more characters.
127: */
128: public boolean hasMoreChars() {
129: return (currentPosition < maxPosition);
130: }
131:
132: /**
133: * Return the next character, but don't consume the string.
134: * @exception NoSuchElementException If no more characters
135: */
136: public String peekChar() throws NoSuchElementException {
137: if (currentPosition >= maxPosition) {
138: throw new NoSuchElementException();
139: }
140:
141: return str.substring(currentPosition, currentPosition + 1);
142: }
143:
144: /**
145: * Return the next n characters.
146: * @param endIndex number of characters to return
147: * @exception NoSuchElementException If there aren't that many
148: */
149: public String nextSubstring(int endIndex)
150: throws NoSuchElementException {
151: if (currentPosition + endIndex >= maxPosition) {
152: throw new NoSuchElementException();
153: }
154:
155: int start = currentPosition;
156:
157: currentPosition += endIndex;
158:
159: return str.substring(start, currentPosition);
160: }
161:
162: /**
163: * Return the next n characters, but don't consume the string.
164: * @param endIndex number of characters to return
165: * @exception NoSuchElementException If there aren't that many
166: */
167: public String peekSubstring(int endIndex)
168: throws NoSuchElementException {
169: if (currentPosition + endIndex >= maxPosition) {
170: throw new NoSuchElementException();
171: }
172:
173: return str.substring(currentPosition, currentPosition
174: + endIndex);
175: }
176:
177: /**
178: * Return number of characters left.
179: */
180: public int stringRemains() {
181: return maxPosition - currentPosition;
182: }
183:
184: /**
185: * Return the remaining string.
186: */
187: public String peekRemains() {
188: return str.substring(currentPosition);
189: }
190:
191: /**
192: * Skip delimiters.
193: */
194: private void skipDelimiters() {
195: while ((!retTokens)
196: && (currentPosition < maxPosition)
197: && (delimiters.indexOf(str.charAt(currentPosition)) >= 0)) {
198: currentPosition++;
199: }
200: }
201:
202: /**
203: * Return true or false there are more tokens.
204: */
205: public boolean hasMoreTokens() {
206: skipDelimiters();
207: return (currentPosition < maxPosition);
208: }
209:
210: /**
211: * Return the next token.
212: * @exception NoSuchElementException If there aren't that many
213: */
214: public String nextToken() throws NoSuchElementException {
215: boolean inQuote = false;
216:
217: skipDelimiters();
218:
219: if (currentPosition >= maxPosition) {
220: throw new NoSuchElementException();
221: }
222:
223: int start = currentPosition;
224:
225: while ((currentPosition < maxPosition)
226: && (delimiters.indexOf(str.charAt(currentPosition)) < 0)) {
227: if ((respectQuotedStrings)
228: && (str.charAt(currentPosition) == '"')) {
229: currentPosition++;
230: while ((currentPosition < maxPosition)
231: && (str.charAt(currentPosition) != '"')) {
232: currentPosition++;
233: }
234: currentPosition++;
235: } else {
236: currentPosition++;
237: }
238: }
239:
240: if ((retTokens)
241: && (start == currentPosition)
242: && (delimiters.indexOf(str.charAt(currentPosition)) >= 0)) {
243: currentPosition++;
244: }
245:
246: return str.substring(start, currentPosition);
247: }
248:
249: /**
250: * Return the next token but change the delimiter set first.
251: * @param delim delimiters
252: */
253: public String nextToken(String delim) {
254: delimiters = delim;
255: return nextToken();
256: }
257:
258: /**
259: * Return the next token, but only as a "peek", don't consume
260: * the string.
261: */
262: public String peekToken() {
263: int start = currentPosition;
264: String s = nextToken();
265:
266: currentPosition = start;
267:
268: return s;
269: }
270:
271: /**
272: * Return the next token, but only as a "peek", don't consume
273: * the string.
274: * First change delimiter set.
275: * @param delim delimiters
276: */
277: public String peekToken(String delim) {
278: int start = currentPosition;
279: String s = nextToken(delim);
280:
281: currentPosition = start;
282:
283: return s;
284: }
285:
286: /**
287: * Are there more elements?
288: */
289: public boolean hasMoreElements() {
290: return hasMoreTokens();
291: }
292:
293: /**
294: * Return the next element.
295: */
296: public Object nextElement() {
297: return nextToken();
298: }
299:
300: /**
301: * Peek at the next element.
302: */
303: public Object peekElement() {
304: return peekToken();
305: }
306:
307: /**
308: * Count tokens.
309: */
310: public int countTokens() {
311: int count = 0;
312: int currpos = currentPosition;
313:
314: while (currpos < maxPosition) {
315: while ((!retTokens) && (currpos < maxPosition)
316: && (delimiters.indexOf(str.charAt(currpos)) >= 0)) {
317: currpos++;
318: }
319:
320: if (currpos >= maxPosition) {
321: break;
322: }
323:
324: int start = currpos;
325: while ((currpos < maxPosition)
326: && (delimiters.indexOf(str.charAt(currpos)) < 0)) {
327: if ((respectQuotedStrings)
328: && (str.charAt(currpos) == '"')) {
329: currpos++;
330: while ((currpos < maxPosition)
331: && (str.charAt(currpos) != '"')) {
332: currpos++;
333: }
334: currpos++;
335: } else {
336: currpos++;
337: }
338: // currpos++;
339: }
340:
341: if ((retTokens) && (start == currpos)
342: && (delimiters.indexOf(str.charAt(currpos)) >= 0)) {
343: currpos++;
344: }
345:
346: count++;
347:
348: }
349:
350: return count;
351: }
352:
353: /**
354: * Return current source line number.
355: * Expensive call because the line number isn't currently tracked.
356: */
357: public int getCurrentLineNumber() {
358: int n = 1;
359: int m = Math.min((maxPosition - 1), currentPosition);
360:
361: for (int i = 0; i <= m; i++) {
362: if (str.charAt(i) == '\n') {
363: n++;
364: }
365: }
366:
367: return n;
368: }
369:
370: /**
371: * Return current line, including newline if any.
372: * Expensive call because the line number isn't currently tracked.
373: */
374: public String getCurrentLine() {
375: return getCurrentLine(false);
376: }
377:
378: /**
379: * Return current line, including newline if any.
380: * Expensive call because the line number isn't currently tracked.
381: * @param decorated with line number and brackets
382: */
383: public String getCurrentLine(boolean decorated) {
384: String s = "";
385: int n = 1;
386: int linebeg = 0;
387: int m = Math.min((maxPosition - 1), currentPosition);
388:
389: for (int i = 0; i <= m; i++) {
390: if (str.charAt(i) == '\n') {
391: n++;
392: }
393:
394: if (str.charAt((i > 0) ? i - 1 : 0) == '\n') {
395: linebeg = i;
396: }
397: }
398:
399: s = str.substring(linebeg);
400: if (s.indexOf('\n') != Header.NOSTRINGINDICE) {
401: s = s.substring(0, s.indexOf('\n') + 1);
402: }
403:
404: if (decorated) {
405: s = "line " + n + ":[" + s + "]";
406: }
407:
408: return s;
409: }
410:
411: /**
412: * Return specified line, including newline if any.
413: * Returns null if the line number requested doesn't exist.
414: * @param targ line number requested
415: */
416: public String getLine(int targ) {
417: return getLine(targ, false);
418: }
419:
420: /**
421: * Return specified line, including newline if any.
422: * Returns null if the line number requested doesn't exist.
423: * @param targ line number requested
424: * @param decorated with line number and brackets
425: */
426: public String getLine(int targ, boolean decorated) {
427: String s = "";
428: int n = 1;
429: int linebeg = 0;
430: int m = Math.min((maxPosition - 1), currentPosition);
431:
432: for (int i = 0; n <= targ; i++) {
433: if (i > m) {
434: return null;
435: }
436:
437: if (str.charAt(i) == '\n') {
438: n++;
439: }
440:
441: if (str.charAt((i > 0) ? i - 1 : 0) == '\n') {
442: linebeg = i;
443: }
444: }
445:
446: s = str.substring(linebeg);
447: if (s.indexOf('\n') != Header.NOSTRINGINDICE) {
448: s = s.substring(0, s.indexOf('\n') + 1);
449: }
450:
451: if (decorated) {
452: s = "line " + targ + ":[" + s + "]";
453: }
454:
455: return s;
456: }
457:
458: /**
459: * Respect double-quoted strings: do not attempt to tokenize
460: * within quotes.
461: * For example, if space is a token delimiter and "tree bark"
462: * is encountered, it isn't tokenized on the space after tree
463: * if quotes are respected.
464: * <p>
465: * Currently only double-quotes are respected.
466: * <p>
467: * If double-quotes are delimiters, the fact that they
468: * are delimters takes precedence over quote respecting.
469: * <p>
470: * If the quote is not terminated, the token is the remaining line.
471: */
472: public void setRespectQuotedStrings(boolean respectQuotedStrings) {
473: this .respectQuotedStrings = respectQuotedStrings;
474: }
475:
476: public boolean respectQuotedStrings() {
477: return respectQuotedStrings;
478: }
479:
480: /*------------*/
481: /* toString() */
482: /*------------*/
483:
484: public String toString() {
485: return "AltSTokenizer: " + " (" + Header.VERSION + ")" + "\n"
486: + "\t" + "currentPosition: " + currentPosition + "\n"
487: + "\t" + "maxPosition: " + maxPosition + "\n" + "\t"
488: + "str: " + str + "\n" + "\t" + "delimiters: "
489: + delimiters + "\n" + "\t" + "retTokens: " + retTokens
490: + "\n";
491: }
492: }
|