001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.admin.visualstudio;
020
021 import java.io.File;
022 import java.io.FileFilter;
023 import java.util.Collection;
024 import java.util.HashMap;
025 import java.util.HashSet;
026 import java.util.LinkedList;
027 import java.util.Map;
028 import java.util.Set;
029 import java.util.concurrent.Semaphore;
030 import java.util.regex.Matcher;
031 import java.util.regex.Pattern;
032
033 import com.ochafik.io.ReadText;
034
035
036 public class Solution {
037 private static final boolean verbose = true;
038
039 public File solutionFile;
040 public Map<String, Project> idToProject;
041 public Set<File> allFiles = new HashSet<File>(10000);
042
043 static Pattern solutionIdPattern = Pattern.compile("Project\\(\"\\{[^}]+\\}\"\\) = \"([^\"]+)\", \"([^\"]+)\", [^{]+\\{([^}]+)\\}\"" +
044 ".*?ProjectSection\\(ProjectDependencies\\)(.*?)EndProjectSection", Pattern.MULTILINE
045 );
046
047 static Pattern projectDependencyPattern = Pattern.compile("\\{[^}]+\\} = \\{([^}]+)\\}");
048
049 static Pattern projectConfigsForSolutionConfigPattern = Pattern.compile("^\\s*\\{([^}]+)\\}\\.([^\\.]+)\\.ActiveCfg\\s*=\\s*(.*)\\s*$");
050 public Solution(File solutionFile) {
051 this.solutionFile = solutionFile;
052 }
053 public void parse() throws Exception {
054 if (idToProject == null) {
055 idToProject = new HashMap<String, Project>();
056
057 String solutionContent = ReadText.readText(solutionFile);
058 File solutionPath = solutionFile.getParentFile();
059
060 for (Matcher solutionIdMatcher = solutionIdPattern.matcher(solutionContent.replace('\n', ' ')); solutionIdMatcher.find();) {
061 Project p = new Project(this, relFile(solutionPath, solutionIdMatcher.group(2)), solutionIdMatcher.group(1), solutionIdMatcher.group(3));
062 for (Matcher depM = projectDependencyPattern.matcher(solutionIdMatcher.group(4)); depM.find();)
063 p.depsIds.add(depM.group(1));
064 idToProject.put(p.id, p);
065 }
066
067 for (Matcher m = projectConfigsForSolutionConfigPattern.matcher(solutionContent); m.find();) {
068 String id = m.group(1), slnConfigName = m.group(2), projConfigName = m.group(3);
069 Project p = idToProject.get(id);
070 if (p == null)
071 continue;
072
073 p.activeConfigurationNameBySolutionConfigurationName.put(slnConfigName, projConfigName);
074 }
075 }
076 }
077
078 public String getName() {
079 return solutionFile == null ? null : solutionFile.getName().replaceAll("\\.[^.]+$", "");
080 }
081
082 public void parseProjects(final FileFilter fileFilter) throws Exception {
083 parse();
084 int nThreads = Runtime.getRuntime().availableProcessors() * 2;
085 if (verbose)
086 System.out.println("Parsing Solution: " + solutionFile.getName() + " (" + nThreads + " threads)");
087
088 final Semaphore semaphore = new Semaphore(0);
089 final LinkedList<Project> projects = new LinkedList<Project>(idToProject.values());
090 class Worker extends Thread { public void run() {
091 for (;;) {
092 try {
093 Project project = null;
094 synchronized (projects) {
095 if (projects.isEmpty())
096 break;
097
098 project = projects.removeLast();
099 }
100 if (verbose) {
101 synchronized (System.out) {
102 System.out.println("Parsing Project: " + project.name);
103 }
104 }
105
106 project.parse(fileFilter, false, Solution.this);
107 synchronized (allFiles) {
108 allFiles.addAll(project.files);
109 }
110 } catch (Exception ex) {
111 synchronized (System.err) {
112 ex.printStackTrace(System.err);
113 }
114
115 }
116 }
117 semaphore.release();
118 }};
119 for (int i = nThreads; i-- != 0;)
120 new Worker().start();
121
122 semaphore.acquire(nThreads);
123 }
124
125 static File relFile(File base, String relPath) {
126 relPath = relPath.replace('\\', File.separatorChar).replace('/', File.separatorChar);
127 return new File(base, relPath);
128 }
129 public Collection<Project> getProjects() {
130 return idToProject.values();
131 }
132 }