1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _H_UTILS 18 #define _H_UTILS 19 20 #ifdef _WIN32 21 22 #define _CRT_SECURE_NO_WARNINGS 1 23 24 #include <direct.h> 25 #include <stdio.h> 26 #include <stdarg.h> 27 #include <string.h> 28 #include <windows.h> 29 30 // VS vs MINGW specific includes 31 #ifdef USE_VS_CRT 32 #include <crtdbg.h> // for _ASSERT 33 #else 34 #define _ASSERT(x) // undef 35 #endif 36 37 extern bool gIsDebug; 38 extern bool gIsConsole; 39 40 // An array that knows its own size. Not dynamically resizable. 41 template <class T> class CArray { 42 T* mPtr; 43 int mSize; 44 public: 45 explicit CArray(int size) { 46 mSize = size; 47 mPtr = new T[size]; 48 } 49 50 ~CArray() { 51 if (mPtr != NULL) { 52 delete[] mPtr; 53 mPtr = NULL; 54 } 55 mSize = 0; 56 } 57 58 T& operator[](int i) { 59 _ASSERT(i >= 0 && i < mSize); 60 return mPtr[i]; 61 } 62 63 int size() const { 64 return mSize; 65 } 66 }; 67 68 // A simple string class wrapper. 69 class CString { 70 protected: 71 char *mStr; 72 public: 73 CString() { mStr = NULL; } 74 CString(const CString &str) { mStr = NULL; set(str.mStr); } 75 explicit CString(const char *str) { mStr = NULL; set(str); } 76 CString(const char *start, size_t length) { mStr = NULL; set(start, length); } 77 78 CString& operator=(const CString &str) { 79 return set(str.cstr()); 80 } 81 82 CString& set(const char *str) { 83 if (str != mStr) { 84 _free(); 85 if (str != NULL) { 86 mStr = _strdup(str); 87 } 88 } 89 return *this; 90 } 91 92 CString& set(const char *start, size_t length) { 93 _free(); 94 if (start != NULL) { 95 mStr = (char *)malloc(length + 1); 96 strncpy(mStr, start, length); 97 mStr[length] = 0; 98 } 99 return *this; 100 } 101 102 CString& setv(const char *str, va_list ap) { 103 _free(); 104 // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW. 105 // Instead we'll iterate till we have enough space to generate the string. 106 size_t len = strlen(str) + 1024; 107 mStr = (char *)malloc(len); 108 strcpy(mStr, str); // provide a default in case vsnprintf totally fails 109 for (int guard = 0; guard < 10; guard++) { 110 int ret = vsnprintf(mStr, len, str, ap); 111 if (ret == -1) { 112 // Some implementations don't give the proper size needed 113 // so double the space and try again. 114 len *= 2; 115 } else if (ret >= len) { 116 len = ret + 1; 117 } else { 118 // There was enough space to write. 119 break; 120 } 121 mStr = (char *)realloc((void *)mStr, len); 122 strcpy(mStr, str); // provide a default in case vsnprintf totally fails 123 } 124 return *this; 125 } 126 127 CString& setf(const char *str, ...) { 128 _free(); 129 va_list ap; 130 va_start(ap, str); 131 setv(str, ap); 132 va_end(ap); 133 return *this; 134 } 135 136 virtual ~CString() { _free(); } 137 138 // Returns the C string owned by this CString. It will be 139 // invalid as soon as this CString is deleted or out of scope. 140 const char * cstr() const { 141 return mStr; 142 } 143 144 bool isEmpty() const { 145 return mStr == NULL || *mStr == 0; 146 } 147 148 size_t length() const { 149 return mStr == NULL ? 0 : strlen(mStr); 150 } 151 152 CString& add(const char *str) { 153 if (mStr == NULL) { 154 set(str); 155 } else { 156 mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1); 157 strcat(mStr, str); 158 } 159 return *this; 160 } 161 162 CString& add(const char *str, int length) { 163 if (mStr == NULL) { 164 set(str, length); 165 } else { 166 size_t l1 = strlen(mStr); 167 mStr = (char *)realloc((void *)mStr, l1 + length + 1); 168 strncpy(mStr + l1, str, length); 169 mStr[l1 + length] = 0; 170 } 171 return *this; 172 } 173 174 CArray<CString> * split(char sep) const { 175 if (mStr == NULL) { 176 return new CArray<CString>(0); 177 } 178 const char *last = NULL; 179 int n = 0; 180 for (const char *s = mStr; *s; s++) { 181 if (*s == sep && s != mStr && (last == NULL || s > last+1)) { 182 n++; 183 last = s; 184 } 185 } 186 187 CArray<CString> *result = new CArray<CString>(n); 188 last = NULL; 189 n = 0; 190 for (const char *s = mStr; *s; s++) { 191 if (*s == sep) { 192 if (s != mStr && (last == NULL || s > last+1)) { 193 const char *start = last ? last : mStr; 194 (*result)[n++].set(start, s-start); 195 } 196 last = s+1; 197 } 198 } 199 200 return result; 201 } 202 203 // Sets the string to the message matching Win32 GetLastError. 204 // If message is non-null, it is prepended to the last error string. 205 CString& setLastWin32Error(const char *message) { 206 DWORD err = GetLastError(); 207 LPSTR errStr; 208 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */ 209 FORMAT_MESSAGE_FROM_SYSTEM, 210 NULL, /* lpSource */ 211 err, /* dwMessageId */ 212 0, /* dwLanguageId */ 213 (LPSTR)&errStr, /* lpBuffer */ 214 0, /* nSize */ 215 NULL) != 0) { /* va_list args */ 216 if (message == NULL) { 217 setf("[%d] %s", err, errStr); 218 } else { 219 setf("%s[%d] %s", message, err, errStr); 220 } 221 LocalFree(errStr); 222 } 223 return *this; 224 } 225 226 private: 227 void _free() { 228 if (mStr != NULL) { 229 free((void *)mStr); 230 mStr = NULL; 231 } 232 } 233 234 }; 235 236 // A simple path class wrapper. 237 class CPath : public CString { 238 public: 239 CPath() : CString() { } 240 CPath(const CString &str) : CString(str) { } 241 CPath(const CPath &str) : CString(str) { } 242 explicit CPath(const char *str) : CString(str) { } 243 CPath(const char *start, int length) : CString(start, length) { } 244 245 CPath& operator=(const CPath &str) { 246 set(str.cstr()); 247 return *this; 248 } 249 250 // Appends a path segment, adding a \ as necessary. 251 CPath& addPath(const CString &s) { 252 return addPath(s.cstr()); 253 } 254 255 // Appends a path segment, adding a \ as necessary. 256 CPath& addPath(const char *s) { 257 _ASSERT(s != NULL); 258 if (s != NULL && s[0] != 0) { 259 size_t n = length(); 260 if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\"); 261 add(s); 262 } 263 return *this; 264 } 265 266 // Returns true if file exist and is not a directory. 267 // There's no garantee we have rights to access it. 268 bool fileExists() const { 269 if (mStr == NULL) return false; 270 DWORD attribs = GetFileAttributesA(mStr); 271 return attribs != INVALID_FILE_ATTRIBUTES && 272 !(attribs & FILE_ATTRIBUTE_DIRECTORY); 273 } 274 275 // Returns true if file exist and is a directory. 276 // There's no garantee we have rights to access it. 277 bool dirExists() const { 278 if (mStr == NULL) return false; 279 DWORD attribs = GetFileAttributesA(mStr); 280 return attribs != INVALID_FILE_ATTRIBUTES && 281 (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; 282 } 283 284 // Returns a copy of the directory portion of the path, if any 285 CPath dirName() const { 286 CPath result; 287 if (mStr != NULL) { 288 char *pos = strrchr(mStr, '\\'); 289 if (pos != NULL) { 290 result.set(mStr, pos - mStr); 291 } 292 } 293 return result; 294 } 295 296 // Returns a pointer to the baseName part of the path. 297 // It becomes invalid if the path changes. 298 const char * baseName() const { 299 if (mStr != NULL) { 300 char *pos = strrchr(mStr, '\\'); 301 if (pos != NULL) { 302 return pos + 1; 303 } 304 } 305 return NULL; 306 } 307 308 // If the path ends with the given searchName, replace in-place by the new name 309 void replaceName(const char *searchName, const char* newName) { 310 if (mStr == NULL) return; 311 size_t n = length(); 312 size_t sn = strlen(searchName); 313 if (n < sn) return; 314 // if mStr ends with searchName 315 if (strcmp(mStr + n - sn, searchName) == 0) { 316 size_t sn2 = strlen(newName); 317 if (sn2 > sn) { 318 mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1); 319 } 320 strcpy(mStr + n - sn, newName); 321 mStr[n + sn2 - sn] = 0; 322 } 323 } 324 325 // Returns a copy of this path as a DOS short path in the destination. 326 // Returns true if the Win32 getShortPathName method worked. 327 // In case of error, returns false and does not change the destination. 328 // It's OK to invoke this->toShortPath(this). 329 bool toShortPath(CPath *dest) { 330 const char *longPath = mStr; 331 if (mStr == NULL) return false; 332 333 DWORD lenShort = (DWORD)strlen(longPath) + 1; // GetShortPathName deals with DWORDs 334 char * shortPath = (char *)malloc(lenShort); 335 336 DWORD length = GetShortPathName(longPath, shortPath, lenShort); 337 if (length > lenShort) { 338 // The buffer wasn't big enough, this is the size to use. 339 free(shortPath); 340 lenShort = length; 341 shortPath = (char *)malloc(length); 342 length = GetShortPathName(longPath, shortPath, lenShort); 343 } 344 345 if (length != 0) dest->set(shortPath); 346 347 free(shortPath); 348 return length != 0; 349 } 350 }; 351 352 // Displays a message in an ok+info dialog box. 353 void msgBox(const char* text, ...); 354 355 // Displays GetLastError prefixed with a description in an error dialog box 356 void displayLastError(const char *description, ...); 357 358 // Executes the command line. Does not wait for the program to finish. 359 // The return code is from CreateProcess (0 means failure), not the running app. 360 int execNoWait(const char *app, const char *params, const char *workDir); 361 362 // Executes command, waits for completion and returns exit code. 363 // As indicated in MSDN for CreateProcess, callers should double-quote the program name 364 // e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2"; 365 int execWait(const char *cmd); 366 367 bool getModuleDir(CPath *outDir); 368 369 #endif /* _WIN32 */ 370 #endif /* _H_UTILS */ 371