1f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/* Copyright (C) 2011 The Android Open Source Project 2f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** 3f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** This software is licensed under the terms of the GNU General Public 4f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** License version 2, as published by the Free Software Foundation, and 5f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** may be copied, distributed, and modified under those terms. 6f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** 7f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** This program is distributed in the hope that it will be useful, 8f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** but WITHOUT ANY WARRANTY; without even the implied warranty of 9f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner** GNU General Public License for more details. 11f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner*/ 1209aa9774a68528f2269813833e2313e20d60d0d3Siva Velusamy#include "android/avd/util.h" 13d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include "android/utils/bufprint.h" 14f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/utils/debug.h" 1552e9942c2e0ffac6f7ccc2d2c916c855ad62c33dDavid 'Digit' Turner#include "android/utils/eintr_wrapper.h" 16f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/utils/path.h" 1783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine#include "android/utils/dirscanner.h" 18f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/main-common.h" 19f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/globals.h" 20f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/resource.h" 21f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#include "android/user-config.h" 22f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 23d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <errno.h> 24d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <fcntl.h> 25d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <limits.h> 26d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#ifdef _WIN32 27d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <process.h> 28d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#endif 29d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <signal.h> 30d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <stdlib.h> 31d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <string.h> 32d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <sys/time.h> 33d174434fbf6fbfce54f7eabaa54b8296f55527b8David 'Digit' Turner#include <unistd.h> 34f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 35f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 36f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***********************************************************************/ 37f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***********************************************************************/ 38f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***** *****/ 39f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***** U T I L I T Y R O U T I N E S *****/ 40f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***** *****/ 41f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***********************************************************************/ 42f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner/***********************************************************************/ 43f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 44f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) 45f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 46c5f12b935ced6c029244b1a3230edc9b7646da97David 'Digit' Turnervoid reassign_string(char** string, const char* new_value) { 47c5f12b935ced6c029244b1a3230edc9b7646da97David 'Digit' Turner free(*string); 48c5f12b935ced6c029244b1a3230edc9b7646da97David 'Digit' Turner *string = ASTRDUP(new_value); 49c5f12b935ced6c029244b1a3230edc9b7646da97David 'Digit' Turner} 50c5f12b935ced6c029244b1a3230edc9b7646da97David 'Digit' Turner 51f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turnerunsigned convertBytesToMB( uint64_t size ) 52f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner{ 53f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner if (size == 0) 54f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner return 0; 55f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 56f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner size = (size + ONE_MB-1) >> 20; 57f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner if (size > UINT_MAX) 58f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner size = UINT_MAX; 59f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 60f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner return (unsigned) size; 61f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner} 62f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 63f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turneruint64_t convertMBToBytes( unsigned megaBytes ) 64f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner{ 65f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner return ((uint64_t)megaBytes << 20); 66f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner} 67f845627c83ce6ce3e306f9b6842d1e30ef89ae97David 'Digit' Turner 6883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine/* this function is used to perform auto-detection of the 6983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * system directory in the case of a SDK installation. 7083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * 7183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * we want to deal with several historical usages, hence 7283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * the slightly complicated logic. 7383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * 7483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * NOTE: the function returns the path to the directory 7583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * containing 'fileName'. this is *not* the full 7683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * path to 'fileName'. 7783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 7883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkinestatic char* 7983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine_getSdkImagePath( const char* fileName ) 8083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine{ 8183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char temp[MAX_PATH]; 8283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* p = temp; 8383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* end = p + sizeof(temp); 8483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* q; 8583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* app; 8683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 8783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine static const char* const searchPaths[] = { 8883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "", /* program's directory */ 8983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "/lib/images", /* this is for SDK 1.0 */ 9083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "/../platforms/android-1.1/images", /* this is for SDK 1.1 */ 9183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine NULL 9283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine }; 9383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 9483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine app = bufprint_app_dir(temp, end); 9583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (app >= end) 9683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return NULL; 9783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 9883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine do { 9983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine int nn; 10083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 10183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* first search a few well-known paths */ 10283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine for (nn = 0; searchPaths[nn] != NULL; nn++) { 10383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine p = bufprint(app, end, "%s", searchPaths[nn]); 10483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine q = bufprint(p, end, "/%s", fileName); 10583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (q < end && path_exists(temp)) { 10683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine *p = 0; 10783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine goto FOUND_IT; 10883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 10983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 11083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 11183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* hmmm. let's assume that we are in a post-1.1 SDK 11283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * scan ../platforms if it exists 11383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 11483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine p = bufprint(app, end, "/../platforms"); 11583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (p < end) { 11683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine DirScanner* scanner = dirScanner_new(temp); 11783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (scanner != NULL) { 11883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine int found = 0; 11983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine const char* subdir; 12083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 12183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine for (;;) { 12283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine subdir = dirScanner_next(scanner); 12383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!subdir) break; 12483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 12583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine q = bufprint(p, end, "/%s/images/%s", subdir, fileName); 12683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (q >= end || !path_exists(temp)) 12783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine continue; 12883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 12983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine found = 1; 13083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine p = bufprint(p, end, "/%s/images", subdir); 13183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine break; 13283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 13383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine dirScanner_free(scanner); 13483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (found) 13583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine break; 13683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 13783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 13883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 13983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* I'm out of ideas */ 14083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return NULL; 14183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 14283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } while (0); 14383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 14483ffd66e78d290aa054ace5e484ae3766f638390Vladimir ChtchetkineFOUND_IT: 14583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine //D("image auto-detection: %s/%s", temp, fileName); 14683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return android_strdup(temp); 14783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine} 14883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 14983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkinestatic char* 15083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine_getSdkImage( const char* path, const char* file ) 15183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine{ 15283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char temp[MAX_PATH]; 15383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char *p = temp, *end = p + sizeof(temp); 15483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 15583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine p = bufprint(temp, end, "%s/%s", path, file); 15683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (p >= end || !path_exists(temp)) 15783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return NULL; 15883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 15983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return android_strdup(temp); 16083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine} 16183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 16283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkinestatic char* 16383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine_getSdkSystemImage( const char* path, const char* optionName, const char* file ) 16483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine{ 16583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* image = _getSdkImage(path, file); 16683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 16783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (image == NULL) { 16883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror("Your system directory is missing the '%s' image file.\n" 16983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "Please specify one with the '%s <filepath>' option", 17083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine file, optionName); 17183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 17283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 17383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return image; 17483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine} 17583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 17625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turnervoid sanitizeOptions( AndroidOptions* opts ) 17725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner{ 17883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* legacy support: we used to use -system <dir> and -image <file> 17983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * instead of -sysdir <dir> and -system <file>, so handle this by checking 18083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * whether the options point to directories or files. 18183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 18283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->image != NULL) { 18383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->system != NULL) { 18483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->sysdir != NULL) { 18583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror( "You can't use -sysdir, -system and -image at the same time.\n" 18683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "You should probably use '-sysdir <path> -system <file>'.\n" ); 18783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 18883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 18983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 19083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine dwarning( "Please note that -image is obsolete and that -system is now used to point\n" 19183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" ); 19283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->sysdir = opts->system; 19383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->system = opts->image; 19483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->image = NULL; 19583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 19683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine else if (opts->system != NULL && path_is_dir(opts->system)) { 19783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->sysdir != NULL) { 19883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror( "Option -system should now be followed by a file path, not a directory one.\n" 19983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "Please use '-sysdir <path>' to point to the system directory.\n" ); 20083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(1); 20183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 20283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine dwarning( "Please note that the -system option should now be used to point to the initial\n" 20383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "system image (like the obsolete -image option). To point to the system directory\n" 20483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "please now use '-sysdir <path>' instead.\n" ); 20583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 20683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->sysdir = opts->system; 20783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->system = NULL; 20883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 20983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 21025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->nojni) { 21125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->no_jni = opts->nojni; 21225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->nojni = 0; 21325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 21425eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 21525eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->nocache) { 21625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->no_cache = opts->nocache; 21725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->nocache = 0; 21825eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 21925eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 22025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->noaudio) { 22125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->no_audio = opts->noaudio; 22225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->noaudio = 0; 22325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 22425eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 22525eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->noskin) { 22625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->no_skin = opts->noskin; 22725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->noskin = 0; 22825eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 22925eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 23025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner /* If -no-cache is used, ignore any -cache argument */ 23125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->no_cache) { 23225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->cache = 0; 23325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 23425eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 23525eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner /* the purpose of -no-audio is to disable sound output from the emulator, 23625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner * not to disable Audio emulation. So simply force the 'none' backends */ 23725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->no_audio) 23825eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->audio = "none"; 23925eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 24025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner /* we don't accept -skindir without -skin now 24125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner * to simplify the autoconfig stuff with virtual devices 24225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner */ 24325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->no_skin) { 24425eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->skin = "320x480"; 24525eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner opts->skindir = NULL; 24625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 24725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 24825eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (opts->skindir) { 24925eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner if (!opts->skin) { 25025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner derror( "the -skindir <path> option requires a -skin <name> option"); 25125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner exit(1); 25225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 25325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner } 2540b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner 2550b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner if (opts->bootchart) { 2560b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner char* end; 2570b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner int timeout = strtol(opts->bootchart, &end, 10); 2580b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner if (timeout == 0) 2590b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner opts->bootchart = NULL; 2600b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner else if (timeout < 0 || timeout > 15*60) { 2610b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner derror( "timeout specified for -bootchart option is invalid.\n" 2620b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner "please use integers between 1 and 900\n"); 2630b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner exit(1); 2640b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner } 2650b0194940523fa3f318c380d0693907bd522241cDavid 'Digit' Turner } 26625eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner} 26725eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 26825eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' TurnerAvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild) 26925eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner{ 27025eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner AvdInfo* ret = NULL; 27125eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner char tmp[MAX_PATH]; 27225eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner char* tmpend = tmp + sizeof(tmp); 27325eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner char* android_build_root = NULL; 27425eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner char* android_build_out = NULL; 27525eb6557b94da066d6e137c07aeced39badf5aa6David 'Digit' Turner 27683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* If no AVD name was given, try to find the top of the 27783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * Android build tree 27883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 27983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->avd == NULL) { 28083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine do { 28183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine char* out = getenv("ANDROID_PRODUCT_OUT"); 28283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 28383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (out == NULL || out[0] == 0) 28483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine break; 28583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 28683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!path_exists(out)) { 28783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n" 28883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "You need to build the Android system before launching the emulator", 28983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine out); 29083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 29183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 29283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 2934bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru android_build_root = getenv("ANDROID_BUILD_TOP"); 2944bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru if (android_build_root == NULL || android_build_root[0] == 0) 2954bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru break; 2964bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru 2974bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru if (!path_exists(android_build_root)) { 2984bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru derror("Can't find the Android build root '%s'\n" 2994bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru "Please check the definition of the ANDROID_BUILD_TOP variable.\n" 3004bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru "It should point to the root of your source tree.\n", 3014bcc1d92f4d49ee7331bd2eacd28d497e505c5c7Jean-Baptiste Queru android_build_root ); 30283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 30383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 30483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine android_build_out = out; 30583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D( "found Android build root: %s", android_build_root ); 30683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D( "found Android build out: %s", android_build_out ); 30783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } while (0); 30883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 30983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* if no virtual device name is given, and we're not in the 31083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * Android build system, we'll need to perform some auto-detection 31183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * magic :-) 31283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 31383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->avd == NULL && !android_build_out) 31483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine { 31583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->sysdir) { 31683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->sysdir = _getSdkImagePath("system.img"); 31783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->sysdir) { 31883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror( 31983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "You did not specify a virtual device name, and the system\n" 32083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "directory could not be found.\n\n" 32183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n" 32283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "to start a given virtual device (see -help-avd for details).\n\n" 32383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 32483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "Otherwise, follow the instructions in -help-disk-images to start the emulator\n" 32583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine ); 32683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 32783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 32883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -sysdir %s", opts->sysdir); 32983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 33083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 33183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->system) { 33283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img"); 333adc34fb9e9ad0700e9752ca67174c68925ca0c71David 'Digit' Turner D("autoconfig: -system %s", opts->system); 33483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 33583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 33683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->kernel) { 33783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu"); 33883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -kernel %s", opts->kernel); 33983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 34083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 34183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->ramdisk) { 34283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img"); 34383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -ramdisk %s", opts->ramdisk); 34483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 34583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 34683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* if no data directory is specified, use the system directory */ 34783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->datadir) { 34883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->datadir = android_strdup(opts->sysdir); 34983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -datadir %s", opts->sysdir); 35083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 35183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 35283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->data) { 35383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* check for userdata-qemu.img in the data directory */ 35483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir); 35583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!path_exists(tmp)) { 35683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine derror( 35783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "You did not provide the name of an Android Virtual Device\n" 35883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "with the '-avd <name>' option. Read -help-avd for more information.\n\n" 35983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 36083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n" 36183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine "to specify a data partition image file (I hope you know what you're doing).\n" 36283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine ); 36383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(2); 36483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 36583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 36683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->data = android_strdup(tmp); 36783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -data %s", opts->data); 36883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 36983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 37083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!opts->snapstorage && opts->datadir) { 37183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir); 37283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (path_exists(tmp)) { 37383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine opts->snapstorage = android_strdup(tmp); 37483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("autoconfig: -snapstorage %s", opts->snapstorage); 37583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 37683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 37783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 37883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 37983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* setup the virtual device differently depending on whether 38083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine * we are in the Android build system or not 38183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine */ 38283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (opts->avd != NULL) 38383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine { 38483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine ret = avdInfo_new( opts->avd, android_avdParams ); 38583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (ret == NULL) { 38683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine /* an error message has already been printed */ 38783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine dprint("could not find virtual device named '%s'", opts->avd); 38883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(1); 38983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 39083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 39183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine else 39283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine { 39383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (!android_build_out) { 39483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine android_build_out = android_build_root = opts->sysdir; 39583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 39683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine ret = avdInfo_newForAndroidBuild( 39783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine android_build_root, 39883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine android_build_out, 39983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine android_avdParams ); 40083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 40183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if(ret == NULL) { 40283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine D("could not start virtual device\n"); 40383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine exit(1); 40483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 40583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 40683ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 40783ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine if (android_build_out) { 40883ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine *inAndroidBuild = 1; 40983ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } else { 41083ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine *inAndroidBuild = 0; 41183ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine } 41283ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 41383ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine return ret; 41483ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine} 41583ffd66e78d290aa054ace5e484ae3766f638390Vladimir Chtchetkine 416bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turnervoid handle_ui_options( AndroidOptions* opts ) 417bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner{ 418bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner return; 419bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner} 420bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner 421bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turnerint attach_ui_to_core( AndroidOptions* opts ) 422bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner{ 423bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner return 0; 424bdb6f2dd35a4c749186e665d55d7b76375d7e71dDavid 'Digit' Turner} 425