Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "depfile_parser.h" 00016 00017 // A note on backslashes in Makefiles, from reading the docs: 00018 // Backslash-newline is the line continuation character. 00019 // Backslash-# escapes a # (otherwise meaningful as a comment start). 00020 // Backslash-% escapes a % (otherwise meaningful as a special). 00021 // Finally, quoting the GNU manual, "Backslashes that are not in danger 00022 // of quoting ‘%’ characters go unmolested." 00023 // How do you end a line with a backslash? The netbsd Make docs suggest 00024 // reading the result of a shell command echoing a backslash! 00025 // 00026 // Rather than implement all of above, we do a simpler thing here: 00027 // Backslashes escape a set of characters (see "escapes" defined below), 00028 // otherwise they are passed through verbatim. 00029 // If anyone actually has depfiles that rely on the more complicated 00030 // behavior we can adjust this. 00031 bool DepfileParser::Parse(string* content, string* err) { 00032 // in: current parser input point. 00033 // end: end of input. 00034 // parsing_targets: whether we are parsing targets or dependencies. 00035 char* in = &(*content)[0]; 00036 char* end = in + content->size(); 00037 bool parsing_targets = true; 00038 while (in < end) { 00039 // out: current output point (typically same as in, but can fall behind 00040 // as we de-escape backslashes). 00041 char* out = in; 00042 // filename: start of the current parsed filename. 00043 char* filename = out; 00044 for (;;) { 00045 // start: beginning of the current parsed span. 00046 const char* start = in; 00047 /*!re2c 00048 re2c:define:YYCTYPE = "char"; 00049 re2c:define:YYCURSOR = in; 00050 re2c:define:YYLIMIT = end; 00051 00052 re2c:yyfill:enable = 0; 00053 00054 re2c:indent:top = 2; 00055 re2c:indent:string = " "; 00056 00057 nul = "\000"; 00058 escape = [ \\#*[|]; 00059 00060 '\\' escape { 00061 // De-escape backslashed character. 00062 *out++ = yych; 00063 continue; 00064 } 00065 '$$' { 00066 // De-escape dollar character. 00067 *out++ = '$'; 00068 continue; 00069 } 00070 '\\' [^\000\n] { 00071 // Let backslash before other characters through verbatim. 00072 *out++ = '\\'; 00073 *out++ = yych; 00074 continue; 00075 } 00076 [a-zA-Z0-9+,/_:.~()@=-!]+ { 00077 // Got a span of plain text. 00078 int len = (int)(in - start); 00079 // Need to shift it over if we're overwriting backslashes. 00080 if (out < start) 00081 memmove(out, start, len); 00082 out += len; 00083 continue; 00084 } 00085 nul { 00086 break; 00087 } 00088 [^] { 00089 // For any other character (e.g. whitespace), swallow it here, 00090 // allowing the outer logic to loop around again. 00091 break; 00092 } 00093 */ 00094 } 00095 00096 int len = (int)(out - filename); 00097 const bool is_target = parsing_targets; 00098 if (len > 0 && filename[len - 1] == ':') { 00099 len--; // Strip off trailing colon, if any. 00100 parsing_targets = false; 00101 } 00102 00103 if (len == 0) 00104 continue; 00105 00106 if (!is_target) { 00107 ins_.push_back(StringPiece(filename, len)); 00108 } else if (!out_.str_) { 00109 out_ = StringPiece(filename, len); 00110 } else if (out_ != StringPiece(filename, len)) { 00111 *err = "depfile has multiple output paths."; 00112 return false; 00113 } 00114 } 00115 return true; 00116 }