Ninja
util.cc
Go to the documentation of this file.
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 
15 #include "util.h"
16 
17 #ifdef _WIN32
18 #include <windows.h>
19 #include <io.h>
20 #include <share.h>
21 #endif
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 
32 #ifndef _WIN32
33 #include <unistd.h>
34 #include <sys/time.h>
35 #endif
36 
37 #include <vector>
38 
39 #if defined(__APPLE__) || defined(__FreeBSD__)
40 #include <sys/sysctl.h>
41 #elif defined(__SVR4) && defined(__sun)
42 #include <unistd.h>
43 #include <sys/loadavg.h>
44 #elif defined(linux) || defined(__GLIBC__)
45 #include <sys/sysinfo.h>
46 #endif
47 
48 #include "edit_distance.h"
49 #include "metrics.h"
50 
51 void Fatal(const char* msg, ...) {
52  va_list ap;
53  fprintf(stderr, "ninja: fatal: ");
54  va_start(ap, msg);
55  vfprintf(stderr, msg, ap);
56  va_end(ap);
57  fprintf(stderr, "\n");
58 #ifdef _WIN32
59  // On Windows, some tools may inject extra threads.
60  // exit() may block on locks held by those threads, so forcibly exit.
61  fflush(stderr);
62  fflush(stdout);
63  ExitProcess(1);
64 #else
65  exit(1);
66 #endif
67 }
68 
69 void Warning(const char* msg, ...) {
70  va_list ap;
71  fprintf(stderr, "ninja: warning: ");
72  va_start(ap, msg);
73  vfprintf(stderr, msg, ap);
74  va_end(ap);
75  fprintf(stderr, "\n");
76 }
77 
78 void Error(const char* msg, ...) {
79  va_list ap;
80  fprintf(stderr, "ninja: error: ");
81  va_start(ap, msg);
82  vfprintf(stderr, msg, ap);
83  va_end(ap);
84  fprintf(stderr, "\n");
85 }
86 
87 bool CanonicalizePath(string* path, string* err) {
88  METRIC_RECORD("canonicalize str");
89  size_t len = path->size();
90  char* str = 0;
91  if (len > 0)
92  str = &(*path)[0];
93  if (!CanonicalizePath(str, &len, err))
94  return false;
95  path->resize(len);
96  return true;
97 }
98 
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");
103  if (*len == 0) {
104  *err = "empty path";
105  return false;
106  }
107 
108  const int kMaxPathComponents = 30;
109  char* components[kMaxPathComponents];
110  int component_count = 0;
111 
112  char* start = path;
113  char* dst = start;
114  const char* src = start;
115  const char* end = start + *len;
116 
117  if (*src == '/') {
118 #ifdef _WIN32
119  // network path starts with //
120  if (*len > 1 && *(src + 1) == '/') {
121  src += 2;
122  dst += 2;
123  } else {
124  ++src;
125  ++dst;
126  }
127 #else
128  ++src;
129  ++dst;
130 #endif
131  }
132 
133  while (src < end) {
134  if (*src == '.') {
135  if (src + 1 == end || src[1] == '/') {
136  // '.' component; eliminate.
137  src += 2;
138  continue;
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];
143  src += 3;
144  --component_count;
145  } else {
146  *dst++ = *src++;
147  *dst++ = *src++;
148  *dst++ = *src++;
149  }
150  continue;
151  }
152  }
153 
154  if (*src == '/') {
155  src++;
156  continue;
157  }
158 
159  if (component_count == kMaxPathComponents)
160  Fatal("path has too many components : %s", path);
161  components[component_count] = dst;
162  ++component_count;
163 
164  while (*src != '/' && src != end)
165  *dst++ = *src++;
166  *dst++ = *src++; // Copy '/' or final \0 character as well.
167  }
168 
169  if (dst == start) {
170  *err = "path canonicalizes to the empty path";
171  return false;
172  }
173 
174  *len = dst - start - 1;
175  return true;
176 }
177 
178 int ReadFile(const string& path, string* contents, string* err) {
179  FILE* f = fopen(path.c_str(), "r");
180  if (!f) {
181  err->assign(strerror(errno));
182  return -errno;
183  }
184 
185  char buf[64 << 10];
186  size_t len;
187  while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
188  contents->append(buf, len);
189  }
190  if (ferror(f)) {
191  err->assign(strerror(errno)); // XXX errno?
192  contents->clear();
193  fclose(f);
194  return -errno;
195  }
196  fclose(f);
197  return 0;
198 }
199 
200 void SetCloseOnExec(int fd) {
201 #ifndef _WIN32
202  int flags = fcntl(fd, F_GETFD);
203  if (flags < 0) {
204  perror("fcntl(F_GETFD)");
205  } else {
206  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
207  perror("fcntl(F_SETFD)");
208  }
209 #else
210  HANDLE hd = (HANDLE) _get_osfhandle(fd);
211  if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
212  fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
213  }
214 #endif // ! _WIN32
215 }
216 
217 
218 const char* SpellcheckStringV(const string& text,
219  const vector<const char*>& words) {
220  const bool kAllowReplacements = true;
221  const int kMaxValidEditDistance = 3;
222 
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;
231  result = *i;
232  }
233  }
234  return result;
235 }
236 
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.
240  va_list ap;
241  va_start(ap, text);
242  vector<const char*> words;
243  const char* word;
244  while ((word = va_arg(ap, const char*)))
245  words.push_back(word);
246  va_end(ap);
247  return SpellcheckStringV(text, words);
248 }
249 
250 #ifdef _WIN32
251 string GetLastErrorString() {
252  DWORD err = GetLastError();
253 
254  char* msg_buf;
255  FormatMessageA(
256  FORMAT_MESSAGE_ALLOCATE_BUFFER |
257  FORMAT_MESSAGE_FROM_SYSTEM |
258  FORMAT_MESSAGE_IGNORE_INSERTS,
259  NULL,
260  err,
261  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
262  (char*)&msg_buf,
263  0,
264  NULL);
265  string msg = msg_buf;
266  LocalFree(msg_buf);
267  return msg;
268 }
269 
270 void Win32Fatal(const char* function) {
271  Fatal("%s: %s", function, GetLastErrorString().c_str());
272 }
273 #endif
274 
275 static bool islatinalpha(int c) {
276  // isalpha() is locale-dependent.
277  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
278 }
279 
280 string StripAnsiEscapeCodes(const string& in) {
281  string stripped;
282  stripped.reserve(in.size());
283 
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]);
288  continue;
289  }
290 
291  // Only strip CSIs for now.
292  if (i + 1 >= in.size()) break;
293  if (in[i + 1] != '[') continue; // Not a CSI.
294  i += 2;
295 
296  // Skip everything up to and including the next [a-zA-Z].
297  while (i < in.size() && !islatinalpha(in[i]))
298  ++i;
299  }
300  return stripped;
301 }
302 
303 #if defined(linux) || defined(__GLIBC__)
304 int GetProcessorCount() {
305  return get_nprocs();
306 }
307 #elif defined(__APPLE__) || defined(__FreeBSD__)
308 int GetProcessorCount() {
309  int processors;
310  size_t processors_size = sizeof(processors);
311  int name[] = {CTL_HW, HW_NCPU};
312  if (sysctl(name, sizeof(name) / sizeof(int),
313  &processors, &processors_size,
314  NULL, 0) < 0) {
315  return 0;
316  }
317  return processors;
318 }
319 #elif defined(_WIN32)
320 int GetProcessorCount() {
321  SYSTEM_INFO info;
322  GetSystemInfo(&info);
323  return info.dwNumberOfProcessors;
324 }
325 #else
326 // This is what get_nprocs() should be doing in the Linux implementation
327 // above, but in a more standard way.
329  return sysconf(_SC_NPROCESSORS_ONLN);
330 }
331 #endif
332 
333 #if defined(_WIN32) || defined(__CYGWIN__)
334 double GetLoadAverage() {
335  // TODO(nicolas.despres@gmail.com): Find a way to implement it on Windows.
336  // Remember to also update Usage() when this is fixed.
337  return -0.0f;
338 }
339 #else
340 double GetLoadAverage() {
341  double loadavg[3] = { 0.0f, 0.0f, 0.0f };
342  if (getloadavg(loadavg, 3) < 0) {
343  // Maybe we should return an error here or the availability of
344  // getloadavg(3) should be checked when ninja is configured.
345  return -0.0f;
346  }
347  return loadavg[0];
348 }
349 #endif // _WIN32
350 
351 string ElideMiddle(const string& str, size_t width) {
352  const int kMargin = 3; // Space for "...".
353  string result = str;
354  if (result.size() + kMargin > width) {
355  size_t elide_size = (width - kMargin) / 2;
356  result = result.substr(0, elide_size)
357  + "..."
358  + result.substr(result.size() - elide_size, elide_size);
359  }
360  return result;
361 }
362 
363 bool Truncate(const string& path, size_t size, string* err) {
364 #ifdef _WIN32
365  int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
366  _S_IREAD | _S_IWRITE);
367  int success = _chsize(fh, size);
368  _close(fh);
369 #else
370  int success = truncate(path.c_str(), size);
371 #endif
372  // Both truncate() and _chsize() return 0 on success and set errno and return
373  // -1 on failure.
374  if (success < 0) {
375  *err = strerror(errno);
376  return false;
377  }
378  return true;
379 }
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
Definition: util.cc:237
IN IN HANDLE
bool CanonicalizePath(string *path, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
Definition: util.cc:87
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
Definition: util.cc:200
double GetLoadAverage()
Definition: util.cc:340
static bool islatinalpha(int c)
Definition: util.cc:275
int ReadFile(const string &path, string *contents, string *err)
Read a file to a string (in text mode: with CRLF conversion on Windows).
Definition: util.cc:178
#define METRIC_RECORD(name)
The primary interface to metrics.
Definition: metrics.h:85
bool Truncate(const string &path, size_t size, string *err)
Truncates a file to the given size.
Definition: util.cc:363
string StripAnsiEscapeCodes(const string &in)
Removes all Ansi escape codes (http://www.termsys.demon.co.uk/vtansi.htm).
Definition: util.cc:280
void Fatal(const char *msg,...)
Log a fatal message and exit.
Definition: util.cc:51
const char * SpellcheckStringV(const string &text, const vector< const char * > &words)
Given a misspelled string and a list of correct spellings, returns the closest match or NULL if there...
Definition: util.cc:218
int GetProcessorCount()
Definition: util.cc:328
IN DWORD
void Warning(const char *msg,...)
Log a warning message.
Definition: util.cc:69
int EditDistance(const StringPiece &s1, const StringPiece &s2, bool allow_replacements, int max_edit_distance)
void Error(const char *msg,...)
Log an error message.
Definition: util.cc:78
string ElideMiddle(const string &str, size_t width)
Elide the given string str with '...' in the middle if the length exceeds width.
Definition: util.cc:351