Ninja
util.cc
Go to the documentation of this file.
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 "util.h"
00016 
00017 #ifdef _WIN32
00018 #include <windows.h>
00019 #include <io.h>
00020 #include <share.h>
00021 #endif
00022 
00023 #include <assert.h>
00024 #include <errno.h>
00025 #include <fcntl.h>
00026 #include <stdarg.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 
00033 #ifndef _WIN32
00034 #include <unistd.h>
00035 #include <sys/time.h>
00036 #endif
00037 
00038 #include <vector>
00039 
00040 #if defined(__APPLE__) || defined(__FreeBSD__)
00041 #include <sys/sysctl.h>
00042 #elif defined(__SVR4) && defined(__sun)
00043 #include <unistd.h>
00044 #include <sys/loadavg.h>
00045 #elif defined(linux) || defined(__GLIBC__)
00046 #include <sys/sysinfo.h>
00047 #endif
00048 
00049 #include "edit_distance.h"
00050 #include "metrics.h"
00051 
00052 void Fatal(const char* msg, ...) {
00053   va_list ap;
00054   fprintf(stderr, "ninja: fatal: ");
00055   va_start(ap, msg);
00056   vfprintf(stderr, msg, ap);
00057   va_end(ap);
00058   fprintf(stderr, "\n");
00059 #ifdef _WIN32
00060   // On Windows, some tools may inject extra threads.
00061   // exit() may block on locks held by those threads, so forcibly exit.
00062   fflush(stderr);
00063   fflush(stdout);
00064   ExitProcess(1);
00065 #else
00066   exit(1);
00067 #endif
00068 }
00069 
00070 void Warning(const char* msg, ...) {
00071   va_list ap;
00072   fprintf(stderr, "ninja: warning: ");
00073   va_start(ap, msg);
00074   vfprintf(stderr, msg, ap);
00075   va_end(ap);
00076   fprintf(stderr, "\n");
00077 }
00078 
00079 void Error(const char* msg, ...) {
00080   va_list ap;
00081   fprintf(stderr, "ninja: error: ");
00082   va_start(ap, msg);
00083   vfprintf(stderr, msg, ap);
00084   va_end(ap);
00085   fprintf(stderr, "\n");
00086 }
00087 
00088 bool CanonicalizePath(string* path, string* err) {
00089   METRIC_RECORD("canonicalize str");
00090   size_t len = path->size();
00091   char* str = 0;
00092   if (len > 0)
00093     str = &(*path)[0];
00094   if (!CanonicalizePath(str, &len, err))
00095     return false;
00096   path->resize(len);
00097   return true;
00098 }
00099 
00100 bool CanonicalizePath(char* path, size_t* len, string* err) {
00101   // WARNING: this function is performance-critical; please benchmark
00102   // any changes you make to it.
00103   METRIC_RECORD("canonicalize path");
00104   if (*len == 0) {
00105     *err = "empty path";
00106     return false;
00107   }
00108 
00109   const int kMaxPathComponents = 30;
00110   char* components[kMaxPathComponents];
00111   int component_count = 0;
00112 
00113   char* start = path;
00114   char* dst = start;
00115   const char* src = start;
00116   const char* end = start + *len;
00117 
00118   if (*src == '/') {
00119 #ifdef _WIN32
00120     // network path starts with //
00121     if (*len > 1 && *(src + 1) == '/') {
00122       src += 2;
00123       dst += 2;
00124     } else {
00125       ++src;
00126       ++dst;
00127     }
00128 #else
00129     ++src;
00130     ++dst;
00131 #endif
00132   }
00133 
00134   while (src < end) {
00135     if (*src == '.') {
00136       if (src + 1 == end || src[1] == '/') {
00137         // '.' component; eliminate.
00138         src += 2;
00139         continue;
00140       } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
00141         // '..' component.  Back up if possible.
00142         if (component_count > 0) {
00143           dst = components[component_count - 1];
00144           src += 3;
00145           --component_count;
00146         } else {
00147           *dst++ = *src++;
00148           *dst++ = *src++;
00149           *dst++ = *src++;
00150         }
00151         continue;
00152       }
00153     }
00154 
00155     if (*src == '/') {
00156       src++;
00157       continue;
00158     }
00159 
00160     if (component_count == kMaxPathComponents)
00161       Fatal("path has too many components : %s", path);
00162     components[component_count] = dst;
00163     ++component_count;
00164 
00165     while (*src != '/' && src != end)
00166       *dst++ = *src++;
00167     *dst++ = *src++;  // Copy '/' or final \0 character as well.
00168   }
00169 
00170   if (dst == start) {
00171     *err = "path canonicalizes to the empty path";
00172     return false;
00173   }
00174 
00175   *len = dst - start - 1;
00176   return true;
00177 }
00178 
00179 static inline bool IsKnownShellSafeCharacter(char ch) {
00180   if ('A' <= ch && ch <= 'Z') return true;
00181   if ('a' <= ch && ch <= 'z') return true;
00182   if ('0' <= ch && ch <= '9') return true;
00183 
00184   switch (ch) {
00185     case '_':
00186     case '+':
00187     case '-':
00188     case '.':
00189     case '/':
00190       return true;
00191     default:
00192       return false;
00193   }
00194 }
00195 
00196 static inline bool IsKnownWin32SafeCharacter(char ch) {
00197   switch (ch) {
00198     case ' ':
00199     case '"':
00200       return false;
00201     default:
00202       return true;
00203   }
00204 }
00205 
00206 static inline bool StringNeedsShellEscaping(const string& input) {
00207   for (size_t i = 0; i < input.size(); ++i) {
00208     if (!IsKnownShellSafeCharacter(input[i])) return true;
00209   }
00210   return false;
00211 }
00212 
00213 static inline bool StringNeedsWin32Escaping(const string& input) {
00214   for (size_t i = 0; i < input.size(); ++i) {
00215     if (!IsKnownWin32SafeCharacter(input[i])) return true;
00216   }
00217   return false;
00218 }
00219 
00220 void GetShellEscapedString(const string& input, string* result) {
00221   assert(result);
00222 
00223   if (!StringNeedsShellEscaping(input)) {
00224     result->append(input);
00225     return;
00226   }
00227 
00228   const char kQuote = '\'';
00229   const char kEscapeSequence[] = "'\\'";
00230 
00231   result->push_back(kQuote);
00232 
00233   string::const_iterator span_begin = input.begin();
00234   for (string::const_iterator it = input.begin(), end = input.end(); it != end;
00235        ++it) {
00236     if (*it == kQuote) {
00237       result->append(span_begin, it);
00238       result->append(kEscapeSequence);
00239       span_begin = it;
00240     }
00241   }
00242   result->append(span_begin, input.end());
00243   result->push_back(kQuote);
00244 }
00245 
00246 
00247 void GetWin32EscapedString(const string& input, string* result) {
00248   assert(result);
00249   if (!StringNeedsWin32Escaping(input)) {
00250     result->append(input);
00251     return;
00252   }
00253 
00254   const char kQuote = '"';
00255   const char kBackslash = '\\';
00256 
00257   result->push_back(kQuote);
00258   size_t consecutive_backslash_count = 0;
00259   string::const_iterator span_begin = input.begin();
00260   for (string::const_iterator it = input.begin(), end = input.end(); it != end;
00261        ++it) {
00262     switch (*it) {
00263       case kBackslash:
00264         ++consecutive_backslash_count;
00265         break;
00266       case kQuote:
00267         result->append(span_begin, it);
00268         result->append(consecutive_backslash_count + 1, kBackslash);
00269         span_begin = it;
00270         consecutive_backslash_count = 0;
00271         break;
00272       default:
00273         consecutive_backslash_count = 0;
00274         break;
00275     }
00276   }
00277   result->append(span_begin, input.end());
00278   result->append(consecutive_backslash_count, kBackslash);
00279   result->push_back(kQuote);
00280 }
00281 
00282 int ReadFile(const string& path, string* contents, string* err) {
00283   FILE* f = fopen(path.c_str(), "r");
00284   if (!f) {
00285     err->assign(strerror(errno));
00286     return -errno;
00287   }
00288 
00289   char buf[64 << 10];
00290   size_t len;
00291   while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
00292     contents->append(buf, len);
00293   }
00294   if (ferror(f)) {
00295     err->assign(strerror(errno));  // XXX errno?
00296     contents->clear();
00297     fclose(f);
00298     return -errno;
00299   }
00300   fclose(f);
00301   return 0;
00302 }
00303 
00304 void SetCloseOnExec(int fd) {
00305 #ifndef _WIN32
00306   int flags = fcntl(fd, F_GETFD);
00307   if (flags < 0) {
00308     perror("fcntl(F_GETFD)");
00309   } else {
00310     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
00311       perror("fcntl(F_SETFD)");
00312   }
00313 #else
00314   HANDLE hd = (HANDLE) _get_osfhandle(fd);
00315   if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
00316     fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
00317   }
00318 #endif  // ! _WIN32
00319 }
00320 
00321 
00322 const char* SpellcheckStringV(const string& text,
00323                               const vector<const char*>& words) {
00324   const bool kAllowReplacements = true;
00325   const int kMaxValidEditDistance = 3;
00326 
00327   int min_distance = kMaxValidEditDistance + 1;
00328   const char* result = NULL;
00329   for (vector<const char*>::const_iterator i = words.begin();
00330        i != words.end(); ++i) {
00331     int distance = EditDistance(*i, text, kAllowReplacements,
00332                                 kMaxValidEditDistance);
00333     if (distance < min_distance) {
00334       min_distance = distance;
00335       result = *i;
00336     }
00337   }
00338   return result;
00339 }
00340 
00341 const char* SpellcheckString(const char* text, ...) {
00342   // Note: This takes a const char* instead of a string& because using
00343   // va_start() with a reference parameter is undefined behavior.
00344   va_list ap;
00345   va_start(ap, text);
00346   vector<const char*> words;
00347   const char* word;
00348   while ((word = va_arg(ap, const char*)))
00349     words.push_back(word);
00350   va_end(ap);
00351   return SpellcheckStringV(text, words);
00352 }
00353 
00354 #ifdef _WIN32
00355 string GetLastErrorString() {
00356   DWORD err = GetLastError();
00357 
00358   char* msg_buf;
00359   FormatMessageA(
00360         FORMAT_MESSAGE_ALLOCATE_BUFFER |
00361         FORMAT_MESSAGE_FROM_SYSTEM |
00362         FORMAT_MESSAGE_IGNORE_INSERTS,
00363         NULL,
00364         err,
00365         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00366         (char*)&msg_buf,
00367         0,
00368         NULL);
00369   string msg = msg_buf;
00370   LocalFree(msg_buf);
00371   return msg;
00372 }
00373 
00374 void Win32Fatal(const char* function) {
00375   Fatal("%s: %s", function, GetLastErrorString().c_str());
00376 }
00377 #endif
00378 
00379 static bool islatinalpha(int c) {
00380   // isalpha() is locale-dependent.
00381   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
00382 }
00383 
00384 string StripAnsiEscapeCodes(const string& in) {
00385   string stripped;
00386   stripped.reserve(in.size());
00387 
00388   for (size_t i = 0; i < in.size(); ++i) {
00389     if (in[i] != '\33') {
00390       // Not an escape code.
00391       stripped.push_back(in[i]);
00392       continue;
00393     }
00394 
00395     // Only strip CSIs for now.
00396     if (i + 1 >= in.size()) break;
00397     if (in[i + 1] != '[') continue;  // Not a CSI.
00398     i += 2;
00399 
00400     // Skip everything up to and including the next [a-zA-Z].
00401     while (i < in.size() && !islatinalpha(in[i]))
00402       ++i;
00403   }
00404   return stripped;
00405 }
00406 
00407 int GetProcessorCount() {
00408 #ifdef _WIN32
00409   SYSTEM_INFO info;
00410   GetSystemInfo(&info);
00411   return info.dwNumberOfProcessors;
00412 #else
00413   return sysconf(_SC_NPROCESSORS_ONLN);
00414 #endif
00415 }
00416 
00417 #if defined(_WIN32) || defined(__CYGWIN__)
00418 double GetLoadAverage() {
00419   // TODO(nicolas.despres@gmail.com): Find a way to implement it on Windows.
00420   // Remember to also update Usage() when this is fixed.
00421   return -0.0f;
00422 }
00423 #else
00424 double GetLoadAverage() {
00425   double loadavg[3] = { 0.0f, 0.0f, 0.0f };
00426   if (getloadavg(loadavg, 3) < 0) {
00427     // Maybe we should return an error here or the availability of
00428     // getloadavg(3) should be checked when ninja is configured.
00429     return -0.0f;
00430   }
00431   return loadavg[0];
00432 }
00433 #endif // _WIN32
00434 
00435 string ElideMiddle(const string& str, size_t width) {
00436   const int kMargin = 3;  // Space for "...".
00437   string result = str;
00438   if (result.size() + kMargin > width) {
00439     size_t elide_size = (width - kMargin) / 2;
00440     result = result.substr(0, elide_size)
00441       + "..."
00442       + result.substr(result.size() - elide_size, elide_size);
00443   }
00444   return result;
00445 }
00446 
00447 bool Truncate(const string& path, size_t size, string* err) {
00448 #ifdef _WIN32
00449   int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
00450                   _S_IREAD | _S_IWRITE);
00451   int success = _chsize(fh, size);
00452   _close(fh);
00453 #else
00454   int success = truncate(path.c_str(), size);
00455 #endif
00456   // Both truncate() and _chsize() return 0 on success and set errno and return
00457   // -1 on failure.
00458   if (success < 0) {
00459     *err = strerror(errno);
00460     return false;
00461   }
00462   return true;
00463 }