]>
Commit | Line | Data |
---|---|---|
878ddf1f | 1 | /*\r |
2 | * \r | |
3 | * Copyright 2002-2004 The Ant-Contrib project\r | |
4 | *\r | |
5 | * Licensed under the Apache License, Version 2.0 (the "License");\r | |
6 | * you may not use this file except in compliance with the License.\r | |
7 | * You may obtain a copy of the License at\r | |
8 | *\r | |
9 | * http://www.apache.org/licenses/LICENSE-2.0\r | |
10 | *\r | |
11 | * Unless required by applicable law or agreed to in writing, software\r | |
12 | * distributed under the License is distributed on an "AS IS" BASIS,\r | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r | |
14 | * See the License for the specific language governing permissions and\r | |
15 | * limitations under the License.\r | |
16 | */\r | |
17 | package net.sf.antcontrib.cpptasks;\r | |
18 | import java.io.BufferedWriter;\r | |
19 | import java.io.File;\r | |
20 | import java.io.FileOutputStream;\r | |
21 | import java.io.IOException;\r | |
22 | import java.io.OutputStreamWriter;\r | |
23 | import java.io.UnsupportedEncodingException;\r | |
24 | import java.util.Enumeration;\r | |
25 | import java.util.Hashtable;\r | |
26 | import java.util.Vector;\r | |
27 | import javax.xml.parsers.ParserConfigurationException;\r | |
28 | import javax.xml.parsers.SAXParser;\r | |
29 | import javax.xml.parsers.SAXParserFactory;\r | |
30 | import net.sf.antcontrib.cpptasks.compiler.CompilerConfiguration;\r | |
31 | import org.apache.tools.ant.BuildException;\r | |
32 | import org.apache.tools.ant.Project;\r | |
33 | import org.xml.sax.Attributes;\r | |
34 | import org.xml.sax.SAXException;\r | |
35 | import org.xml.sax.helpers.DefaultHandler;\r | |
36 | /**\r | |
37 | * @author Curt Arnold\r | |
38 | */\r | |
39 | public final class DependencyTable {\r | |
40 | /**\r | |
41 | * This class handles populates the TargetHistory hashtable in response to\r | |
42 | * SAX parse events\r | |
43 | */\r | |
44 | private class DependencyTableHandler extends DefaultHandler {\r | |
45 | private File baseDir;\r | |
46 | private final DependencyTable dependencyTable;\r | |
47 | private String includePath;\r | |
48 | private Vector includes;\r | |
49 | private String source;\r | |
50 | private long sourceLastModified;\r | |
51 | private Vector sysIncludes;\r | |
52 | /**\r | |
53 | * Constructor\r | |
54 | * \r | |
55 | * @param history\r | |
56 | * hashtable of TargetHistory keyed by output name\r | |
57 | * @param outputFiles\r | |
58 | * existing files in output directory\r | |
59 | */\r | |
60 | private DependencyTableHandler(DependencyTable dependencyTable,\r | |
61 | File baseDir) {\r | |
62 | this.dependencyTable = dependencyTable;\r | |
63 | this.baseDir = baseDir;\r | |
64 | includes = new Vector();\r | |
65 | sysIncludes = new Vector();\r | |
66 | source = null;\r | |
67 | }\r | |
68 | public void endElement(String namespaceURI, String localName,\r | |
69 | String qName) throws SAXException {\r | |
70 | //\r | |
71 | // if </source> then\r | |
72 | // create Dependency object and add to hashtable\r | |
73 | // if corresponding source file exists and\r | |
74 | // has the same timestamp\r | |
75 | //\r | |
76 | if (qName.equals("source")) {\r | |
77 | if (source != null && includePath != null) {\r | |
78 | File existingFile = new File(baseDir, source);\r | |
79 | //\r | |
80 | // if the file exists and the time stamp is right\r | |
81 | // preserve the dependency info\r | |
82 | if (existingFile.exists()) {\r | |
83 | //\r | |
84 | // would have expected exact matches\r | |
85 | // but was seeing some unexpected difference by\r | |
86 | // a few tens of milliseconds, as long\r | |
87 | // as the times are within a second\r | |
88 | long existingLastModified = existingFile.lastModified();\r | |
89 | long diff = existingLastModified - sourceLastModified;\r | |
90 | if (diff >= -500 && diff <= 500) {\r | |
91 | DependencyInfo dependInfo = new DependencyInfo(\r | |
92 | includePath, source, sourceLastModified,\r | |
93 | includes, sysIncludes);\r | |
94 | dependencyTable.putDependencyInfo(source,\r | |
95 | dependInfo);\r | |
96 | }\r | |
97 | }\r | |
98 | source = null;\r | |
99 | includes.setSize(0);\r | |
100 | }\r | |
101 | } else {\r | |
102 | //\r | |
103 | // this causes any <source> elements outside the\r | |
104 | // scope of an <includePath> to be discarded\r | |
105 | //\r | |
106 | if (qName.equals("includePath")) {\r | |
107 | includePath = null;\r | |
108 | }\r | |
109 | }\r | |
110 | }\r | |
111 | /**\r | |
112 | * startElement handler\r | |
113 | */\r | |
114 | public void startElement(String namespaceURI, String localName,\r | |
115 | String qName, Attributes atts) throws SAXException {\r | |
116 | //\r | |
117 | // if includes, then add relative file name to vector\r | |
118 | //\r | |
119 | if (qName.equals("include")) {\r | |
120 | includes.addElement(atts.getValue("file"));\r | |
121 | } else {\r | |
122 | if (qName.equals("sysinclude")) {\r | |
123 | sysIncludes.addElement(atts.getValue("file"));\r | |
124 | } else {\r | |
125 | //\r | |
126 | // if source then\r | |
127 | // capture source file name,\r | |
128 | // modification time and reset includes vector\r | |
129 | //\r | |
130 | if (qName.equals("source")) {\r | |
131 | source = atts.getValue("file");\r | |
132 | sourceLastModified = Long.parseLong(atts\r | |
133 | .getValue("lastModified"), 16);\r | |
134 | includes.setSize(0);\r | |
135 | sysIncludes.setSize(0);\r | |
136 | } else {\r | |
137 | if (qName.equals("includePath")) {\r | |
138 | includePath = atts.getValue("signature");\r | |
139 | }\r | |
140 | }\r | |
141 | }\r | |
142 | }\r | |
143 | }\r | |
144 | }\r | |
145 | public abstract class DependencyVisitor {\r | |
146 | /**\r | |
147 | * Previews all the children of this source file.\r | |
148 | * \r | |
149 | * May be called multiple times as DependencyInfo's for children are\r | |
150 | * filled in.\r | |
151 | * \r | |
152 | * @return true to continue towards recursion into included files\r | |
153 | */\r | |
154 | public abstract boolean preview(DependencyInfo parent,\r | |
155 | DependencyInfo[] children);\r | |
156 | /**\r | |
157 | * Called if the dependency depth exhausted the stack.\r | |
158 | */\r | |
159 | public abstract void stackExhausted();\r | |
160 | /**\r | |
161 | * Visits the dependency info.\r | |
162 | * \r | |
163 | * @returns true to continue towards recursion into included files\r | |
164 | */\r | |
165 | public abstract boolean visit(DependencyInfo dependInfo);\r | |
166 | }\r | |
167 | public class TimestampChecker extends DependencyVisitor {\r | |
168 | private boolean noNeedToRebuild;\r | |
169 | private long outputLastModified;\r | |
170 | private boolean rebuildOnStackExhaustion;\r | |
171 | public TimestampChecker(final long outputLastModified,\r | |
172 | boolean rebuildOnStackExhaustion) {\r | |
173 | this.outputLastModified = outputLastModified;\r | |
174 | noNeedToRebuild = true;\r | |
175 | this.rebuildOnStackExhaustion = rebuildOnStackExhaustion;\r | |
176 | }\r | |
177 | public boolean getMustRebuild() {\r | |
178 | return !noNeedToRebuild;\r | |
179 | }\r | |
180 | public boolean preview(DependencyInfo parent, DependencyInfo[] children) {\r | |
181 | int withCompositeTimes = 0;\r | |
182 | long parentCompositeLastModified = parent.getSourceLastModified();\r | |
183 | for (int i = 0; i < children.length; i++) {\r | |
184 | if (children[i] != null) {\r | |
185 | //\r | |
186 | // expedient way to determine if a child forces us to\r | |
187 | // rebuild\r | |
188 | //\r | |
189 | visit(children[i]);\r | |
190 | long childCompositeLastModified = children[i]\r | |
191 | .getCompositeLastModified();\r | |
192 | if (childCompositeLastModified != Long.MIN_VALUE) {\r | |
193 | withCompositeTimes++;\r | |
194 | if (childCompositeLastModified > parentCompositeLastModified) {\r | |
195 | parentCompositeLastModified = childCompositeLastModified;\r | |
196 | }\r | |
197 | }\r | |
198 | }\r | |
199 | }\r | |
200 | if (withCompositeTimes == children.length) {\r | |
201 | parent.setCompositeLastModified(parentCompositeLastModified);\r | |
202 | }\r | |
203 | //\r | |
204 | // may have been changed by an earlier call to visit()\r | |
205 | //\r | |
206 | return noNeedToRebuild;\r | |
207 | }\r | |
208 | public void stackExhausted() {\r | |
209 | if (rebuildOnStackExhaustion) {\r | |
210 | noNeedToRebuild = false;\r | |
211 | }\r | |
212 | }\r | |
213 | public boolean visit(DependencyInfo dependInfo) {\r | |
214 | if (noNeedToRebuild) {\r | |
215 | if (dependInfo.getSourceLastModified() > outputLastModified\r | |
216 | || dependInfo.getCompositeLastModified() > outputLastModified) {\r | |
217 | noNeedToRebuild = false;\r | |
218 | }\r | |
219 | }\r | |
220 | //\r | |
221 | // only need to process the children if\r | |
222 | // it has not yet been determined whether\r | |
223 | // we need to rebuild and the composite modified time\r | |
224 | // has not been determined for this file\r | |
225 | return noNeedToRebuild\r | |
226 | && dependInfo.getCompositeLastModified() == Long.MIN_VALUE;\r | |
227 | }\r | |
228 | }\r | |
229 | private/* final */File baseDir;\r | |
230 | private String baseDirPath;\r | |
231 | /**\r | |
232 | * a hashtable of DependencyInfo[] keyed by output file name\r | |
233 | */\r | |
234 | private final Hashtable dependencies = new Hashtable();\r | |
235 | /** The file the cache was loaded from. */\r | |
236 | private/* final */File dependenciesFile;\r | |
237 | /** Flag indicating whether the cache should be written back to file. */\r | |
238 | private boolean dirty;\r | |
239 | /**\r | |
240 | * Creates a target history table from dependencies.xml in the prject\r | |
241 | * directory, if it exists. Otherwise, initializes the dependencies empty.\r | |
242 | * \r | |
243 | * @param task\r | |
244 | * task used for logging history load errors\r | |
245 | * @param baseDir\r | |
246 | * output directory for task\r | |
247 | */\r | |
248 | public DependencyTable(File baseDir) {\r | |
249 | if (baseDir == null) {\r | |
250 | throw new NullPointerException("baseDir");\r | |
251 | }\r | |
252 | this.baseDir = baseDir;\r | |
253 | try {\r | |
254 | baseDirPath = baseDir.getCanonicalPath();\r | |
255 | } catch (IOException ex) {\r | |
256 | baseDirPath = baseDir.toString();\r | |
257 | }\r | |
258 | dirty = false;\r | |
259 | //\r | |
260 | // load any existing dependencies from file\r | |
261 | dependenciesFile = new File(baseDir, "dependencies.xml");\r | |
262 | }\r | |
263 | public void commit(CCTask task) {\r | |
264 | //\r | |
265 | // if not dirty, no need to update file\r | |
266 | //\r | |
267 | if (dirty) {\r | |
268 | //\r | |
269 | // walk through dependencies to get vector of include paths\r | |
270 | // identifiers\r | |
271 | //\r | |
272 | Vector includePaths = getIncludePaths();\r | |
273 | //\r | |
274 | //\r | |
275 | // write dependency file\r | |
276 | //\r | |
277 | try {\r | |
278 | FileOutputStream outStream = new FileOutputStream(\r | |
279 | dependenciesFile);\r | |
280 | OutputStreamWriter streamWriter;\r | |
281 | //\r | |
282 | // Early VM's may not have UTF-8 support\r | |
283 | // fallback to default code page which\r | |
284 | // "should" be okay unless there are\r | |
285 | // non ASCII file names\r | |
286 | String encodingName = "UTF-8";\r | |
287 | try {\r | |
288 | streamWriter = new OutputStreamWriter(outStream, "UTF-8");\r | |
289 | } catch (UnsupportedEncodingException ex) {\r | |
290 | streamWriter = new OutputStreamWriter(outStream);\r | |
291 | encodingName = streamWriter.getEncoding();\r | |
292 | }\r | |
293 | BufferedWriter writer = new BufferedWriter(streamWriter);\r | |
294 | writer.write("<?xml version='1.0' encoding='");\r | |
295 | writer.write(encodingName);\r | |
296 | writer.write("'?>\n");\r | |
297 | writer.write("<dependencies>\n");\r | |
298 | StringBuffer buf = new StringBuffer();\r | |
299 | Enumeration includePathEnum = includePaths.elements();\r | |
300 | while (includePathEnum.hasMoreElements()) {\r | |
301 | writeIncludePathDependencies((String) includePathEnum\r | |
302 | .nextElement(), writer, buf);\r | |
303 | }\r | |
304 | writer.write("</dependencies>\n");\r | |
305 | writer.close();\r | |
306 | dirty = false;\r | |
307 | } catch (IOException ex) {\r | |
308 | task.log("Error writing " + dependenciesFile.toString() + ":"\r | |
309 | + ex.toString());\r | |
310 | }\r | |
311 | }\r | |
312 | }\r | |
313 | /**\r | |
314 | * Returns an enumerator of DependencyInfo's\r | |
315 | */\r | |
316 | public Enumeration elements() {\r | |
317 | return dependencies.elements();\r | |
318 | }\r | |
319 | /**\r | |
320 | * This method returns a DependencyInfo for the specific source file and\r | |
321 | * include path identifier\r | |
322 | * \r | |
323 | */\r | |
324 | public DependencyInfo getDependencyInfo(String sourceRelativeName,\r | |
325 | String includePathIdentifier) {\r | |
326 | DependencyInfo dependInfo = null;\r | |
327 | DependencyInfo[] dependInfos = (DependencyInfo[]) dependencies\r | |
328 | .get(sourceRelativeName);\r | |
329 | if (dependInfos != null) {\r | |
330 | for (int i = 0; i < dependInfos.length; i++) {\r | |
331 | dependInfo = dependInfos[i];\r | |
332 | if (dependInfo.getIncludePathIdentifier().equals(\r | |
333 | includePathIdentifier)) {\r | |
334 | return dependInfo;\r | |
335 | }\r | |
336 | }\r | |
337 | }\r | |
338 | return null;\r | |
339 | }\r | |
340 | private Vector getIncludePaths() {\r | |
341 | Vector includePaths = new Vector();\r | |
342 | DependencyInfo[] dependInfos;\r | |
343 | Enumeration dependenciesEnum = dependencies.elements();\r | |
344 | while (dependenciesEnum.hasMoreElements()) {\r | |
345 | dependInfos = (DependencyInfo[]) dependenciesEnum.nextElement();\r | |
346 | for (int i = 0; i < dependInfos.length; i++) {\r | |
347 | DependencyInfo dependInfo = dependInfos[i];\r | |
348 | boolean matchesExisting = false;\r | |
349 | final String dependIncludePath = dependInfo\r | |
350 | .getIncludePathIdentifier();\r | |
351 | Enumeration includePathEnum = includePaths.elements();\r | |
352 | while (includePathEnum.hasMoreElements()) {\r | |
353 | if (dependIncludePath.equals(includePathEnum.nextElement())) {\r | |
354 | matchesExisting = true;\r | |
355 | break;\r | |
356 | }\r | |
357 | }\r | |
358 | if (!matchesExisting) {\r | |
359 | includePaths.addElement(dependIncludePath);\r | |
360 | }\r | |
361 | }\r | |
362 | }\r | |
363 | return includePaths;\r | |
364 | }\r | |
365 | public void load() throws IOException, ParserConfigurationException,\r | |
366 | SAXException {\r | |
367 | dependencies.clear();\r | |
368 | if (dependenciesFile.exists()) {\r | |
369 | SAXParserFactory factory = SAXParserFactory.newInstance();\r | |
370 | factory.setValidating(false);\r | |
371 | SAXParser parser = factory.newSAXParser();\r | |
372 | parser.parse(dependenciesFile, new DependencyTableHandler(this,\r | |
373 | baseDir));\r | |
374 | dirty = false;\r | |
375 | }\r | |
376 | }\r | |
377 | /**\r | |
378 | * Determines if the specified target needs to be rebuilt.\r | |
379 | * \r | |
380 | * This task may result in substantial IO as files are parsed to determine\r | |
381 | * their dependencies\r | |
382 | */\r | |
383 | public boolean needsRebuild(CCTask task, TargetInfo target,\r | |
384 | int dependencyDepth) {\r | |
385 | // look at any files where the compositeLastModified\r | |
386 | // is not known, but the includes are known\r | |
387 | //\r | |
388 | boolean mustRebuild = false;\r | |
389 | CompilerConfiguration compiler = (CompilerConfiguration) target\r | |
390 | .getConfiguration();\r | |
391 | String includePathIdentifier = compiler.getIncludePathIdentifier();\r | |
392 | File[] sources = target.getSources();\r | |
393 | DependencyInfo[] dependInfos = new DependencyInfo[sources.length];\r | |
394 | long outputLastModified = target.getOutput().lastModified();\r | |
395 | //\r | |
396 | // try to solve problem using existing dependency info\r | |
397 | // (not parsing any new files)\r | |
398 | //\r | |
399 | DependencyInfo[] stack = new DependencyInfo[50];\r | |
400 | boolean rebuildOnStackExhaustion = true;\r | |
401 | if (dependencyDepth >= 0) {\r | |
402 | if (dependencyDepth < 50) {\r | |
403 | stack = new DependencyInfo[dependencyDepth];\r | |
404 | }\r | |
405 | rebuildOnStackExhaustion = false;\r | |
406 | }\r | |
407 | TimestampChecker checker = new TimestampChecker(outputLastModified,\r | |
408 | rebuildOnStackExhaustion);\r | |
409 | for (int i = 0; i < sources.length && !mustRebuild; i++) {\r | |
410 | File source = sources[i];\r | |
411 | String relative = CUtil.getRelativePath(baseDirPath, source);\r | |
412 | DependencyInfo dependInfo = getDependencyInfo(relative,\r | |
413 | includePathIdentifier);\r | |
414 | if (dependInfo == null) {\r | |
415 | task.log("Parsing " + relative, Project.MSG_VERBOSE);\r | |
416 | dependInfo = parseIncludes(task, compiler, source);\r | |
417 | }\r | |
418 | walkDependencies(task, dependInfo, compiler, stack, checker);\r | |
419 | mustRebuild = checker.getMustRebuild();\r | |
420 | }\r | |
421 | return mustRebuild;\r | |
422 | }\r | |
423 | public DependencyInfo parseIncludes(CCTask task,\r | |
424 | CompilerConfiguration compiler, File source) {\r | |
425 | DependencyInfo dependInfo = compiler.parseIncludes(task, baseDir,\r | |
426 | source);\r | |
427 | String relativeSource = CUtil.getRelativePath(baseDirPath, source);\r | |
428 | putDependencyInfo(relativeSource, dependInfo);\r | |
429 | return dependInfo;\r | |
430 | }\r | |
431 | private void putDependencyInfo(String key, DependencyInfo dependInfo) {\r | |
432 | //\r | |
433 | // optimistic, add new value\r | |
434 | //\r | |
435 | DependencyInfo[] old = (DependencyInfo[]) dependencies.put(key,\r | |
436 | new DependencyInfo[]{dependInfo});\r | |
437 | dirty = true;\r | |
438 | //\r | |
439 | // something was already there\r | |
440 | //\r | |
441 | if (old != null) {\r | |
442 | //\r | |
443 | // see if the include path matches a previous entry\r | |
444 | // if so replace it\r | |
445 | String includePathIdentifier = dependInfo\r | |
446 | .getIncludePathIdentifier();\r | |
447 | for (int i = 0; i < old.length; i++) {\r | |
448 | DependencyInfo oldDepend = old[i];\r | |
449 | if (oldDepend.getIncludePathIdentifier().equals(\r | |
450 | includePathIdentifier)) {\r | |
451 | old[i] = dependInfo;\r | |
452 | dependencies.put(key, old);\r | |
453 | return;\r | |
454 | }\r | |
455 | }\r | |
456 | //\r | |
457 | // no match prepend the new entry to the array\r | |
458 | // of dependencies for the file\r | |
459 | DependencyInfo[] combined = new DependencyInfo[old.length + 1];\r | |
460 | combined[0] = dependInfo;\r | |
461 | for (int i = 0; i < old.length; i++) {\r | |
462 | combined[i + 1] = old[i];\r | |
463 | }\r | |
464 | dependencies.put(key, combined);\r | |
465 | }\r | |
466 | return;\r | |
467 | }\r | |
468 | public void walkDependencies(CCTask task, DependencyInfo dependInfo,\r | |
469 | CompilerConfiguration compiler, DependencyInfo[] stack,\r | |
470 | DependencyVisitor visitor) throws BuildException {\r | |
471 | //\r | |
472 | // visit this node\r | |
473 | // if visit returns true then\r | |
474 | // visit the referenced include and sysInclude dependencies\r | |
475 | //\r | |
476 | if (visitor.visit(dependInfo)) {\r | |
477 | //\r | |
478 | // find first null entry on stack\r | |
479 | //\r | |
480 | int stackPosition = -1;\r | |
481 | for (int i = 0; i < stack.length; i++) {\r | |
482 | if (stack[i] == null) {\r | |
483 | stackPosition = i;\r | |
484 | stack[i] = dependInfo;\r | |
485 | break;\r | |
486 | } else {\r | |
487 | //\r | |
488 | // if we have appeared early in the calling history\r | |
489 | // then we didn't exceed the criteria\r | |
490 | if (stack[i] == dependInfo) {\r | |
491 | return;\r | |
492 | }\r | |
493 | }\r | |
494 | }\r | |
495 | if (stackPosition == -1) {\r | |
496 | visitor.stackExhausted();\r | |
497 | return;\r | |
498 | }\r | |
499 | //\r | |
500 | // locate dependency infos\r | |
501 | //\r | |
502 | String[] includes = dependInfo.getIncludes();\r | |
503 | String includePathIdentifier = compiler.getIncludePathIdentifier();\r | |
504 | DependencyInfo[] includeInfos = new DependencyInfo[includes.length];\r | |
505 | for (int i = 0; i < includes.length; i++) {\r | |
506 | DependencyInfo includeInfo = getDependencyInfo(includes[i],\r | |
507 | includePathIdentifier);\r | |
508 | includeInfos[i] = includeInfo;\r | |
509 | }\r | |
510 | //\r | |
511 | // preview with only the already available dependency infos\r | |
512 | //\r | |
513 | if (visitor.preview(dependInfo, includeInfos)) {\r | |
514 | //\r | |
515 | // now need to fill in the missing DependencyInfos\r | |
516 | //\r | |
517 | int missingCount = 0;\r | |
518 | for (int i = 0; i < includes.length; i++) {\r | |
519 | if (includeInfos[i] == null) {\r | |
520 | missingCount++;\r | |
521 | task.log("Parsing " + includes[i], Project.MSG_VERBOSE);\r | |
522 | // If the include is part of a UNC don't go building a\r | |
523 | // relative file name.\r | |
524 | File src = includes[i].startsWith("\\\\") ? new File(\r | |
525 | includes[i]) : new File(baseDir, includes[i]);\r | |
526 | DependencyInfo includeInfo = parseIncludes(task,\r | |
527 | compiler, src);\r | |
528 | includeInfos[i] = includeInfo;\r | |
529 | }\r | |
530 | }\r | |
531 | //\r | |
532 | // if it passes a review the second time\r | |
533 | // then recurse into all the children\r | |
534 | if (missingCount == 0\r | |
535 | || visitor.preview(dependInfo, includeInfos)) {\r | |
536 | //\r | |
537 | // recurse into\r | |
538 | //\r | |
539 | for (int i = 0; i < includeInfos.length; i++) {\r | |
540 | DependencyInfo includeInfo = includeInfos[i];\r | |
541 | walkDependencies(task, includeInfo, compiler, stack,\r | |
542 | visitor);\r | |
543 | }\r | |
544 | }\r | |
545 | }\r | |
546 | stack[stackPosition] = null;\r | |
547 | }\r | |
548 | }\r | |
549 | private void writeDependencyInfo(BufferedWriter writer, StringBuffer buf,\r | |
550 | DependencyInfo dependInfo) throws IOException {\r | |
551 | String[] includes = dependInfo.getIncludes();\r | |
552 | String[] sysIncludes = dependInfo.getSysIncludes();\r | |
553 | //\r | |
554 | // if the includes have not been evaluted then\r | |
555 | // it is not worth our time saving it\r | |
556 | // and trying to distiguish between files with\r | |
557 | // no dependencies and those with undetermined dependencies\r | |
558 | buf.setLength(0);\r | |
559 | buf.append(" <source file=\"");\r | |
560 | buf.append(CUtil.xmlAttribEncode(dependInfo.getSource()));\r | |
561 | buf.append("\" lastModified=\"");\r | |
562 | buf.append(Long.toHexString(dependInfo.getSourceLastModified()));\r | |
563 | buf.append("\">\n");\r | |
564 | writer.write(buf.toString());\r | |
565 | for (int i = 0; i < includes.length; i++) {\r | |
566 | buf.setLength(0);\r | |
567 | buf.append(" <include file=\"");\r | |
568 | buf.append(CUtil.xmlAttribEncode(includes[i]));\r | |
569 | buf.append("\"/>\n");\r | |
570 | writer.write(buf.toString());\r | |
571 | }\r | |
572 | for (int i = 0; i < sysIncludes.length; i++) {\r | |
573 | buf.setLength(0);\r | |
574 | buf.append(" <sysinclude file=\"");\r | |
575 | buf.append(CUtil.xmlAttribEncode(sysIncludes[i]));\r | |
576 | buf.append("\"/>\n");\r | |
577 | writer.write(buf.toString());\r | |
578 | }\r | |
579 | writer.write(" </source>\n");\r | |
580 | return;\r | |
581 | }\r | |
582 | private void writeIncludePathDependencies(String includePathIdentifier,\r | |
583 | BufferedWriter writer, StringBuffer buf) throws IOException {\r | |
584 | //\r | |
585 | // include path element\r | |
586 | //\r | |
587 | buf.setLength(0);\r | |
588 | buf.append(" <includePath signature=\"");\r | |
589 | buf.append(CUtil.xmlAttribEncode(includePathIdentifier));\r | |
590 | buf.append("\">\n");\r | |
591 | writer.write(buf.toString());\r | |
592 | Enumeration dependenciesEnum = dependencies.elements();\r | |
593 | while (dependenciesEnum.hasMoreElements()) {\r | |
594 | DependencyInfo[] dependInfos = (DependencyInfo[]) dependenciesEnum\r | |
595 | .nextElement();\r | |
596 | for (int i = 0; i < dependInfos.length; i++) {\r | |
597 | DependencyInfo dependInfo = dependInfos[i];\r | |
598 | //\r | |
599 | // if this is for the same include path\r | |
600 | // then output the info\r | |
601 | if (dependInfo.getIncludePathIdentifier().equals(\r | |
602 | includePathIdentifier)) {\r | |
603 | writeDependencyInfo(writer, buf, dependInfo);\r | |
604 | }\r | |
605 | }\r | |
606 | }\r | |
607 | writer.write(" </includePath>\n");\r | |
608 | }\r | |
609 | }\r |