001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.java.guards;
043:
044: import java.nio.CharBuffer;
045: import java.util.ArrayList;
046: import java.util.Arrays;
047: import java.util.LinkedList;
048: import java.util.List;
049: import java.util.logging.Level;
050: import java.util.logging.Logger;
051: import java.util.regex.Matcher;
052: import java.util.regex.Pattern;
053: import javax.swing.text.BadLocationException;
054: import org.netbeans.api.editor.guards.GuardedSection;
055: import org.netbeans.modules.java.guards.GuardTag;
056: import org.netbeans.modules.java.guards.SectionDescriptor;
057:
058: /**
059: *
060: * @author Jan Pokorsky
061: */
062: final class JavaGuardedReader {
063:
064: /** The prefix of all magic strings */
065: final static String MAGIC_PREFIX = "//GEN-"; // NOI18N
066:
067: Pattern magicsAsRE;
068:
069: private static final int LONGEST_ITEM = 10;
070:
071: /** The list of the SectionsDesc. */
072: private final LinkedList<SectionDescriptor> list;
073:
074: private final JavaGuardedSectionsProvider provider;
075:
076: /** Creates a new instance of JavaGuardedReader */
077: public JavaGuardedReader(JavaGuardedSectionsProvider provider) {
078: list = new LinkedList<SectionDescriptor>();
079: this .provider = provider;
080: }
081:
082: public List<GuardedSection> getGuardedSections() {
083: return fillSections(list);
084: }
085:
086: public char[] translateToCharBuff(char[] readBuff) {
087: char[] charBuff = new char[readBuff.length];
088: // points to first unused cell in charBuff
089: int charBuffPtr = 0;
090: int stop = readBuff.length - 1;
091:
092: // read char
093: int c;
094: // ptr to first not processed char in readBuff
095: int i = 0;
096: // points to a character right after a newline
097: int lastNewLine = 0;
098:
099: // final automata
100: int fatpos = 0;
101: final int MAGICLEN = MAGIC_PREFIX.length();
102:
103: //process newlines so only '\n' appears in the charBuff
104: //count all kinds of newlines - most used will be used on save
105: while (i < stop) {
106: c = readBuff[i];
107: if (c == '\n') {
108: lastNewLine = charBuffPtr;
109: }
110: charBuff[charBuffPtr++] = readBuff[i++];
111:
112: switch (fatpos) {
113: case 0:
114: if (c == '/') {
115: fatpos++;
116: } else {
117: fatpos = 0;
118: }
119: break;
120:
121: case 1:
122: if (c == '/') {
123: fatpos++;
124: } else {
125: fatpos = 0;
126: }
127: break;
128:
129: case 2:
130: if (c == 'G') {
131: fatpos++;
132: } else if (c == '/') {
133: fatpos = 2; // what if /////GEN-xxx?
134: } else {
135: fatpos = 0;
136: }
137: break;
138:
139: case 3:
140: if (c == 'E') {
141: fatpos++;
142: } else {
143: fatpos = 0;
144: }
145: break;
146:
147: case 4:
148: if (c == 'N') {
149: fatpos++;
150: } else {
151: fatpos = 0;
152: }
153: break;
154:
155: case 5:
156: if (c == '-') {
157: fatpos++;
158: } else {
159: fatpos = 0;
160: }
161: break;
162:
163: default:
164: fatpos = 0;
165: }
166:
167: // "//GEN-" was reached at this time
168: if (fatpos == MAGICLEN) {
169: fatpos = 0;
170: Pattern magics = getMagicsAsRE();
171: int searchLen = Math.min(LONGEST_ITEM, readBuff.length
172: - i);
173: CharBuffer chi = CharBuffer
174: .wrap(readBuff, i, searchLen);
175: Matcher matcher = magics.matcher(chi);
176: if (matcher.find()) {
177: String match = matcher.group();
178:
179: charBuffPtr -= MAGICLEN;
180: i += match.length();
181: int toNl = toNewLine(i, readBuff);
182: int sectionSize = MAGICLEN + match.length() + toNl;
183:
184: // if (!justFilter) {
185: // System.out.println("## MATCH: '" + match.substring(0, match.length() - 1) + "'");
186: SectionDescriptor desc = new SectionDescriptor(
187: GuardTag.valueOf(match.substring(0, match
188: .length() - 1)), //XXX catch IAE
189: String.valueOf(readBuff, i, toNl),
190: lastNewLine + 1, charBuffPtr + sectionSize);
191: // new SectionDescriptor(GuardTag.valueOf(match.substring(0, match.length() - 1))); //XXX catch IAE
192: // desc.begin = lastNewLine;
193: // desc.end = charBuffPtr + sectionSize + 1;
194: // desc.name = new String(readBuff, i, toNl);
195: list.add(desc);
196: // }
197: i += toNl;
198: Arrays.fill(charBuff, charBuffPtr, charBuffPtr
199: + sectionSize, ' ');
200: charBuffPtr += sectionSize;
201: }
202: }
203: }
204:
205: if (i == stop) {
206: // c = readBuff[i];
207: // switch(c) {
208: // case (int) '\n':
209: //
210: // newLineTypes[NewLine.N.ordinal()]++;
211: //
212: // charBuff[charBuffPtr++] = '\n';
213: //
214: // break;
215: // case (int) '\r':
216: //
217: // newLineTypes[NewLine.R.ordinal()]++;
218: //
219: // charBuff[charBuffPtr++] = '\n';
220: //
221: // break;
222: // default:
223: //
224: charBuff[charBuffPtr++] = readBuff[i++];
225: // }
226: }
227:
228: // repair last SectionDesc
229: if (/*!justFilter && */(list.size() > 0)) {
230: SectionDescriptor desc = (SectionDescriptor) list.getLast();
231: if (desc.getEnd() > charBuffPtr) {
232: desc.setEnd(charBuffPtr);
233: }
234: }
235:
236: char[] res;
237: if (charBuffPtr != charBuff.length) {
238: res = new char[charBuffPtr];
239: System.arraycopy(charBuff, 0, res, 0, charBuffPtr);
240: } else {
241: res = charBuff;
242: }
243: return charBuff;
244: }
245:
246: /** @return searching engine for magics */
247: final Pattern getMagicsAsRE() {
248: if (magicsAsRE == null) {
249: magicsAsRE = Pattern.compile(makeOrRegexp());
250: }
251: return magicsAsRE;
252: }
253:
254: /** Makes or regular expression for magics */
255: final String makeOrRegexp() {
256: StringBuilder sb = new StringBuilder(100);
257: // final int len = MAGIC_PREFIX.length();
258: for (GuardTag t : GuardTag.values()) {
259: sb.append(t.name() + ':');
260: sb.append('|');
261: }
262:
263: return sb.substring(0, sb.length() - 1);
264: }
265:
266: /** Searches for newline from i */
267: static int toNewLine(int i, char[] readBuff) {
268: int c;
269: int counter = i;
270: final int len = readBuff.length;
271: while (counter < len) {
272: c = readBuff[counter++];
273: if (c == '\r' || c == '\n') {
274: counter--;
275: break;
276: }
277: }
278:
279: return counter - i;
280: }
281:
282: /** Takes the section descriptors from the GuardedReader and
283: * fills the table 'sections', also marks as guarded all sections
284: * in the given document.
285: * @param is Where to take the guarded section descriptions.
286: * @param doc Where to mark guarded.
287: */
288: List<GuardedSection> fillSections(List<SectionDescriptor> descs) {
289: SectionDescriptor descBegin = null;
290: List<GuardedSection> sections = new ArrayList<GuardedSection>(
291: descs.size());
292:
293: for (SectionDescriptor descCurrent : descs) {
294: try {
295: GuardedSection sect = null;
296: switch (descCurrent.getType()) {
297: case LINE:
298: sect = provider.createSimpleSection(descCurrent
299: .getName(), descCurrent.getBegin(),
300: descCurrent.getEnd());
301: break;
302:
303: case BEGIN:
304: case HEADER:
305: case FIRST:
306: descBegin = descCurrent;
307: break;
308:
309: case HEADEREND:
310: if ((descBegin != null)
311: && ((descBegin.getType() == GuardTag.HEADER) || (descBegin
312: .getType() == GuardTag.FIRST))
313: && (descCurrent.getName().equals(descBegin
314: .getName()))) {
315: descBegin.setEnd(descCurrent.getEnd());
316: } else {
317: //SYNTAX ERROR - ignore it.
318: descBegin = null;
319: }
320: break;
321:
322: case END:
323: case LAST:
324: if ((descBegin != null)
325: && (descBegin.getName().equals(descCurrent
326: .getName()))) {
327: if ((descBegin.getType() == GuardTag.BEGIN)
328: && (descCurrent.getType() == GuardTag.END)) {
329: // simple section
330: sect = provider.createSimpleSection(
331: descCurrent.getName(), descBegin
332: .getBegin(), descCurrent
333: .getEnd());
334: break;
335: }
336: if (((descBegin.getType() == GuardTag.FIRST) && (descCurrent
337: .getType() == GuardTag.LAST))
338: || ((descBegin.getType() == GuardTag.HEADER) && (descCurrent
339: .getType() == GuardTag.END))) {
340: // interior section
341: sect = provider.createInteriorSection(
342: descCurrent.getName(), descBegin
343: .getBegin(), descBegin
344: .getEnd(), descCurrent
345: .getBegin(), descCurrent
346: .getEnd());
347: break;
348: }
349: }
350: //SYNTAX ERROR - ignore it.
351: descBegin = null;
352: break;
353: }
354:
355: if (sect != null) {
356: sections.add(sect);
357: }
358: } catch (BadLocationException ex) {
359: Logger
360: .getLogger(JavaGuardedReader.class.getName())
361: .log(Level.SEVERE, ex.getLocalizedMessage(), ex);
362: }
363: }
364:
365: return sections;
366: }
367:
368: // static String magic(GuardTag tag) {
369: // return MAGIC_PREFIX + tag.name() + ':';
370: // }
371: }
|