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 <assert.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 
33 #ifndef _WIN32
34 #include <unistd.h>
35 #include <sys/time.h>
36 #endif
37 
38 #include <vector>
39 
40 #if defined(__APPLE__) || defined(__FreeBSD__)
41 #include <sys/sysctl.h>
42 #elif defined(__SVR4) && defined(__sun)
43 #include <unistd.h>
44 #include <sys/loadavg.h>
45 #elif defined(linux) || defined(__GLIBC__)
46 #include <sys/sysinfo.h>
47 #endif
48 
49 #include "edit_distance.h"
50 #include "metrics.h"
51 
52 void Fatal(const char* msg, ...) {
53  va_list ap;
54  fprintf(stderr, "ninja: fatal: ");
55  va_start(ap, msg);
56  vfprintf(stderr, msg, ap);
57  va_end(ap);
58  fprintf(stderr, "\n");
59 #ifdef _WIN32
60  // On Windows, some tools may inject extra threads.
61  // exit() may block on locks held by those threads, so forcibly exit.
62  fflush(stderr);
63  fflush(stdout);
64  ExitProcess(1);
65 #else
66  exit(1);
67 #endif
68 }
69 
70 void Warning(const char* msg, ...) {
71  va_list ap;
72  fprintf(stderr, "ninja: warning: ");
73  va_start(ap, msg);
74  vfprintf(stderr, msg, ap);
75  va_end(ap);
76  fprintf(stderr, "\n");
77 }
78 
79 void Error(const char* msg, ...) {
80  va_list ap;
81  fprintf(stderr, "ninja: error: ");
82  va_start(ap, msg);
83  vfprintf(stderr, msg, ap);
84  va_end(ap);
85  fprintf(stderr, "\n");
86 }
87 
88 bool CanonicalizePath(string* path, string* err) {
89  METRIC_RECORD("canonicalize str");
90  size_t len = path->size();
91  char* str = 0;
92  if (len > 0)
93  str = &(*path)[0];
94  if (!CanonicalizePath(str, &len, err))
95  return false;
96  path->resize(len);
97  return true;
98 }
99 
100 bool CanonicalizePath(char* path, size_t* len, string* err) {
101  // WARNING: this function is performance-critical; please benchmark
102  // any changes you make to it.
103  METRIC_RECORD("canonicalize path");
104  if (*len == 0) {
105  *err = "empty path";
106  return false;
107  }
108 
109  const int kMaxPathComponents = 30;
110  char* components[kMaxPathComponents];
111  int component_count = 0;
112 
113  char* start = path;
114  char* dst = start;
115  const char* src = start;
116  const char* end = start + *len;
117 
118  if (*src == '/') {
119 #ifdef _WIN32
120  // network path starts with //
121  if (*len > 1 && *(src + 1) == '/') {
122  src += 2;
123  dst += 2;
124  } else {
125  ++src;
126  ++dst;
127  }
128 #else
129  ++src;
130  ++dst;
131 #endif
132  }
133 
134  while (src < end) {
135  if (*src == '.') {
136  if (src + 1 == end || src[1] == '/') {
137  // '.' component; eliminate.
138  src += 2;
139  continue;
140  } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
141  // '..' component. Back up if possible.
142  if (component_count > 0) {
143  dst = components[component_count - 1];
144  src += 3;
145  --component_count;
146  } else {
147  *dst++ = *src++;
148  *dst++ = *src++;
149  *dst++ = *src++;
150  }
151  continue;
152  }
153  }
154 
155  if (*src == '/') {
156  src++;
157  continue;
158  }
159 
160  if (component_count == kMaxPathComponents)
161  Fatal("path has too many components : %s", path);
162  components[component_count] = dst;
163  ++component_count;
164 
165  while (*src != '/' && src != end)
166  *dst++ = *src++;
167  *dst++ = *src++; // Copy '/' or final \0 character as well.
168  }
169 
170  if (dst == start) {
171  *err = "path canonicalizes to the empty path";
172  return false;
173  }
174 
175  *len = dst - start - 1;
176  return true;
177 }
178 
179 static inline bool IsKnownShellSafeCharacter(char ch) {
180  if ('A' <= ch && ch <= 'Z') return true;
181  if ('a' <= ch && ch <= 'z') return true;
182  if ('0' <= ch && ch <= '9') return true;
183 
184  switch (ch) {
185  case '_':
186  case '+':
187  case '-':
188  case '.':
189  case '/':
190  return true;
191  default:
192  return false;
193  }
194 }
195 
196 static inline bool IsKnownWin32SafeCharacter(char ch) {
197  switch (ch) {
198  case ' ':
199  case '"':
200  return false;
201  default:
202  return true;
203  }
204 }
205 
206 static inline bool StringNeedsShellEscaping(const string& input) {
207  for (size_t i = 0; i < input.size(); ++i) {
208  if (!IsKnownShellSafeCharacter(input[i])) return true;
209  }
210  return false;
211 }
212 
213 static inline bool StringNeedsWin32Escaping(const string& input) {
214  for (size_t i = 0; i < input.size(); ++i) {
215  if (!IsKnownWin32SafeCharacter(input[i])) return true;
216  }
217  return false;
218 }
219 
220 void GetShellEscapedString(const string& input, string* result) {
221  assert(result);
222 
223  if (!StringNeedsShellEscaping(input)) {
224  result->append(input);
225  return;
226  }
227 
228  const char kQuote = '\'';
229  const char kEscapeSequence[] = "'\\'";
230 
231  result->push_back(kQuote);
232 
233  string::const_iterator span_begin = input.begin();
234  for (string::const_iterator it = input.begin(), end = input.end(); it != end;
235  ++it) {
236  if (*it == kQuote) {
237  result->append(span_begin, it);
238  result->append(kEscapeSequence);
239  span_begin = it;
240  }
241  }
242  result->append(span_begin, input.end());
243  result->push_back(kQuote);
244 }
245 
246 
247 void GetWin32EscapedString(const string& input, string* result) {
248  assert(result);
249  if (!StringNeedsWin32Escaping(input)) {
250  result->append(input);
251  return;
252  }
253 
254  const char kQuote = '"';
255  const char kBackslash = '\\';
256 
257  result->push_back(kQuote);
258  size_t consecutive_backslash_count = 0;
259  string::const_iterator span_begin = input.begin();
260  for (string::const_iterator it = input.begin(), end = input.end(); it != end;
261  ++it) {
262  switch (*it) {
263  case kBackslash:
264  ++consecutive_backslash_count;
265  break;
266  case kQuote:
267  result->append(span_begin, it);
268  result->append(consecutive_backslash_count + 1, kBackslash);
269  span_begin = it;
270  consecutive_backslash_count = 0;
271  break;
272  default:
273  consecutive_backslash_count = 0;
274  break;
275  }
276  }
277  result->append(span_begin, input.end());
278  result->append(consecutive_backslash_count, kBackslash);
279  result->push_back(kQuote);
280 }
281 
282 int ReadFile(const string& path, string* contents, string* err) {
283  FILE* f = fopen(path.c_str(), "r");
284  if (!f) {
285  err->assign(strerror(errno));
286  return -errno;
287  }
288 
289  char buf[64 << 10];
290  size_t len;
291  while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
292  contents->append(buf, len);
293  }
294  if (ferror(f)) {
295  err->assign(strerror(errno)); // XXX errno?
296  contents->clear();
297  fclose(f);
298  return -errno;
299  }
300  fclose(f);
301  return 0;
302 }
303 
304 void SetCloseOnExec(int fd) {
305 #ifndef _WIN32
306  int flags = fcntl(fd, F_GETFD);
307  if (flags < 0) {
308  perror("fcntl(F_GETFD)");
309  } else {
310  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
311  perror("fcntl(F_SETFD)");
312  }
313 #else
314  HANDLE hd = (HANDLE) _get_osfhandle(fd);
315  if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
316  fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str());
317  }
318 #endif // ! _WIN32
319 }
320 
321 
322 const char* SpellcheckStringV(const string& text,
323  const vector<const char*>& words) {
324  const bool kAllowReplacements = true;
325  const int kMaxValidEditDistance = 3;
326 
327  int min_distance = kMaxValidEditDistance + 1;
328  const char* result = NULL;
329  for (vector<const char*>::const_iterator i = words.begin();
330  i != words.end(); ++i) {
331  int distance = EditDistance(*i, text, kAllowReplacements,
332  kMaxValidEditDistance);
333  if (distance < min_distance) {
334  min_distance = distance;
335  result = *i;
336  }
337  }
338  return result;
339 }
340 
341 const char* SpellcheckString(const char* text, ...) {
342  // Note: This takes a const char* instead of a string& because using
343  // va_start() with a reference parameter is undefined behavior.
344  va_list ap;
345  va_start(ap, text);
346  vector<const char*> words;
347  const char* word;
348  while ((word = va_arg(ap, const char*)))
349  words.push_back(word);
350  va_end(ap);
351  return SpellcheckStringV(text, words);
352 }
353 
354 #ifdef _WIN32
355 string GetLastErrorString() {
356  DWORD err = GetLastError();
357 
358  char* msg_buf;
359  FormatMessageA(
360  FORMAT_MESSAGE_ALLOCATE_BUFFER |
361  FORMAT_MESSAGE_FROM_SYSTEM |
362  FORMAT_MESSAGE_IGNORE_INSERTS,
363  NULL,
364  err,
365  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
366  (char*)&msg_buf,
367  0,
368  NULL);
369  string msg = msg_buf;
370  LocalFree(msg_buf);
371  return msg;
372 }
373 
374 void Win32Fatal(const char* function) {
375  Fatal("%s: %s", function, GetLastErrorString().c_str());
376 }
377 #endif
378 
379 static bool islatinalpha(int c) {
380  // isalpha() is locale-dependent.
381  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
382 }
383 
384 string StripAnsiEscapeCodes(const string& in) {
385  string stripped;
386  stripped.reserve(in.size());
387 
388  for (size_t i = 0; i < in.size(); ++i) {
389  if (in[i] != '\33') {
390  // Not an escape code.
391  stripped.push_back(in[i]);
392  continue;
393  }
394 
395  // Only strip CSIs for now.
396  if (i + 1 >= in.size()) break;
397  if (in[i + 1] != '[') continue; // Not a CSI.
398  i += 2;
399 
400  // Skip everything up to and including the next [a-zA-Z].
401  while (i < in.size() && !islatinalpha(in[i]))
402  ++i;
403  }
404  return stripped;
405 }
406 
408 #ifdef _WIN32
409  SYSTEM_INFO info;
410  GetSystemInfo(&info);
411  return info.dwNumberOfProcessors;
412 #else
413  return sysconf(_SC_NPROCESSORS_ONLN);
414 #endif
415 }
416 
417 #if defined(_WIN32) || defined(__CYGWIN__)
418 double GetLoadAverage() {
419  // TODO(nicolas.despres@gmail.com): Find a way to implement it on Windows.
420  // Remember to also update Usage() when this is fixed.
421  return -0.0f;
422 }
423 #else
424 double GetLoadAverage() {
425  double loadavg[3] = { 0.0f, 0.0f, 0.0f };
426  if (getloadavg(loadavg, 3) < 0) {
427  // Maybe we should return an error here or the availability of
428  // getloadavg(3) should be checked when ninja is configured.
429  return -0.0f;
430  }
431  return loadavg[0];
432 }
433 #endif // _WIN32
434 
435 string ElideMiddle(const string& str, size_t width) {
436  const int kMargin = 3; // Space for "...".
437  string result = str;
438  if (result.size() + kMargin > width) {
439  size_t elide_size = (width - kMargin) / 2;
440  result = result.substr(0, elide_size)
441  + "..."
442  + result.substr(result.size() - elide_size, elide_size);
443  }
444  return result;
445 }
446 
447 bool Truncate(const string& path, size_t size, string* err) {
448 #ifdef _WIN32
449  int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
450  _S_IREAD | _S_IWRITE);
451  int success = _chsize(fh, size);
452  _close(fh);
453 #else
454  int success = truncate(path.c_str(), size);
455 #endif
456  // Both truncate() and _chsize() return 0 on success and set errno and return
457  // -1 on failure.
458  if (success < 0) {
459  *err = strerror(errno);
460  return false;
461  }
462  return true;
463 }
static bool StringNeedsShellEscaping(const string &input)
Definition: util.cc:206
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
Definition: util.cc:341
void GetWin32EscapedString(const string &input, string *result)
Definition: util.cc:247
void GetShellEscapedString(const string &input, string *result)
Appends |input| to |*result|, escaping according to the whims of either Bash, or Win32&#39;s CommandLineT...
Definition: util.cc:220
IN IN HANDLE
bool CanonicalizePath(string *path, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
Definition: util.cc:88
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
Definition: util.cc:304
static bool IsKnownWin32SafeCharacter(char ch)
Definition: util.cc:196
double GetLoadAverage()
Definition: util.cc:424
static bool StringNeedsWin32Escaping(const string &input)
Definition: util.cc:213
static bool islatinalpha(int c)
Definition: util.cc:379
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:282
#define METRIC_RECORD(name)
The primary interface to metrics.
Definition: metrics.h:85
static bool IsKnownShellSafeCharacter(char ch)
Definition: util.cc:179
bool Truncate(const string &path, size_t size, string *err)
Truncates a file to the given size.
Definition: util.cc:447
string StripAnsiEscapeCodes(const string &in)
Removes all Ansi escape codes (http://www.termsys.demon.co.uk/vtansi.htm).
Definition: util.cc:384
void Fatal(const char *msg,...)
Log a fatal message and exit.
Definition: util.cc:52
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:322
int GetProcessorCount()
Definition: util.cc:407
IN DWORD
void Warning(const char *msg,...)
Log a warning message.
Definition: util.cc:70
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:79
string ElideMiddle(const string &str, size_t width)
Elide the given string str with &#39;...&#39; in the middle if the length exceeds width.
Definition: util.cc:435