diff --git a/libs/pbd/fallback_folders.cc b/libs/pbd/fallback_folders.cc new file mode 100644 index 0000000000..deecd60d7a --- /dev/null +++ b/libs/pbd/fallback_folders.cc @@ -0,0 +1,591 @@ +/* + Copyright (C) 2008 John Emmas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include + + + +#ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!! +#include +#include + +//*************************************************************** +// +// get_win_special_folder() +// +// Gets the full path name that corresponds of one of the Windows +// special folders, such as "My Documents" and the like. The input +// parameter must be one of the corresponding CSIDL values, such +// as CSIDL_SYSTEM etc. +// +// Returns: +// +// On Success: A pointer to a newly allocated string containing +// the name of the special folder (must later be freed). +// On Failure: NULL +// +gchar * +get_win_special_folder (int csidl) +{ +wchar_t path[PATH_MAX+1]; +HRESULT hr; +LPITEMIDLIST pidl = 0; +gchar *retval = 0; + + if (S_OK == (hr = SHGetSpecialFolderLocation (0, csidl, &pidl))) + { + if (SHGetPathFromIDListW (pidl, path)) + retval = g_utf16_to_utf8 ((const gunichar2*)path, -1, 0, 0, 0); + CoTaskMemFree (pidl); + } + + return retval; +} +#endif // PLATFORM_WINDOWS + +namespace PBD { + +static gchar **fallback_folders = 0; + +//*************************************************************** +// +// get_platform_fallback_folders() +// +// Returns an array of folders to fall back to if the folders +// weren't named at build time and subsequently couldn't be found +// in the user's environment. This might not be needed any more +// because the function 'fixup_bundle_environment()' (in the +// gtk2_ardour branch) now explicitly sets up any environment +// paths that the program will need at run time. However, having +// the folders here might help us to simplify the above function +// which would be useful (currently, there are different versions +// of 'fixup_bundle_environment()' for each supported platform). +// Twelve fallback folders are currently catered for, corresponding to:- +// +// LOCALEDIR +// GTK_DIR +// CONFIG_DIR +// ARDOUR_DIR +// MODULE_DIR +// DATA_DIR +// ICONS_DIR +// PIXMAPS_DIR +// CONTROL_SURFACES_DIR +// VAMP_DIR +// LADSPA_PATH - note that there's only one entry in the path +// VST_PATH - note that there may only be one entry in the path +// +// Returns: +// +// On Success: A pointer to an array containing the above dirs. +// On Failure: NULL +// +#ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!! + +static gchar** +get_platform_fallback_folders () +{ +gchar **fallback_dir_vector = 0; +const gchar *pUsrHome = 0; // Do not free !! + + if (!fallback_folders) + { + GArray *pFallbackDirs; + gchar *pAppData = 0; + gchar *pMyAppData = 0; + gchar *pExeRoot = 0; + gchar *pPersonal = 0; + + pFallbackDirs = g_array_new (TRUE, TRUE, sizeof (char *)); + + if (pFallbackDirs) + { + /* Get the path for the user's personal folder */ + gchar *pPersonalTemp = get_win_special_folder (CSIDL_PERSONAL); + + /* and the path for the user's personal application data */ + gchar *pMyAppDataTemp = get_win_special_folder (CSIDL_LOCAL_APPDATA); + + /* and the path for common application data ("Documents and Settings\All Users\Application Data") */ + gchar *pAppDataTemp = get_win_special_folder (CSIDL_COMMON_APPDATA); + + if (0 == pAppDataTemp) + pAppData = g_build_filename("C:\\", "Documents and Settings", "All Users", "Application Data", PROGRAM_NAME, "local", 0); + else + { + pAppData = g_build_filename(pAppDataTemp, PROGRAM_NAME, "local", 0); + g_free (pAppDataTemp); + } + + if (0 == pMyAppDataTemp) + { + pMyAppData = g_build_filename(g_get_home_dir(), "Application Data", "local", 0); + } + else + { + pMyAppData = g_build_filename(pMyAppDataTemp, 0); + g_free (pMyAppDataTemp); + } + + if (0 == pPersonalTemp) + pPersonal = g_build_filename(g_get_home_dir(), 0); + else + { + pPersonal = g_build_filename(pPersonalTemp, 0); + g_free (pPersonalTemp); + } + + /* Get the path to the running application */ + pExeRoot = g_win32_get_package_installation_directory_of_module (0); + + if (0 == pExeRoot) + { + pExeRoot = g_build_filename("C:\\", "Program Files", PROGRAM_NAME, 0); + } + + if ((pExeRoot) && (pAppData) && (pMyAppData) && (pPersonal)) + { + gchar tmp[PATH_MAX+1]; + gchar* p; + + // Build our LOCALEDIR entry + if (0 != (p = g_build_filename(pAppData, "share", "locale", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our GTK_DIR entry + if (0 != (p = g_build_filename(pPersonal, ".gtk-2.0", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our CONFIG_DIR entry + if (0 != (p = g_build_filename(pAppData, "etc", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our ARDOUR_DIR entry + p = g_build_filename(pMyAppData, PROGRAM_NAME, 0); + + if (0 != p) + { + g_array_append_val (pFallbackDirs, p); + + // Build our MODULE_DIR entry + strcpy(tmp, pExeRoot); + if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR))) + { + *p = '\0'; + + if (0 != (p = g_build_filename(tmp, 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our DATA_DIR entry + if (0 != (p = g_build_filename(pAppData, "share", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our ICONS_DIR entry + if (0 != (p = g_build_filename(pAppData, "share", "icons", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our PIXMAPS_DIR entry + if (0 != (p = g_build_filename(pAppData, "share", "pixmaps", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our CONTROL_SURFACES_DIR entry + if (0 != (p = g_build_filename(pExeRoot, "bin", "surfaces", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our VAMP_DIR entry + p = g_build_filename(pExeRoot, "bin", "vamp", 0); + if (p) + g_array_append_val (pFallbackDirs, p); + else + g_array_append_val (pFallbackDirs, ""); + + // Next, build our LADSPA_PATH entry + p = g_build_filename(pExeRoot, "bin", "plugins", 0); + if (p) + g_array_append_val (pFallbackDirs, p); + else + g_array_append_val (pFallbackDirs, ""); + + // And finally, build our VST_PATH entry + DWORD dwType = REG_SZ; HKEY hKey; + DWORD dwSize = PATH_MAX; p = 0; + if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_CURRENT_USER, "Software\\VST", 0, KEY_READ, &hKey)) + { + // Look for the user's VST Registry entry + if (ERROR_SUCCESS == RegQueryValueExA (hKey, "VSTPluginsPath", 0, &dwType, (LPBYTE)tmp, &dwSize)) + p = g_build_filename (Glib::locale_to_utf8(tmp).c_str(), 0); + + RegCloseKey (hKey); + } + + if (p == 0) + if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\VST", 0, KEY_READ, &hKey)) + { + // Look for a global VST Registry entry + if (ERROR_SUCCESS == RegQueryValueExA (hKey, "VSTPluginsPath", 0, &dwType, (LPBYTE)tmp, &dwSize)) + p = g_build_filename (Glib::locale_to_utf8(tmp).c_str(), 0); + + RegCloseKey (hKey); + } + + if (p == 0) + { + gchar *pVSTx86 = 0; + gchar *pProgFilesX86 = get_win_special_folder (CSIDL_PROGRAM_FILESX86); + + if (pProgFilesX86) + { + // Look for a VST folder under C:\Program Files (x86) + if (pVSTx86 = g_build_filename (pProgFilesX86, "Steinberg", "VSTPlugins", 0)) + { + if (Glib::file_test (pVSTx86, Glib::FILE_TEST_EXISTS)) + if (Glib::file_test (pVSTx86, Glib::FILE_TEST_IS_DIR)) + p = g_build_filename (pVSTx86, 0); + + g_free (pVSTx86); + } + + g_free (pProgFilesX86); + } + + if (p == 0) + { + // Look for a VST folder under C:\Program Files + gchar *pVST = 0; + gchar *pProgFiles = get_win_special_folder (CSIDL_PROGRAM_FILES); + + if (pProgFiles) + { + if (pVST = g_build_filename (pProgFiles, "Steinberg", "VSTPlugins", 0)) + { + if (Glib::file_test (pVST, Glib::FILE_TEST_EXISTS)) + if (Glib::file_test (pVST, Glib::FILE_TEST_IS_DIR)) + p = g_build_filename (pVST, 0); + + g_free (pVST); + } + + g_free (pProgFiles); + } + } + } + + if (p == 0) + { + // If all else failed, assume the plugins are under "My Documents" + pUsrHome = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); + if (pUsrHome) + p = g_build_filename (pUsrHome, "Plugins", "VST", 0); + else + { + pUsrHome = g_build_filename(g_get_home_dir(), "My Documents", 0); + if (pUsrHome) + p = g_build_filename (pUsrHome, "Plugins", "VST", 0); + } + } + else + { + gchar* q = 0; + + // Concatenate the registry path with the user's personal path + pUsrHome = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); + + if (pUsrHome) + { + q = p; + p = g_build_path (";", q, g_build_filename(pUsrHome, "Plugins", "VST", 0), 0); + } + else + { + pUsrHome = g_build_filename(g_get_home_dir(), "My Documents", 0); + if (pUsrHome) + { + q = p; + p = g_build_path (";", q, g_build_filename (pUsrHome, "Plugins", "VST", 0), 0); + } + } + } + + if (p) //VST + g_array_append_val (pFallbackDirs, p); + else + g_array_append_val (pFallbackDirs, ""); + + // BUNDLED_LV2 + p = g_build_filename(pExeRoot, "bin", "lv2", 0); + if (p) + g_array_append_val (pFallbackDirs, p); + else + g_array_append_val (pFallbackDirs, ""); + } + } + } + } + } + } + } + } + } + } + + g_free (pAppData); + g_free (pMyAppData); + g_free (pExeRoot); + g_free (pPersonal); + } + + fallback_dir_vector = fallback_folders = (gchar **) g_array_free (pFallbackDirs, FALSE); + } + } + else + fallback_dir_vector = fallback_folders; + + return (fallback_dir_vector); +} + +#else +// Assume Linux, Cygwin or OS-X. Note that in all 3 cases we only +// need to cater for unbundled releases (those built by a user from +// source). Bundled releases of Ardour and Mixbus now specifically +// write their folders and paths to the user's environment at startup. +// See the function 'fixup_bundle_environment()'. + +static gchar** +get_platform_fallback_folders () +{ +gchar **fallback_dir_vector = 0; +gchar *pUsrHome = 0; + + if (!fallback_folders) + { + GArray *pFallbackDirs; + gchar *pAppData = 0; + gchar *pExeRoot = 0; + gchar *pPersonal = 0; + + pFallbackDirs = g_array_new (TRUE, TRUE, sizeof (char *)); + + if (pFallbackDirs) + { + pAppData = g_build_filename("/usr", "local", 0); + pExeRoot = g_build_filename("/usr", "local", "lib", "ardour2", 0); + pPersonal = g_build_filename(g_get_home_dir(), 0); + + if ((pExeRoot) && (pAppData) && (pPersonal)) + { + gchar tmp[PATH_MAX+1]; + gchar* p; + + // Build our LOCALEDIR entry + if (0 != (p = g_build_filename(pAppData, "share", "locale", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our GTK_DIR entry + if (0 != (p = g_build_filename(pPersonal, ".gtk-2.0", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our CONFIG_DIR entry + if (0 != (p = g_build_filename(pAppData, "etc", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our ARDOUR_DIR entry + p = ""; // Empty string (temporary) + if (0 != p) + { + g_array_append_val (pFallbackDirs, p); + + // Build our MODULE_DIR entry + strcpy(tmp, pExeRoot); + if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR))) + { + *p = '\0'; + + if (0 != (p = g_build_filename(tmp, 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our DATA_DIR entry + if (0 != (p = g_build_filename(pAppData, "share", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our ICONS_DIR entry (re-use 'tmp') + strcpy(tmp, "/usr/local/share/ardour2"); + if (0 != (p = g_build_filename(tmp, "icons", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our PIXMAPS_DIR entry + if (0 != (p = g_build_filename(tmp, "pixmaps", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our CONTROL_SURFACES_DIR entry + if (0 != (p = g_build_filename(pExeRoot, "surfaces", 0))) + { + g_array_append_val (pFallbackDirs, p); + + // Build our VAMP_DIR entry + p = g_build_filename(pExeRoot, "vamp", 0); + if (p) + g_array_append_val (pFallbackDirs, p); + + // Next, build our LADSPA_PATH entry + p = g_build_filename(Glib::path_get_dirname(pExeRoot).c_str(), "plugins", 0); + if (p) + g_array_append_val (pFallbackDirs, p); + + // And finally, build our VST_PATH entry + if (g_getenv("HOME")) + p = g_build_filename(g_getenv("HOME"), "VST", "plugins", 0); + else + p = g_build_filename(g_get_home_dir(), "VST", "plugins", 0); + + if (p) + g_array_append_val (pFallbackDirs, p); + } + } + } + } + } + } + } + } + } + } + + g_free (pAppData); + g_free (pExeRoot); + g_free (pPersonal); + } + + fallback_dir_vector = fallback_folders = (gchar **) g_array_free (pFallbackDirs, FALSE); + } + } + else + fallback_dir_vector = fallback_folders; + + if (pUsrHome) + g_free (pUsrHome); + + return (fallback_dir_vector); +} +#endif + + +//*************************************************************** +// +// get_platform_fallback_folder() +// +// Returns a const gchar* which points to a string describing +// the full path to the Ardour fallback folder corresponding to +// the supplied index. See 'get_platform_fallback_folders()' for a +// complete list of the supported index enumerations. Calling this +// function will initialize the fallback folder array if it wasn't +// already initiaized. The array should then (eventually) be freed +// using 'free_platform_fallback_folders()'. +// +// Returns: +// +// On Success: A pointer to the path string contained at the +// relevant index. +// On Failure: NULL +// +PBD_API G_CONST_RETURN gchar* PBD_APICALLTYPE +get_platform_fallback_folder (PBD::fallback_folder_t index) +{ + if ((index >= 0) && (index < FALLBACK_FOLDER_MAX)) + return ((G_CONST_RETURN gchar *)get_platform_fallback_folders ()[index]); + else + return (G_CONST_RETURN gchar *) 0; +} + + +//*************************************************************** +// +// alloc_platform_fallback_folders() +// +// Calls 'get_platform_fallback_folders()' to ensure that memory +// for the fallback folder array is already allocated before the +// array gets used. It doesn't cause any problems if the array gets +// used prior to calling this function (since the memory will get +// allocated anyway, on fist usage). Either way however, the momory +// must later be freed using 'free_platform_fallback_folders()'. +// +// Returns: +// +// The value obtained from 'get_platform_fallback_folders()' +// +PBD_API G_CONST_RETURN gchar* G_CONST_RETURN * PBD_APICALLTYPE +alloc_platform_fallback_folders () +{ + return ((G_CONST_RETURN gchar* G_CONST_RETURN *)get_platform_fallback_folders ()); +} + + +//*************************************************************** +// +// free_platform_fallback_folders() +// +// Frees the memory that was previously allocated for the Ardour +// fallback folder array. +// +// Returns: +// +// NONE. +// +PBD_API void PBD_APICALLTYPE +free_platform_fallback_folders () +{ +int index = FOLDER_LOCALE; + + if (fallback_folders) + { + gchar *p = get_platform_fallback_folders()[(fallback_folder_t)index++]; + + while (index < (FALLBACK_FOLDER_MAX+1)) { + if (p) + g_free (p); + + if (index < FALLBACK_FOLDER_MAX) + p = get_platform_fallback_folders()[(fallback_folder_t)index++]; + else + break; + } + + fallback_folders = 0; + } +} + +} // namespace PBD + diff --git a/libs/pbd/localeguard.cc b/libs/pbd/localeguard.cc new file mode 100644 index 0000000000..12093beeaa --- /dev/null +++ b/libs/pbd/localeguard.cc @@ -0,0 +1,34 @@ +#include +#include +#include + +#include "pbd/localeguard.h" + +// JE - added temporarily, to reduce the delay effects when calling +// setlocale() recursively in a Windows GUI thread (we should think +// about moving the caller(s) into a dedicated worker thread). +std::string PBD::LocaleGuard::current; + +PBD::LocaleGuard::LocaleGuard (const char* str) + : old(0) +{ + if (current != str) { + old = strdup (setlocale (LC_NUMERIC, NULL)); + if (strcmp (old, str)) { + if (setlocale (LC_NUMERIC, str)) + current = str; + } + } +} + +PBD::LocaleGuard::~LocaleGuard () +{ + if (old) { + if (setlocale (LC_NUMERIC, old)) + current = old; + + free ((char*)old); + } +} + + diff --git a/libs/pbd/msvc/fpu.cc b/libs/pbd/msvc/fpu.cc new file mode 100644 index 0000000000..6997405928 --- /dev/null +++ b/libs/pbd/msvc/fpu.cc @@ -0,0 +1,124 @@ +#ifdef COMPILER_MSVC // Added by JE - 05-12-2009. Inline assembler instructions + // have been changed to Intel format and (in the case of + // cpuid) was replaced by the equivalent VC++ system call). +#define _XOPEN_SOURCE 600 +#include +#include +#include // Added by JE - 05-12-2009 + +#include +#include + +#include "i18n.h" + +using namespace PBD; +using namespace std; + +FPU::FPU () +{ + unsigned long cpuflags = 0; + + _flags = (Flags)0; + +#ifndef ARCH_X86 + return; + +#else + +#ifndef USE_X86_64_ASM +int cpuInfo[4]; + + __cpuid (cpuInfo, 1); + cpuflags = cpuInfo[3]; +/* + __asm { // This is how the original section would look if converted to Intel syntax. + // However, I have grave doubts about whether it's doing the right thing. + // It seems as if the intention was to retrieve feature information from + // the processor. However, feature information is returned in the ebx register + // (if you believe Wikipedia) or in edx (if you believe Microsoft). Unfortunately, + // both registers get ignored in the original code!! Confused?? Join the club!! + mov eax, 1 + push ebx + cpuid + mov edx, 0 + pop ebx + mov cpuflags, ecx // This can't be right, surely??? + }; */ +#else +// Note that this syntax is currently still in AT&T format ! + asm volatile ( + "pushq %%rbx\n" + "movq $1, %%rax\n" + "cpuid\n" + "movq %%rdx, %0\n" + "popq %%rbx\n" + : "=r" (cpuflags) + : + : "%rax", "%rcx", "%rdx", "memory" + ); + +#endif /* USE_X86_64_ASM */ + + if (cpuflags & (1<<25)) { + _flags = Flags (_flags | (HasSSE|HasFlushToZero)); + } + + if (cpuflags & (1<<26)) { + _flags = Flags (_flags | HasSSE2); + } + + if (cpuflags & (1 << 24)) { + bool aligned_malloc = false; // Added by JE - 05-12-2009 + char* fxbuf = 0; +// This section changed by JE - 05-12-2009 +#ifdef NO_POSIX_MEMALIGN +#if defined(COMPILER_MSVC) || defined(COMPILER_MINGW) // All of these support '_aligned_malloc()' + fxbuf = (char *) _aligned_malloc(512, 16); // (note that they all need at least MSVC runtime 7.0) + aligned_malloc = true; +#else + fxbuf = (char *) malloc(512); +#endif +#else + fxbuf = posix_memalign ((void**)&fxbuf, 16, 512); +#endif + // Verify that fxbuf is correctly aligned + unsigned long buf_addr = (unsigned long)(void*)fxbuf; + if ((0 == buf_addr) || (buf_addr % 16)) + error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg; + else + { + memset(fxbuf, 0, 512); // Initialize the buffer !!! Added by JE - 12-12-2009 + + __asm { + mov eax, fxbuf + fxsave [eax] + }; + + uint32_t mxcsr_mask = *((uint32_t*) &fxbuf[28]); + + /* if the mask is zero, set its default value (from intel specs) */ + + if (mxcsr_mask == 0) { + mxcsr_mask = 0xffbf; + } + + if (mxcsr_mask & (1<<6)) { + _flags = Flags (_flags | HasDenormalsAreZero); + } + + if (aligned_malloc) + _aligned_free (fxbuf); + else + free (fxbuf); + } + } +#endif // ARCH_X86 +} + +FPU::~FPU () +{ +} + +#else // !COMPILER_MSVC + const char* pbd_fpu = "original pbd/fpu.cc takes precedence over this file"; +#endif // COMPILER_MSVC diff --git a/libs/pbd/msvc/mountpoint.cc b/libs/pbd/msvc/mountpoint.cc new file mode 100644 index 0000000000..d30b24462f --- /dev/null +++ b/libs/pbd/msvc/mountpoint.cc @@ -0,0 +1,166 @@ +/* + Copyright (C) 2002 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: mountpoint.cc 3920 2008-10-11 12:34:46Z paul $ +*/ + +#ifdef COMPILER_MSVC + +/* TODO - Still to be implemented */ + +#include +#include +#include +#include +#include + +#include + +using std::string; + +#if HAVE_GETMNTENT +#include + +struct mntent_sorter { + bool operator() (const mntent *a, const mntent *b) { + return strcmp (a->mnt_dir, b->mnt_dir); + } +}; + +string +mountpoint (string path) +{ + FILE *mntf; + mntent *mnt; + unsigned int maxmatch = 0; + unsigned int matchlen; + const char *cpath = path.c_str(); + char best[PATH_MAX+1]; + + if ((mntf = setmntent ("/etc/mtab", "r")) == 0) { + return ""; + } + + best[0] = '\0'; + + while ((mnt = getmntent (mntf))) { + unsigned int n; + + n = 0; + matchlen = 0; + + /* note: strcmp's semantics are not + strict enough to use for this. + */ + + while (cpath[n] && mnt->mnt_dir[n]) { + if (cpath[n] != mnt->mnt_dir[n]) { + break; + } + matchlen++; + n++; + } + + if (cpath[matchlen] == '\0') { + + endmntent (mntf); + return mnt->mnt_dir; + + } else { + + if (matchlen > maxmatch) { + snprintf (best, sizeof(best), "%s", mnt->mnt_dir); + maxmatch = matchlen; + } + } + } + + endmntent (mntf); + + return best; +} + +#else // !HAVE_GETMNTENT + +string +mountpoint (string path) +{ +return ""; + +/* // The rest is commented out temporarily by JE - 30-11-2009 + // (I think this must be the implementation for MacOS). + struct statfs *mntbufp = 0; + int count; + unsigned int maxmatch = 0; + unsigned int matchlen; + const char *cpath = path.c_str(); + char best[PATH_MAX+1]; + + if ((count = getmntinfo(&mntbufp, MNT_NOWAIT)) == 0) { + free(mntbufp); + return "\0"; + } + + best[0] = '\0'; + + for (int i = 0; i < count; ++i) { + unsigned int n = 0; + matchlen = 0; + + // note: strcmp's semantics are not + // strict enough to use for this. + + while (cpath[n] && mntbufp[i].f_mntonname[n]) { + if (cpath[n] != mntbufp[i].f_mntonname[n]) { + break; + } + matchlen++; + n++; + } + + if (cpath[matchlen] == '\0') { + snprintf(best, sizeof(best), "%s", mntbufp[i].f_mntonname); + free(mntbufp); + return best; + + } else { + + if (matchlen > maxmatch) { + snprintf (best, sizeof(best), "%s", mntbufp[i].f_mntonname); + maxmatch = matchlen; + } + } + } + + return best; +*/ +} +#endif // HAVE_GETMNTENT + +#ifdef TEST_MOUNTPOINT + +main (int argc, char *argv[]) +{ + printf ("mp of %s = %s\n", argv[1], mountpoint (argv[1]).c_str()); + exit (0); +} + +#endif // TEST_MOUNTPOINT + +#else // !COMPILER_MSVC + const char* pbd_mountpoint = "original pbd/mountpoint.cc takes precedence over this file"; +#endif // COMPILER_MSVC diff --git a/libs/pbd/msvc/msvc_pbd.cc b/libs/pbd/msvc/msvc_pbd.cc new file mode 100644 index 0000000000..45137da0f3 --- /dev/null +++ b/libs/pbd/msvc/msvc_pbd.cc @@ -0,0 +1,895 @@ +/* + Copyright (C) 2009 John Emmas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef COMPILER_MSVC + +#include + +extern "C" WINBASEAPI BOOL WINAPI +CreateHardLinkA( LPCSTR lpFileName, + LPCSTR lpExistingFileName, + LPSECURITY_ATTRIBUTES lpSecurityAttributes ); // Needs kernel32.lib on anything higher than Win2K + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Should ensure that we include the right + // version - but we'll check anyway, later + +#include + +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +PBD_API int PBD_APICALLTYPE +gettimeofday(struct timeval *__restrict tv, __timezone_ptr_t tz) // Does this need to be exported ? +{ +FILETIME ft; +unsigned __int64 tmpres = 0; +static int tzflag = 0; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres /= 10; /*convert into microseconds*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + struct timezone *ptz = static_cast (tz); + if (!tzflag) + { + _tzset(); + tzflag++; + } + if (ptz) + { + ptz->tz_minuteswest = _timezone / 60; + ptz->tz_dsttime = _daylight; + } + } + + return 0; +} + +// Define the default comparison operators for Windows (ptw32) 'pthread_t' (not used +// by Ardour AFAIK but would be needed if an array of 'pthread_t' had to be sorted). +#ifndef PTHREAD_H // Defined by PTW32 (Linux and other versions define _PTHREAD_H) +#error "An incompatible version of 'pthread.h' is #included. Use only the Windows (ptw32) version!" +#else +bool operator> (const pthread_t& lhs, const pthread_t& rhs) +{ + return (std::greater()(lhs.p, rhs.p)); +} + +bool operator< (const pthread_t& lhs, const pthread_t& rhs) +{ + return (std::less()(lhs.p, rhs.p)); +} + +bool operator!= (const pthread_t& lhs, const pthread_t& rhs) +{ + return (std::not_equal_to()(lhs.p, rhs.p)); +} + +bool operator== (const pthread_t& lhs, const pthread_t& rhs) +{ + return (!(lhs != rhs)); +} +#endif + +// Functions supplied (later) to std::transform +//*************************************************************** +// +// invert_backslash() +// +// Examines a supplied ASCII character and (if the character is +// a backslash) converts it to a forward slash, +// +// Returns: +// +// The supplied character (converted, if it was a backslash) +// +char invert_backslash(char character) +{ + if ('\\' == character) + character = '/'; + + return (character); +} + +//*************************************************************** +// +// invert_forwardslash() +// +// Examines a supplied ASCII character and (if the character is +// a forward slash) converts it to a backslash, +// +// Returns: +// +// The supplied character (converted, if it was a fwd slash) +// +char invert_forwardslash(char character) +{ + if ('/' == character) + character = '\\'; + + return (character); +} + + +//*************************************************************** +// +// pread() +// +// Emulates pread() using _lseek()/_read()/_lseek(). +// +// Returns: +// +// On Success: The number of bytes read from the file +// On Failure: -1 +// +PBD_API ssize_t PBD_APICALLTYPE +pread(int handle, void *buf, size_t nbytes, off_t offset) +{ +int old_errno; +ssize_t ret; + + off_t old_offset = _tell(handle); + + if (0 > old_offset) + ret = (-1); + else + { + _lseek(handle, offset, SEEK_SET); + ret = _read(handle, buf, nbytes); + + old_errno = errno; + _lseek(handle, old_offset, SEEK_SET); + errno = old_errno; + } + + return (ret); +} + + +//*************************************************************** +// +// pwrite() +// +// Emulates pwrite() using _lseek()/_write()/_lseek(). +// +// Returns: +// +// On Success: The number of bytes written to the file +// On Failure: -1 +// +PBD_API ssize_t PBD_APICALLTYPE +pwrite(int handle, const void *buf, size_t nbytes, off_t offset) +{ +int old_errno; +ssize_t ret; + + off_t old_offset = _lseek(handle, offset, SEEK_SET); + + if (0 > old_offset) + ret = (-1); + else + { + ret = _write(handle, buf, nbytes); + + old_errno = errno; + _lseek(handle, old_offset, SEEK_SET); + errno = old_errno; + } + + return (ret); +} + +namespace PBD { + +//*************************************************************** +// +// TestForMinimumSpecOS() +// +// Tests the user's OS to see if it is Win2K or later (could be +// expanded quite easily to accommodate other OS's) +// +// Returns: +// +// On Success: TRUE (if the user's OS matches the minimum spec) +// On Failure: FALSE otherwise +// +PBD_API bool PBD_APICALLTYPE +TestForMinimumSpecOS(char *revision /* currently ignored */) +{ +bool bRet = true; +#ifdef PLATFORM_WINDOWS + bRet = false; + HINSTANCE hKernelDll = (HINSTANCE)dlopen("kernel32.dll", RTLD_NOW); + + if (hKernelDll) + { + // 'CreateHardLink()' is only available from Win2K onwards. + if (NULL != dlsym(hKernelDll, "CreateHardLinkA")) + bRet = true; + + dlclose(hKernelDll); + } +#endif + // Other OS's could be accommodated here + + return (bRet); +} + + +//*************************************************************** +// +// realpath() +// +// Emulates POSIX realpath() using Win32 _fullpath(). +// +// Returns: +// +// On Success: A pointer to the resolved (absolute) path +// On Failure: NULL +// +PBD_API char* PBD_APICALLTYPE +realpath (const char *original_path, char resolved_path[_MAX_PATH+1]) +{ +char *pRet = NULL; +bool bIsSymLink = 0; // We'll probably need to test the incoming path + // to find out if it points to a Windows shortcut + // (or a hard link) and set this appropriately. + if (bIsSymLink) + { + // At the moment I'm not sure if Windows '_fullpath()' is directly + // equivalent to POSIX 'realpath()' - in as much as the latter will + // resolve the supplied path if it happens to point to a symbolic + // link ('_fullpath()' probably DOESN'T do this but I'm not really + // sure if Ardour needs such functionality anyway). Therefore we'll + // possibly need to add that functionality here at a later date. + } + else + { + char temp[(MAX_PATH+1)*6]; // Allow for maximum length of a path in UTF8 characters + + // POSIX 'realpath()' requires that the buffer size is at + // least PATH_MAX+1, so assume that the user knew this !! + pRet = _fullpath(temp, Glib::locale_from_utf8(original_path).c_str(), _MAX_PATH); + if (NULL != pRet) + strcpy(resolved_path, Glib::locale_to_utf8(temp).c_str()); + } + + return (pRet); +} + + +//*************************************************************** +// +// opendir() +// +// Creates a pointer to a DIR structure, appropriately filled in +// and ready to begin a directory search iteration. +// +// Returns: +// +// On Success: Pointer to a (heap based) DIR structure +// On Failure: NULL +// +PBD_API DIR* PBD_APICALLTYPE +opendir (const char *szPath) +{ +wchar_t wpath[PATH_MAX+1]; +unsigned int rc; +DIR *pDir = 0; + + errno = 0; + + if (!szPath) + errno = EFAULT; + + if ((!errno) && ('\0' == szPath[0])) + errno = ENOTDIR; + + // Determine if the given path really is a directory + + if (!errno) + if (0 == MultiByteToWideChar (CP_UTF8, 0, (LPCSTR)szPath, -1, (LPWSTR)wpath, sizeof(wpath))) + errno = EFAULT; + + if ((!errno) && ((rc = GetFileAttributesW(wpath)) == -1)) + errno = ENOENT; + + if ((!errno) && (!(rc & FILE_ATTRIBUTE_DIRECTORY))) + // Error. Entry exists but not a directory. */ + errno = ENOTDIR; + + if (!errno) + { + // Allocate enough memory to store DIR structure, plus + // the complete directory path originally supplied. + pDir = (DIR *)malloc(sizeof(DIR) + strlen(szPath) + strlen("\\") + strlen ("*")); + + if (!pDir) + { + // Error - out of memory + errno = ENOMEM; + } + } + + if (!errno) + { + // Create the search expression + strcpy(pDir->dd_name, szPath); + + // Add a backslash if the path doesn't already end with one + if (pDir->dd_name[0] != '\0' && + pDir->dd_name[strlen(pDir->dd_name) - 1] != '/' && + pDir->dd_name[strlen(pDir->dd_name) - 1] != '\\') + { + strcat (pDir->dd_name, "\\"); + } + + // Add the search pattern + strcat(pDir->dd_name, "*"); + + // Initialize handle to -1 so that a premature closedir() + // doesn't try to call _findclose() on it. + pDir->dd_handle = (-1); + + // Initialize the status + pDir->dd_stat = 0; + + // Initialize the dirent structure. 'ino' and 'reclen' are invalid under Win32 + // and 'name' simply points at the appropriate part of the findfirst_t struct. + pDir->dd_dir.d_ino = 0; + pDir->dd_dir.d_reclen = 0; + pDir->dd_dir.d_namlen = 0; + strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name); + + return (pDir); // Succeeded + } + + if (pDir) + free (pDir); + return (DIR *) 0; // Failed +} + + +//*************************************************************** +// +// readdir() +// +// Return a pointer to a dirent struct, filled with information +// about the next entry in the directory. +// +// Returns: +// +// On Success: A pointer to the supplied DIR's 'dirent' struct +// On Failure: NULL +// +PBD_API struct dirent* PBD_APICALLTYPE +readdir (DIR* pDir) +{ +int old_errno = 0; +errno = 0; + + // Check for valid DIR struct + if (!pDir) + errno = EFAULT; + + if ((strcmp(pDir->dd_dir.d_name, pDir->dd_dta.name)) && (!errno)) + // The structure does not seem to be set up correctly + errno = EINVAL; + else + { + if (pDir->dd_stat < 0) + { + // We have already returned all files in this directory + // (or the structure has an invalid dd_stat). + return (struct dirent *)0; + } + else if (pDir->dd_stat == 0) + { + // We haven't started the search yet. + // Start the search + pDir->dd_handle = _findfirst (Glib::locale_from_utf8(pDir->dd_name).c_str(), &(pDir->dd_dta)); + + if (pDir->dd_handle == -1) + // The directory is empty + pDir->dd_stat = -1; + else + pDir->dd_stat = 1; + } + else + { + // Do not return ENOENT on last file in directory + old_errno = errno; + + // Get the next search entry + if (_findnext (pDir->dd_handle, &(pDir->dd_dta))) + { + // We are off the end or otherwise error + errno = old_errno; + _findclose (pDir->dd_handle); + pDir->dd_handle = -1; + pDir->dd_stat = -1; + } + else + // Update to indicate the correct status number + pDir->dd_stat++; + } + + if (pDir->dd_stat > 0) + { + // We successfully got an entry. Details about the file are + // already appropriately filled in except for the length of + // file name. + strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name); + pDir->dd_dir.d_namlen = strlen (pDir->dd_dir.d_name); + return (&pDir->dd_dir); // Succeeded + } + } + + return (struct dirent *) 0; // Failed +} + + +//*************************************************************** +// +// closedir() +// +// Frees the resources allocated by opendir(). +// +// Returns: +// +// On Success: 0 +// On Failure: -1 +// +PBD_API int PBD_APICALLTYPE +closedir (DIR *pDir) +{ +int rc = 0; + + errno = 0; + + if (!pDir) + errno = EFAULT; + else + { + if ((-1) != pDir->dd_handle) + rc = _findclose (pDir->dd_handle); + + // Free the DIR structure + free (pDir); + + return rc; // Succeeded + } + + return (-1); // Failed +} + +//*************************************************************** +// +// mkstemp() +// +// Emulates Linux mkstemp() using Win32 _mktemp() and _open() etc. +// +// Returns: +// +// On Success: A file descriptor for the opened file. +// On Failure: (-1) +// +PBD_API int PBD_APICALLTYPE +mkstemp (char *template_name) +{ +int ret = (-1); +char *szFileName; +char szTempPath[PATH_MAX+100]; // Just ensure we have plenty of buffer space + + if (NULL != (szFileName = _mktemp(template_name))) + { + if (0 != ::GetTempPathA(sizeof(szTempPath), szTempPath)) + { + strcat(szTempPath, szFileName); + ret = _open(szTempPath, (_O_CREAT|_O_BINARY|_O_TEMPORARY|_O_RDWR|_O_TRUNC), _S_IWRITE); + } + } + + return (ret); +} + + +//*************************************************************** +// +// ntfs_link() +// +// Emulates Linux link() using Win32 CreateHardLink()(NTFS only). +// +// Returns: +// +// On Success: Non-zero. +// On Failure: Zero (call 'GetLastError()' to retrieve info) +// +PBD_API int PBD_APICALLTYPE +ntfs_link (const char *existing_filepath, const char *link_filepath) +{ +int ret = 1; // 'ERROR_INVALID_FUNCTION' +bool bValidPath = false; + + // Make sure we've been sent a valid input string + if (existing_filepath && link_filepath) + { + std::string strRoot = existing_filepath; + + if ((1 < strRoot.length()) && ('\\' == existing_filepath[0]) && ('\\' == existing_filepath[1])) + { + int slashcnt = 0; + + // We've been sent a network path. Convert backslashes to forward slashes temporarily. + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash); + + // Now, if there are less than four slashes, add a fourth one or abort + std::string::iterator iter = strRoot.begin(); + while ((slashcnt < 4) && (iter != strRoot.end())) + { + if ('/' == (*iter)) + slashcnt++; + + ++iter; + } + + if (slashcnt > 2) + { + // If only 3 slashes were counted, add a trailing slash + if (slashcnt == 3) + strRoot += '/'; + + // Now find the position of the fourth slash + iter = strRoot.begin(); + int charcnt = 0; + for (slashcnt=0; slashcnt<4;) + { + charcnt++; + + if ('/' == (*iter)) + slashcnt++; + + if (++iter == strRoot.end()) + break; + } + + strRoot.resize(charcnt); + bValidPath = true; + } + } + else + { + // Assume a standard Windows style path + if (1 < strRoot.length() && (':' == existing_filepath[1])) + { + // Convert backslashes to forward slashes temporarily. + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash); + + if (2 == strRoot.length()) + strRoot += '/'; + + if ('/' == strRoot[2]) + { + strRoot.resize(3); + bValidPath = true; + } + } + } + + if (bValidPath) + { + char szFileSystemType[_MAX_PATH+1]; + + // Restore the original backslashes + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash); + + // Windows only supports hard links for the NTFS filing + // system, so let's make sure that's what we're using!! + if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1)) + { + std::string strRootFileSystemType = szFileSystemType; + std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper); +#if (_WIN32_WINNT >= 0x0500) + if (0 == strRootFileSystemType.compare("NTFS")) + { + if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards + if (0 == CreateHardLinkA(link_filepath, existing_filepath, NULL)) + { // Note that the above API call cannot create a link to a directory, so + // should we also be checking that the supplied path was actually a file? + ret = GetLastError(); + } + else + SetLastError(ret = 0); // 'NO_ERROR' + } + else + { + ret = 4300; // 'ERROR_INVALID_MEDIA' + } +#endif + } + } + else + ret = 123; // 'ERROR_INVALID_NAME' + } + else + ret = 161; // 'ERROR_BAD_PATHNAME' + + if (ret) + { + SetLastError(ret); + return (-1); + } + else + return (0); +} + + +//*************************************************************** +// +// ntfs_unlink() +// +// Emulates Linux unlink() using Win32 DeleteFile()(NTFS only). +// +// Returns: +// +// On Success: Non-zero. +// On Failure: Zero (call 'GetLastError()' to retrieve info) +// +PBD_API int PBD_APICALLTYPE +ntfs_unlink (const char *link_filepath) +{ +int ret = 1; // 'ERROR_INVALID_FUNCTION' +bool bValidPath = false; + + // Make sure we've been sent a valid input string + if (link_filepath) + { + std::string strRoot = link_filepath; + + if ((1 < strRoot.length()) && ('\\' == link_filepath[0]) && ('\\' == link_filepath[1])) + { + int slashcnt = 0; + + // We've been sent a network path. Convert backslashes to forward slashes temporarily. + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash); + + // Now, if there are less than four slashes, add a fourth one or abort + std::string::iterator iter = strRoot.begin(); + while ((slashcnt < 4) && (iter != strRoot.end())) + { + if ('/' == (*iter)) + slashcnt++; + + ++iter; + } + + if (slashcnt > 2) + { + // If only 3 slashes were counted, add a trailing slash + if (slashcnt == 3) + strRoot += '/'; + + // Now find the position of the fourth slash + iter = strRoot.begin(); + int charcnt = 0; + for (slashcnt=0; slashcnt<4;) + { + charcnt++; + + if ('/' == (*iter)) + slashcnt++; + + if (++iter == strRoot.end()) + break; + } + + strRoot.resize(charcnt); + bValidPath = true; + } + } + else + { + // Assume a standard Windows style path + if (1 < strRoot.length() && (':' == link_filepath[1])) + { + // Convert backslashes to forward slashes temporarily. + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash); + + if (2 == strRoot.length()) + strRoot += '/'; + + if ('/' == strRoot[2]) + { + strRoot.resize(3); + bValidPath = true; + } + } + } + + if (bValidPath) + { + char szFileSystemType[_MAX_PATH+1]; + + // Restore the original backslashes + std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash); + + // Windows only supports hard links for the NTFS filing + // system, so let's make sure that's what we're using!! + if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1)) + { + std::string strRootFileSystemType = szFileSystemType; + std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper); +#if (_WIN32_WINNT >= 0x0500) + if (0 == strRootFileSystemType.compare("NTFS")) + if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards + if (0 == DeleteFileA(link_filepath)) + ret = GetLastError(); + else + ret = 0; // 'NO_ERROR' +#endif + } + } + else + ret = 123; // 'ERROR_INVALID_NAME' + } + else + ret = 161; // 'ERROR_BAD_PATHNAME' + + if (ret) + { + SetLastError(ret); + return (-1); + } + else + return (0); +} + +} // namespace PBD + + +//*************************************************************** +// +// dlopen() +// +// Emulates POSIX dlopen() using Win32 LoadLibrary(). +// +// Returns: +// +// On Success: A handle to the opened DLL +// On Failure: NULL +// +PBD_API void* PBD_APICALLTYPE +dlopen (const char *file_name, int mode) +{ + // Note that 'mode' is ignored in Win32 + return(::LoadLibraryA(Glib::locale_from_utf8(file_name).c_str())); +} + + +//*************************************************************** +// +// dlclose() +// +// Emulates POSIX dlclose() using Win32 FreeLibrary(). +// +// Returns: +// +// On Success: A non-zero number +// On Failure: 0 +// +PBD_API int PBD_APICALLTYPE +dlclose (void *handle) +{ + return (::FreeLibrary((HMODULE)handle)); +} + + +//*************************************************************** +// +// dlsym() +// +// Emulates POSIX dlsym() using Win32 GetProcAddress(). +// +// Returns: +// +// On Success: A pointer to the found function or symbol +// On Failure: NULL +// +PBD_API void* PBD_APICALLTYPE +dlsym (void *handle, const char *symbol_name) +{ + // First test for RTLD_DEFAULT and RTLD_NEXT + if ((handle == 0/*RTLD_DEFAULT*/) || (handle == ((void *) -1L)/*RTLD_NEXT*/)) + { + return 0; // Not yet supported for Win32 + } + else + return (::GetProcAddress((HMODULE)handle, symbol_name)); +} + +#define LOCAL_ERROR_BUF_SIZE 1024 +static char szLastWinError[LOCAL_ERROR_BUF_SIZE]; +//*************************************************************** +// +// dlerror() +// +// Emulates POSIX dlerror() using Win32 GetLastError(). +// +// Returns: +// +// On Success: The translated message corresponding to the +// last error +// On Failure: NULL (if the last error was ERROR_SUCCESS) +// +PBD_API char* PBD_APICALLTYPE +dlerror () +{ + DWORD dwLastErrorId = GetLastError(); + if (ERROR_SUCCESS == dwLastErrorId) + return 0; + else + { + if (0 == FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwLastErrorId, + 0, + szLastWinError, + LOCAL_ERROR_BUF_SIZE, + 0)) + { + sprintf(szLastWinError, "Could not decipher the previous error message"); + } + + // POSIX dlerror() seems to reset the + // error system, so emulate that here + SetLastError(ERROR_SUCCESS); + } + + return(szLastWinError); +} + +#endif // COMPILER_MSVC diff --git a/libs/pbd/msvc/msvc_poll.cc b/libs/pbd/msvc/msvc_poll.cc new file mode 100644 index 0000000000..e12ef2bbef --- /dev/null +++ b/libs/pbd/msvc/msvc_poll.cc @@ -0,0 +1,215 @@ +/* + Copyright (C) 2009 John Emmas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef COMPILER_MSVC + +//#include +#include "pbd/msvc_pbd.h" + +#ifndef _DWORD_DEFINED +#define _DWORD_DEFINED +typedef unsigned long DWORD; +#endif // !_DWORD_DEFINED + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Note that this entire strategy failed to work, at least for pipes. It turned * + * out that Windows 'tell()' always returns 0 when used on a pipe. This strategy * + * is now deprecated, having been replaced by a new pipe-like object, which I've * + * called 'PBD::pipex'. This polling functionality is included here mostly so * + * that Ardour will build and launch under Windows. However, any module that * + * relies on polling a pipe will eventually need to use the new pipex object. * + * This code will allow it to compile and link successfully, although it won't * + * poll successfully at run time. Having said that, these functions might well * + * work for ports and/or other machanisms that get represented by a file handle. * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int poll_input (struct pollfd *fds, nfds_t nfds, int& elapsed_time, int timeout) +{ +DWORD dwOldTickCount, + dwNewTickCount = GetTickCount(); +bool input = false, + error = false; +int ret = 0; + + if (NULL != fds) + { + nfds_t loop; + short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND); + + errno = NO_ERROR; + + do + { + dwOldTickCount = dwNewTickCount; + + for (loop=0; loop pos) + { + // An error occured ('errno' should have been set by '_tell()') + ret = (-1); + fds[loop].revents = POLLERR; + if (fds[loop].events & POLLRDNORM) + fds[loop].revents |= POLLRDNORM; + if (fds[loop].events & POLLRDBAND) + fds[loop].revents |= POLLRDBAND; + if (fds[loop].events & POLLPRI) + fds[loop].revents |= POLLPRI; + + // Do we want to abort on error? + if (fds[loop].events & POLLERR) + error = true; + } + else if (pos > 0) + { + // Input characters were found for this fd + ret += 1; + if (fds[loop].events & POLLRDNORM) + fds[loop].revents |= POLLRDNORM; + if (fds[loop].events & POLLRDBAND) + fds[loop].revents |= POLLRDBAND; + if (fds[loop].events & POLLPRI) + fds[loop].revents |= POLLPRI; + + // Do we want to abort on input? + if ((fds[loop].events & POLLIN) || + (fds[loop].events & POLLPRI) || + (fds[loop].events & POLLRDNORM) || + (fds[loop].events & POLLRDBAND)) + input = true; + } + } + } + + if (input) + break; + + dwNewTickCount = GetTickCount(); + elapsed_time += (dwNewTickCount-dwOldTickCount); + // Note that the above will wrap round if the user leaves + // his computer powered up for more than about 50 days! + + // Sleep briefly because GetTickCount() only has an accuracy of 10mS + Sleep(10); // For some reason 'g_usleep()' craps over everything here. Different 'C' runtimes??? + + } while ((!error) && ((timeout == (-1)) || (elapsed_time < timeout))); + } + else + { + errno = ERROR_BAD_ARGUMENTS; + ret = (-1); + } + + return (ret); +} + +int poll_output (struct pollfd *fds, nfds_t nfds, int& elapsed_time, int timeout) +{ +int ret = 0; // This functionality is not yet implemented + + if (NULL != fds) + { + // Just flag whichever pollfd was specified for writing + short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND); + + errno = NO_ERROR; + elapsed_time = 0; + + for (nfds_t loop=0; loop OPEN_MAX) || (nfds > NPOLLFILE)) + { + errno = ERROR_TOO_MANY_OPEN_FILES; + } + else + { + ret = 0; + + for (nfds_t loop=0; loop +#include + +#ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!! + PBD_API gchar* PBD_APICALLTYPE get_win_special_folder (int csidl); +#endif + +namespace PBD { + + typedef enum fallback_folder_t { + FOLDER_LOCALE, + FOLDER_GTK, + FOLDER_CONFIG, + FOLDER_ARDOUR, + FOLDER_MODULE, + FOLDER_DATA, + FOLDER_ICONS, + FOLDER_PIXMAPS, + FOLDER_CONTROL_SURFACES, + FOLDER_VAMP, + FOLDER_LADSPA, + FOLDER_VST, + FOLDER_BUNDLED_LV2, + FALLBACK_FOLDER_MAX + }; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + PBD_API G_CONST_RETURN gchar* PBD_APICALLTYPE get_platform_fallback_folder (PBD::fallback_folder_t index); + PBD_API G_CONST_RETURN gchar* G_CONST_RETURN * PBD_APICALLTYPE alloc_platform_fallback_folders (); + PBD_API void PBD_APICALLTYPE free_platform_fallback_folders (); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +} // namespace PBD + +#endif /* __platform_fallback_folders_h__ */ diff --git a/libs/pbd/pbd/localeguard.h b/libs/pbd/pbd/localeguard.h new file mode 100644 index 0000000000..20899b5c80 --- /dev/null +++ b/libs/pbd/pbd/localeguard.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 1999-2010 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_localeguard_h__ +#define __pbd_localeguard_h__ + +#include + +namespace PBD { + +struct LocaleGuard { + LocaleGuard (const char*); + ~LocaleGuard (); + const char* old; + + /* JE - temporary !!!! */static std::string current; +}; + +}; // namespace + +#endif /* __pbd_localeguard_h__ */ diff --git a/libs/pbd/pbd/msvc_pbd.h b/libs/pbd/pbd/msvc_pbd.h new file mode 100644 index 0000000000..1c971308d7 --- /dev/null +++ b/libs/pbd/pbd/msvc_pbd.h @@ -0,0 +1,235 @@ +/* + Copyright (C) 2009 John Emmas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +#ifndef _msvc_pbd_h_ +#define _msvc_pbd_h_ + +#ifdef PBD_IS_IN_WIN_STATIC_LIB // #define if your project uses libpbd (under Windows) as a static library +#define PBD_IS_IN_WINDLL 0 +#endif + +#ifdef COMPILER_MSVC +#include +#else +#include +#include +#endif + +#if !defined(PBD_IS_IN_WINDLL) + #if defined(COMPILER_MSVC) || defined(COMPILER_MINGW) + // If you need '__declspec' compatibility, add extra compilers to the above as necessary + #define PBD_IS_IN_WINDLL 1 + #else + #define PBD_IS_IN_WINDLL 0 + #endif +#endif + +#if PBD_IS_IN_WINDLL && !defined(PBD_API) + #if defined(BUILDING_PBD) + #define PBD_API __declspec(dllexport) + #define PBD_APICALLTYPE __stdcall + #elif defined(COMPILER_MSVC) || defined(COMPILER_MINGW) // Probably needs Cygwin too, at some point + #define PBD_API __declspec(dllimport) + #define PBD_APICALLTYPE __stdcall + #else + #error "Attempting to define __declspec with an incompatible compiler !" + #endif +#elif !defined(PBD_API) + // Other compilers / platforms could be accommodated here + #define PBD_API + #define PBD_APICALLTYPE +#endif + +#ifndef _MAX_PATH +#define _MAX_PATH 260 +#endif +#ifndef PATH_MAX +#define PATH_MAX _MAX_PATH +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +// This function is (hopefully) temporary and is placed here +// because 'g_usleep()' doesn't seem to work very well for glib-win32 +void pbd_g_usleep (unsigned long microseconds); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#ifndef POLLIN +#define POLLIN 1 +#define POLLPRI 2 +#define POLLOUT 4 +#define POLLERR 8 +#define POLLHUP 16 +#define POLLNVAL 32 +#define NPOLLFILE 64 + +#define POLLRDNORM POLLIN +#define POLLRDBAND POLLIN +#define POLLWRNORM POLLOUT +#define POLLWRBAND POLLOUT +#endif + +#ifdef PLATFORM_WINDOWS + +#ifndef PBDEXTN_API + #if defined(BUILDING_PBDEXTN) + #define PBDEXTN_API __declspec(dllexport) + #define PBDEXTN_APICALLTYPE __cdecl + #elif defined(COMPILER_MSVC) || defined(COMPILER_MINGW) // Probably needs Cygwin too, at some point + #define PBDEXTN_API __declspec(dllimport) + #define PBDEXTN_APICALLTYPE __cdecl + #else + #error "Attempting to define __declspec with an incompatible compiler !" + #endif +#endif // PBDEXTN_API + +#ifndef CYGIMPORT_API + #define CYGIMPORT_API __declspec(dllimport) + #define CYGIMPORT_APICALLTYPE __cdecl +#endif // CYGIMPORT_API + +#ifndef __THROW +#define __THROW throw() +#endif + +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT ((void *) 0) +#define RTLD_NEXT ((void *) -1L) +#define RTLD_LAZY 0x00001 +#define RTLD_NOW 0x00002 +#define RTLD_BINDING_MASK 0x00003 +#define RTLD_NOLOAD 0x00004 +#define RTLD_GLOBAL 0x00004 +#define RTLD_DEEPBIND 0x00008 +#endif + +#ifndef OPEN_MAX +#define OPEN_MAX 32 +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +PBDEXTN_API int PBDEXTN_APICALLTYPE cyginit (unsigned int result); +PBD_API int PBD_APICALLTYPE dlclose (void *handle) __THROW; +PBD_API void* PBD_APICALLTYPE dlopen (const char *file_name, int mode) __THROW; +PBD_API void* PBD_APICALLTYPE dlsym (void *handle, const char *symbol_name) __THROW; +PBD_API char* PBD_APICALLTYPE dlerror () __THROW; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#ifndef __CYGWIN__ +#include +#include +#include + +typedef int (FAR PBDEXTN_APICALLTYPE *CYGINIT_API)(unsigned int); + +#ifndef FILENAME_MAX +#define FILENAME_MAX (260) +#endif + +#ifndef _SSIZE_T_ +#define _SSIZE_T_ +typedef long _ssize_t; + +#ifndef _NO_OLDNAMES +typedef _ssize_t ssize_t; +#endif +#endif /* ! _SSIZE_T_ */ + +struct dirent +{ + long d_ino; // Always zero + unsigned short d_reclen; // Always zero + unsigned short d_namlen; // Length of name in d_name + char d_name[FILENAME_MAX]; // File name +}; + +// This is an internal data structure. Do not use it +// except as an argument to one of the functions below. +typedef struct +{ + // Disk transfer area for this dir + struct _finddata_t dd_dta; + + // 'dirent' struct to return from dir (NOTE: this + // is not thread safe). + struct dirent dd_dir; + + // '_findnext()' handle + long dd_handle; + + // Current status of search: + // 0 = not started yet (next entry to read is first entry) + // -1 = off the end + // Otherwise - positive (0 based) index of next entry + int dd_stat; + + // Full path for dir with search pattern (struct will be extended) + char dd_name[1]; +} DIR; + +struct pollfd +{ + int fd; + short events; + short revents; +}; + +typedef unsigned int nfds_t; + +PBD_API int PBD_APICALLTYPE gettimeofday(struct timeval *__restrict tv, __timezone_ptr_t tz); +PBD_API ssize_t PBD_APICALLTYPE pread(int handle, void *buf, size_t nbytes, off_t offset); +PBD_API ssize_t PBD_APICALLTYPE pwrite(int handle, const void *buf, size_t nbytes, off_t offset); +PBD_API int PBD_APICALLTYPE poll(struct pollfd *fds, nfds_t nfds, int timeout); + +namespace PBD { + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +PBD_API bool PBD_APICALLTYPE TestForMinimumSpecOS(char *revision="currently ignored"); +PBD_API char* PBD_APICALLTYPE realpath (const char *original_path, char resolved_path[_MAX_PATH+1]); +PBD_API int PBD_APICALLTYPE mkstemp (char *template_name); +PBD_API int PBD_APICALLTYPE ntfs_link (const char *existing_filepath, const char *link_filepath); +PBD_API int PBD_APICALLTYPE ntfs_unlink (const char *link_filepath); + +// These are used to replicate 'dirent.h' functionality +PBD_API DIR* PBD_APICALLTYPE opendir (const char *szPath); +PBD_API struct dirent* PBD_APICALLTYPE readdir (DIR *pDir); +PBD_API int PBD_APICALLTYPE closedir (DIR *pDir); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +} // namespace PBD + +#endif // !__CYGWIN__ +#endif // PLATFORM_WINDOWS +#endif // _msvc_pbd_h_