git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1674 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			610 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			610 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
/*
 | 
						|
 * 
 | 
						|
 * Copyright 2002-2004 The Ant-Contrib project
 | 
						|
 *
 | 
						|
 *  Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 *  you may not use this file except in compliance with the License.
 | 
						|
 *  You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 *  Unless required by applicable law or agreed to in writing, software
 | 
						|
 *  distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 *  See the License for the specific language governing permissions and
 | 
						|
 *  limitations under the License.
 | 
						|
 */
 | 
						|
package net.sf.antcontrib.cpptasks;
 | 
						|
import java.io.BufferedWriter;
 | 
						|
import java.io.File;
 | 
						|
import java.io.FileOutputStream;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.OutputStreamWriter;
 | 
						|
import java.io.UnsupportedEncodingException;
 | 
						|
import java.util.Enumeration;
 | 
						|
import java.util.Hashtable;
 | 
						|
import java.util.Vector;
 | 
						|
import javax.xml.parsers.ParserConfigurationException;
 | 
						|
import javax.xml.parsers.SAXParser;
 | 
						|
import javax.xml.parsers.SAXParserFactory;
 | 
						|
import net.sf.antcontrib.cpptasks.compiler.CompilerConfiguration;
 | 
						|
import org.apache.tools.ant.BuildException;
 | 
						|
import org.apache.tools.ant.Project;
 | 
						|
import org.xml.sax.Attributes;
 | 
						|
import org.xml.sax.SAXException;
 | 
						|
import org.xml.sax.helpers.DefaultHandler;
 | 
						|
/**
 | 
						|
 * @author Curt Arnold
 | 
						|
 */
 | 
						|
