synchronized from quantum plugin
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / PHPCodeReader.java
1 package net.sourceforge.phpdt.internal.ui.text;
2
3 /*
4  * (c) Copyright IBM Corp. 2000, 2001.
5  * All Rights Reserved.
6  */
7
8 import java.io.IOException;
9
10 import net.sourceforge.phpdt.internal.corext.phpdoc.SingleCharReader;
11
12 import org.eclipse.jface.text.BadLocationException;
13 import org.eclipse.jface.text.IDocument;
14
15 /**
16  * Reads from a document either forwards or backwards. May be configured to
17  * skip comments and strings.
18  */
19 public class PHPCodeReader extends SingleCharReader {
20         
21         /** The EOF character */
22         public static final int EOF= -1;
23         
24         private boolean fSkipComments= false;
25         private boolean fSkipStrings= false;
26         private boolean fForward= false;
27         
28         private IDocument fDocument;
29         private int fOffset;
30         
31         private int fEnd= -1;
32         private int fCachedLineNumber= -1;
33         private int fCachedLineOffset= -1;
34         
35         
36         public PHPCodeReader() {
37         }
38         
39         /**
40          * Returns the offset of the last read character. Should only be called after read has been called.
41          */
42         public int getOffset() {
43                 return fForward ? fOffset -1 : fOffset;
44         }
45         
46         public void configureForwardReader(IDocument document, int offset, int length, boolean skipComments, boolean skipStrings) throws IOException {
47                 fDocument= document;
48                 fOffset= offset;
49                 fSkipComments= skipComments;
50                 fSkipStrings= skipStrings;
51                 
52                 fForward= true;
53                 fEnd= Math.min(fDocument.getLength(), fOffset + length);                
54         }
55         
56         public void configureBackwardReader(IDocument document, int offset, boolean skipComments, boolean skipStrings) throws IOException {
57                 fDocument= document;
58                 fOffset= offset;
59                 fSkipComments= skipComments;
60                 fSkipStrings= skipStrings;
61                 
62                 fForward= false;
63                 try {
64                         fCachedLineNumber= fDocument.getLineOfOffset(fOffset);
65                 } catch (BadLocationException x) {
66                         throw new IOException(x.getMessage());
67                 }
68         }
69         
70         /*
71          * @see Reader#close()
72          */
73         public void close() throws IOException {
74                 fDocument= null;
75         }
76         
77         /*
78          * @see SingleCharReader#read()
79          */
80         public int read() throws IOException {
81                 try {
82                         return fForward ? readForwards() : readBackwards();
83                 } catch (BadLocationException x) {
84                         throw new IOException(x.getMessage());
85                 }
86         }
87         
88         private void gotoCommentEnd() throws BadLocationException {
89                 while (fOffset < fEnd) {
90                         char current= fDocument.getChar(fOffset++);
91                         if (current == '*') {
92                                 if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') {
93                                         ++ fOffset;
94                                         return;
95                                 }
96                         }
97                 }
98         }
99         
100         private void gotoStringEnd(char delimiter) throws BadLocationException {
101                 while (fOffset < fEnd) {
102                         char current= fDocument.getChar(fOffset++);
103                         if (current == '\\') {
104                                 // ignore escaped characters
105                                 ++ fOffset;
106                         } else if (current == delimiter) {
107                                 return;
108                         }
109                 }
110         }
111         
112         private void gotoLineEnd() throws BadLocationException {
113                 int line= fDocument.getLineOfOffset(fOffset);
114                 fOffset= fDocument.getLineOffset(line + 1);
115         }
116         
117         private int readForwards() throws BadLocationException {
118                 while (fOffset < fEnd) {
119                         char current= fDocument.getChar(fOffset++);
120                         
121                         switch (current) {
122         case '#':
123                                         
124           if (fSkipComments && fOffset < fEnd) {
125               gotoLineEnd();
126               continue;
127           }
128                                         
129           return current;
130           
131                                 case '/':
132                                         
133                                         if (fSkipComments && fOffset < fEnd) {
134                                                 char next= fDocument.getChar(fOffset);
135                                                 if (next == '*') {
136                                                         // a comment starts, advance to the comment end
137                                                         ++ fOffset;
138                                                         gotoCommentEnd();
139                                                         continue;
140                                                 } else if (next == '/') {
141                                                         // '//'-comment starts, advance to the line end
142                                                         gotoLineEnd();
143                                                         continue;
144                                                 }
145                                         }
146                                         
147                                         return current;
148                                         
149                                 case '"':
150                                 case '\'':
151                                 
152                                         if (fSkipStrings) {
153                                                 gotoStringEnd(current);
154                                                 continue;
155                                         }
156                                         
157                                         return current;
158                         }
159                         
160                         return current;
161                 }
162                 
163                 return EOF;
164         }
165         
166         private void handleSingleLineComment() throws BadLocationException {
167                 int line= fDocument.getLineOfOffset(fOffset);
168                 if (line < fCachedLineNumber) {
169                         fCachedLineNumber= line;
170                         fCachedLineOffset= fDocument.getLineOffset(line);
171                         int offset= fOffset;
172                         while (fCachedLineOffset < offset) {
173                                 char current= fDocument.getChar(offset--);
174                                 if (current == '/' && fCachedLineOffset <= offset && fDocument.getChar(offset) == '/') {
175                                         fOffset= offset;
176                                         return;
177                                 }
178         if (current == '#' && fCachedLineOffset <= offset) {
179           fOffset= offset;
180           return;
181         }
182                         }
183                 }
184         }
185         
186         private void gotoCommentStart() throws BadLocationException {
187                 while (0 < fOffset) {
188                         char current= fDocument.getChar(fOffset--);
189                         if (current == '*' && 0 <= fOffset && fDocument.getChar(fOffset) == '/')
190                                 return;
191                 }
192         }
193         
194         private void gotoStringStart(char delimiter) throws BadLocationException {
195                 while (0 < fOffset) {
196                         char current= fDocument.getChar(fOffset);
197                         if (current == delimiter) {
198                                 if ( !(0 <= fOffset && fDocument.getChar(fOffset -1) == '\\'))
199                                         return;
200                         }
201                         -- fOffset;
202                 }
203         }
204                 
205         private int readBackwards() throws BadLocationException {
206                 
207                 while (0 < fOffset) {
208                         -- fOffset;
209                         
210                         handleSingleLineComment();
211                         
212                         char current= fDocument.getChar(fOffset);
213                         switch (current) {
214                                 case '/':
215                                         
216                                         if (fSkipComments && fOffset > 1) {
217                                                 char next= fDocument.getChar(fOffset - 1);
218                                                 if (next == '*') {
219                                                         // a comment ends, advance to the comment start
220                                                         fOffset -= 2;
221                                                         gotoCommentStart();
222                                                         continue;
223                                                 }
224                                         }
225                                         
226                                         return current;
227                                         
228                                 case '"':
229                                 case '\'':
230                                 
231                                         if (fSkipStrings) {
232                                                 -- fOffset;
233                                                 gotoStringStart(current);
234                                                 continue;
235                                         }
236                                         
237                                         return current;
238                         }
239                         
240                         return current;
241                 }
242                 
243                 return EOF;
244         }
245 }
246