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 "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 #if defined(linux) || defined(__GLIBC__) 00304 int GetProcessorCount() { 00305 return get_nprocs(); 00306 } 00307 #elif defined(__APPLE__) || defined(__FreeBSD__) 00308 int GetProcessorCount() { 00309 int processors; 00310 size_t processors_size = sizeof(processors); 00311 int name[] = {CTL_HW, HW_NCPU}; 00312 if (sysctl(name, sizeof(name) / sizeof(int), 00313 &processors, &processors_size, 00314 NULL, 0) < 0) { 00315 return 0; 00316 } 00317 return processors; 00318 } 00319 #elif defined(_WIN32) 00320 int GetProcessorCount() { 00321 SYSTEM_INFO info; 00322 GetSystemInfo(&info); 00323 return info.dwNumberOfProcessors; 00324 } 00325 #else 00326 // This is what get_nprocs() should be doing in the Linux implementation 00327 // above, but in a more standard way. 00328 int GetProcessorCount() { 00329 return sysconf(_SC_NPROCESSORS_ONLN); 00330 } 00331 #endif 00332 00333 #if defined(_WIN32) || defined(__CYGWIN__) 00334 double GetLoadAverage() { 00335 // TODO(nicolas.despres@gmail.com): Find a way to implement it on Windows. 00336 // Remember to also update Usage() when this is fixed. 00337 return -0.0f; 00338 } 00339 #else 00340 double GetLoadAverage() { 00341 double loadavg[3] = { 0.0f, 0.0f, 0.0f }; 00342 if (getloadavg(loadavg, 3) < 0) { 00343 // Maybe we should return an error here or the availability of 00344 // getloadavg(3) should be checked when ninja is configured. 00345 return -0.0f; 00346 } 00347 return loadavg[0]; 00348 } 00349 #endif // _WIN32 00350 00351 string ElideMiddle(const string& str, size_t width) { 00352 const int kMargin = 3; // Space for "...". 00353 string result = str; 00354 if (result.size() + kMargin > width) { 00355 size_t elide_size = (width - kMargin) / 2; 00356 result = result.substr(0, elide_size) 00357 + "..." 00358 + result.substr(result.size() - elide_size, elide_size); 00359 } 00360 return result; 00361 } 00362 00363 bool Truncate(const string& path, size_t size, string* err) { 00364 #ifdef _WIN32 00365 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO, 00366 _S_IREAD | _S_IWRITE); 00367 int success = _chsize(fh, size); 00368 _close(fh); 00369 #else 00370 int success = truncate(path.c_str(), size); 00371 #endif 00372 // Both truncate() and _chsize() return 0 on success and set errno and return 00373 // -1 on failure. 00374 if (success < 0) { 00375 *err = strerror(errno); 00376 return false; 00377 } 00378 return true; 00379 }