/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.internal.dependencies;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
public class GCCDependencyFileParser {
private static final int IN_DEPFILE = 0;
private static final int IN_DEP_LIST = 1;
private Map<IResource, Collection<IResource>> dependencies = new HashMap<IResource, Collection<IResource>>();
private IResource currentDependentFile;
private ArrayList<IResource> currentDependencies;
private String projectRoot;
public GCCDependencyFileParser() {
}
public void parse(File mmdFile) throws IOException {
FileInputStream mmdFileInputStream = new FileInputStream(mmdFile);
try {
IResource fileInWs = getFile(mmdFile.getAbsolutePath());
String projectRoot = fileInWs == null ? "" : fileInWs.getProject().getLocation().toOSString();
parse(projectRoot, mmdFileInputStream);
} finally {
mmdFileInputStream.close();
}
}
public void parse(String projectRoot, InputStream input) throws IOException {
this.projectRoot = projectRoot;
LineNumberReader lines = new LineNumberReader(new InputStreamReader(
input));
StringBuffer compoundLine = new StringBuffer();
for (String line = lines.readLine(); line != null; line = lines
.readLine()) {
int continuationIx = line.lastIndexOf('\\');
boolean endsWithSlash = line.trim().endsWith("\\");
if (continuationIx != -1 && endsWithSlash) {
compoundLine.append(line.substring(0, continuationIx));
} else {
compoundLine.append(line);
parseLine(compoundLine);
compoundLine = new StringBuffer();
}
}
// Just in case; should never happen, though.
if (compoundLine.length() > 0) {
parseLine(compoundLine);
}
}
private void parseLine(StringBuffer line) {
char[] lineAr = new char[line.length()];
line.getChars(0, line.length(), lineAr, 0);
StringBuffer depFile = new StringBuffer();
int pos = -1;
int state = IN_DEPFILE;
while (pos < lineAr.length - 1) {
pos++;
boolean doAppend = true;
char ch = lineAr[pos];
char peek = pos == lineAr.length - 1 ? '\0' : lineAr[pos + 1];
char prev = pos == 0 ? '\0' : lineAr[pos - 1];
boolean potentialEscapeState = ch == '\\';
boolean isInEscapeState = prev == '\\' && ch == ' ';
switch (state) {
case IN_DEPFILE:
if (ch == ':') {
// Is this the full name? A colon followed by a space, or
// an existing file -> full name!
if (peek == ' ' || new File(depFile.toString()).exists()) {
currentDependentFile = getFile(depFile);
if (currentDependentFile != null) {
currentDependencies = new ArrayList<IResource>();
dependencies.put(currentDependentFile,
currentDependencies);
}
depFile.delete(0, depFile.length());
doAppend = false;
state = IN_DEP_LIST;
}
} else {
doAppend = !potentialEscapeState || peek != ' ';
}
break;
case IN_DEP_LIST:
doAppend = !potentialEscapeState || peek != ' ';
if (!isInEscapeState && ch == ' ' && currentDependencies != null) {
addCurrentFileToDependencies(depFile);
doAppend = false;
}
}
boolean unappendableCh = ch == '\t';
if (doAppend && !unappendableCh) {
depFile.append(ch);
}
}
addCurrentFileToDependencies(depFile);
if (CoreMoSyncPlugin.getDefault().isDebugging()) {
CoreMoSyncPlugin.trace("GCC dependency parsing:\n{0}", dependencies);
}
currentDependentFile = null;
currentDependencies = null;
}
private void addCurrentFileToDependencies(StringBuffer depFile) {
if (currentDependencies != null && depFile != null && depFile.length() > 0) {
IResource file = getFile(depFile);
if (file != null) {
currentDependencies.add(file);
}
depFile.delete(0, depFile.length());
}
}
public IResource getFile(StringBuffer filename) {
String filenameStr = filename.toString();
String absFilenameStr = new File(projectRoot, filenameStr).getAbsolutePath();
IResource result = getFile(filenameStr);
return result == null ? getFile(absFilenameStr) : result;
}
public static IResource getFile(String filename) {
IWorkspace ws = ResourcesPlugin.getWorkspace();
IFile[] files = ws.getRoot().findFilesForLocation(new Path(filename.toString().trim()));
if (files != null && files.length > 0) {
return files[0];
}
return null;
}
public Map<IResource, Collection<IResource>> getDependencies() {
return dependencies;
}
}