in src/com/facebook/buck/cxx/Depfiles.java [104:208]
public static Depfile parseDepfile(Readable readable) throws IOException {
String target = null;
ImmutableList.Builder<String> prereqsBuilder = ImmutableList.builder();
State state = State.LOOKING_FOR_TARGET;
StringBuilder identifierBuilder = new StringBuilder();
CharBuffer buffer = CharBuffer.allocate(4096);
int numBackslashes = 0;
while (readable.read(buffer) != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
char c = buffer.get();
Action action = Action.NONE;
boolean isBackslash = c == '\\';
boolean isCarriageReturn = c == '\r';
boolean isNewline = c == '\n';
boolean isWhitespace = WHITESPACE_CHARS.indexOf(c) != -1;
boolean inIdentifier = identifierBuilder.length() > 0;
boolean isEscaped;
if (state == State.LOOKING_FOR_TARGET) {
isEscaped = ESCAPED_TARGET_CHARS.indexOf(c) != -1;
} else {
isEscaped = ESCAPED_PREREQ_CHARS.indexOf(c) != -1;
}
if (isBackslash) {
// We need to count the number of backslashes in case the
// first non-backslash is an escaped character.
numBackslashes++;
} else if (numBackslashes > 0 && isEscaped) {
// Consume one backslash to escape the special char.
numBackslashes--;
if (inIdentifier) {
action = Action.APPEND_TO_IDENTIFIER;
}
} else if (isWhitespace) {
if (numBackslashes == 0) {
if (state == State.FOUND_TARGET && inIdentifier) {
action = Action.ADD_PREREQ;
}
if (state == State.FOUND_TARGET && (isNewline || isCarriageReturn)) {
state = State.LOOKING_FOR_TARGET;
}
} else if (isNewline) {
// Consume one backslash to escape \n or \r\n.
numBackslashes--;
} else if (!isCarriageReturn) {
action = Action.APPEND_TO_IDENTIFIER;
}
} else if (c == ':' && state == State.LOOKING_FOR_TARGET) {
state = State.FOUND_TARGET;
action = Action.SET_TARGET;
} else {
action = Action.APPEND_TO_IDENTIFIER;
}
if (!isBackslash && numBackslashes > 0 && !isCarriageReturn) {
int numBackslashesToAppend;
if (isEscaped || isWhitespace) {
// Backslashes escape themselves before an escaped character or whitespace.
numBackslashesToAppend = numBackslashes / 2;
} else {
// Backslashes are literal before a non-escaped character.
numBackslashesToAppend = numBackslashes;
}
for (int i = 0; i < numBackslashesToAppend; i++) {
identifierBuilder.append('\\');
}
numBackslashes = 0;
}
switch (action) {
case NONE:
break;
case APPEND_TO_IDENTIFIER:
identifierBuilder.append(c);
break;
case SET_TARGET:
if (target != null) {
throw new HumanReadableException(
"Depfile parser cannot handle .d file with multiple targets");
}
target = identifierBuilder.toString();
identifierBuilder.setLength(0);
break;
case ADD_PREREQ:
prereqsBuilder.add(identifierBuilder.toString());
identifierBuilder.setLength(0);
break;
}
}
buffer.clear();
}
ImmutableList<String> prereqs = prereqsBuilder.build();
if (target == null || prereqs.isEmpty()) {
throw new IOException("Could not find target or prereqs parsing depfile");
} else {
return new Depfile(target, prereqs);
}
}