Home | History | Annotate | Download | only in source
      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