/******************************************************************************* * Copyright (c) 2012 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.cdt.internal.autotools.ui.editors.automake; import java.util.Arrays; import java.util.Comparator; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IPredicateRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; public class AutoconfSubstRule implements IPredicateRule { private IToken token; private char[][] fLineDelimiters; private char[][] fSortedLineDelimiters; private static class DecreasingCharArrayLengthComparator implements Comparator<Object> { @Override public int compare(Object o1, Object o2) { return ((char[]) o2).length - ((char[]) o1).length; } } private Comparator<Object> fLineDelimiterComparator= new DecreasingCharArrayLengthComparator(); public AutoconfSubstRule(IToken token) { this.token = token; } @Override public IToken evaluate(ICharacterScanner scanner, boolean resume) { char[][] originalDelimiters= scanner.getLegalLineDelimiters(); int count= originalDelimiters.length; if (fLineDelimiters == null || originalDelimiters.length != count) { fSortedLineDelimiters= new char[count][]; } else { while (count > 0 && fLineDelimiters[count-1] == originalDelimiters[count-1]) count--; } if (count != 0) { fLineDelimiters= originalDelimiters; System.arraycopy(fLineDelimiters, 0, fSortedLineDelimiters, 0, fLineDelimiters.length); Arrays.sort(fSortedLineDelimiters, fLineDelimiterComparator); } int c; boolean okToScan = resume; int charCount = 0; if (!resume) { // Not resuming. Verify first char is '@'. c = scanner.read(); ++charCount; if (c == '@') { okToScan = true; } } if (okToScan) { // We want to make sure we have a valid id (not @@) or (@_@). When // we resume, we have no choice but to assume it is valid so far. boolean isId = resume; ++charCount; while ((c = scanner.read()) != ICharacterScanner.EOF) { if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') { // A valid id has some alphabetic character in it. isId = true; } else if (c >= '0' && c <= '9' || c == '_') { ; // continue } else if (c == '@' && isId) return getSuccessToken(); else break; ++charCount; } } for (int i = 0; i < charCount; ++i) scanner.unread(); return Token.UNDEFINED; } @Override public IToken getSuccessToken() { return token; } @Override public IToken evaluate(ICharacterScanner scanner) { return evaluate(scanner, false); } }