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