370 lines
11 KiB
C++
Executable file
370 lines
11 KiB
C++
Executable file
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef _H_UTILS
|
|
#define _H_UTILS
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS 1
|
|
|
|
#include <direct.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
|
|
// VS vs MINGW specific includes
|
|
#ifdef USE_VS_CRT
|
|
#include <crtdbg.h> // for _ASSERT
|
|
#else
|
|
#define _ASSERT(x) // undef
|
|
#endif
|
|
|
|
extern bool gIsDebug;
|
|
extern bool gIsConsole;
|
|
|
|
// An array that knows its own size. Not dynamically resizable.
|
|
template <class T> class CArray {
|
|
T* mPtr;
|
|
int mSize;
|
|
public:
|
|
explicit CArray(int size) {
|
|
mSize = size;
|
|
mPtr = new T[size];
|
|
}
|
|
|
|
~CArray() {
|
|
if (mPtr != NULL) {
|
|
delete[] mPtr;
|
|
mPtr = NULL;
|
|
}
|
|
mSize = 0;
|
|
}
|
|
|
|
T& operator[](int i) {
|
|
_ASSERT(i >= 0 && i < mSize);
|
|
return mPtr[i];
|
|
}
|
|
|
|
int size() const {
|
|
return mSize;
|
|
}
|
|
};
|
|
|
|
// A simple string class wrapper.
|
|
class CString {
|
|
protected:
|
|
char *mStr;
|
|
public:
|
|
CString() { mStr = NULL; }
|
|
CString(const CString &str) { mStr = NULL; set(str.mStr); }
|
|
explicit CString(const char *str) { mStr = NULL; set(str); }
|
|
CString(const char *start, size_t length) { mStr = NULL; set(start, length); }
|
|
|
|
CString& operator=(const CString &str) {
|
|
return set(str.cstr());
|
|
}
|
|
|
|
CString& set(const char *str) {
|
|
if (str != mStr) {
|
|
_free();
|
|
if (str != NULL) {
|
|
mStr = _strdup(str);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CString& set(const char *start, size_t length) {
|
|
_free();
|
|
if (start != NULL) {
|
|
mStr = (char *)malloc(length + 1);
|
|
strncpy(mStr, start, length);
|
|
mStr[length] = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CString& setv(const char *str, va_list ap) {
|
|
_free();
|
|
// _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
|
|
// Instead we'll iterate till we have enough space to generate the string.
|
|
size_t len = strlen(str) + 1024;
|
|
mStr = (char *)malloc(len);
|
|
strcpy(mStr, str); // provide a default in case vsnprintf totally fails
|
|
for (int guard = 0; guard < 10; guard++) {
|
|
int ret = vsnprintf(mStr, len, str, ap);
|
|
if (ret == -1) {
|
|
// Some implementations don't give the proper size needed
|
|
// so double the space and try again.
|
|
len *= 2;
|
|
} else if (ret >= len) {
|
|
len = ret + 1;
|
|
} else {
|
|
// There was enough space to write.
|
|
break;
|
|
}
|
|
mStr = (char *)realloc((void *)mStr, len);
|
|
strcpy(mStr, str); // provide a default in case vsnprintf totally fails
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CString& setf(const char *str, ...) {
|
|
_free();
|
|
va_list ap;
|
|
va_start(ap, str);
|
|
setv(str, ap);
|
|
va_end(ap);
|
|
return *this;
|
|
}
|
|
|
|
virtual ~CString() { _free(); }
|
|
|
|
// Returns the C string owned by this CString. It will be
|
|
// invalid as soon as this CString is deleted or out of scope.
|
|
const char * cstr() const {
|
|
return mStr;
|
|
}
|
|
|
|
bool isEmpty() const {
|
|
return mStr == NULL || *mStr == 0;
|
|
}
|
|
|
|
size_t length() const {
|
|
return mStr == NULL ? 0 : strlen(mStr);
|
|
}
|
|
|
|
CString& add(const char *str) {
|
|
if (mStr == NULL) {
|
|
set(str);
|
|
} else {
|
|
mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(str) + 1);
|
|
strcat(mStr, str);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CString& add(const char *str, int length) {
|
|
if (mStr == NULL) {
|
|
set(str, length);
|
|
} else {
|
|
size_t l1 = strlen(mStr);
|
|
mStr = (char *)realloc((void *)mStr, l1 + length + 1);
|
|
strncpy(mStr + l1, str, length);
|
|
mStr[l1 + length] = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CArray<CString> * split(char sep) const {
|
|
if (mStr == NULL) {
|
|
return new CArray<CString>(0);
|
|
}
|
|
const char *last = NULL;
|
|
int n = 0;
|
|
for (const char *s = mStr; *s; s++) {
|
|
if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
|
|
n++;
|
|
last = s;
|
|
}
|
|
}
|
|
|
|
CArray<CString> *result = new CArray<CString>(n);
|
|
last = NULL;
|
|
n = 0;
|
|
for (const char *s = mStr; *s; s++) {
|
|
if (*s == sep) {
|
|
if (s != mStr && (last == NULL || s > last+1)) {
|
|
const char *start = last ? last : mStr;
|
|
(*result)[n++].set(start, s-start);
|
|
}
|
|
last = s+1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Sets the string to the message matching Win32 GetLastError.
|
|
// If message is non-null, it is prepended to the last error string.
|
|
CString& setLastWin32Error(const char *message) {
|
|
DWORD err = GetLastError();
|
|
LPSTR errStr;
|
|
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, /* lpSource */
|
|
err, /* dwMessageId */
|
|
0, /* dwLanguageId */
|
|
(LPSTR)&errStr, /* lpBuffer */
|
|
0, /* nSize */
|
|
NULL) != 0) { /* va_list args */
|
|
if (message == NULL) {
|
|
setf("[%d] %s", err, errStr);
|
|
} else {
|
|
setf("%s[%d] %s", message, err, errStr);
|
|
}
|
|
LocalFree(errStr);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
void _free() {
|
|
if (mStr != NULL) {
|
|
free((void *)mStr);
|
|
mStr = NULL;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
// A simple path class wrapper.
|
|
class CPath : public CString {
|
|
public:
|
|
CPath() : CString() { }
|
|
CPath(const CString &str) : CString(str) { }
|
|
CPath(const CPath &str) : CString(str) { }
|
|
explicit CPath(const char *str) : CString(str) { }
|
|
CPath(const char *start, int length) : CString(start, length) { }
|
|
|
|
CPath& operator=(const CPath &str) {
|
|
set(str.cstr());
|
|
return *this;
|
|
}
|
|
|
|
// Appends a path segment, adding a \ as necessary.
|
|
CPath& addPath(const CString &s) {
|
|
return addPath(s.cstr());
|
|
}
|
|
|
|
// Appends a path segment, adding a \ as necessary.
|
|
CPath& addPath(const char *s) {
|
|
_ASSERT(s != NULL);
|
|
if (s != NULL && s[0] != 0) {
|
|
size_t n = length();
|
|
if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
|
|
add(s);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Returns true if file exist and is not a directory.
|
|
// There's no garantee we have rights to access it.
|
|
bool fileExists() const {
|
|
if (mStr == NULL) return false;
|
|
DWORD attribs = GetFileAttributesA(mStr);
|
|
return attribs != INVALID_FILE_ATTRIBUTES &&
|
|
!(attribs & FILE_ATTRIBUTE_DIRECTORY);
|
|
}
|
|
|
|
// Returns true if file exist and is a directory.
|
|
// There's no garantee we have rights to access it.
|
|
bool dirExists() const {
|
|
if (mStr == NULL) return false;
|
|
DWORD attribs = GetFileAttributesA(mStr);
|
|
return attribs != INVALID_FILE_ATTRIBUTES &&
|
|
(attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
}
|
|
|
|
// Returns a copy of the directory portion of the path, if any
|
|
CPath dirName() const {
|
|
CPath result;
|
|
if (mStr != NULL) {
|
|
char *pos = strrchr(mStr, '\\');
|
|
if (pos != NULL) {
|
|
result.set(mStr, pos - mStr);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Returns a pointer to the baseName part of the path.
|
|
// It becomes invalid if the path changes.
|
|
const char * baseName() const {
|
|
if (mStr != NULL) {
|
|
char *pos = strrchr(mStr, '\\');
|
|
if (pos != NULL) {
|
|
return pos + 1;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// If the path ends with the given searchName, replace in-place by the new name
|
|
void replaceName(const char *searchName, const char* newName) {
|
|
if (mStr == NULL) return;
|
|
size_t n = length();
|
|
size_t sn = strlen(searchName);
|
|
if (n < sn) return;
|
|
// if mStr ends with searchName
|
|
if (strcmp(mStr + n - sn, searchName) == 0) {
|
|
size_t sn2 = strlen(newName);
|
|
if (sn2 > sn) {
|
|
mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
|
|
}
|
|
strcpy(mStr + n - sn, newName);
|
|
mStr[n + sn2 - sn] = 0;
|
|
}
|
|
}
|
|
|
|
// Returns a copy of this path as a DOS short path in the destination.
|
|
// Returns true if the Win32 getShortPathName method worked.
|
|
// In case of error, returns false and does not change the destination.
|
|
// It's OK to invoke this->toShortPath(this).
|
|
bool toShortPath(CPath *dest) {
|
|
const char *longPath = mStr;
|
|
if (mStr == NULL) return false;
|
|
|
|
DWORD lenShort = (DWORD)strlen(longPath) + 1; // GetShortPathName deals with DWORDs
|
|
char * shortPath = (char *)malloc(lenShort);
|
|
|
|
DWORD length = GetShortPathName(longPath, shortPath, lenShort);
|
|
if (length > lenShort) {
|
|
// The buffer wasn't big enough, this is the size to use.
|
|
free(shortPath);
|
|
lenShort = length;
|
|
shortPath = (char *)malloc(length);
|
|
length = GetShortPathName(longPath, shortPath, lenShort);
|
|
}
|
|
|
|
if (length != 0) dest->set(shortPath);
|
|
|
|
free(shortPath);
|
|
return length != 0;
|
|
}
|
|
};
|
|
|
|
// Displays a message in an ok+info dialog box.
|
|
void msgBox(const char* text, ...);
|
|
|
|
// Displays GetLastError prefixed with a description in an error dialog box
|
|
void displayLastError(const char *description, ...);
|
|
|
|
// Executes the command line. Does not wait for the program to finish.
|
|
// The return code is from CreateProcess (0 means failure), not the running app.
|
|
int execNoWait(const char *app, const char *params, const char *workDir);
|
|
|
|
// Executes command, waits for completion and returns exit code.
|
|
// As indicated in MSDN for CreateProcess, callers should double-quote the program name
|
|
// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
|
|
int execWait(const char *cmd);
|
|
|
|
bool getModuleDir(CPath *outDir);
|
|
|
|
#endif /* _WIN32 */
|
|
#endif /* _H_UTILS */
|