1 package net.sourceforge.phpeclipse.builder;
3 import java.io.BufferedReader;
4 import java.io.FileNotFoundException;
5 import java.io.FileReader;
6 import java.io.FileWriter;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.Comparator;
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.SortedMap;
16 import java.util.StringTokenizer;
17 import java.util.TreeMap;
19 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
20 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
21 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
22 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
23 import net.sourceforge.phpeclipse.mover.obfuscator.PHPIdentifier;
25 import org.eclipse.core.resources.IFile;
26 import org.eclipse.core.runtime.CoreException;
29 * Manages the identifer index information for a specific project
32 public class IdentifierIndexManager {
34 public class LineCreator implements ITerminalSymbols {
36 private Scanner fScanner;
39 public LineCreator() {
40 fScanner = new Scanner(true, false);
44 * Add the information of the current identifier to the line
46 * @param typeOfIdentifier the type of the identifier ('c'lass, 'd'efine, 'f'unction, 'm'ethod, 'v'ariable)
47 * @param identifier current identifier
48 * @param line Buffer for the current index line
49 * @param phpdocOffset the offset of the PHPdoc comment if available
50 * @param phpdocLength the length of the PHPdoc comment if available
52 private void addIdentifierInformation(
53 char typeOfIdentifier,
60 line.append(typeOfIdentifier);
61 line.append(identifier);
62 line.append("\to"); // Offset
63 line.append(fScanner.getCurrentTokenStartPosition());
64 if (phpdocOffset >= 0) {
65 line.append("\tp"); // phpdoc offset
66 line.append(phpdocOffset);
67 line.append("\tl"); // phpdoc length
68 line.append(phpdocLength);
73 * Get the next token from input
75 private void getNextToken() {
77 fToken = fScanner.getNextToken();
79 int currentEndPosition = fScanner.getCurrentTokenEndPosition();
80 int currentStartPosition = fScanner.getCurrentTokenStartPosition();
82 System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
83 System.out.println(fScanner.toStringAction(fToken));
86 } catch (InvalidInputException e) {
89 fToken = TokenNameERROR;
92 private void parseDeclarations(StringBuffer buf, boolean goBack) {
96 int phpdocOffset = -1;
97 int phpdocLength = -1;
100 while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
102 if (fToken == TokenNameCOMMENT_PHPDOC) {
103 phpdocOffset = fScanner.getCurrentTokenStartPosition();
104 phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
106 if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
110 if (fToken == TokenNamevar) {
112 if (fToken == TokenNameVariable) {
113 ident = fScanner.getCurrentIdentifierSource();
114 classVariable = new char[ident.length-1];
115 System.arraycopy(ident, 1, classVariable, 0, ident.length-1);
116 addIdentifierInformation('v', classVariable, buf, phpdocOffset, phpdocLength);
119 } else if (fToken == TokenNamefunction) {
121 if (fToken == TokenNameAND) {
124 if (fToken == TokenNameIdentifier) {
125 ident = fScanner.getCurrentIdentifierSource();
126 addIdentifierInformation('m', ident, buf, phpdocOffset, phpdocLength);
128 parseDeclarations(buf, true);
130 } else if (fToken == TokenNameclass) {
132 if (fToken == TokenNameIdentifier) {
133 ident = fScanner.getCurrentIdentifierSource();
134 addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
137 //skip tokens for classname, extends and others until we have the opening '{'
138 while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
141 parseDeclarations(buf, true);
143 } else if (fToken == TokenNamedefine) {
145 if (fToken == TokenNameLPAREN) {
147 if (fToken == TokenNameStringLiteral) {
148 ident = fScanner.getCurrentStringLiteralSource();
149 addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
153 } else if ((fToken == TokenNameLBRACE) || (fToken == TokenNameDOLLAR_LBRACE)) {
156 } else if (fToken == TokenNameRBRACE) {
159 if (counter == 0 && goBack) {
166 } catch (SyntaxError e) {
167 // TODO Auto-generated catch block
172 public void parseIdentifiers(char[] charArray, StringBuffer buf) {
176 int phpdocOffset = -1;
177 int phpdocLength = -1;
179 fScanner.setSource(charArray);
180 fScanner.setPHPMode(false);
181 fToken = TokenNameEOF;
185 while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
187 if (fToken == TokenNameCOMMENT_PHPDOC) {
188 phpdocOffset = fScanner.getCurrentTokenStartPosition();
189 phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
191 if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
195 if (fToken == TokenNamefunction) {
197 if (fToken == TokenNameAND) {
200 if (fToken == TokenNameIdentifier) {
201 ident = fScanner.getCurrentIdentifierSource();
202 addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
204 parseDeclarations(buf, true);
206 } else if (fToken == TokenNameclass) {
208 if (fToken == TokenNameIdentifier) {
209 ident = fScanner.getCurrentIdentifierSource();
210 addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
213 //skip fTokens for classname, extends and others until we have the opening '{'
214 while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
218 parseDeclarations(buf, true);
221 } else if (fToken == TokenNamedefine) {
223 if (fToken == TokenNameLPAREN) {
225 if (fToken == TokenNameStringLiteral) {
226 ident = fScanner.getCurrentStringLiteralSource();
227 addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
235 } catch (SyntaxError e) {
236 // TODO Auto-generated catch block
242 class StringComparator implements Comparator {
243 public int compare(Object o1, Object o2) {
244 String s1 = (String)o1;
245 String s2 = (String)o2;
246 return s1.compareTo(s2);
247 // return s1.toUpperCase().compareTo(s2.toUpperCase());
249 public boolean equals(Object o) {
250 String s = (String)o;
251 return compare(this, o)==0;
255 private HashMap fFileMap;
256 private String fFilename;
257 private TreeMap fIndentifierMap;
259 public IdentifierIndexManager(String filename) {
260 fFilename = filename;
266 * Add the information for a given IFile resource
269 public void addFile(IFile fileToParse) {
271 LineCreator lineCreator = new LineCreator();
273 iStream = fileToParse.getContents();
275 StringBuffer buf = new StringBuffer();
278 while ((c0 = iStream.read()) != (-1)) {
279 buf.append((char) c0);
281 } catch (IOException e) {
285 StringBuffer lineBuffer = new StringBuffer();
286 // lineBuffer.append(fileToParse.getLocation().toString());
287 lineBuffer.append(fileToParse.getFullPath().toString());
288 int lineLength = lineBuffer.length();
289 lineCreator.parseIdentifiers(buf.toString().toCharArray(), lineBuffer);
290 if (lineLength != lineBuffer.length()) {
291 addLine(lineBuffer.toString());
293 } catch (CoreException e1) {
294 // TODO Auto-generated catch block
295 e1.printStackTrace();
300 * Adds a line of the index file for function, class, class-method and class-variable names
304 private void addLine(String line) {
305 StringTokenizer tokenizer;
306 String phpFileName = null;
308 String identifier = null;
309 String classname = null;
310 String offset = null;
311 PHPIdentifierLocation phpIdentifier = null;
312 boolean tokenExists = false;
314 tokenizer = new StringTokenizer(line, "\t");
315 // first token contains the filename:
316 if (tokenizer.hasMoreTokens()) {
317 phpFileName = tokenizer.nextToken();
318 //System.out.println(token);
322 // all the other tokens are identifiers:
323 while (tokenizer.hasMoreTokens()) {
324 token = tokenizer.nextToken();
325 //System.out.println(token);
326 switch (token.charAt(0)) {
327 case 'c' : // class name
328 identifier = token.substring(1);
329 classname = identifier;
330 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
333 identifier = token.substring(1);
334 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
336 case 'f' : // function name
337 identifier = token.substring(1);
338 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
340 case 'm' : //method inside a class
341 identifier = token.substring(1);
342 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
344 case 'v' : // variable inside a class
345 identifier = token.substring(1);
346 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
348 case 'o' : // offset information
350 if (phpIdentifier != null) {
351 offset = token.substring(1);
352 phpIdentifier.setOffset(Integer.parseInt(offset));
355 case 'p' : // PHPdoc offset information
357 if (phpIdentifier != null) {
358 offset = token.substring(1);
359 phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
362 case 'l' : // PHPdoc length information
364 if (phpIdentifier != null) {
365 offset = token.substring(1);
366 phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
371 phpIdentifier = null;
374 if (identifier != null && phpIdentifier != null) {
376 ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
378 list = new ArrayList();
379 list.add(phpIdentifier);
380 fIndentifierMap.put(identifier, list);
382 boolean flag = false;
383 for (int i = 0; i < list.size(); i++) {
384 if (list.get(i).equals(phpIdentifier)) {
390 list.add(phpIdentifier);
396 fFileMap.put(phpFileName, line);
401 * Change the information for a given IFile resource
404 public void changeFile(IFile fileToParse) {
405 removeFile(fileToParse);
406 addFile(fileToParse);
410 * Get a list of all PHPIdentifierLocation object's associated with an identifier
415 public List getLocations(String identifier) {
416 return (List) fIndentifierMap.get(identifier);
420 * Initialize (i.e. clear) the current index information
423 public void initialize() {
424 fIndentifierMap = new TreeMap(new StringComparator());
425 fFileMap = new HashMap();
428 private void readFile() {
430 FileReader fileReader;
432 fileReader = new FileReader(fFilename);
434 BufferedReader bufferedReader = new BufferedReader(fileReader);
437 while (bufferedReader.ready()) {
438 // all entries for one file are in a line
439 // separated by tabs !
440 line = bufferedReader.readLine();
445 } catch (FileNotFoundException e) {
447 // TODO DialogBox which asks the user if she/he likes to build new index?
448 } catch (IOException e) {
449 // TODO Auto-generated catch block
456 * Remove the information for a given IFile resource
459 public void removeFile(IFile fileToParse) {
460 // String line = (String) fFileMap.get(fileToParse.getLocation().toString());
461 String line = (String) fFileMap.get(fileToParse.getFullPath().toString());
468 * Removes a line of the index file for function, class, class-method and class-variable names
472 private void removeLine(String line) {
473 StringTokenizer tokenizer;
474 String phpFileName = null;
476 String identifier = null;
477 String classname = null;
478 PHPIdentifier phpIdentifier = null;
479 boolean tokenExists = false;
481 tokenizer = new StringTokenizer(line, "\t");
482 // first token contains the filename:
483 if (tokenizer.hasMoreTokens()) {
484 phpFileName = tokenizer.nextToken();
485 //System.out.println(token);
489 // all the other tokens are identifiers:
490 while (tokenizer.hasMoreTokens()) {
491 token = tokenizer.nextToken();
492 //System.out.println(token);
493 switch (token.charAt(0)) {
494 case 'c' : // class name
495 identifier = token.substring(1);
496 classname = identifier;
497 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
500 identifier = token.substring(1);
501 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
503 case 'f' : // function name
504 identifier = token.substring(1);
505 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
507 case 'm' : //method inside a class
508 identifier = token.substring(1);
509 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
511 case 'v' : // variable inside a class
512 identifier = token.substring(1);
513 phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
517 phpIdentifier = null;
520 if (identifier != null && phpIdentifier != null) {
521 ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
524 for (int i = 0; i < list.size(); i++) {
525 if (list.get(i).equals(phpIdentifier)) {
530 if (list.size() == 0) {
531 fIndentifierMap.remove(identifier);
536 fFileMap.remove(phpFileName);
540 * Save the current index information in the projects index file
543 public void writeFile() {
544 FileWriter fileWriter;
546 fileWriter = new FileWriter(fFilename);
548 Collection collection = fFileMap.values();
549 Iterator iterator = collection.iterator();
550 while (iterator.hasNext()) {
551 line = (String) iterator.next();
552 fileWriter.write(line + '\n');
555 } catch (FileNotFoundException e) {
556 // ignore exception; project is deleted by user
557 } catch (IOException e) {
558 // TODO Auto-generated catch block
568 public SortedMap getIdentifierMap() {
569 return fIndentifierMap;