/******************************************************************************* * Copyright (c) 2006, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Andrew Niefer * Martin Oberhuber (Wind River) - [176805] Support Solaris9 by adding setenv() *******************************************************************************/ #include "eclipseCommon.h" #include "eclipseUnicode.h" #ifdef _WIN32 #include #include #else #include #include #include #include #endif #include #include #include #include /* Global Variables */ _TCHAR* osArg = _T_ECLIPSE(DEFAULT_OS); #ifdef MACOSX /* on the mac we have a universal binary, decide ppc vs x86 based on endianness */ #ifdef __BIG_ENDIAN__ _TCHAR* osArchArg = _T_ECLIPSE("ppc"); #else _TCHAR* osArchArg = _T_ECLIPSE(DEFAULT_OS_ARCH); #endif #else _TCHAR* osArchArg = _T_ECLIPSE(DEFAULT_OS_ARCH); #endif _TCHAR* wsArg = _T_ECLIPSE(DEFAULT_WS); /* the SWT supported GUI to be used */ /* Local Variables */ static _TCHAR* filterPrefix = NULL; /* prefix for the find files filter */ static size_t prefixLength = 0; static int isFolder(const _TCHAR* path, const _TCHAR* entry); typedef struct { int segment[3]; _TCHAR * qualifier; } Version; static void freeVersion(Version *version) { if(version->qualifier) free(version->qualifier); free(version); } static Version* parseVersion(const _TCHAR * str) { _TCHAR *copy; _TCHAR *c1, *c2 = NULL; int i = 0; Version *version = malloc(sizeof(Version)); memset(version, 0, sizeof(Version)); c1 = copy = _tcsdup(str); while (c1 && *c1 != 0) { if (i < 3) { version->segment[i] = (int)_tcstol(c1, &c2, 10); /* if the next character is not '.', then we couldn't * parse as a int, the remainder is not valid (or we are at the end)*/ if (*c2 && *c2 != _T_ECLIPSE('.')) break; c2++; /* increment past the . */ } else { c2 = _tcschr(c1, _T_ECLIPSE('.')); if(c2 != NULL) { *c2 = 0; version->qualifier = _tcsdup(c1); *c2 = _T_ECLIPSE('.'); /* put the dot back */ } else { if(_tcsicmp(c1, _T_ECLIPSE("jar")) == 0) version->qualifier = 0; else version->qualifier = _tcsdup(c1); } break; } c1 = c2; i++; } free(copy); return version; } static int compareVersions(const _TCHAR* str1, const _TCHAR* str2) { int result = 0, i = 0; Version *v1 = parseVersion(str1); Version *v2 = parseVersion(str2); while (result == 0 && i < 3) { result = v1->segment[i] - v2->segment[i]; i++; } if(result == 0) { _TCHAR * q1 = v1->qualifier ? v1->qualifier : _T_ECLIPSE(""); _TCHAR * q2 = v2->qualifier ? v2->qualifier : _T_ECLIPSE(""); result = _tcscmp(q1, q2); } freeVersion(v1); freeVersion(v2); return result; } /** * Convert a wide string to a narrow one * Caller must free the null terminated string returned. */ char *toNarrow(const _TCHAR* src) { #ifdef UNICODE int byteCount = WideCharToMultiByte (CP_ACP, 0, (wchar_t *)src, -1, NULL, 0, NULL, NULL); char *dest = malloc(byteCount+1); dest[byteCount] = 0; WideCharToMultiByte (CP_ACP, 0, (wchar_t *)src, -1, dest, byteCount, NULL, NULL); return dest; #else return (char*)_tcsdup(src); #endif } /** * Set an environment variable. * Solaris versions <= Solaris 9 did not know setenv in libc, * so emulate it here. */ #if defined(SOLARIS) || defined(HPUX) int setenv (const char *name, const char *value, int replace) { int namelen, valuelen, rc; char *var; if (replace == 0) { const char *oldval = getenv(name); if (oldval != NULL) { return 0; } } namelen = strlen(name); valuelen = strlen(value); var = malloc( (namelen + valuelen + 2) * sizeof(char) ); if (var == NULL) { return -1; } /* Use strncpy as protection, in case a thread modifies var * after we obtained its length */ strncpy(var, name, namelen); var[namelen] = '='; strncpy( &var[namelen + 1], value, valuelen); var[namelen + valuelen + 1] = '\0'; rc = putenv(var); if (rc != 0) rc = -1; /*putenv returns non-zero on error; setenv -1*/ return rc; } #endif /* * Find the absolute pathname to where a command resides. * * The string returned by the function must be freed. */ #define EXTRA 20 _TCHAR* findCommand( _TCHAR* command ) { return findSymlinkCommand( command, 1 ); } _TCHAR* findSymlinkCommand( _TCHAR* command, int resolve ) { _TCHAR* cmdPath; size_t length; _TCHAR* ch; _TCHAR* dir; _TCHAR* path; struct _stat stats; /* If the command was an abolute pathname, use it as is. */ if (IS_ABSOLUTE(command)) { length = _tcslen( command ); cmdPath = malloc( (length + EXTRA) * sizeof(_TCHAR) ); /* add extra space for a possible ".exe" extension */ _tcscpy( cmdPath, command ); } else { /* If the command string contains a path separator */ if (firstDirSeparator( command ) != NULL) { /* It must be relative to the current directory. */ length = MAX_PATH_LENGTH + EXTRA + _tcslen( command ); cmdPath = malloc( length * sizeof (_TCHAR)); _tgetcwd( cmdPath, length ); length = _tcslen(cmdPath); if (!IS_DIR_SEPARATOR(cmdPath[ length - 1 ])) { cmdPath[ length ] = dirSeparator; cmdPath[ length+1 ] = _T_ECLIPSE('\0'); } _tcscat( cmdPath, command ); } /* else the command must be in the PATH somewhere */ else { /* Get the directory PATH where executables reside. */ path = _tgetenv( _T_ECLIPSE("PATH") ); #ifdef _WIN32 /* on windows, prepend the current directory */ if (path == NULL) path = _T_ECLIPSE(""); ch = malloc((_tcslen(path) + MAX_PATH_LENGTH + 2) * sizeof(_TCHAR)); _tgetcwd( ch, MAX_PATH_LENGTH ); length = _tcslen(ch); ch[length] = pathSeparator; _tcscpy(&ch[length + 1], path); path = ch; #endif if (!path) { return NULL; } else { length = _tcslen( path ) + _tcslen( command ) + MAX_PATH_LENGTH; cmdPath = malloc( length * sizeof(_TCHAR)); /* Foreach directory in the PATH */ dir = path; while (dir != NULL && *dir != _T_ECLIPSE('\0')) { ch = _tcschr( dir, pathSeparator ); if (ch == NULL) { _tcscpy( cmdPath, dir ); } else { length = ch - dir; _tcsncpy( cmdPath, dir, length ); cmdPath[ length ] = _T_ECLIPSE('\0'); ch++; } dir = ch; /* advance for the next iteration */ #ifdef _WIN32 /* Remove quotes */ if (_tcschr( cmdPath, _T_ECLIPSE('"') ) != NULL) { size_t i = 0, j = 0; _TCHAR c; length = _tcslen( cmdPath ); while (i < length) { c = cmdPath[ i++ ]; if (c == _T_ECLIPSE('"')) continue; cmdPath[ j++ ] = c; } cmdPath[ j ] = _T_ECLIPSE('\0'); } #endif /* Determine if the executable resides in this directory. */ if (_tcslen(cmdPath) == 0 || /*an empty path entry is treated as '.' */ (cmdPath[0] == _T_ECLIPSE('.') && (_tcslen(cmdPath) == 1 || (_tcslen(cmdPath) == 2 && IS_DIR_SEPARATOR(cmdPath[1]))))) { _tgetcwd( cmdPath, MAX_PATH_LENGTH ); } length = _tcslen(cmdPath); if (!IS_DIR_SEPARATOR(cmdPath[ length - 1 ])) { cmdPath[ length ] = dirSeparator; cmdPath[ length+1 ] = _T_ECLIPSE('\0'); } _tcscat( cmdPath, command ); /* If the file is not a directory and can be executed */ if (_tstat( cmdPath, &stats ) == 0 && (stats.st_mode & S_IFREG) != 0) { /* Stop searching */ dir = NULL; } } } } } #ifdef _WIN32 /* If the command does not exist */ if (_tstat( cmdPath, &stats ) != 0 || (stats.st_mode & S_IFREG) == 0) { /* If the command does not end with .exe, append it an try again. */ length = _tcslen( cmdPath ); if (length > 4 && _tcsicmp( &cmdPath[ length - 4 ], _T_ECLIPSE(".exe") ) != 0) _tcscat( cmdPath, _T_ECLIPSE(".exe") ); } #endif /* Verify the resulting command actually exists. */ if (_tstat( cmdPath, &stats ) != 0 || (stats.st_mode & S_IFREG) == 0) { free( cmdPath ); cmdPath = NULL; return cmdPath; } if (resolve) { ch = resolveSymlinks(cmdPath); if (ch != cmdPath) { free(cmdPath); cmdPath = ch; } } return cmdPath; } #if !defined(_WIN32) && !defined(MACOSX) char * resolveSymlinks( char * path ) { char * ch, *buffer; if(path == NULL) return path; /* resolve symlinks */ ch = path; buffer = malloc(PATH_MAX); path = realpath(path, buffer); if (path != buffer) free(buffer); if (path == NULL) return ch; /* failed to resolve the links, return original path */ return path; } #endif #ifdef _WIN32 static int filter(_TCHAR* candidate, int isFolder) { #else #ifdef MACOSX static int filter(struct dirent *dir, int isFolder) { #else static int filter(const struct dirent *dir, int isFolder) { #endif char * candidate = (char *)dir->d_name; #endif _TCHAR *lastDot, *lastUnderscore; int result; if(_tcslen(candidate) <= prefixLength) return 0; if (_tcsncmp(candidate, filterPrefix, prefixLength) != 0 || candidate[prefixLength] != _T_ECLIPSE('_')) return 0; candidate = _tcsdup(candidate); /* remove trailing .jar and .zip extensions, leave other extensions because we need the '.' */ lastDot = _tcsrchr(candidate, _T_ECLIPSE('.')); if (!isFolder && lastDot != NULL && (_tcscmp(lastDot, _T_ECLIPSE(".jar")) == 0 || _tcscmp(lastDot, _T_ECLIPSE(".zip")) == 0)) { *lastDot = 0; lastDot = _tcsrchr(candidate, _T_ECLIPSE('.')); } if (lastDot < &candidate[prefixLength]) { free(candidate); return 0; } lastUnderscore = _tcsrchr(candidate, _T_ECLIPSE('_')); /* get past all the '_' that are part of the qualifier */ while(lastUnderscore > lastDot) { *lastUnderscore = 0; lastUnderscore = _tcsrchr(candidate, _T_ECLIPSE('_')); } /* is this the underscore at the end of the prefix? */ result = (lastUnderscore == &candidate[prefixLength]); free(candidate); return result; } /* * Looks for files of the form /path/prefix_version. and returns the full path to * the file with the largest version number */ _TCHAR* findFile( _TCHAR* path, _TCHAR* prefix) { struct _stat stats; size_t pathLength; _TCHAR* candidate = NULL; _TCHAR* result = NULL; #ifdef _WIN32 _TCHAR* fileName = NULL; WIN32_FIND_DATA data; HANDLE handle; #else DIR *dir = NULL; struct dirent * entry = NULL; #endif path = _tcsdup(path); pathLength = _tcslen(path); /* strip dirSeparators off the end */ while (IS_DIR_SEPARATOR(path[pathLength - 1])) { path[--pathLength] = 0; } /* does path exist? */ if( _tstat(path, &stats) != 0 ) { free(path); return NULL; } filterPrefix = prefix; prefixLength = _tcslen(prefix); #ifdef _WIN32 fileName = malloc( (_tcslen(path) + 1 + _tcslen(prefix) + 3) * sizeof(_TCHAR)); _stprintf(fileName, _T_ECLIPSE("%s%c%s_*"), path, dirSeparator, prefix); handle = FindFirstFile(fileName, &data); if(handle != INVALID_HANDLE_VALUE) { if (filter(data.cFileName, isFolder(path, data.cFileName))) candidate = _tcsdup(data.cFileName); while(FindNextFile(handle, &data) != 0) { if (filter(data.cFileName, isFolder(path, data.cFileName))) { if (candidate == NULL) { candidate = _tcsdup(data.cFileName); } else if( compareVersions(candidate + prefixLength + 1, data.cFileName + prefixLength + 1) < 0) { /* compare, take the highest version */ free(candidate); candidate = _tcsdup(data.cFileName); } } } FindClose(handle); } #else if ((dir = opendir(path)) == NULL) { free(path); return NULL; } while ((entry = readdir(dir)) != NULL) { if (filter(entry, isFolder(path, entry->d_name))) { if (candidate == NULL) { candidate = _tcsdup(entry->d_name); } else if (compareVersions(candidate + prefixLength + 1, entry->d_name + prefixLength + 1) < 0) { free(candidate); candidate = _tcsdup(entry->d_name); } } } closedir(dir); #endif if(candidate != NULL) { result = malloc((pathLength + 1 + _tcslen(candidate) + 1) * sizeof(_TCHAR)); _tcscpy(result, path); result[pathLength] = dirSeparator; result[pathLength + 1] = 0; _tcscat(result, candidate); free(candidate); } free(path); return result; } int isFolder(const _TCHAR* path, const _TCHAR* entry) { int result = 0; struct _stat stats; _TCHAR * fullPath = malloc((_tcslen(path) + _tcslen(entry) + 2) * sizeof(_TCHAR)); _stprintf(fullPath, _T_ECLIPSE("%s%c%s"), path, dirSeparator, entry); result = _tstat(fullPath, &stats); free(fullPath); return (result == 0 && (stats.st_mode & S_IFDIR) != 0); } /* * If path is relative, attempt to make it absolute by * 1) check relative to working directory * 2) check relative to provided programDir * If reverseOrder, then check the programDir before the working dir */ _TCHAR* checkPath( _TCHAR* path, _TCHAR* programDir, int reverseOrder ) { int cwdLength = MAX_PATH_LENGTH; int i; _TCHAR * workingDir, * buffer, * result = NULL; _TCHAR * paths[2]; struct _stat stats; /* If the command was an abolute pathname, use it as is. */ if (IS_ABSOLUTE(path)) { return path; } /* get the current working directory */ workingDir = malloc(cwdLength * sizeof(_TCHAR)); while ( _tgetcwd( workingDir, cwdLength ) == NULL ){ if (errno == ERANGE) { /* ERANGE : the buffer isn't big enough, allocate more memory */ cwdLength *= 2; workingDir = realloc(workingDir, cwdLength * sizeof(_TCHAR)); continue; } else { /* some other error occurred, perhaps ENOENT (directory has been unlinked) */ /* the contents of workingDir are undefined, set it to empty, we will end up testing against root */ workingDir[0] = _T_ECLIPSE('\0'); break; } } paths[0] = reverseOrder ? programDir : workingDir; paths[1] = reverseOrder ? workingDir : programDir; /* just make a buffer big enough to hold everything */ buffer = malloc((_tcslen(paths[0]) + _tcslen(paths[1]) + _tcslen(path) + 2) * sizeof(_TCHAR)); for ( i = 0; i < 2; i++ ) { if (_tcslen(paths[i]) == 0) continue; _stprintf(buffer, _T_ECLIPSE("%s%c%s"), paths[i], dirSeparator, path); if (_tstat(buffer, &stats) == 0) { result = _tcsdup(buffer); break; } } free(buffer); free(workingDir); /* if we found something, return it, otherwise, return the original */ return result != NULL ? result : path; } _TCHAR * lastDirSeparator(_TCHAR* str) { #ifndef _WIN32 return _tcsrchr(str, dirSeparator); #else int i = -1; _TCHAR * c = NULL; while (str[++i] != 0) { if (str[i] == _T_ECLIPSE('\\') || str[i] == _T_ECLIPSE('/')) c = &str[i]; } return c; #endif } _TCHAR * firstDirSeparator(_TCHAR* str) { #ifdef _WIN32 return _tcspbrk(str, _T_ECLIPSE("\\/")); #else return _tcschr(str, dirSeparator); #endif }