Skip to main content
summaryrefslogtreecommitdiffstats
blob: 4f8cbb0118a367b5a7580d84cef10d48137f01d1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package org.eclipse.ui.examples.readmetool;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.CoreException;
import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * This class is a simple parser implementing the IReadmeFileParser
 * interface. It parses a Readme file into sections based on the
 * existence of numbered section tags in the input. A line beginning
 * with a number followed by a dot will be taken as a section indicator
 * (for example, 1., 2., or 12.). 
 * As well, a line beginning with a subsection-style series of numbers
 * will also be taken as a section indicator, and can be used to 
 * indicate subsections (for example, 1.1, or 1.1.12).
 */
public class DefaultSectionsParser implements IReadmeFileParser {
/**
 * Returns the mark element that is the logical parent
 * of the given mark number.  Each dot in a mark number
 * represents a parent-child separation.  For example,
 * the parent of 1.2 is 1, the parent of 1.4.1 is 1.4.
 * Returns null if there is no appropriate parent.
 */
protected IAdaptable getParent(Hashtable toc, String number) {
	int lastDot = number.lastIndexOf('.');
	if (lastDot < 0)
		return null;
	String parentNumber = number.substring(0, lastDot);
	return (IAdaptable) toc.get(parentNumber);
}
/**
 * Returns a string containing the contents of the given
 * file.  Returns an empty string if there were any errors
 * reading the file.
 */
protected String getText(IFile file) {
	try {
		InputStream in = file.getContents();
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buf = new byte[1024];
		int read = in.read(buf);
		while (read > 0) {
			out.write(buf, 0, read);
			read = in.read(buf);
		}
		return out.toString();
	} catch (CoreException e) {
	} catch (IOException e) {
	}
	return ""; //$NON-NLS-1$
}
/**
 * Parses the input given by the argument.
 *
 * @param file  the element containing the input text
 * @return an element collection representing the parsed input
 */
public MarkElement[] parse(IFile file) {
	Hashtable markTable = new Hashtable(40);
	Vector topLevel = new Vector();
	String s = getText(file);
	int start = 0;
	int end = -1;
	int lineno = 0;
	int lastlineno = 0;
	MarkElement lastme = null;
	int ix;

	// parse content for headings
	ix = s.indexOf('\n', start);
	while (ix != -1) {
		start = end + 1;
		end = ix = s.indexOf('\n', start);
		lineno++;
		if (ix != -1) {
			// skip blanks
			while (s.charAt(start) == ' ' || s.charAt(start) == '\t') {
				start++;
			}
			if (Character.isDigit(s.charAt(start))) {
				if (lastme != null) {
					lastme.setNumberOfLines(lineno - lastlineno - 1);
				}
				lastlineno = lineno;
			    String markName = parseHeading(s, start, end);

			    //get the parent mark, if any.
			    String markNumber = parseNumber(markName);
			    IAdaptable parent = getParent(markTable, markNumber);
			    if (parent == null)
				    parent = file;

				MarkElement me = new MarkElement(parent, markName, start, end - start);
				lastme = me;
				
				markTable.put(markNumber, me);
				if (parent == file) {
					topLevel.add(me);
				}
			}
		}
	}
	if (lastme != null) {
		// set the number of lines for the last section
		lastme.setNumberOfLines(lineno - lastlineno - 1);
	}
	MarkElement[] results = new MarkElement[topLevel.size()];
	topLevel.copyInto(results);
	return results;
}
/**
 * Creates a section name from the buffer and trims trailing
 * space characters.
 *
 * @param buffer  the string from which to create the section name
 * @param start  the start index
 * @param end  the end index
 * @return a section name
 */
private String parseHeading(String buffer, int start, int end) {
	while (Character.isWhitespace(buffer.charAt(end-1)) && end >start) {
		end--;
	}
	return buffer.substring(start, end);
}
/**
 * Returns the number for this heading.  A heading consists
 * of a number (an arbitrary string of numbers and dots), followed by
 * arbitrary text.
 */
protected String parseNumber(String heading) {
	int start = 0;
	int end = heading.length();
	char c;
	do {
		c = heading.charAt(start++);
	} while ((c == '.' || Character.isDigit(c)) && start < end);

	//disregard trailing dots
	while (heading.charAt(start-1) == '.' && start > 0) {
		start--;
	}
	return heading.substring(0, start);
}
}

Back to the top