public static Depfile parseDepfile()

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);
    }
  }