1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 13 #include "android/utils/bufprint.h" 14 #include "android/utils/path.h" 15 #include "android/utils/debug.h" 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #ifdef _WIN32 21 # define WIN32_LEAN_AND_MEAN 22 # include "windows.h" 23 # include "shlobj.h" 24 #else 25 # include <unistd.h> 26 # include <sys/stat.h> 27 #endif 28 29 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 30 31 32 /** USEFUL STRING BUFFER FUNCTIONS 33 **/ 34 35 char* 36 vbufprint( char* buffer, 37 char* buffer_end, 38 const char* fmt, 39 va_list args ) 40 { 41 int len = vsnprintf( buffer, buffer_end - buffer, fmt, args ); 42 if (len < 0 || buffer+len >= buffer_end) { 43 if (buffer < buffer_end) 44 buffer_end[-1] = 0; 45 return buffer_end; 46 } 47 return buffer + len; 48 } 49 50 char* 51 bufprint(char* buffer, char* end, const char* fmt, ... ) 52 { 53 va_list args; 54 char* result; 55 56 va_start(args, fmt); 57 result = vbufprint(buffer, end, fmt, args); 58 va_end(args); 59 return result; 60 } 61 62 /** USEFUL DIRECTORY SUPPORT 63 ** 64 ** bufprint_app_dir() returns the directory where the emulator binary is located 65 ** 66 ** get_android_home() returns a user-specific directory where the emulator will 67 ** store its writable data (e.g. config files, profiles, etc...). 68 ** on Unix, this is $HOME/.android, on Windows, this is something like 69 ** "%USERPROFILE%/Local Settings/AppData/Android" on XP, and something different 70 ** on Vista. 71 ** 72 ** both functions return a string that must be freed by the caller 73 **/ 74 75 #ifdef __linux__ 76 char* 77 bufprint_app_dir(char* buff, char* end) 78 { 79 char path[1024]; 80 int len; 81 char* x; 82 83 len = readlink("/proc/self/exe", path, sizeof(path)); 84 if (len <= 0 || len >= (int)sizeof(path)) goto Fail; 85 path[len] = 0; 86 87 x = strrchr(path, '/'); 88 if (x == 0) goto Fail; 89 *x = 0; 90 91 return bufprint(buff, end, "%s", path); 92 Fail: 93 fprintf(stderr,"cannot locate application directory\n"); 94 exit(1); 95 return end; 96 } 97 98 #elif defined(__APPLE__) 99 /* the following hack is needed in order to build with XCode 3.1 100 * don't ask me why, but it seems that there were changes in the 101 * GCC compiler that we don't have in our pre-compiled version 102 */ 103 #ifndef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 104 #define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ MAC_OS_X_VERSION_10_4 105 #endif 106 #import <Carbon/Carbon.h> 107 #include <unistd.h> 108 109 char* 110 bufprint_app_dir(char* buff, char* end) 111 { 112 ProcessSerialNumber psn; 113 CFDictionaryRef dict; 114 CFStringRef value; 115 char s[PATH_MAX]; 116 char* x; 117 118 GetCurrentProcess(&psn); 119 dict = ProcessInformationCopyDictionary(&psn, 0xffffffff); 120 value = (CFStringRef)CFDictionaryGetValue(dict, 121 CFSTR("CFBundleExecutable")); 122 CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8); 123 x = strrchr(s, '/'); 124 if (x == 0) goto fail; 125 *x = 0; 126 127 return bufprint(buff, end, "%s", s); 128 fail: 129 fprintf(stderr,"cannot locate application directory\n"); 130 exit(1); 131 return end; 132 } 133 #elif defined _WIN32 134 char* 135 bufprint_app_dir(char* buff, char* end) 136 { 137 char appDir[MAX_PATH]; 138 int len; 139 char* sep; 140 141 len = GetModuleFileName( 0, appDir, sizeof(appDir)-1 ); 142 if (len == 0) { 143 fprintf(stderr, "PANIC CITY!!\n"); 144 exit(1); 145 } 146 if (len >= (int)sizeof(appDir)) { 147 len = sizeof(appDir)-1; 148 appDir[len] = 0; 149 } 150 151 sep = strrchr(appDir, '\\'); 152 if (sep) 153 *sep = 0; 154 155 return bufprint(buff, end, "%s", appDir); 156 } 157 #else 158 char* 159 bufprint_app_dir(char* buff, char* end) 160 { 161 return bufprint(buff, end, "."); 162 } 163 #endif 164 165 #define _ANDROID_PATH ".android" 166 167 char* 168 bufprint_config_path(char* buff, char* end) 169 { 170 #ifdef _WIN32 171 const char* home = getenv("ANDROID_SDK_HOME"); 172 if (home != NULL) { 173 return bufprint(buff, end, "%s\\%s", home, _ANDROID_PATH ); 174 } else { 175 char path[MAX_PATH]; 176 177 SHGetFolderPath( NULL, CSIDL_PROFILE, 178 NULL, 0, path); 179 180 return bufprint(buff, end, "%s\\%s", path, _ANDROID_PATH ); 181 } 182 #else 183 const char* home = getenv("ANDROID_SDK_HOME"); 184 if (home == NULL) 185 home = getenv("HOME"); 186 if (home == NULL) 187 home = "/tmp"; 188 return bufprint(buff, end, "%s/%s", home, _ANDROID_PATH ); 189 #endif 190 } 191 192 char* 193 bufprint_config_file(char* buff, char* end, const char* suffix) 194 { 195 char* p; 196 p = bufprint_config_path(buff, end); 197 p = bufprint(p, end, PATH_SEP "%s", suffix); 198 return p; 199 } 200 201 char* 202 bufprint_temp_dir(char* buff, char* end) 203 { 204 #ifdef _WIN32 205 char path[MAX_PATH]; 206 DWORD retval; 207 208 retval = GetTempPath( sizeof(path), path ); 209 if (retval > sizeof(path) || retval == 0) { 210 D( "can't locate TEMP directory" ); 211 strncpy(path, "C:\\Temp", sizeof(path) ); 212 } 213 strncat( path, "\\AndroidEmulator", sizeof(path)-1 ); 214 path_mkdir(path, 0744); 215 216 return bufprint(buff, end, "%s", path); 217 #else 218 char path[MAX_PATH]; 219 const char* tmppath = getenv("ANDROID_TMP"); 220 if (!tmppath) { 221 const char* user = getenv("USER"); 222 if (user == NULL || user[0] == '\0') 223 user = "unknown"; 224 225 snprintf(path, sizeof path, "/tmp/android-%s", user); 226 tmppath = path; 227 } 228 mkdir(tmppath, 0744); 229 return bufprint(buff, end, "%s", tmppath ); 230 #endif 231 } 232 233 char* 234 bufprint_temp_file(char* buff, char* end, const char* suffix) 235 { 236 char* p; 237 p = bufprint_temp_dir(buff, end); 238 p = bufprint(p, end, PATH_SEP "%s", suffix); 239 return p; 240 } 241 242