001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.examples.readmetool;
011:
012: import java.io.ByteArrayOutputStream;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.util.Hashtable;
016: import java.util.Vector;
017:
018: import org.eclipse.core.resources.IFile;
019: import org.eclipse.core.runtime.CoreException;
020: import org.eclipse.core.runtime.IAdaptable;
021:
022: /**
023: * This class is a simple parser implementing the IReadmeFileParser
024: * interface. It parses a Readme file into sections based on the
025: * existence of numbered section tags in the input. A line beginning
026: * with a number followed by a dot will be taken as a section indicator
027: * (for example, 1., 2., or 12.).
028: * As well, a line beginning with a subsection-style series of numbers
029: * will also be taken as a section indicator, and can be used to
030: * indicate subsections (for example, 1.1, or 1.1.12).
031: */
032: public class DefaultSectionsParser implements IReadmeFileParser {
033: /**
034: * Returns the mark element that is the logical parent
035: * of the given mark number. Each dot in a mark number
036: * represents a parent-child separation. For example,
037: * the parent of 1.2 is 1, the parent of 1.4.1 is 1.4.
038: * Returns null if there is no appropriate parent.
039: */
040: protected IAdaptable getParent(Hashtable toc, String number) {
041: int lastDot = number.lastIndexOf('.');
042: if (lastDot < 0)
043: return null;
044: String parentNumber = number.substring(0, lastDot);
045: return (IAdaptable) toc.get(parentNumber);
046: }
047:
048: /**
049: * Returns a string containing the contents of the given
050: * file. Returns an empty string if there were any errors
051: * reading the file.
052: */
053: protected String getText(IFile file) {
054: try {
055: InputStream in = file.getContents();
056: ByteArrayOutputStream out = new ByteArrayOutputStream();
057: byte[] buf = new byte[1024];
058: int read = in.read(buf);
059: while (read > 0) {
060: out.write(buf, 0, read);
061: read = in.read(buf);
062: }
063: return out.toString();
064: } catch (CoreException e) {
065: // do nothing
066: } catch (IOException e) {
067: // do nothing
068: }
069: return ""; //$NON-NLS-1$
070: }
071:
072: /**
073: * Parses the input given by the argument.
074: *
075: * @param file the element containing the input text
076: * @return an element collection representing the parsed input
077: */
078: public MarkElement[] parse(IFile file) {
079: Hashtable markTable = new Hashtable(40);
080: Vector topLevel = new Vector();
081: String s = getText(file);
082: int start = 0;
083: int end = -1;
084: int lineno = 0;
085: int lastlineno = 0;
086: MarkElement lastme = null;
087: int ix;
088:
089: // parse content for headings
090: ix = s.indexOf('\n', start);
091: while (ix != -1) {
092: start = end + 1;
093: end = ix = s.indexOf('\n', start);
094: lineno++;
095: if (ix != -1) {
096: // skip blanks
097: while (s.charAt(start) == ' '
098: || s.charAt(start) == '\t') {
099: start++;
100: }
101: if (Character.isDigit(s.charAt(start))) {
102: if (lastme != null) {
103: lastme
104: .setNumberOfLines(lineno - lastlineno
105: - 1);
106: }
107: lastlineno = lineno;
108: String markName = parseHeading(s, start, end);
109:
110: //get the parent mark, if any.
111: String markNumber = parseNumber(markName);
112: IAdaptable parent = getParent(markTable, markNumber);
113: if (parent == null)
114: parent = file;
115:
116: MarkElement me = new MarkElement(parent, markName,
117: start, end - start);
118: lastme = me;
119:
120: markTable.put(markNumber, me);
121: if (parent == file) {
122: topLevel.add(me);
123: }
124: }
125: }
126: }
127: if (lastme != null) {
128: // set the number of lines for the last section
129: lastme.setNumberOfLines(lineno - lastlineno - 1);
130: }
131: MarkElement[] results = new MarkElement[topLevel.size()];
132: topLevel.copyInto(results);
133: return results;
134: }
135:
136: /**
137: * Creates a section name from the buffer and trims trailing
138: * space characters.
139: *
140: * @param buffer the string from which to create the section name
141: * @param start the start index
142: * @param end the end index
143: * @return a section name
144: */
145: private String parseHeading(String buffer, int start, int end) {
146: while (Character.isWhitespace(buffer.charAt(end - 1))
147: && end > start) {
148: end--;
149: }
150: return buffer.substring(start, end);
151: }
152:
153: /**
154: * Returns the number for this heading. A heading consists
155: * of a number (an arbitrary string of numbers and dots), followed by
156: * arbitrary text.
157: */
158: protected String parseNumber(String heading) {
159: int start = 0;
160: int end = heading.length();
161: char c;
162: do {
163: c = heading.charAt(start++);
164: } while ((c == '.' || Character.isDigit(c)) && start < end);
165:
166: //disregard trailing dots
167: while (heading.charAt(start - 1) == '.' && start > 0) {
168: start--;
169: }
170: return heading.substring(0, start);
171: }
172: }
|