blob: 2161e437919cd85a41070e90438ec5c05859f79c [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace NaCl.Build.CPPTasks
{
/// <summary>
/// Parser for the dependancy files generated by gcc (.d files).
/// This is not a general purpose .d file parser. In particular it
/// assumes exactly one dependancy per line.
/// </summary>
public class DependencyParser
{
private List<string> m_dependencies = new List<string>();
public List<String> Dependencies
{
get
{
return m_dependencies;
}
}
public DependencyParser()
{
}
public DependencyParser(string filename)
{
using (StreamReader reader = new StreamReader(filename, Encoding.ASCII))
{
Parse(reader);
}
}
public void Parse(string content)
{
Parse(new StringReader(content));
}
public void Parse(TextReader reader)
{
while (true)
{
string str = reader.ReadLine();
if (str == null)
break;
ParseLine(str);
}
reader.Close();
}
private void AddDependency(string filename)
{
filename = GCCUtilities.ConvertPathPosixToWindows(filename);
filename = filename.Replace("\\ ", " ");
m_dependencies.Add(filename);
}
/// <summary>
/// Find the end of the current filename on the given line from a dependancy file.
/// Normally this is the space char but, spaces can be escaped with backslash and
/// end of string could also terminate the filename.
/// </summary>
private static int FindEndOfFilename(string line)
{
bool escapeSpace = false;
int i = 0;
for (i = 0; i < line.Length; i++)
{
if (line.ElementAt(i) == '\\')
{
escapeSpace = true;
}
else if (line.ElementAt(i) == ' ' && !escapeSpace)
{
// we found an unescaped space which represents the
// end of the current filename.
break;
}
else if (escapeSpace)
{
escapeSpace = false;
}
}
return i;
}
/// <summary>
/// Parse a single line from a dependancy file.
/// </summary>
private void ParseLine(string line)
{
// Strip any trailing line continuation character. Most lines of a gcc
// generated .d files end with this char
if (line.ElementAt(line.Length - 1) == '\\')
line = line.Substring(0, line.Length - 1);
if (m_dependencies.Count == 0)
{
// The first line of the .d files is <target>: <first_dep>.
// For this line we want to strip the <target>: part.
line = line.Split(new[] { ':' }, 2)[1];
}
// trim trailing whitespace
line = line.Trim();
// Now iterate through the line which can contain zero or more dependencies.
// Although they are seperated by spaces we can't use Split() here since filenames
// can also contain spaces that are escaped using backslash. For some reason only
// spaces are escaped. Even literal backslash chars don't need escaping.
while (line.Length != 0)
{
int end = FindEndOfFilename(line);
AddDependency(line.Substring(0, end));
if (end == line.Length)
break;
line = line.Substring(end + 1).Trim();
}
}
}
}