summaryrefslogtreecommitdiff
path: root/libs/pbd/msvc
diff options
context:
space:
mode:
authorJohn Emmas <johne53@tiscali.co.uk>2013-07-17 14:53:17 +0100
committerJohn Emmas <johne53@tiscali.co.uk>2013-07-17 14:53:17 +0100
commit110972e59aee51ec90e79980232ab746bfb15aef (patch)
treeaf1b277918ba06e8fd2ab1b432f7ebd8aba86576 /libs/pbd/msvc
parent57f9a4c344fc1142530d66283f07e9aa6524461c (diff)
JOHNE source files (needed for building libpbd with MSVC)
Diffstat (limited to 'libs/pbd/msvc')
-rw-r--r--libs/pbd/msvc/fpu.cc124
-rw-r--r--libs/pbd/msvc/mountpoint.cc166
-rw-r--r--libs/pbd/msvc/msvc_pbd.cc895
-rw-r--r--libs/pbd/msvc/msvc_poll.cc215
4 files changed, 1400 insertions, 0 deletions
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 <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
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 <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
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 <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
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 <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