1 // Copyright 2011 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
30 #include <sys/types.h>
39 #if defined(__APPLE__) || defined(__FreeBSD__)
40 #include <sys/sysctl.h>
41 #elif defined(__SVR4) && defined(__sun)
43 #include <sys/loadavg.h>
44 #elif defined(linux) || defined(__GLIBC__)
45 #include <sys/sysinfo.h>
48 #include "edit_distance.h"
51 void Fatal(const char* msg, ...) {
53 fprintf(stderr, "ninja: fatal: ");
55 vfprintf(stderr, msg, ap);
57 fprintf(stderr, "\n");
59 // On Windows, some tools may inject extra threads.
60 // exit() may block on locks held by those threads, so forcibly exit.
69 void Warning(const char* msg, ...) {
71 fprintf(stderr, "ninja: warning: ");
73 vfprintf(stderr, msg, ap);
75 fprintf(stderr, "\n");
78 void Error(const char* msg, ...) {
80 fprintf(stderr, "ninja: error: ");
82 vfprintf(stderr, msg, ap);
84 fprintf(stderr, "\n");
87 bool CanonicalizePath(string* path, string* err) {
88 METRIC_RECORD("canonicalize str");
89 size_t len = path->size();
93 if (!CanonicalizePath(str, &len, err))
99 bool CanonicalizePath(char* path, size_t* len, string* err) {
100 // WARNING: this function is performance-critical; please benchmark
101 // any changes you make to it.
102 METRIC_RECORD("canonicalize path");
108 const int kMaxPathComponents = 30;
109 char* components[kMaxPathComponents];
110 int component_count = 0;
114 const char* src = start;
115 const char* end = start + *len;
119 // network path starts with //
120 if (*len > 1 && *(src + 1) == '/') {
135 if (src + 1 == end || src[1] == '/') {
136 // '.' component; eliminate.
139 } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
140 // '..' component. Back up if possible.
141 if (component_count > 0) {
142 dst = components[component_count - 1];
159 if (component_count == kMaxPathComponents)
160 Fatal("path has too many components : %s", path);
161 components[component_count] = dst;
164 while (*src != '/' && src != end)
166 *dst++ = *src++; // Copy '/' or final \0 character as well.
170 *err = "path canonicalizes to the empty path";
174 *len = dst - start - 1;
178 int ReadFile(const string& path, string* contents, string* err) {
179 FILE* f = fopen(path.c_str(), "r");
181 err->assign(strerror(errno));
187 while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
188 contents->append(buf, len);
191 err->assign(strerror(errno)); // XXX errno?
200 void SetCloseOnExec(int fd) {
202 int flags = fcntl(fd, F_GETFD);
204 perror("fcntl(F_GETFD)");
206 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
207 perror("fcntl(F_SETFD)");
210 HANDLE hd = (HANDLE) _get_osfhandle(fd);
211 if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
212 fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
218 const char* SpellcheckStringV(const string& text,
219 const vector<const char*>& words) {
220 const bool kAllowReplacements = true;
221 const int kMaxValidEditDistance = 3;
223 int min_distance = kMaxValidEditDistance + 1;
224 const char* result = NULL;
225 for (vector<const char*>::const_iterator i = words.begin();
226 i != words.end(); ++i) {
227 int distance = EditDistance(*i, text, kAllowReplacements,
228 kMaxValidEditDistance);
229 if (distance < min_distance) {
230 min_distance = distance;
237 const char* SpellcheckString(const char* text, ...) {
238 // Note: This takes a const char* instead of a string& because using
239 // va_start() with a reference parameter is undefined behavior.
242 vector<const char*> words;
244 while ((word = va_arg(ap, const char*)))
245 words.push_back(word);
247 return SpellcheckStringV(text, words);
251 string GetLastErrorString() {
252 DWORD err = GetLastError();
256 FORMAT_MESSAGE_ALLOCATE_BUFFER |
257 FORMAT_MESSAGE_FROM_SYSTEM |
258 FORMAT_MESSAGE_IGNORE_INSERTS,
261 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
265 string msg = msg_buf;
270 void Win32Fatal(const char* function) {
271 Fatal("%s: %s", function, GetLastErrorString().c_str());
275 static bool islatinalpha(int c) {
276 // isalpha() is locale-dependent.
277 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
280 string StripAnsiEscapeCodes(const string& in) {
282 stripped.reserve(in.size());
284 for (size_t i = 0; i < in.size(); ++i) {
285 if (in[i] != '\33') {
286 // Not an escape code.
287 stripped.push_back(in[i]);
291 // Only strip CSIs for now.
292 if (i + 1 >= in.size()) break;
293 if (in[i + 1] != '[') continue; // Not a CSI.
296 // Skip everything up to and including the next [a-zA-Z].
297 while (i < in.size() && !islatinalpha(in[i]))
303 int GetProcessorCount() {
306 GetSystemInfo(&info);
307 return info.dwNumberOfProcessors;
309 return sysconf(_SC_NPROCESSORS_ONLN);
313 #if defined(_WIN32) || defined(__CYGWIN__)
314 double GetLoadAverage() {
315 // TODO(nicolas.despres@gmail.com): Find a way to implement it on Windows.
316 // Remember to also update Usage() when this is fixed.
320 double GetLoadAverage() {
321 double loadavg[3] = { 0.0f, 0.0f, 0.0f };
322 if (getloadavg(loadavg, 3) < 0) {
323 // Maybe we should return an error here or the availability of
324 // getloadavg(3) should be checked when ninja is configured.
331 string ElideMiddle(const string& str, size_t width) {
332 const int kMargin = 3; // Space for "...".
334 if (result.size() + kMargin > width) {
335 size_t elide_size = (width - kMargin) / 2;
336 result = result.substr(0, elide_size)
338 + result.substr(result.size() - elide_size, elide_size);
343 bool Truncate(const string& path, size_t size, string* err) {
345 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
346 _S_IREAD | _S_IWRITE);
347 int success = _chsize(fh, size);
350 int success = truncate(path.c_str(), size);
352 // Both truncate() and _chsize() return 0 on success and set errno and return
355 *err = strerror(errno);