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 #endif
00020 
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <stdarg.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <sys/stat.h>
00028 #include <sys/types.h>
00029 
00030 #ifndef _WIN32
00031 #include <sys/time.h>
00032 #endif
00033 
00034 #include <vector>
00035 
00036 #ifdef _WIN32
00037 #include <direct.h>  // _mkdir
00038 #endif
00039 
00040 void Fatal(const char* msg, ...) {
00041   va_list ap;
00042   fprintf(stderr, "ninja: FATAL: ");
00043   va_start(ap, msg);
00044   vfprintf(stderr, msg, ap);
00045   va_end(ap);
00046   fprintf(stderr, "\n");
00047   exit(1);
00048 }
00049 
00050 void Warning(const char* msg, ...) {
00051   va_list ap;
00052   fprintf(stderr, "ninja: WARNING: ");
00053   va_start(ap, msg);
00054   vfprintf(stderr, msg, ap);
00055   va_end(ap);
00056   fprintf(stderr, "\n");
00057 }
00058 
00059 void Error(const char* msg, ...) {
00060   va_list ap;
00061   fprintf(stderr, "ninja: error: ");
00062   va_start(ap, msg);
00063   vfprintf(stderr, msg, ap);
00064   va_end(ap);
00065   fprintf(stderr, "\n");
00066 }
00067 
00068 bool CanonicalizePath(string* path, string* err) {
00069   // WARNING: this function is performance-critical; please benchmark
00070   // any changes you make to it.
00071 
00072   if (path->empty()) {
00073     *err = "empty path";
00074     return false;
00075   }
00076 
00077   const int kMaxPathComponents = 30;
00078   char* components[kMaxPathComponents];
00079   int component_count = 0;
00080 
00081   char* start = &(*path)[0];
00082   char* dst = start;
00083   const char* src = start;
00084   const char* end = start + path->size();
00085 
00086   if (*src == '/') {
00087     ++src;
00088     ++dst;
00089   }
00090 
00091   while (src < end) {
00092     const char* sep = (const char*)memchr(src, '/', end - src);
00093     if (sep == NULL)
00094       sep = end;
00095 
00096     if (*src == '.') {
00097       if (sep - src == 1) {
00098         // '.' component; eliminate.
00099         src += 2;
00100         continue;
00101       } else if (sep - src == 2 && src[1] == '.') {
00102         // '..' component.  Back up if possible.
00103         if (component_count > 0) {
00104           dst = components[component_count - 1];
00105           src += 3;
00106           --component_count;
00107         } else {
00108           while (src <= sep)
00109             *dst++ = *src++;
00110         }
00111         continue;
00112       }
00113     }
00114 
00115     if (sep > src) {
00116       if (component_count == kMaxPathComponents)
00117         Fatal("path has too many components");
00118       components[component_count] = dst;
00119       ++component_count;
00120       while (src <= sep) {
00121         *dst++ = *src++;
00122       }
00123     }
00124 
00125     src = sep + 1;
00126   }
00127 
00128   path->resize(dst - path->c_str() - 1);
00129   return true;
00130 }
00131 
00132 int MakeDir(const string& path) {
00133 #ifdef _WIN32
00134   return _mkdir(path.c_str());
00135 #else
00136   return mkdir(path.c_str(), 0777);
00137 #endif
00138 }
00139 
00140 int ReadFile(const string& path, string* contents, string* err) {
00141   FILE* f = fopen(path.c_str(), "r");
00142   if (!f) {
00143     err->assign(strerror(errno));
00144     return -errno;
00145   }
00146 
00147   char buf[64 << 10];
00148   size_t len;
00149   while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
00150     contents->append(buf, len);
00151   }
00152   if (ferror(f)) {
00153     err->assign(strerror(errno));  // XXX errno?
00154     contents->clear();
00155     fclose(f);
00156     return -errno;
00157   }
00158   fclose(f);
00159   return 0;
00160 }
00161 
00162 void SetCloseOnExec(int fd) {
00163 #ifndef _WIN32
00164   int flags = fcntl(fd, F_GETFD);
00165   if (flags < 0) {
00166     perror("fcntl(F_GETFD)");
00167   } else {
00168     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
00169       perror("fcntl(F_SETFD)");
00170   }
00171 #else
00172   // On Windows, handles must be explicitly marked to be passed to a
00173   // spawned process, so there's nothing to do here.
00174 #endif  // WIN32
00175 }
00176 
00177 int64_t GetTimeMillis() {
00178 #ifdef _WIN32
00179   // GetTickCount64 is only available on Vista or later.
00180   return GetTickCount();
00181 #else
00182   timeval now;
00183   gettimeofday(&now, NULL);
00184   return ((int64_t)now.tv_sec * 1000) + (now.tv_usec / 1000);
00185 #endif
00186 }