5f5d8dc1a3f3f995bdd5b62d83b7fab4fbd6362a
[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 #endif
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #ifndef _WIN32
31 #include <sys/time.h>
32 #endif
33
34 #include <vector>
35
36 #ifdef _WIN32
37 #include <direct.h>  // _mkdir
38 #endif
39
40 #include "edit_distance.h"
41 #include "metrics.h"
42
43 void Fatal(const char* msg, ...) {
44   va_list ap;
45   fprintf(stderr, "ninja: FATAL: ");
46   va_start(ap, msg);
47   vfprintf(stderr, msg, ap);
48   va_end(ap);
49   fprintf(stderr, "\n");
50 #ifdef WIN32
51   // On Windows, some tools may inject extra threads.
52   // exit() may block on locks held by those threads, so forcibly exit.
53   fflush(stderr);
54   fflush(stdout);
55   ExitProcess(1);
56 #else
57   exit(1);
58 #endif
59 }
60
61 void Warning(const char* msg, ...) {
62   va_list ap;
63   fprintf(stderr, "ninja: WARNING: ");
64   va_start(ap, msg);
65   vfprintf(stderr, msg, ap);
66   va_end(ap);
67   fprintf(stderr, "\n");
68 }
69
70 void Error(const char* msg, ...) {
71   va_list ap;
72   fprintf(stderr, "ninja: ERROR: ");
73   va_start(ap, msg);
74   vfprintf(stderr, msg, ap);
75   va_end(ap);
76   fprintf(stderr, "\n");
77 }
78
79 bool CanonicalizePath(string* path, string* err) {
80   METRIC_RECORD("canonicalize str");
81   int len = path->size();
82   if (!CanonicalizePath(&(*path)[0], &len, err))
83     return false;
84   path->resize(len);
85   return true;
86 }
87
88 bool CanonicalizePath(char* path, int* len, string* err) {
89   // WARNING: this function is performance-critical; please benchmark
90   // any changes you make to it.
91   METRIC_RECORD("canonicalize path");
92   if (*len == 0) {
93     *err = "empty path";
94     return false;
95   }
96
97   const int kMaxPathComponents = 30;
98   char* components[kMaxPathComponents];
99   int component_count = 0;
100
101   char* start = path;
102   char* dst = start;
103   const char* src = start;
104   const char* end = start + *len;
105
106   if (*src == '/') {
107     ++src;
108     ++dst;
109   }
110
111   while (src < end) {
112     const char* sep = (const char*)memchr(src, '/', end - src);
113     if (sep == NULL)
114       sep = end;
115
116     if (*src == '.') {
117       if (sep - src == 1) {
118         // '.' component; eliminate.
119         src += 2;
120         continue;
121       } else if (sep - src == 2 && src[1] == '.') {
122         // '..' component.  Back up if possible.
123         if (component_count > 0) {
124           dst = components[component_count - 1];
125           src += 3;
126           --component_count;
127         } else {
128           while (src <= sep)
129             *dst++ = *src++;
130         }
131         continue;
132       }
133     }
134
135     if (sep > src) {
136       if (component_count == kMaxPathComponents)
137         Fatal("path has too many components");
138       components[component_count] = dst;
139       ++component_count;
140       while (src <= sep) {
141         *dst++ = *src++;
142       }
143     }
144
145     src = sep + 1;
146   }
147
148   *len = dst - start - 1;
149   return true;
150 }
151
152 int MakeDir(const string& path) {
153 #ifdef _WIN32
154   return _mkdir(path.c_str());
155 #else
156   return mkdir(path.c_str(), 0777);
157 #endif
158 }
159
160 int ReadFile(const string& path, string* contents, string* err) {
161   FILE* f = fopen(path.c_str(), "r");
162   if (!f) {
163     err->assign(strerror(errno));
164     return -errno;
165   }
166
167   char buf[64 << 10];
168   size_t len;
169   while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
170     contents->append(buf, len);
171   }
172   if (ferror(f)) {
173     err->assign(strerror(errno));  // XXX errno?
174     contents->clear();
175     fclose(f);
176     return -errno;
177   }
178   fclose(f);
179   return 0;
180 }
181
182 void SetCloseOnExec(int fd) {
183 #ifndef _WIN32
184   int flags = fcntl(fd, F_GETFD);
185   if (flags < 0) {
186     perror("fcntl(F_GETFD)");
187   } else {
188     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
189       perror("fcntl(F_SETFD)");
190   }
191 #else
192   // On Windows, handles must be explicitly marked to be passed to a
193   // spawned process, so there's nothing to do here.
194   NINJA_UNUSED_ARG(fd);
195 #endif  // ! _WIN32
196 }
197
198 int64_t GetTimeMillis() {
199 #ifdef _WIN32
200   // GetTickCount64 is only available on Vista or later.
201   return GetTickCount();
202 #else
203   timeval now;
204   gettimeofday(&now, NULL);
205   return ((int64_t)now.tv_sec * 1000) + (now.tv_usec / 1000);
206 #endif
207 }
208
209 const char* SpellcheckStringV(const string& text,
210                               const vector<const char*>& words) {
211   const bool kAllowReplacements = true;
212   const int kMaxValidEditDistance = 3;
213
214   int min_distance = kMaxValidEditDistance + 1;
215   const char* result = NULL;
216   for (vector<const char*>::const_iterator i = words.begin();
217        i != words.end(); ++i) {
218     int distance = EditDistance(*i, text, kAllowReplacements,
219                                 kMaxValidEditDistance);
220     if (distance < min_distance) {
221       min_distance = distance;
222       result = *i;
223     }
224   }
225   return result;
226 }
227
228 const char* SpellcheckString(const string& text, ...) {
229   va_list ap;
230   va_start(ap, text);
231   vector<const char*> words;
232   const char* word;
233   while ((word = va_arg(ap, const char*)))
234     words.push_back(word);
235   return SpellcheckStringV(text, words);
236 }
237
238 #ifdef WIN32
239 string GetLastErrorString() {
240   DWORD err = GetLastError();
241
242   char* msg_buf;
243   FormatMessageA(
244         FORMAT_MESSAGE_ALLOCATE_BUFFER |
245         FORMAT_MESSAGE_FROM_SYSTEM |
246         FORMAT_MESSAGE_IGNORE_INSERTS,
247         NULL,
248         err,
249         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
250         (char*)&msg_buf,
251         0,
252         NULL);
253   string msg = msg_buf;
254   LocalFree(msg_buf);
255   return msg;
256 }
257 #endif
258
259 static bool islatinalpha(int c) {
260   // isalpha() is locale-dependent.
261   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
262 }
263
264 string StripAnsiEscapeCodes(const string& in) {
265   string stripped;
266   stripped.reserve(in.size());
267
268   for (size_t i = 0; i < in.size(); ++i) {
269     if (in[i] != '\33') {
270       // Not an escape code.
271       stripped.push_back(in[i]);
272       continue;
273     }
274
275     // Only strip CSIs for now.
276     if (i + 1 >= in.size()) break;
277     if (in[i + 1] != '[') continue;  // Not a CSI.
278     i += 2;
279
280     // Skip everything up to and including the next [a-zA-Z].
281     while (i < in.size() && !islatinalpha(in[i]))
282       ++i;
283   }
284   return stripped;
285 }