Ninja
depfile_parser.in.cc
Go to the documentation of this file.
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "depfile_parser.h"
16 
17 // A note on backslashes in Makefiles, from reading the docs:
18 // Backslash-newline is the line continuation character.
19 // Backslash-# escapes a # (otherwise meaningful as a comment start).
20 // Backslash-% escapes a % (otherwise meaningful as a special).
21 // Finally, quoting the GNU manual, "Backslashes that are not in danger
22 // of quoting ‘%’ characters go unmolested."
23 // How do you end a line with a backslash? The netbsd Make docs suggest
24 // reading the result of a shell command echoing a backslash!
25 //
26 // Rather than implement all of above, we do a simpler thing here:
27 // Backslashes escape a set of characters (see "escapes" defined below),
28 // otherwise they are passed through verbatim.
29 // If anyone actually has depfiles that rely on the more complicated
30 // behavior we can adjust this.
31 bool DepfileParser::Parse(string* content, string* err) {
32  // in: current parser input point.
33  // end: end of input.
34  // parsing_targets: whether we are parsing targets or dependencies.
35  char* in = &(*content)[0];
36  char* end = in + content->size();
37  bool parsing_targets = true;
38  while (in < end) {
39  // out: current output point (typically same as in, but can fall behind
40  // as we de-escape backslashes).
41  char* out = in;
42  // filename: start of the current parsed filename.
43  char* filename = out;
44  for (;;) {
45  // start: beginning of the current parsed span.
46  const char* start = in;
47  /*!re2c
48  re2c:define:YYCTYPE = "char";
49  re2c:define:YYCURSOR = in;
50  re2c:define:YYLIMIT = end;
51 
52  re2c:yyfill:enable = 0;
53 
54  re2c:indent:top = 2;
55  re2c:indent:string = " ";
56 
57  nul = "\000";
58  escape = [ \\#*[|];
59 
60  '\\' escape {
61  // De-escape backslashed character.
62  *out++ = yych;
63  continue;
64  }
65  '$$' {
66  // De-escape dollar character.
67  *out++ = '$';
68  continue;
69  }
70  '\\' [^\000\n] {
71  // Let backslash before other characters through verbatim.
72  *out++ = '\\';
73  *out++ = yych;
74  continue;
75  }
76  [a-zA-Z0-9+,/_:.~()@=-!]+ {
77  // Got a span of plain text.
78  int len = (int)(in - start);
79  // Need to shift it over if we're overwriting backslashes.
80  if (out < start)
81  memmove(out, start, len);
82  out += len;
83  continue;
84  }
85  nul {
86  break;
87  }
88  [^] {
89  // For any other character (e.g. whitespace), swallow it here,
90  // allowing the outer logic to loop around again.
91  break;
92  }
93  */
94  }
95 
96  int len = (int)(out - filename);
97  const bool is_target = parsing_targets;
98  if (len > 0 && filename[len - 1] == ':') {
99  len--; // Strip off trailing colon, if any.
100  parsing_targets = false;
101  }
102 
103  if (len == 0)
104  continue;
105 
106  if (!is_target) {
107  ins_.push_back(StringPiece(filename, len));
108  } else if (!out_.str_) {
109  out_ = StringPiece(filename, len);
110  } else if (out_ != StringPiece(filename, len)) {
111  *err = "depfile has multiple output paths.";
112  return false;
113  }
114  }
115  return true;
116 }
const char * str_
Definition: string_piece.h:49
StringPiece represents a slice of a string whose memory is managed externally.
Definition: string_piece.h:27
bool Parse(string *content, string *err)
Parse an input file.
vector< StringPiece > ins_
StringPiece out_