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*
vbufprint(char * buffer,char * buffer_end,const char * fmt,va_list args)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*
bufprint(char * buffer,char * end,const char * fmt,...)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*
bufprint_app_dir(char * buff,char * end)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*
bufprint_app_dir(char * buff,char * end)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*
bufprint_app_dir(char * buff,char * end)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*
bufprint_app_dir(char * buff,char * end)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*
bufprint_config_path(char * buff,char * end)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*
bufprint_config_file(char * buff,char * end,const char * suffix)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*
bufprint_temp_dir(char * buff,char * end)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*
bufprint_temp_file(char * buff,char * end,const char * suffix)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