| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "tools/gn/filesystem_utils.h" | 
|  | 6 | 
|  | 7 #include "base/logging.h" | 
|  | 8 #include "base/strings/utf_string_conversions.h" | 
|  | 9 #include "build/build_config.h" | 
|  | 10 #include "tools/gn/location.h" | 
|  | 11 #include "tools/gn/source_dir.h" | 
|  | 12 | 
|  | 13 namespace { | 
|  | 14 | 
|  | 15 enum DotDisposition { | 
|  | 16   // The given dot is just part of a filename and is not special. | 
|  | 17   NOT_A_DIRECTORY, | 
|  | 18 | 
|  | 19   // The given dot is the current directory. | 
|  | 20   DIRECTORY_CUR, | 
|  | 21 | 
|  | 22   // The given dot is the first of a double dot that should take us up one. | 
|  | 23   DIRECTORY_UP | 
|  | 24 }; | 
|  | 25 | 
|  | 26 // When we find a dot, this function is called with the character following | 
|  | 27 // that dot to see what it is. The return value indicates what type this dot is | 
|  | 28 // (see above). This code handles the case where the dot is at the end of the | 
|  | 29 // input. | 
|  | 30 // | 
|  | 31 // |*consumed_len| will contain the number of characters in the input that | 
|  | 32 // express what we found. | 
|  | 33 DotDisposition ClassifyAfterDot(const std::string& path, | 
|  | 34                                 size_t after_dot, | 
|  | 35                                 size_t* consumed_len) { | 
|  | 36   if (after_dot == path.size()) { | 
|  | 37     // Single dot at the end. | 
|  | 38     *consumed_len = 1; | 
|  | 39     return DIRECTORY_CUR; | 
|  | 40   } | 
|  | 41   if (path[after_dot] == '/') { | 
|  | 42     // Single dot followed by a slash. | 
|  | 43     *consumed_len = 2;  // Consume the slash | 
|  | 44     return DIRECTORY_CUR; | 
|  | 45   } | 
|  | 46 | 
|  | 47   if (path[after_dot] == '.') { | 
|  | 48     // Two dots. | 
|  | 49     if (after_dot + 1 == path.size()) { | 
|  | 50       // Double dot at the end. | 
|  | 51       *consumed_len = 2; | 
|  | 52       return DIRECTORY_UP; | 
|  | 53     } | 
|  | 54     if (path[after_dot + 1] == '/') { | 
|  | 55       // Double dot folowed by a slash. | 
|  | 56       *consumed_len = 3; | 
|  | 57       return DIRECTORY_UP; | 
|  | 58     } | 
|  | 59   } | 
|  | 60 | 
|  | 61   // The dots are followed by something else, not a directory. | 
|  | 62   *consumed_len = 1; | 
|  | 63   return NOT_A_DIRECTORY; | 
|  | 64 } | 
|  | 65 | 
|  | 66 }  // namesapce | 
|  | 67 | 
|  | 68 SourceFileType GetSourceFileType(const SourceFile& file, | 
|  | 69                                  Settings::TargetOS os) { | 
|  | 70   base::StringPiece extension = FindExtension(&file.value()); | 
|  | 71   if (extension == "cc" || extension == "cpp" || extension == "cxx") | 
|  | 72     return SOURCE_CC; | 
|  | 73   if (extension == "h") | 
|  | 74     return SOURCE_H; | 
|  | 75   if (extension == "c") | 
|  | 76     return SOURCE_C; | 
|  | 77 | 
|  | 78   switch (os) { | 
|  | 79     case Settings::MAC: | 
|  | 80       if (extension == "m") | 
|  | 81         return SOURCE_M; | 
|  | 82       if (extension == "mm") | 
|  | 83         return SOURCE_MM; | 
|  | 84       break; | 
|  | 85 | 
|  | 86     case Settings::WIN: | 
|  | 87       if (extension == "rc") | 
|  | 88         return SOURCE_RC; | 
|  | 89       break; | 
|  | 90 | 
|  | 91     default: | 
|  | 92       break; | 
|  | 93   } | 
|  | 94 | 
|  | 95   // TODO(brettw) asm files. | 
|  | 96   // TODO(brettw) weird thing with .S on non-Windows platforms. | 
|  | 97   return SOURCE_UNKNOWN; | 
|  | 98 } | 
|  | 99 | 
|  | 100 const char* GetExtensionForOutputType(Target::OutputType type, | 
|  | 101                                       Settings::TargetOS os) { | 
|  | 102   switch (os) { | 
|  | 103     case Settings::WIN: | 
|  | 104       switch (type) { | 
|  | 105         case Target::NONE: | 
|  | 106           NOTREACHED(); | 
|  | 107           return ""; | 
|  | 108         case Target::EXECUTABLE: | 
|  | 109           return "exe"; | 
|  | 110         case Target::SHARED_LIBRARY: | 
|  | 111           return "dll.lib";  // Extension of import library. | 
|  | 112         case Target::STATIC_LIBRARY: | 
|  | 113           return "lib"; | 
|  | 114         case Target::LOADABLE_MODULE: | 
|  | 115           return "dll";  // TODO(brettw) what's this? | 
|  | 116         default: | 
|  | 117           NOTREACHED(); | 
|  | 118       } | 
|  | 119       break; | 
|  | 120 | 
|  | 121     default: | 
|  | 122       NOTREACHED(); | 
|  | 123   } | 
|  | 124   return ""; | 
|  | 125 } | 
|  | 126 | 
|  | 127 std::string FilePathToUTF8(const base::FilePath& path) { | 
|  | 128 #if defined(OS_WIN) | 
|  | 129   return WideToUTF8(path.value()); | 
|  | 130 #else | 
|  | 131   return path.value(); | 
|  | 132 #endif | 
|  | 133 } | 
|  | 134 | 
|  | 135 base::FilePath UTF8ToFilePath(const base::StringPiece& sp) { | 
|  | 136 #if defined(OS_WIN) | 
|  | 137   return base::FilePath(UTF8ToWide(sp)); | 
|  | 138 #else | 
|  | 139   return base::FilePath(sp.as_string()); | 
|  | 140 #endif | 
|  | 141 } | 
|  | 142 | 
|  | 143 size_t FindExtensionOffset(const std::string& path) { | 
|  | 144   for (int i = static_cast<int>(path.size()); i >= 0; i--) { | 
|  | 145     if (path[i] == '/') | 
|  | 146       break; | 
|  | 147     if (path[i] == '.') | 
|  | 148       return i + 1; | 
|  | 149   } | 
|  | 150   return std::string::npos; | 
|  | 151 } | 
|  | 152 | 
|  | 153 base::StringPiece FindExtension(const std::string* path) { | 
|  | 154   size_t extension_offset = FindExtensionOffset(*path); | 
|  | 155   if (extension_offset == std::string::npos) | 
|  | 156     return base::StringPiece(); | 
|  | 157   return base::StringPiece(&path->data()[extension_offset], | 
|  | 158                            path->size() - extension_offset); | 
|  | 159 } | 
|  | 160 | 
|  | 161 size_t FindFilenameOffset(const std::string& path) { | 
|  | 162   for (int i = static_cast<int>(path.size()) - 1; i >= 0; i--) { | 
|  | 163     if (path[i] == '/') | 
|  | 164       return i + 1; | 
|  | 165   } | 
|  | 166   return 0;  // No filename found means everything was the filename. | 
|  | 167 } | 
|  | 168 | 
|  | 169 base::StringPiece FindFilename(const std::string* path) { | 
|  | 170   size_t filename_offset = FindFilenameOffset(*path); | 
|  | 171   if (filename_offset == 0) | 
|  | 172     return base::StringPiece(*path);  // Everything is the file name. | 
|  | 173   return base::StringPiece(&(*path).data()[filename_offset], | 
|  | 174                            path->size() - filename_offset); | 
|  | 175 } | 
|  | 176 | 
|  | 177 base::StringPiece FindFilenameNoExtension(const std::string* path) { | 
|  | 178   if (path->empty()) | 
|  | 179     return base::StringPiece(); | 
|  | 180   size_t filename_offset = FindFilenameOffset(*path); | 
|  | 181   size_t extension_offset = FindExtensionOffset(*path); | 
|  | 182 | 
|  | 183   size_t name_len; | 
|  | 184   if (extension_offset == std::string::npos) | 
|  | 185     name_len = path->size() - filename_offset; | 
|  | 186   else | 
|  | 187     name_len = extension_offset - filename_offset - 1; | 
|  | 188 | 
|  | 189   return base::StringPiece(&(*path).data()[filename_offset], name_len); | 
|  | 190 } | 
|  | 191 | 
|  | 192 void RemoveFilename(std::string* path) { | 
|  | 193   path->resize(FindFilenameOffset(*path)); | 
|  | 194 } | 
|  | 195 | 
|  | 196 bool EndsWithSlash(const std::string& s) { | 
|  | 197   return !s.empty() && s[s.size() - 1] == '/'; | 
|  | 198 } | 
|  | 199 | 
|  | 200 base::StringPiece FindDir(const std::string* path) { | 
|  | 201   size_t filename_offset = FindFilenameOffset(*path); | 
|  | 202   if (filename_offset == 0u) | 
|  | 203     return base::StringPiece(); | 
|  | 204   return base::StringPiece(path->data(), filename_offset); | 
|  | 205 } | 
|  | 206 | 
|  | 207 bool EnsureStringIsInOutputDir(const SourceDir& dir, | 
|  | 208                                const std::string& str, | 
|  | 209                                const Value& originating, | 
|  | 210                                Err* err) { | 
|  | 211   // The last char of the dir will be a slash. We don't care if the input ends | 
|  | 212   // in a slash or not, so just compare up until there. | 
|  | 213   // | 
|  | 214   // This check will be wrong for all proper prefixes "e.g. "/output" will | 
|  | 215   // match "/out" but we don't really care since this is just a sanity check. | 
|  | 216   const std::string& dir_str = dir.value(); | 
|  | 217   if (str.compare(0, dir_str.length() - 1, dir_str, 0, dir_str.length() - 1) | 
|  | 218       != 0) { | 
|  | 219     *err = Err(originating, "File not inside output directory.", | 
|  | 220         "The given file should be in the output directory. Normally you would " | 
|  | 221         "specify\n\"$target_output_dir/foo\" or " | 
|  | 222         "\"$target_gen_dir/foo\". I interpreted this as\n\"" | 
|  | 223         + str + "\"."); | 
|  | 224     return false; | 
|  | 225   } | 
|  | 226   return true; | 
|  | 227 } | 
|  | 228 | 
|  | 229 std::string InvertDir(const SourceDir& path) { | 
|  | 230   const std::string value = path.value(); | 
|  | 231   if (value.empty()) | 
|  | 232     return std::string(); | 
|  | 233 | 
|  | 234   DCHECK(value[0] == '/'); | 
|  | 235   size_t begin_index = 1; | 
|  | 236 | 
|  | 237   // If the input begins with two slashes, skip over both (this is a | 
|  | 238   // source-relative dir). | 
|  | 239   if (value.size() > 1 && value[1] == '/') | 
|  | 240     begin_index = 2; | 
|  | 241 | 
|  | 242   std::string ret; | 
|  | 243   for (size_t i = begin_index; i < value.size(); i++) { | 
|  | 244     if (value[i] == '/') | 
|  | 245       ret.append("../"); | 
|  | 246   } | 
|  | 247   return ret; | 
|  | 248 } | 
|  | 249 | 
|  | 250 void NormalizePath(std::string* path) { | 
|  | 251   char* pathbuf = path->empty() ? NULL : &(*path)[0]; | 
|  | 252 | 
|  | 253   // top_index is the first character we can modify in the path. Anything | 
|  | 254   // before this indicates where the path is relative to. | 
|  | 255   size_t top_index = 0; | 
|  | 256   bool is_relative = true; | 
|  | 257   if (!path->empty() && pathbuf[0] == '/') { | 
|  | 258     is_relative = false; | 
|  | 259 | 
|  | 260     if (path->size() > 1 && pathbuf[1] == '/') { | 
|  | 261       // Two leading slashes, this is a path into the source dir. | 
|  | 262       top_index = 2; | 
|  | 263     } else { | 
|  | 264       // One leading slash, this is a system-absolute path. | 
|  | 265       top_index = 1; | 
|  | 266     } | 
|  | 267   } | 
|  | 268 | 
|  | 269   size_t dest_i = top_index; | 
|  | 270   for (size_t src_i = top_index; src_i < path->size(); /* nothing */) { | 
|  | 271     if (pathbuf[src_i] == '.') { | 
|  | 272       if (src_i == 0 || pathbuf[src_i - 1] == '/') { | 
|  | 273         // Slash followed by a dot, see if it's something special. | 
|  | 274         size_t consumed_len; | 
|  | 275         switch (ClassifyAfterDot(*path, src_i + 1, &consumed_len)) { | 
|  | 276           case NOT_A_DIRECTORY: | 
|  | 277             // Copy the dot to the output, it means nothing special. | 
|  | 278             pathbuf[dest_i++] = pathbuf[src_i++]; | 
|  | 279             break; | 
|  | 280           case DIRECTORY_CUR: | 
|  | 281             // Current directory, just skip the input. | 
|  | 282             src_i += consumed_len; | 
|  | 283             break; | 
|  | 284           case DIRECTORY_UP: | 
|  | 285             // Back up over previous directory component. If we're already | 
|  | 286             // at the top, preserve the "..". | 
|  | 287             if (dest_i > top_index) { | 
|  | 288               // The previous char was a slash, remove it. | 
|  | 289               dest_i--; | 
|  | 290             } | 
|  | 291 | 
|  | 292             if (dest_i == top_index) { | 
|  | 293               if (is_relative) { | 
|  | 294                 // We're already at the beginning of a relative input, copy the | 
|  | 295                 // ".." and continue. We need the trailing slash if there was | 
|  | 296                 // one before (otherwise we're at the end of the input). | 
|  | 297                 pathbuf[dest_i++] = '.'; | 
|  | 298                 pathbuf[dest_i++] = '.'; | 
|  | 299                 if (consumed_len == 3) | 
|  | 300                   pathbuf[dest_i++] = '/'; | 
|  | 301 | 
|  | 302                 // This also makes a new "root" that we can't delete by going | 
|  | 303                 // up more levels.  Otherwise "../.." would collapse to | 
|  | 304                 // nothing. | 
|  | 305                 top_index = dest_i; | 
|  | 306               } | 
|  | 307               // Otherwise we're at the beginning of an absolute path. Don't | 
|  | 308               // allow ".." to go up another level and just eat it. | 
|  | 309             } else { | 
|  | 310               // Just find the previous slash or the beginning of input. | 
|  | 311               while (dest_i > 0 && pathbuf[dest_i - 1] != '/') | 
|  | 312                 dest_i--; | 
|  | 313             } | 
|  | 314             src_i += consumed_len; | 
|  | 315         } | 
|  | 316       } else { | 
|  | 317         // Dot not preceeded by a slash, copy it literally. | 
|  | 318         pathbuf[dest_i++] = pathbuf[src_i++]; | 
|  | 319       } | 
|  | 320     } else if (pathbuf[src_i] == '/') { | 
|  | 321       if (src_i > 0 && pathbuf[src_i - 1] == '/') { | 
|  | 322         // Two slashes in a row, skip over it. | 
|  | 323         src_i++; | 
|  | 324       } else { | 
|  | 325         // Just one slash, copy it. | 
|  | 326         pathbuf[dest_i++] = pathbuf[src_i++]; | 
|  | 327       } | 
|  | 328     } else { | 
|  | 329       // Input nothing special, just copy it. | 
|  | 330       pathbuf[dest_i++] = pathbuf[src_i++]; | 
|  | 331     } | 
|  | 332   } | 
|  | 333   path->resize(dest_i); | 
|  | 334 } | 
|  | 335 | 
|  | 336 void ConvertPathToSystem(std::string* path) { | 
|  | 337 #if defined(OS_WIN) | 
|  | 338   for (size_t i = 0; i < path->size(); i++) { | 
|  | 339     if ((*path)[i] == '/') | 
|  | 340       (*path)[i] = '\\'; | 
|  | 341   } | 
|  | 342 #endif | 
|  | 343 } | 
|  | 344 | 
|  | 345 std::string PathToSystem(const std::string& path) { | 
|  | 346   std::string ret(path); | 
|  | 347   ConvertPathToSystem(&ret); | 
|  | 348   return ret; | 
|  | 349 } | 
|  | 350 | 
| OLD | NEW | 
|---|