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
35char*
36vbufprint( 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
50char*
51bufprint(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__
76char*
77bufprint_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);
92Fail:
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
109char*
110bufprint_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);
128fail:
129    fprintf(stderr,"cannot locate application directory\n");
130    exit(1);
131    return end;
132}
133#elif defined _WIN32
134char*
135bufprint_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
158char*
159bufprint_app_dir(char*  buff, char*  end)
160{
161    return bufprint(buff, end, ".");
162}
163#endif
164
165#define  _ANDROID_PATH   ".android"
166
167char*
168bufprint_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
192char*
193bufprint_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
201char*
202bufprint_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
233char*
234bufprint_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