JOHNE source files (needed for building libpbd with MSVC)
This commit is contained in:
parent
57f9a4c344
commit
110972e59a
591
libs/pbd/fallback_folders.cc
Normal file
591
libs/pbd/fallback_folders.cc
Normal file
@ -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 <pbd/fallback_folders.h>
|
||||
#include <glib.h>
|
||||
#include <glibmm.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
#ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!!
|
||||
#include <shlobj.h>
|
||||
#include <winreg.h>
|
||||
|
||||
//***************************************************************
|
||||
//
|
||||
// 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
|
||||
|
34
libs/pbd/localeguard.cc
Normal file
34
libs/pbd/localeguard.cc
Normal file
@ -0,0 +1,34 @@
|
||||
#include <cstring>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
|
124
libs/pbd/msvc/fpu.cc
Normal file
124
libs/pbd/msvc/fpu.cc
Normal file
@ -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 <cstdlib>
|
||||
#include <stdint.h>
|
||||
#include <intrin.h> // Added by JE - 05-12-2009
|
||||
|
||||
#include <pbd/fpu.h>
|
||||
#include <pbd/error.h>
|
||||
|
||||
#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
|
166
libs/pbd/msvc/mountpoint.cc
Normal file
166
libs/pbd/msvc/mountpoint.cc
Normal file
@ -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 <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
|
||||
#include <pbd/mountpoint.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
#if HAVE_GETMNTENT
|
||||
#include <mntent.h>
|
||||
|
||||
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
|
895
libs/pbd/msvc/msvc_pbd.cc
Normal file
895
libs/pbd/msvc/msvc_pbd.cc
Normal file
@ -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 <WTypes.h>
|
||||
|
||||
extern "C" WINBASEAPI BOOL WINAPI
|
||||
CreateHardLinkA( LPCSTR lpFileName,
|
||||
LPCSTR lpExistingFileName,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes ); // Needs kernel32.lib on anything higher than Win2K
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pbd/error.h>
|
||||
#include <ardourext/misc.h>
|
||||
#include <ardourext/pthread.h> // Should ensure that we include the right
|
||||
// version - but we'll check anyway, later
|
||||
|
||||
#include <glibmm.h>
|
||||
|
||||
#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<struct timezone*> (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<void*>()(lhs.p, rhs.p));
|
||||
}
|
||||
|
||||
bool operator< (const pthread_t& lhs, const pthread_t& rhs)
|
||||
{
|
||||
return (std::less<void*>()(lhs.p, rhs.p));
|
||||
}
|
||||
|
||||
bool operator!= (const pthread_t& lhs, const pthread_t& rhs)
|
||||
{
|
||||
return (std::not_equal_to<void*>()(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
|
215
libs/pbd/msvc/msvc_poll.cc
Normal file
215
libs/pbd/msvc/msvc_poll.cc
Normal file
@ -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 <glib/gtimer.h>
|
||||
#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<nfds; loop++)
|
||||
fds[loop].revents = 0;
|
||||
|
||||
for (loop=0; (loop<nfds && !error); loop++)
|
||||
{
|
||||
if (!(fds[loop].events & ev_mask))
|
||||
{
|
||||
long pos = _tell(fds[loop].fd);
|
||||
|
||||
if (0 > 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<nfds; loop++)
|
||||
{
|
||||
if (fds[loop].events & ev_mask)
|
||||
{
|
||||
fds[loop].revents = POLLNVAL;
|
||||
errno = ERROR_INVALID_ACCESS;
|
||||
ret = (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ERROR_BAD_ARGUMENTS;
|
||||
ret = (-1);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
//***************************************************************
|
||||
//
|
||||
// poll()
|
||||
//
|
||||
// Emulates POSIX poll() using Win32 _tell().
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// On Success: A positive integer indicating the total number
|
||||
// of file descriptors that were available for
|
||||
// writing or had data available for reading.
|
||||
// On Failure: -1 (the actual error is saved in 'errno').
|
||||
//
|
||||
PBD_API int PBD_APICALLTYPE
|
||||
poll (struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
int elapsed_time = 0;
|
||||
int ret = (-1);
|
||||
|
||||
// Note that this functionality is not fully implemented.
|
||||
// At the time of writing, Ardour seems only to poll on
|
||||
// read pipes. Therefore return an error if any write
|
||||
// pipe seems to have been specified or if too many file
|
||||
// descriptors were passed.
|
||||
short ev_mask = (POLLOUT|POLLWRNORM|POLLWRBAND);
|
||||
|
||||
if ((nfds > OPEN_MAX) || (nfds > NPOLLFILE))
|
||||
{
|
||||
errno = ERROR_TOO_MANY_OPEN_FILES;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
|
||||
for (nfds_t loop=0; loop<nfds; loop++)
|
||||
{
|
||||
if (fds[loop].events & ev_mask)
|
||||
{
|
||||
ret = poll_output(fds, nfds, elapsed_time, timeout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == ret)
|
||||
{
|
||||
// Poll for input
|
||||
ret = poll_input(fds, nfds, elapsed_time, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif //COMPILER_MSVC
|
62
libs/pbd/pbd/fallback_folders.h
Normal file
62
libs/pbd/pbd/fallback_folders.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
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 __platform_fallback_folders_h__
|
||||
#define __platform_fallback_folders_h__
|
||||
|
||||
#include <pbd/msvc_pbd.h>
|
||||
#include <glib/gtypes.h>
|
||||
|
||||
#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__ */
|
37
libs/pbd/pbd/localeguard.h
Normal file
37
libs/pbd/pbd/localeguard.h
Normal file
@ -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 <string>
|
||||
|
||||
namespace PBD {
|
||||
|
||||
struct LocaleGuard {
|
||||
LocaleGuard (const char*);
|
||||
~LocaleGuard ();
|
||||
const char* old;
|
||||
|
||||
/* JE - temporary !!!! */static std::string current;
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif /* __pbd_localeguard_h__ */
|
235
libs/pbd/pbd/msvc_pbd.h
Normal file
235
libs/pbd/pbd/msvc_pbd.h
Normal file
@ -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 <sys/time.h>
|
||||
#else
|
||||
#include <ardourext/misc.h>
|
||||
#include <ardourext/sys/time.h>
|
||||
#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 <rpc.h>
|
||||
#include <io.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
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_
|
Loading…
Reference in New Issue
Block a user