/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.cpp; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; /** * A custom {@link Reader} which completely omits C/C++ continuation character * sequences from an underlying reader. Specifically the sequences {@code \ \n} * (backslash, carriage return), or {@code \ \r \n} (backslash, line feed, * carriage return). * <p> * This reader exists because to modify a JavaCC lexer to understand arbitrary * continuations inside of any token is cumbersome, and just removing them from * the input entirely is easier to implement. See this discussion on the JavaCC * mailing list on <a href= * "http://java.net/projects/javacc/lists/users/archive/2005-06/message/16">line * continuation character</a>. */ public class ContinuationReader extends Reader { private static final int EOF = -1; private static final char BACKSLASH = '\\'; private static final char CARRIAGE_RETURN = '\n'; private static final char LINE_FEED = '\r'; /** the original stream is wrapped in this pushback reader. */ protected final PushbackReader in; /** * Creates a new {@link ContinuationReader} which filters the given reader. * * @param in * the given reader */ public ContinuationReader(Reader in) { this.in = new PushbackReader(in, 2); } @Override public int read(char[] cbuf, int off, int len) throws IOException { int count = 0; while (count < len) { int c1 = in.read(); if (c1 == EOF) { break; } else if (c1 == BACKSLASH) { int c2 = in.read(); if (c2 == EOF) { // No match } else if (c2 == CARRIAGE_RETURN) { // Match: backslash, carriage return continue; } else if (c2 == LINE_FEED) { int c3 = in.read(); if (c3 == EOF) { // No match in.unread(c2); } else if (c3 == CARRIAGE_RETURN) { // Match: backslash, line feed, carriage return continue; } else { // No match in.unread(c3); in.unread(c2); } } else { // No match in.unread(c2); } } cbuf[off + count] = (char) c1; count++; } return count > 0 ? count : -1; } @Override public void close() throws IOException { in.close(); } }