/* Copyright (C) 2007-2008 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "android/utils/bufprint.h" #include "android/utils/path.h" #include "android/utils/debug.h" #include #include #include #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include "windows.h" # include "shlobj.h" #else # include # include #endif #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) /** USEFUL STRING BUFFER FUNCTIONS **/ char* vbufprint( char* buffer, char* buffer_end, const char* fmt, va_list args ) { int len = vsnprintf( buffer, buffer_end - buffer, fmt, args ); if (len < 0 || buffer+len >= buffer_end) { if (buffer < buffer_end) buffer_end[-1] = 0; return buffer_end; } return buffer + len; } char* bufprint(char* buffer, char* end, const char* fmt, ... ) { va_list args; char* result; va_start(args, fmt); result = vbufprint(buffer, end, fmt, args); va_end(args); return result; } /** USEFUL DIRECTORY SUPPORT ** ** bufprint_app_dir() returns the directory where the emulator binary is located ** ** get_android_home() returns a user-specific directory where the emulator will ** store its writable data (e.g. config files, profiles, etc...). ** on Unix, this is $HOME/.android, on Windows, this is something like ** "%USERPROFILE%/Local Settings/AppData/Android" on XP, and something different ** on Vista. ** ** both functions return a string that must be freed by the caller **/ #ifdef __linux__ char* bufprint_app_dir(char* buff, char* end) { char path[1024]; int len; char* x; len = readlink("/proc/self/exe", path, sizeof(path)); if (len <= 0 || len >= (int)sizeof(path)) goto Fail; path[len] = 0; x = strrchr(path, '/'); if (x == 0) goto Fail; *x = 0; return bufprint(buff, end, "%s", path); Fail: fprintf(stderr,"cannot locate application directory\n"); exit(1); return end; } #elif defined(__APPLE__) /* the following hack is needed in order to build with XCode 3.1 * don't ask me why, but it seems that there were changes in the * GCC compiler that we don't have in our pre-compiled version */ #ifndef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ MAC_OS_X_VERSION_10_4 #endif #import #include char* bufprint_app_dir(char* buff, char* end) { ProcessSerialNumber psn; CFDictionaryRef dict; CFStringRef value; char s[PATH_MAX]; char* x; GetCurrentProcess(&psn); dict = ProcessInformationCopyDictionary(&psn, 0xffffffff); value = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("CFBundleExecutable")); CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8); x = strrchr(s, '/'); if (x == 0) goto fail; *x = 0; return bufprint(buff, end, "%s", s); fail: fprintf(stderr,"cannot locate application directory\n"); exit(1); return end; } #elif defined _WIN32 char* bufprint_app_dir(char* buff, char* end) { char appDir[MAX_PATH]; int len; char* sep; len = GetModuleFileName( 0, appDir, sizeof(appDir)-1 ); if (len == 0) { fprintf(stderr, "PANIC CITY!!\n"); exit(1); } if (len >= (int)sizeof(appDir)) { len = sizeof(appDir)-1; appDir[len] = 0; } sep = strrchr(appDir, '\\'); if (sep) *sep = 0; return bufprint(buff, end, "%s", appDir); } #else char* bufprint_app_dir(char* buff, char* end) { return bufprint(buff, end, "."); } #endif #define _ANDROID_PATH ".android" char* bufprint_config_path(char* buff, char* end) { #ifdef _WIN32 const char* home = getenv("ANDROID_SDK_HOME"); if (home != NULL) { return bufprint(buff, end, "%s\\%s", home, _ANDROID_PATH ); } else { char path[MAX_PATH]; SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path); return bufprint(buff, end, "%s\\%s", path, _ANDROID_PATH ); } #else const char* home = getenv("ANDROID_SDK_HOME"); if (home == NULL) home = getenv("HOME"); if (home == NULL) home = "/tmp"; return bufprint(buff, end, "%s/%s", home, _ANDROID_PATH ); #endif } char* bufprint_config_file(char* buff, char* end, const char* suffix) { char* p; p = bufprint_config_path(buff, end); p = bufprint(p, end, PATH_SEP "%s", suffix); return p; } char* bufprint_temp_dir(char* buff, char* end) { #ifdef _WIN32 char path[MAX_PATH]; DWORD retval; retval = GetTempPath( sizeof(path), path ); if (retval > sizeof(path) || retval == 0) { D( "can't locate TEMP directory" ); strncpy(path, "C:\\Temp", sizeof(path) ); } strncat( path, "\\AndroidEmulator", sizeof(path)-1 ); path_mkdir(path, 0744); return bufprint(buff, end, "%s", path); #else char path[MAX_PATH]; const char* tmppath = getenv("ANDROID_TMP"); if (!tmppath) { const char* user = getenv("USER"); if (user == NULL || user[0] == '\0') user = "unknown"; snprintf(path, sizeof path, "/tmp/android-%s", user); tmppath = path; } mkdir(tmppath, 0744); return bufprint(buff, end, "%s", tmppath ); #endif } char* bufprint_temp_file(char* buff, char* end, const char* suffix) { char* p; p = bufprint_temp_dir(buff, end); p = bufprint(p, end, PATH_SEP "%s", suffix); return p; }