public final class DependencyTable {
 | 
						|
    /**
 | 
						|
     * This class handles populates the TargetHistory hashtable in response to
 | 
						|
     * SAX parse events
 | 
						|
     */
 | 
						|
    private class DependencyTableHandler extends DefaultHandler {
 | 
						|
        private File baseDir;
 | 
						|
        private final DependencyTable dependencyTable;
 | 
						|
        private String includePath;
 | 
						|
        private Vector includes;
 | 
						|
        private String source;
 | 
						|
        private long sourceLastModified;
 | 
						|
        private Vector sysIncludes;
 | 
						|
        /**
 | 
						|
         * Constructor
 | 
						|
         * 
 | 
						|
         * @param history
 | 
						|
         *            hashtable of TargetHistory keyed by output name
 | 
						|
         * @param outputFiles
 | 
						|
         *            existing files in output directory
 | 
						|
         */
 | 
						|
        private DependencyTableHandler(DependencyTable dependencyTable,
 | 
						|
                File baseDir) {
 | 
						|
            this.dependencyTable = dependencyTable;
 | 
						|
            this.baseDir = baseDir;
 | 
						|
            includes = new Vector();
 | 
						|
            sysIncludes = new Vector();
 | 
						|
            source = null;
 | 
						|
        }
 | 
						|
        public void endElement(String namespaceURI, String localName,
 | 
						|
                String qName) throws SAXException {
 | 
						|
            //
 | 
						|
            //   if </source> then
 | 
						|
            //       create Dependency object and add to hashtable
 | 
						|
            //           if corresponding source file exists and
 | 
						|
            //           has the same timestamp
 | 
						|
            //
 | 
						|
            if (qName.equals("source")) {
 | 
						|
                if (source != null && includePath != null) {
 | 
						|
                    File existingFile = new File(baseDir, source);
 | 
						|
                    //
 | 
						|
                    //   if the file exists and the time stamp is right
 | 
						|
                    //       preserve the dependency info
 | 
						|
                    if (existingFile.exists()) {
 | 
						|
                        //
 | 
						|
                        //   would have expected exact matches
 | 
						|
                        //       but was seeing some unexpected difference by
 | 
						|
                        //       a few tens of milliseconds, as long
 | 
						|
                        //       as the times are within a second
 | 
						|
                        long existingLastModified = existingFile.lastModified();
 | 
						|
                        long diff = existingLastModified - sourceLastModified;
 | 
						|
                        if (diff >= -500 && diff <= 500) {
 | 
						|
                            DependencyInfo dependInfo = new DependencyInfo(
 | 
						|
                                    includePath, source, sourceLastModified,
 | 
						|
                                    includes, sysIncludes);
 | 
						|
                            dependencyTable.putDependencyInfo(source,
 | 
						|
                                    dependInfo);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    source = null;
 | 
						|
                    includes.setSize(0);
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                //
 | 
						|
                //    this causes any <source> elements outside the
 | 
						|
                //       scope of an <includePath> to be discarded
 | 
						|
                //
 | 
						|
                if (qName.equals("includePath")) {
 | 
						|
                    includePath = null;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        /**
 | 
						|
         * startElement handler
 | 
						|
         */
 | 
						|
        public void startElement(String namespaceURI, String localName,
 | 
						|
                String qName, Attributes atts) throws SAXException {
 | 
						|
            //
 | 
						|
            //   if includes, then add relative file name to vector
 | 
						|
            //
 | 
						|
            if (qName.equals("include")) {
 | 
						|
                includes.addElement(atts.getValue("file"));
 | 
						|
            } else {
 | 
						|
                if (qName.equals("sysinclude")) {
 | 
						|
                    sysIncludes.addElement(atts.getValue("file"));
 | 
						|
                } else {
 | 
						|
                    //
 | 
						|
                    //    if source then
 | 
						|
                    //        capture source file name,
 | 
						|
                    //        modification time and reset includes vector
 | 
						|
                    //
 | 
						|
                    if (qName.equals("source")) {
 | 
						|
                        source = atts.getValue("file");
 | 
						|
                        sourceLastModified = Long.parseLong(atts
 | 
						|
                                .getValue("lastModified"), 16);
 | 
						|
                        includes.setSize(0);
 | 
						|
                        sysIncludes.setSize(0);
 | 
						|
                    } else {
 | 
						|
                        if (qName.equals("includePath")) {
 | 
						|
                            includePath = atts.getValue("signature");
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    public abstract class DependencyVisitor {
 | 
						|
        /**
 | 
						|
         * Previews all the children of this source file.
 | 
						|
         * 
 | 
						|
         * May be called multiple times as DependencyInfo's for children are
 | 
						|
         * filled in.
 | 
						|
         * 
 | 
						|
         * @return true to continue towards recursion into included files
 | 
						|
         */
 | 
						|
        public abstract boolean preview(DependencyInfo parent,
 | 
						|
                DependencyInfo[] children);
 | 
						|
        /**
 | 
						|
         * Called if the dependency depth exhausted the stack.
 | 
						|
         */
 | 
						|
        public abstract void stackExhausted();
 | 
						|
        /**
 | 
						|
         * Visits the dependency info.
 | 
						|
         * 
 | 
						|
         * @returns true to continue towards recursion into included files
 | 
						|
         */
 | 
						|
        public abstract boolean visit(DependencyInfo dependInfo);
 | 
						|
    }
 | 
						|
    public class TimestampChecker extends DependencyVisitor {
 | 
						|
        private boolean noNeedToRebuild;
 | 
						|
        private long outputLastModified;
 | 
						|
        private boolean rebuildOnStackExhaustion;
 | 
						|
        public TimestampChecker(final long outputLastModified,
 | 
						|
                boolean rebuildOnStackExhaustion) {
 | 
						|
            this.outputLastModified = outputLastModified;
 | 
						|
            noNeedToRebuild = true;
 | 
						|
            this.rebuildOnStackExhaustion = rebuildOnStackExhaustion;
 | 
						|
        }
 | 
						|
        public boolean getMustRebuild() {
 | 
						|
            return !noNeedToRebuild;
 | 
						|
        }
 | 
						|
        public boolean preview(DependencyInfo parent, DependencyInfo[] children) {
 | 
						|
            int withCompositeTimes = 0;
 | 
						|
            long parentCompositeLastModified = parent.getSourceLastModified();
 | 
						|
            for (int i = 0; i < children.length; i++) {
 | 
						|
                if (children[i] != null) {
 | 
						|
                    //
 | 
						|
                    //  expedient way to determine if a child forces us to
 | 
						|
                    // rebuild
 | 
						|
                    //
 | 
						|
                    visit(children[i]);
 | 
						|
                    long childCompositeLastModified = children[i]
 | 
						|
                            .getCompositeLastModified();
 | 
						|
                    if (childCompositeLastModified != Long.MIN_VALUE) {
 | 
						|
                        withCompositeTimes++;
 | 
						|
                        if (childCompositeLastModified > parentCompositeLastModified) {
 | 
						|
                            parentCompositeLastModified = childCompositeLastModified;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (withCompositeTimes == children.length) {
 | 
						|
                parent.setCompositeLastModified(parentCompositeLastModified);
 | 
						|
            }
 | 
						|
            //
 | 
						|
            //  may have been changed by an earlier call to visit()
 | 
						|
            //
 | 
						|
            return noNeedToRebuild;
 | 
						|
        }
 | 
						|
        public void stackExhausted() {
 | 
						|
            if (rebuildOnStackExhaustion) {
 | 
						|
                noNeedToRebuild = false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        public boolean visit(DependencyInfo dependInfo) {
 | 
						|
            if (noNeedToRebuild) {
 | 
						|
                if (dependInfo.getSourceLastModified() > outputLastModified
 | 
						|
                        || dependInfo.getCompositeLastModified() > outputLastModified) {
 | 
						|
                    noNeedToRebuild = false;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            //
 | 
						|
            //   only need to process the children if
 | 
						|
            //      it has not yet been determined whether
 | 
						|
            //      we need to rebuild and the composite modified time
 | 
						|
            //         has not been determined for this file
 | 
						|
            return noNeedToRebuild
 | 
						|
                    && dependInfo.getCompositeLastModified() == Long.MIN_VALUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    private/* final */File baseDir;
 | 
						|
    private String baseDirPath;
 | 
						|
    /**
 | 
						|
     * a hashtable of DependencyInfo[] keyed by output file name
 | 
						|
     */
 | 
						|
    private final Hashtable dependencies = new Hashtable();
 | 
						|
    /** The file the cache was loaded from. */
 | 
						|
    private/* final */File dependenciesFile;
 | 
						|
    /** Flag indicating whether the cache should be written back to file. */
 | 
						|
    private boolean dirty;
 | 
						|
    /**
 | 
						|
     * Creates a target history table from dependencies.xml in the prject
 | 
						|
     * directory, if it exists. Otherwise, initializes the dependencies empty.
 | 
						|
     * 
 | 
						|
     * @param task
 | 
						|
     *            task used for logging history load errors
 | 
						|
     * @param baseDir
 | 
						|
     *            output directory for task
 | 
						|
     */
 | 
						|
    public DependencyTable(File baseDir) {
 | 
						|
        if (baseDir == null) {
 | 
						|
            throw new NullPointerException("baseDir");
 | 
						|
        }
 | 
						|
        this.baseDir = baseDir;
 | 
						|
        try {
 | 
						|
            baseDirPath = baseDir.getCanonicalPath();
 | 
						|
        } catch (IOException ex) {
 | 
						|
            baseDirPath = baseDir.toString();
 | 
						|
        }
 | 
						|
        dirty = false;
 | 
						|
        //
 | 
						|
        //   load any existing dependencies from file
 | 
						|
        dependenciesFile = new File(baseDir, "dependencies.xml");
 | 
						|
    }
 | 
						|
    public void commit(CCTask task) {
 | 
						|
        //
 | 
						|
        //   if not dirty, no need to update file
 | 
						|
        //
 | 
						|
        if (dirty) {
 | 
						|
            //
 | 
						|
            //   walk through dependencies to get vector of include paths
 | 
						|
            // identifiers
 | 
						|
            //
 | 
						|
            Vector includePaths = getIncludePaths();
 | 
						|
            //
 | 
						|
            //
 | 
						|
            //   write dependency file
 | 
						|
            //
 | 
						|
            try {
 | 
						|
                FileOutputStream outStream = new FileOutputStream(
 | 
						|
                        dependenciesFile);
 | 
						|
                OutputStreamWriter streamWriter;
 | 
						|
                //
 | 
						|
                //    Early VM's may not have UTF-8 support
 | 
						|
                //       fallback to default code page which
 | 
						|
                //           "should" be okay unless there are
 | 
						|
                //            non ASCII file names
 | 
						|
                String encodingName = "UTF-8";
 | 
						|
                try {
 | 
						|
                    streamWriter = new OutputStreamWriter(outStream, "UTF-8");
 | 
						|
                } catch (UnsupportedEncodingException ex) {
 | 
						|
                    streamWriter = new OutputStreamWriter(outStream);
 | 
						|
                    encodingName = streamWriter.getEncoding();
 | 
						|
                }
 | 
						|
                BufferedWriter writer = new BufferedWriter(streamWriter);
 | 
						|
                writer.write("<?xml version='1.0' encoding='");
 | 
						|
                writer.write(encodingName);
 | 
						|
                writer.write("'?>\n");
 | 
						|
                writer.write("<dependencies>\n");
 | 
						|
                StringBuffer buf = new StringBuffer();
 | 
						|
                Enumeration includePathEnum = includePaths.elements();
 | 
						|
                while (includePathEnum.hasMoreElements()) {
 | 
						|
                    writeIncludePathDependencies((String) includePathEnum
 | 
						|
                            .nextElement(), writer, buf);
 | 
						|
                }
 | 
						|
                writer.write("</dependencies>\n");
 | 
						|
                writer.close();
 | 
						|
                dirty = false;
 | 
						|
            } catch (IOException ex) {
 | 
						|
                task.log("Error writing " + dependenciesFile.toString() + ":"
 | 
						|
                        + ex.toString());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     * Returns an enumerator of DependencyInfo's
 | 
						|
     */
 | 
						|
    public Enumeration elements() {
 | 
						|
        return dependencies.elements();
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     * This method returns a DependencyInfo for the specific source file and
 | 
						|
     * include path identifier
 | 
						|
     *  
 | 
						|
     */
 | 
						|
    public DependencyInfo getDependencyInfo(String sourceRelativeName,
 | 
						|
            String includePathIdentifier) {
 | 
						|
        DependencyInfo dependInfo = null;
 | 
						|
        DependencyInfo[] dependInfos = (DependencyInfo[]) dependencies
 | 
						|
                .get(sourceRelativeName);
 | 
						|
        if (dependInfos != null) {
 | 
						|
            for (int i = 0; i < dependInfos.length; i++) {
 | 
						|
                dependInfo = dependInfos[i];
 | 
						|
                if (dependInfo.getIncludePathIdentifier().equals(
 | 
						|
                        includePathIdentifier)) {
 | 
						|
                    return dependInfo;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
    private Vector getIncludePaths() {
 | 
						|
        Vector includePaths = new Vector();
 | 
						|
        DependencyInfo[] dependInfos;
 | 
						|
        Enumeration dependenciesEnum = dependencies.elements();
 | 
						|
        while (dependenciesEnum.hasMoreElements()) {
 | 
						|
            dependInfos = (DependencyInfo[]) dependenciesEnum.nextElement();
 | 
						|
            for (int i = 0; i < dependInfos.length; i++) {
 | 
						|
                DependencyInfo dependInfo = dependInfos[i];
 | 
						|
                boolean matchesExisting = false;
 | 
						|
                final String dependIncludePath = dependInfo
 | 
						|
                        .getIncludePathIdentifier();
 | 
						|
                Enumeration includePathEnum = includePaths.elements();
 | 
						|
                while (includePathEnum.hasMoreElements()) {
 | 
						|
                    if (dependIncludePath.equals(includePathEnum.nextElement())) {
 | 
						|
                        matchesExisting = true;
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (!matchesExisting) {
 | 
						|
                    includePaths.addElement(dependIncludePath);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return includePaths;
 | 
						|
    }
 | 
						|
    public void load() throws IOException, ParserConfigurationException,
 | 
						|
            SAXException {
 | 
						|
        dependencies.clear();
 | 
						|
        if (dependenciesFile.exists()) {
 | 
						|
            SAXParserFactory factory = SAXParserFactory.newInstance();
 | 
						|
            factory.setValidating(false);
 | 
						|
            SAXParser parser = factory.newSAXParser();
 | 
						|
            parser.parse(dependenciesFile, new DependencyTableHandler(this,
 | 
						|
                    baseDir));
 | 
						|
            dirty = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     * Determines if the specified target needs to be rebuilt.
 | 
						|
     * 
 | 
						|
     * This task may result in substantial IO as files are parsed to determine
 | 
						|
     * their dependencies
 | 
						|
     */
 | 
						|
    public boolean needsRebuild(CCTask task, TargetInfo target,
 | 
						|
            int dependencyDepth) {
 | 
						|
        //    look at any files where the compositeLastModified
 | 
						|
        //    is not known, but the includes are known
 | 
						|
        //
 | 
						|
        boolean mustRebuild = false;
 | 
						|
        CompilerConfiguration compiler = (CompilerConfiguration) target
 | 
						|
                .getConfiguration();
 | 
						|
        String includePathIdentifier = compiler.getIncludePathIdentifier();
 | 
						|
        File[] sources = target.getSources();
 | 
						|
        DependencyInfo[] dependInfos = new DependencyInfo[sources.length];
 | 
						|
        long outputLastModified = target.getOutput().lastModified();
 | 
						|
        //
 | 
						|
        //   try to solve problem using existing dependency info
 | 
						|
        //      (not parsing any new files)
 | 
						|
        //
 | 
						|
        DependencyInfo[] stack = new DependencyInfo[50];
 | 
						|
        boolean rebuildOnStackExhaustion = true;
 | 
						|
        if (dependencyDepth >= 0) {
 | 
						|
            if (dependencyDepth < 50) {
 | 
						|
                stack = new DependencyInfo[dependencyDepth];
 | 
						|
            }
 | 
						|
            rebuildOnStackExhaustion = false;
 | 
						|
        }
 | 
						|
        TimestampChecker checker = new TimestampChecker(outputLastModified,
 | 
						|
                rebuildOnStackExhaustion);
 | 
						|
        for (int i = 0; i < sources.length && !mustRebuild; i++) {
 | 
						|
            File source = sources[i];
 | 
						|
            String relative = CUtil.getRelativePath(baseDirPath, source);
 | 
						|
            DependencyInfo dependInfo = getDependencyInfo(relative,
 | 
						|
                    includePathIdentifier);
 | 
						|
            if (dependInfo == null) {
 | 
						|
                task.log("Parsing " + relative, Project.MSG_VERBOSE);
 | 
						|
                dependInfo = parseIncludes(task, compiler, source);
 | 
						|
            }
 | 
						|
            walkDependencies(task, dependInfo, compiler, stack, checker);
 | 
						|
            mustRebuild = checker.getMustRebuild();
 | 
						|
        }
 | 
						|
        return mustRebuild;
 | 
						|
    }
 | 
						|
    public DependencyInfo parseIncludes(CCTask task,
 | 
						|
            CompilerConfiguration compiler, File source) {
 | 
						|
        DependencyInfo dependInfo = compiler.parseIncludes(task, baseDir,
 | 
						|
                source);
 | 
						|
        String relativeSource = CUtil.getRelativePath(baseDirPath, source);
 | 
						|
        putDependencyInfo(relativeSource, dependInfo);
 | 
						|
        return dependInfo;
 | 
						|
    }
 | 
						|
    private void putDependencyInfo(String key, DependencyInfo dependInfo) {
 | 
						|
        //
 | 
						|
        //   optimistic, add new value
 | 
						|
        //
 | 
						|
        DependencyInfo[] old = (DependencyInfo[]) dependencies.put(key,
 | 
						|
                new DependencyInfo[]{dependInfo});
 | 
						|
        dirty = true;
 | 
						|
        //
 | 
						|
        //   something was already there
 | 
						|
        //
 | 
						|
        if (old != null) {
 | 
						|
            //
 | 
						|
            //   see if the include path matches a previous entry
 | 
						|
            //       if so replace it
 | 
						|
            String includePathIdentifier = dependInfo
 | 
						|
                    .getIncludePathIdentifier();
 | 
						|
            for (int i = 0; i < old.length; i++) {
 | 
						|
                DependencyInfo oldDepend = old[i];
 | 
						|
                if (oldDepend.getIncludePathIdentifier().equals(
 | 
						|
                        includePathIdentifier)) {
 | 
						|
                    old[i] = dependInfo;
 | 
						|
                    dependencies.put(key, old);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            //
 | 
						|
            //   no match prepend the new entry to the array
 | 
						|
            //      of dependencies for the file
 | 
						|
            DependencyInfo[] combined = new DependencyInfo[old.length + 1];
 | 
						|
            combined[0] = dependInfo;
 | 
						|
            for (int i = 0; i < old.length; i++) {
 | 
						|
                combined[i + 1] = old[i];
 | 
						|
            }
 | 
						|
            dependencies.put(key, combined);
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    public void walkDependencies(CCTask task, DependencyInfo dependInfo,
 | 
						|
            CompilerConfiguration compiler, DependencyInfo[] stack,
 | 
						|
            DependencyVisitor visitor) throws BuildException {
 | 
						|
        //
 | 
						|
        //   visit this node
 | 
						|
        //       if visit returns true then
 | 
						|
        //          visit the referenced include and sysInclude dependencies
 | 
						|
        //
 | 
						|
        if (visitor.visit(dependInfo)) {
 | 
						|
            //
 | 
						|
            //   find first null entry on stack
 | 
						|
            //
 | 
						|
            int stackPosition = -1;
 | 
						|
            for (int i = 0; i < stack.length; i++) {
 | 
						|
                if (stack[i] == null) {
 | 
						|
                    stackPosition = i;
 | 
						|
                    stack[i] = dependInfo;
 | 
						|
                    break;
 | 
						|
                } else {
 | 
						|
                    //
 | 
						|
                    //   if we have appeared early in the calling history
 | 
						|
                    //      then we didn't exceed the criteria
 | 
						|
                    if (stack[i] == dependInfo) {
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (stackPosition == -1) {
 | 
						|
                visitor.stackExhausted();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            //
 | 
						|
            //   locate dependency infos
 | 
						|
            //
 | 
						|
            String[] includes = dependInfo.getIncludes();
 | 
						|
            String includePathIdentifier = compiler.getIncludePathIdentifier();
 | 
						|
            DependencyInfo[] includeInfos = new DependencyInfo[includes.length];
 | 
						|
            for (int i = 0; i < includes.length; i++) {
 | 
						|
                DependencyInfo includeInfo = getDependencyInfo(includes[i],
 | 
						|
                        includePathIdentifier);
 | 
						|
                includeInfos[i] = includeInfo;
 | 
						|
            }
 | 
						|
            //
 | 
						|
            //   preview with only the already available dependency infos
 | 
						|
            //
 | 
						|
            if (visitor.preview(dependInfo, includeInfos)) {
 | 
						|
                //
 | 
						|
                //   now need to fill in the missing DependencyInfos
 | 
						|
                //
 | 
						|
                int missingCount = 0;
 | 
						|
                for (int i = 0; i < includes.length; i++) {
 | 
						|
                    if (includeInfos[i] == null) {
 | 
						|
                        missingCount++;
 | 
						|
                        task.log("Parsing " + includes[i], Project.MSG_VERBOSE);
 | 
						|
                        // If the include is part of a UNC don't go building a
 | 
						|
                        // relative file name.
 | 
						|
                        File src = includes[i].startsWith("\\\\") ? new File(
 | 
						|
                                includes[i]) : new File(baseDir, includes[i]);
 | 
						|
                        DependencyInfo includeInfo = parseIncludes(task,
 | 
						|
                                compiler, src);
 | 
						|
                        includeInfos[i] = includeInfo;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                //
 | 
						|
                //   if it passes a review the second time
 | 
						|
                //      then recurse into all the children
 | 
						|
                if (missingCount == 0
 | 
						|
                        || visitor.preview(dependInfo, includeInfos)) {
 | 
						|
                    //
 | 
						|
                    //   recurse into
 | 
						|
                    //
 | 
						|
                    for (int i = 0; i < includeInfos.length; i++) {
 | 
						|
                        DependencyInfo includeInfo = includeInfos[i];
 | 
						|
                        walkDependencies(task, includeInfo, compiler, stack,
 | 
						|
                                visitor);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            stack[stackPosition] = null;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    private void writeDependencyInfo(BufferedWriter writer, StringBuffer buf,
 | 
						|
            DependencyInfo dependInfo) throws IOException {
 | 
						|
        String[] includes = dependInfo.getIncludes();
 | 
						|
        String[] sysIncludes = dependInfo.getSysIncludes();
 | 
						|
        //
 | 
						|
        //   if the includes have not been evaluted then
 | 
						|
        //       it is not worth our time saving it
 | 
						|
        //       and trying to distiguish between files with
 | 
						|
        //       no dependencies and those with undetermined dependencies
 | 
						|
        buf.setLength(0);
 | 
						|
        buf.append("      <source file=\"");
 | 
						|
        buf.append(CUtil.xmlAttribEncode(dependInfo.getSource()));
 | 
						|
        buf.append("\" lastModified=\"");
 | 
						|
        buf.append(Long.toHexString(dependInfo.getSourceLastModified()));
 | 
						|
        buf.append("\">\n");
 | 
						|
        writer.write(buf.toString());
 | 
						|
        for (int i = 0; i < includes.length; i++) {
 | 
						|
            buf.setLength(0);
 | 
						|
            buf.append("         <include file=\"");
 | 
						|
            buf.append(CUtil.xmlAttribEncode(includes[i]));
 | 
						|
            buf.append("\"/>\n");
 | 
						|
            writer.write(buf.toString());
 | 
						|
        }
 | 
						|
        for (int i = 0; i < sysIncludes.length; i++) {
 | 
						|
            buf.setLength(0);
 | 
						|
            buf.append("         <sysinclude file=\"");
 | 
						|
            buf.append(CUtil.xmlAttribEncode(sysIncludes[i]));
 | 
						|
            buf.append("\"/>\n");
 | 
						|
            writer.write(buf.toString());
 | 
						|
        }
 | 
						|
        writer.write("      </source>\n");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    private void writeIncludePathDependencies(String includePathIdentifier,
 | 
						|
            BufferedWriter writer, StringBuffer buf) throws IOException {
 | 
						|
        //
 | 
						|
        //  include path element
 | 
						|
        //
 | 
						|
        buf.setLength(0);
 | 
						|
        buf.append("   <includePath signature=\"");
 | 
						|
        buf.append(CUtil.xmlAttribEncode(includePathIdentifier));
 | 
						|
        buf.append("\">\n");
 | 
						|
        writer.write(buf.toString());
 | 
						|
        Enumeration dependenciesEnum = dependencies.elements();
 | 
						|
        while (dependenciesEnum.hasMoreElements()) {
 | 
						|
            DependencyInfo[] dependInfos = (DependencyInfo[]) dependenciesEnum
 | 
						|
                    .nextElement();
 | 
						|
            for (int i = 0; i < dependInfos.length; i++) {
 | 
						|
                DependencyInfo dependInfo = dependInfos[i];
 | 
						|
                //
 | 
						|
                //   if this is for the same include path
 | 
						|
                //      then output the info
 | 
						|
                if (dependInfo.getIncludePathIdentifier().equals(
 | 
						|
                        includePathIdentifier)) {
 | 
						|
                    writeDependencyInfo(writer, buf, dependInfo);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        writer.write("   </includePath>\n");
 | 
						|
    }
 | 
						|
}
 |