Merge pull request #647 from bmeurer/SimplifyGetProcessorCount
[platform/upstream/ninja.git] / src / util.cc
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 int GetProcessorCount() {
304 #ifdef _WIN32
305   SYSTEM_INFO info;
306   GetSystemInfo(&info);
307   return info.dwNumberOfProcessors;
308 #else
309   return sysconf(_SC_NPROCESSORS_ONLN);
310 #endif
311 }
312
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.
317   return -0.0f;
318 }
319 #else
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.
325     return -0.0f;
326   }
327   return loadavg[0];
328 }
329 #endif // _WIN32
330
331 string ElideMiddle(const string& str, size_t width) {
332   const int kMargin = 3;  // Space for "...".
333   string result = str;
334   if (result.size() + kMargin > width) {
335     size_t elide_size = (width - kMargin) / 2;
336     result = result.substr(0, elide_size)
337       + "..."
338       + result.substr(result.size() - elide_size, elide_size);
339   }
340   return result;
341 }
342
343 bool Truncate(const string& path, size_t size, string* err) {
344 #ifdef _WIN32
345   int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
346                   _S_IREAD | _S_IWRITE);
347   int success = _chsize(fh, size);
348   _close(fh);
349 #else
350   int success = truncate(path.c_str(), size);
351 #endif
352   // Both truncate() and _chsize() return 0 on success and set errno and return
353   // -1 on failure.
354   if (success < 0) {
355     *err = strerror(errno);
356     return false;
357   }
358   return true;
359 }