1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.lang.cpp;
5
6 import java.io.IOException;
7 import java.io.PushbackReader;
8 import java.io.Reader;
9
10 /**
11 * A custom {@link Reader} which completely omits C/C++ continuation character
12 * sequences from an underlying reader. Specifically the sequences {@code \ \n}
13 * (backslash, carriage return), or {@code \ \r \n} (backslash, line feed,
14 * carriage return).
15 * <p>
16 * This reader exists because to modify a JavaCC lexer to understand arbitrary
17 * continuations inside of any token is cumbersome, and just removing them from
18 * the input entirely is easier to implement. See this discussion on the JavaCC
19 * mailing list on <a href=
20 * "http://java.net/projects/javacc/lists/users/archive/2005-06/message/16">line
21 * continuation character</a>.
22 */
23 public class ContinuationReader extends Reader {
24 private static final int EOF = -1;
25 private static final char BACKSLASH = '\\';
26 private static final char CARRIAGE_RETURN = '\n';
27 private static final char LINE_FEED = '\r';
28
29 /** the original stream is wrapped in this pushback reader. */
30 protected final PushbackReader in;
31
32 /**
33 * Creates a new {@link ContinuationReader} which filters the given reader.
34 * @param in the given reader
35 */
36 public ContinuationReader(Reader in) {
37 this.in = new PushbackReader(in, 2);
38 }
39
40 @Override
41 public int read(char[] cbuf, int off, int len) throws IOException {
42 int count = 0;
43 while (count < len) {
44 int c1 = in.read();
45 if (c1 == EOF) {
46 break;
47 } else if (c1 == BACKSLASH) {
48 int c2 = in.read();
49 if (c2 == EOF) {
50 // No match
51 } else if (c2 == CARRIAGE_RETURN) {
52 // Match: backslash, carriage return
53 continue;
54 } else if (c2 == LINE_FEED) {
55 int c3 = in.read();
56 if (c3 == EOF) {
57 // No match
58 in.unread(c2);
59 } else if (c3 == CARRIAGE_RETURN) {
60 // Match: backslash, line feed, carriage return
61 continue;
62 } else {
63 // No match
64 in.unread(c3);
65 in.unread(c2);
66 }
67 } else {
68 // No match
69 in.unread(c2);
70 }
71 }
72 cbuf[off + count] = (char) c1;
73 count++;
74 }
75
76 return count > 0 ? count : -1;
77 }
78
79 @Override
80 public void close() throws IOException {
81 in.close();
82 }
83 }