/*******************************************************************************
* Copyright (c) 2011 Wind River Systems, 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
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import static org.eclipse.cdt.core.parser.OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
import org.eclipse.cdt.core.parser.IPreprocessorDirective;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
/**
* Helper class for detecting include guards
*/
public class IncludeGuardDetection {
public static char[] detectIncludeGuard(AbstractCharArray content, Lexer.LexerOptions lexOptions, CharArrayIntMap ppKeywords) {
Lexer l= new Lexer(content, lexOptions, ILexerLog.NULL, null);
char[] guard= findIncludeGuard(l, ppKeywords);
if (guard != null && currentIfSpansFile(l, ppKeywords)) {
return guard;
}
return null;
}
private static char[] findIncludeGuard(Lexer l, CharArrayIntMap ppKeywords) {
try {
if (skipAll(l, Lexer.tNEWLINE).getType() == IToken.tPOUND) {
Token t = l.nextToken();
if (t.getType() == IToken.tIDENTIFIER) {
char[] guard= null;
switch(ppKeywords.get(t.getCharImage())) {
case IPreprocessorDirective.ppIfndef:
// #ifndef GUARD
t= l.nextToken();
if (t.getType() == IToken.tIDENTIFIER) {
guard= t.getCharImage();
}
break;
case IPreprocessorDirective.ppIf:
// #if !defined GUARD
// #if ((!((defined (GUARD)))))
guard = findNotDefined(l);
break;
}
if (guard != null) {
// #define GUARD
l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
if (skipAll(l, Lexer.tNEWLINE).getType() == IToken.tPOUND
&& checkToken(l.nextToken(), Keywords.cDEFINE)
&& checkToken(l.nextToken(), guard)) {
l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
return guard;
}
}
}
}
} catch (OffsetLimitReachedException e) {
}
return null;
}
private static char[] findNotDefined(Lexer l) throws OffsetLimitReachedException {
Token t;
if (skipAll(l, IToken.tLPAREN).getType() == IToken.tNOT
&& checkToken(skipAll(l, IToken.tLPAREN), Keywords.cDEFINED)) {
t= l.nextToken(); // only a single parenthesis is allowed
if (t.getType() == IToken.tLPAREN)
t= l.nextToken();
if (t.getType() == IToken.tIDENTIFIER) {
char[] guard= t.getCharImage();
if (skipAll(l, IToken.tRPAREN).getType() == Lexer.tNEWLINE)
return guard;
}
}
return null;
}
private static boolean checkToken(Token t, char[] image) throws OffsetLimitReachedException {
return CharArrayUtils.equals(t.getCharImage(), image);
}
private static boolean currentIfSpansFile(Lexer l, CharArrayIntMap ppKeywords) {
// Check if the #ifndef spans the entire file
try {
int nesting= 1;
while (nesting > 0) {
Token t= l.nextDirective();
if (t.getType() == IToken.tEND_OF_INPUT)
return true;
switch(ppKeywords.get(l.nextToken().getCharImage())) {
case IPreprocessorDirective.ppIf:
case IPreprocessorDirective.ppIfdef:
case IPreprocessorDirective.ppIfndef:
nesting++;
break;
case IPreprocessorDirective.ppEndif:
nesting--;
break;
}
}
l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
return skipAll(l, Lexer.tNEWLINE).getType() == IToken.tEND_OF_INPUT;
} catch (OffsetLimitReachedException e) {
}
return true;
}
private static Token skipAll(Lexer l, int kind) throws OffsetLimitReachedException {
// Skip empty lines
Token t= l.nextToken();
while (t.getType() == kind)
t= l.nextToken();
return t;
}
public static boolean detectIncludeEndif(Lexer l) {
l.saveState();
try {
return findIncludeEndif(l);
} catch (OffsetLimitReachedException e) {
} finally {
l.restoreState();
}
return false;
}
private static boolean findIncludeEndif(Lexer l) throws OffsetLimitReachedException {
if (skipAll(l, Lexer.tNEWLINE).getType() != IToken.tPOUND)
return false;
if (!checkToken(l.nextToken(), Keywords.cINCLUDE))
return false;
l.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
if (skipAll(l, Lexer.tNEWLINE).getType() != IToken.tPOUND)
return false;
if (!checkToken(l.nextToken(), Keywords.cENDIF))
return false;
return true;
}
public static char[] detectIfNotDefinedIncludeEndif(Lexer l) {
l.saveState();
try {
char[] guard= findNotDefined(l);
if (guard != null && findIncludeEndif(l))
return guard;
} catch (OffsetLimitReachedException e) {
} finally {
l.restoreState();
}
return null;
}
}