View Javadoc
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  }