[med-svn] [htslib] 04/10: Further Windows/Mingw/MSYS improvements.

Andreas Tille tille at debian.org
Wed Jul 19 19:54:43 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository htslib.

commit 75d9f0d9a973898686a51b60277f239c7e729ea5
Author: James Bonfield <jkb at sanegr.ac.uk>
Date:   Thu Apr 27 09:01:10 2017 +0100

    Further Windows/Mingw/MSYS improvements.
    
    - Added an AppVeyor config (travis equivalent for Windows).
    
    - The test harness now copes with windows style pathnames under msys
      by using 'cygpath'.  You will likely already also need to set
      MSYS2_ARG_CONV_EXCL=* environment variable prior to "make check".
    
      Thanks to Anders Kaplan for hints at pathname handling.
      https://github.com/anderskaplan/htslib/commit/0c52ae6711659e2cf072bb2a3de01bf6bf42c626
    
      It also now handles nl vs cr-nl and the extra digits that appear in
      printf %g output.
    
    - Fixed the code looking for connect/recv calls.  The previous
      -lsocket check was incomplete but we also now work with -lws2_32
      on windows.
    
    - Setting of _POSIX_C_SOURCE=600 define so that snprintf return values
      work and to enable %lld and %z formatting options.
    
    - Fixed various shared library types in the Makefile.  The existing
      cygwin code there is unmodified, but also untested.
    
    - Added hts_os.[ch] for operating system specific tweaks.  This only
      affects windows/mingw at the moment and includes various
      drand/random implementations and a tweak to handle 1 less argument
      in mkdir.
    
      win/rand.[ch] contains a BSD implementation of the drand48 code,
      which produces identical random numbers to linux (needed for the
      tests to work).
    
    - Added fseeko and fsync checks to autoconf with appropriate ifdefs in
      the code.
    
    - Cope with seek on pipes returning EINVAL instead of ESPIPE.
    
    - Cope with the lack of SIGPIPE.  We spot this is fd_write and raise a
      SIGTERM instead in lieu of anything better to do.
    
    - Additional enabling of O_BINARY mode in various places.
    
    - Avoidance for enum / define clases in windows (cram block method
      ERROR and MF_APPEND).
    
    - Support for windows C:/path as a full pathname.
    
    - Work around the gcc __format__ attribute requiring a different type
      (printf vs gnu_printf).
---
 .appveyor.yml            | 43 +++++++++++++++++++++
 INSTALL                  |  6 +++
 Makefile                 | 25 +++++++++++-
 bgzf.c                   |  4 ++
 bgzip.c                  | 18 ++++++++-
 configure.ac             | 22 ++++++++---
 cram/cram_io.c           |  8 +++-
 cram/cram_structs.h      |  2 +-
 cram/mFILE.h             |  5 +++
 cram/os.h                |  7 +++-
 errmod.c                 |  2 +
 hfile.c                  | 26 +++++++++++--
 hfile_libcurl.c          |  4 +-
 hts.c                    |  1 +
 hts_os.c                 | 35 +++++++++++++++++
 htslib/hts_defs.h        | 12 ++++++
 htslib/hts_os.h          | 49 ++++++++++++++++++++++++
 tabix.c                  |  2 +-
 test/hfile.c             |  2 +-
 test/sam.c               |  2 +-
 test/tabix/test-tabix.sh |  7 ++--
 test/test-bcf-sr.pl      |  6 ++-
 test/test.pl             | 24 +++++++++++-
 win/rand.c               | 98 ++++++++++++++++++++++++++++++++++++++++++++++++
 win/rand.h               | 23 ++++++++++++
 25 files changed, 407 insertions(+), 26 deletions(-)

diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..f90c61d
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,43 @@
+# version format.
+# you can use {branch} name in version format too
+# version: 1.0.{build}-{branch}
+version: 'vers.{build}'
+
+# branches to build
+branches:
+    # Whitelist
+    only:
+      - develop
+
+    # Blacklist
+    except:
+      - gh-pages
+
+# Do not build on tags (GitHub and BitBucket)
+skip_tags: true
+
+# Skipping commits affecting specific files (GitHub only). More details here: /docs/appveyor-yml
+#skip_commits:
+#  files:
+#    - docs/*
+#    - '**/*.html'
+
+# We use Mingw/Msys, so use pacman for installs
+install:
+  - set HOME=.
+  - set MSYSTEM=MINGW64
+  - set PATH=C:/msys64/usr/bin;C:/msys64/mingw64/bin;%PATH%
+  - set MINGWPREFIX=x86_64-w64-mingw32
+  - "sh -lc \"pacman -S --noconfirm --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib mingw-w64-x86_64-bzip2 mingw-w64-x86_64-xz mingw-w64-x86_64-curl\""
+
+build_script:
+  - set HOME=.
+  - set MSYSTEM=MINGW64
+  - set PATH=C:/msys64/usr/bin;C:/msys64/mingw64/bin;%PATH%
+  - "sh -lc \"aclocal && autoheader && autoconf && ./configure && make -j2\""
+
+#build_script:
+#  - make
+
+test_script:
+  - "sh -lc \"make test\""
diff --git a/INSTALL b/INSTALL
index 2413ba6..8d9c3b6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -48,6 +48,12 @@ library is used.  Systems that do not have CChmac will get this from
 libcrypto.  libcrypto is part of OpenSSL or one of its derivatives (LibreSSL
 or BoringSSL).
 
+On Microsoft Windows we recommend use of Mingw64/Msys2.  Note that
+currently for the test harness to work you will need to override the
+test temporary directory with e.g.: make check TEST_OPTS="-t C:/msys64/tmp/_"
+Whilst the code may work on Windows with other environments, these have
+not be verified.
+
 Building Configure
 ==================
 
diff --git a/Makefile b/Makefile
index 9a44b62..da08cbf 100644
--- a/Makefile
+++ b/Makefile
@@ -138,6 +138,7 @@ print-version:
 
 
 LIBHTS_OBJS = \
+	hts_os.o\
 	kfunc.o \
 	knetfile.o \
 	kstring.o \
@@ -208,6 +209,8 @@ config.h:
 	echo '/* Default config.h generated by Makefile */' > $@
 	echo '#define HAVE_LIBBZ2 1' >> $@
 	echo '#define HAVE_LIBLZMA 1' >> $@
+	echo '#define HAVE_FSEEKO 1' >> $@
+	echo '#define HAVE_DRAND48 1' >> $@
 
 # And similarly for htslib.pc.tmp ("pkg-config template").  No dependency
 # on htslib.pc.in listed, as if that file is newer the usual way to regenerate
@@ -235,6 +238,9 @@ lib-shared: libhts.dylib
 else ifeq "$(findstring CYGWIN,$(PLATFORM))" "CYGWIN"
 SHLIB_FLAVOUR = cygdll
 lib-shared: cyghts-$(LIBHTS_SOVERSION).dll
+else ifeq "$(findstring MSYS,$(PLATFORM))" "MSYS"
+SHLIB_FLAVOUR = dll
+lib-shared: hts-$(LIBHTS_SOVERSION).dll
 else
 SHLIB_FLAVOUR = so
 lib-shared: libhts.so
@@ -276,6 +282,9 @@ libhts.dylib: $(LIBHTS_OBJS)
 cyghts-$(LIBHTS_SOVERSION).dll: $(LIBHTS_OBJS)
 	$(CC) -shared -Wl,--out-implib=libhts.dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import $(LDFLAGS) -o $@ -Wl,--whole-archive $(LIBHTS_OBJS) -Wl,--no-whole-archive $(LIBS) -lpthread
 
+hts-$(LIBHTS_SOVERSION).dll: $(LIBHTS_OBJS)
+	$(CC) -shared -Wl,--out-implib=hts.dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import $(LDFLAGS) -o $@ -Wl,--whole-archive $(LIBHTS_OBJS) -Wl,--no-whole-archive $(LIBS) -lpthread
+
 
 .pico.so:
 	$(CC) -shared -Wl,-E $(LDFLAGS) -o $@ $< $(LIBS) -lpthread
@@ -286,6 +295,9 @@ cyghts-$(LIBHTS_SOVERSION).dll: $(LIBHTS_OBJS)
 .o.cygdll:
 	$(CC) -shared $(LDFLAGS) -o $@ $< libhts.dll.a $(LIBS)
 
+.o.dll:
+	$(CC) -shared $(LDFLAGS) -o $@ $< hts.dll.a $(LIBS)
+
 
 bgzf.o bgzf.pico: bgzf.c config.h $(htslib_hts_h) $(htslib_bgzf_h) $(htslib_hfile_h) $(htslib_thread_pool_h) cram/pooled_alloc.h $(htslib_khash_h)
 errmod.o errmod.pico: errmod.c config.h $(htslib_hts_h) $(htslib_ksort_h)
@@ -348,6 +360,9 @@ tabix.o: tabix.c config.h $(htslib_tbx_h) $(htslib_sam_h) $(htslib_vcf_h) $(htsl
 
 # For tests that might use it, set $REF_PATH explicitly to use only reference
 # areas within the test suite (or set it to ':' to use no reference areas).
+#
+# If using MSYS, avoid poor shell expansion via:
+#    MSYS2_ARG_CONV_EXCL="*" make check
 check test: $(BUILT_PROGRAMS) $(BUILT_TEST_PROGRAMS)
 	test/hts_endian
 	test/fieldarith test/fieldarith.sam
@@ -356,7 +371,7 @@ check test: $(BUILT_PROGRAMS) $(BUILT_TEST_PROGRAMS)
 	cd test/tabix && ./test-tabix.sh tabix.tst
 	REF_PATH=: test/sam test/ce.fa test/faidx.fa
 	test/test-regidx
-	cd test && REF_PATH=: ./test.pl
+	cd test && REF_PATH=: ./test.pl $${TEST_OPTS:-}
 
 test/hts_endian: test/hts_endian.o
 	$(CC) $(LDFLAGS) -o $@ test/hts_endian.o $(LIBS)
@@ -446,6 +461,10 @@ install-cygdll: cyghts-$(LIBHTS_SOVERSION).dll installdirs
 	$(INSTALL_PROGRAM) cyghts-$(LIBHTS_SOVERSION).dll $(DESTDIR)$(bindir)/cyghts-$(LIBHTS_SOVERSION).dll
 	$(INSTALL_PROGRAM) libhts.dll.a $(DESTDIR)$(libdir)/libhts.dll.a
 
+install-dll: hts-$(LIBHTS_SOVERSION).dll installdirs
+	$(INSTALL_PROGRAM) hts-$(LIBHTS_SOVERSION).dll $(DESTDIR)$(bindir)/hts-$(LIBHTS_SOVERSION).dll
+	$(INSTALL_PROGRAM) hts.dll.a $(DESTDIR)$(libdir)/hts.dll.a
+
 install-dylib: libhts.dylib installdirs
 	$(INSTALL_PROGRAM) libhts.dylib $(DESTDIR)$(libdir)/libhts.$(PACKAGE_VERSION).dylib
 	ln -sf libhts.$(PACKAGE_VERSION).dylib $(DESTDIR)$(libdir)/libhts.dylib
@@ -483,6 +502,9 @@ clean-so:
 clean-cygdll:
 	-rm -f cyghts-*.dll libhts.dll.a
 
+clean-dll:
+	-rm -f hts-*.dll hts.dll.a
+
 clean-dylib:
 	-rm -f libhts.dylib libhts.*.dylib
 
@@ -510,4 +532,5 @@ force:
 .PHONY: tags test testclean
 .PHONY: clean-so install-so
 .PHONY: clean-cygdll install-cygdll
+.PHONY: clean-dll install-dll
 .PHONY: clean-dylib install-dylib
diff --git a/bgzf.c b/bgzf.c
index 7e80b8c..0f62173 100644
--- a/bgzf.c
+++ b/bgzf.c
@@ -1038,6 +1038,9 @@ static int bgzf_check_EOF_common(BGZF *fp)
     off_t offset = htell(fp->fp);
     if (hseek(fp->fp, -28, SEEK_END) < 0) {
         if (errno == ESPIPE) { hclearerr(fp->fp); return 2; }
+#ifdef _WIN32
+        if (errno == EINVAL) { hclearerr(fp->fp); return 2; }
+#endif
         else return -1;
     }
     if ( hread(fp->fp, buf, 28) != 28 ) return -1;
@@ -1179,6 +1182,7 @@ restart:
             pthread_exit(NULL);
         }
     }
+    return NULL;
 }
 
 int bgzf_thread_pool(BGZF *fp, hts_tpool *pool, int qsize) {
diff --git a/bgzip.c b/bgzip.c
index e078185..931e7a0 100644
--- a/bgzip.c
+++ b/bgzip.c
@@ -36,6 +36,11 @@
 #include "htslib/bgzf.h"
 #include "htslib/hts.h"
 
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#endif
+
 static const int WINDOW_SIZE = 64 * 1024;
 
 static void error(const char *format, ...)
@@ -198,6 +203,9 @@ int main(int argc, char **argv)
 
         if ( index ) bgzf_index_build_init(fp);
         buffer = malloc(WINDOW_SIZE);
+#ifdef _WIN32
+        _setmode(f_src, O_BINARY);
+#endif
         if (rebgzip){
             if ( bgzf_index_load(fp, index_fname, NULL) < 0 ) error("Could not load index: %s.gzi\n", argv[optind]);
 
@@ -319,13 +327,21 @@ int main(int argc, char **argv)
             if ( bgzf_index_load(fp, argv[optind], ".gzi") < 0 ) error("Could not load index: %s.gzi\n", argv[optind]);
             if ( bgzf_useek(fp, start, SEEK_SET) < 0 ) error("Could not seek to %d-th (uncompressd) byte\n", start);
         }
+#ifdef _WIN32
+        _setmode(f_dst, O_BINARY);
+#endif
         while (1) {
             if (end < 0) c = bgzf_read(fp, buffer, WINDOW_SIZE);
             else c = bgzf_read(fp, buffer, (end - start > WINDOW_SIZE)? WINDOW_SIZE:(end - start));
             if (c == 0) break;
             if (c < 0) error("Could not read %d bytes: Error %d\n", (end - start > WINDOW_SIZE)? WINDOW_SIZE:(end - start), fp->errcode);
             start += c;
-            if ( write(f_dst, buffer, c) != c ) error("Could not write %d bytes\n", c);
+            if ( write(f_dst, buffer, c) != c ) {
+#ifdef _WIN32
+                if (GetLastError() != ERROR_NO_DATA)
+#endif
+                error("Could not write %d bytes\n", c);
+            }
             if (end >= 0 && start >= end) break;
         }
         free(buffer);
diff --git a/configure.ac b/configure.ac
index 308a5c1..5cfffaa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,6 +71,7 @@ AC_ARG_ENABLE([gcs],
   [], [enable_gcs=check])
 
 AC_SYS_LARGEFILE
+AC_FUNC_FSEEKO
 
 AC_ARG_ENABLE([libcurl],
   [AS_HELP_STRING([--enable-libcurl],
@@ -112,8 +113,8 @@ AC_ARG_ENABLE([s3],
                   [support Amazon AWS S3 URLs])],
   [], [enable_s3=check])
 
-AC_MSG_CHECKING([shared library type])
 test -n "$host_alias" || host_alias=unknown-`uname -s`
+AC_MSG_CHECKING([shared library type for $host_alias])
 case $host_alias in
   *-cygwin* | *-CYGWIN*)
     host_result="Cygwin DLL"
@@ -125,6 +126,15 @@ case $host_alias in
     PLATFORM=Darwin
     PLUGIN_EXT=.bundle
     ;;
+  *-msys* | *-MSYS* | *-mingw* | *-MINGW*)
+    host_result="MSYS dll"
+    PLATFORM=MSYS
+    PLUGIN_EXT=.dll
+    # This also sets __USE_MINGW_ANSI_STDIO which in turn makes PRId64,
+    # %lld and %z printf formats work.  It also enforces the snprintf to
+    # be C99 compliant so it returns the correct values (in kstring.c).
+    CPPFLAGS="$CPPCFLAGS -D_POSIX_C_SOURCE=600"
+    ;;
   *)
     host_result="plain .so"
     PLATFORM=default
@@ -136,7 +146,7 @@ AC_SUBST([PLATFORM])
 
 dnl FIXME This pulls in dozens of standard header checks
 AC_FUNC_MMAP
-AC_CHECK_FUNCS(gmtime_r)
+AC_CHECK_FUNCS([gmtime_r fsync drand48])
 
 # Darwin has a dubious fdatasync() symbol, but no declaration in <unistd.h>
 AC_CHECK_DECL([fdatasync(int)], [AC_CHECK_FUNCS(fdatasync)])
@@ -183,9 +193,11 @@ FAILED.  This error must be resolved in order to build HTSlib successfully.])
 fi
 
 dnl connect() etc. fns are in libc on linux, but libsocket on illumos/Solaris
-libsocket=unneeded
-AC_SEARCH_LIBS(connect, socket, [libsocket=needed], [])
-
+AC_SEARCH_LIBS([recv], [socket ws2_32], [
+if test "$ac_cv_search_recv" != "none required"
+then
+  static_LIBS="$static_LIBS $ac_cv_search_recv"
+fi], [AC_MSG_ERROR([unable to find the recv() function])])
 
 if test "$enable_bz2" != no; then
   bz2_devel=ok
diff --git a/cram/cram_io.c b/cram/cram_io.c
index 8e2f1ea..e2b416f 100644
--- a/cram/cram_io.c
+++ b/cram/cram_io.c
@@ -1446,7 +1446,7 @@ char *cram_block_method2str(enum cram_block_method m) {
     case RANS0:    return "RANS0";
     case RANS1:    return "RANS1";
     case GZIP_RLE: return "GZIP_RLE";
-    case ERROR:    break;
+    case BM_ERROR: break;
     }
     return "?";
 }
@@ -3663,7 +3663,11 @@ SAM_hdr *cram_read_SAM_hdr(cram_fd *fd) {
  * Out must be at least PATH_MAX bytes long.
  */
 static void full_path(char *out, char *in) {
-    if (*in == '/') {
+    size_t in_l = strlen(in);
+    if (*in == '/' ||
+	// Windows paths
+	(in_l > 3 && toupper(*in) >= 'A'  && toupper(*in) <= 'Z' &&
+	 in[1] == ':' && (in[2] == '/' || in[2] == '\\'))) {
 	strncpy(out, in, PATH_MAX);
 	out[PATH_MAX-1] = 0;
     } else {
diff --git a/cram/cram_structs.h b/cram/cram_structs.h
index 5165605..eeba679 100644
--- a/cram/cram_structs.h
+++ b/cram/cram_structs.h
@@ -192,7 +192,7 @@ typedef struct cram_file_def {
 struct cram_slice;
 
 enum cram_block_method {
-    ERROR    = -1,
+    BM_ERROR = -1,
     RAW      = 0,
     GZIP     = 1,
     BZIP2    = 2,
diff --git a/cram/mFILE.h b/cram/mFILE.h
index 05a3a88..a6b067a 100644
--- a/cram/mFILE.h
+++ b/cram/mFILE.h
@@ -48,6 +48,11 @@ typedef struct {
     size_t flush_pos;
 } mFILE;
 
+// Work around a clash with winuser.h
+#ifdef MF_APPEND
+#  undef MF_APPEND
+#endif
+
 #define MF_READ    1
 #define MF_WRITE   2
 #define MF_APPEND  4
diff --git a/cram/os.h b/cram/os.h
index b1fdca6..ad3d441 100644
--- a/cram/os.h
+++ b/cram/os.h
@@ -205,9 +205,12 @@ static inline uint16_t le_int2(uint16_t x) {
  * Microsoft Windows running MinGW
  */
 #if defined(__MINGW32__)
-/* #define mkdir(filename,mode) mkdir((filename)) */
+#include <io.h>
+#define mkdir(filename,mode) mkdir((filename))
 #define sysconf(x) 512
-#define ftruncate(fd,len) _chsize(fd,len)
+#ifndef ftruncate
+#  define ftruncate(fd,len) _chsize(fd,len)
+#endif
 #endif
 
 /* Generic WIN32 API issues */
diff --git a/errmod.c b/errmod.c
index ee4823b..bb9fc28 100644
--- a/errmod.c
+++ b/errmod.c
@@ -28,6 +28,8 @@ DEALINGS IN THE SOFTWARE.  */
 #include <math.h>
 #include "htslib/hts.h"
 #include "htslib/ksort.h"
+#include "htslib/hts_os.h" // for drand48
+
 KSORT_INIT_GENERIC(uint16_t)
 
 struct errmod_t {
diff --git a/hfile.c b/hfile.c
index 57e2b89..ce0899e 100644
--- a/hfile.c
+++ b/hfile.c
@@ -526,6 +526,18 @@ static ssize_t fd_write(hFILE *fpv, const void *buffer, size_t nbytes)
         n = fp->is_socket?  send(fp->fd, buffer, nbytes, 0)
                          : write(fp->fd, buffer, nbytes);
     } while (n < 0 && errno == EINTR);
+#ifdef _WIN32
+        // On windows we have no SIGPIPE.  Instead write returns
+        // EINVAL.  We check for this and our fd being a pipe.
+        // If so, we raise SIGTERM instead of SIGPIPE.  It's not
+        // ideal, but I think the only alternative is extra checking
+        // in every single piece of code.
+        if (n < 0 && errno == EINVAL &&
+            GetLastError() == ERROR_NO_DATA &&
+            GetFileType((HANDLE)_get_osfhandle(fp->fd)) == FILE_TYPE_PIPE) {
+            raise(SIGTERM);
+        }
+#endif
     return n;
 }
 
@@ -537,12 +549,13 @@ static off_t fd_seek(hFILE *fpv, off_t offset, int whence)
 
 static int fd_flush(hFILE *fpv)
 {
-    hFILE_fd *fp = (hFILE_fd *) fpv;
-    int ret;
+    int ret = 0;
     do {
 #ifdef HAVE_FDATASYNC
+        hFILE_fd *fp = (hFILE_fd *) fpv;
         ret = fdatasync(fp->fd);
-#else
+#elif defined(HAVE_FSYNC)
+        hFILE_fd *fp = (hFILE_fd *) fpv;
         ret = fsync(fp->fd);
 #endif
         // Ignore invalid-for-fsync(2) errors due to being, e.g., a pipe,
@@ -616,7 +629,11 @@ hFILE *hdopen(int fd, const char *mode)
 static hFILE *hopen_fd_fileuri(const char *url, const char *mode)
 {
     if (strncmp(url, "file://localhost/", 17) == 0) url += 16;
+#ifdef _WIN32
+    else if (strncmp(url, "file:///", 8) == 0) url += 8;
+#else
     else if (strncmp(url, "file:///", 8) == 0) url += 7;
+#endif
     else { errno = EPROTONOSUPPORT; return NULL; }
 
     return hopen_fd(url, mode);
@@ -876,7 +893,8 @@ static const struct hFILE_scheme_handler *find_scheme_handler(const char *s)
         else if (s[i] == ':') break;
         else return NULL;
 
-    if (i == 0 || i >= sizeof scheme) return NULL;
+    // 1 byte schemes are likely windows C:/foo pathnames
+    if (i <= 1 || i >= sizeof scheme) return NULL;
     scheme[i] = '\0';
 
     pthread_mutex_lock(&plugins_lock);
diff --git a/hfile_libcurl.c b/hfile_libcurl.c
index ea99aa7..461e891 100644
--- a/hfile_libcurl.c
+++ b/hfile_libcurl.c
@@ -28,7 +28,9 @@ DEALINGS IN THE SOFTWARE.  */
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/select.h>
+#ifndef _WIN32
+# include <sys/select.h>
+#endif
 
 #include "hfile_internal.h"
 #ifdef ENABLE_PLUGINS
diff --git a/hts.c b/hts.c
index 1c6ca8a..fe35d78 100644
--- a/hts.c
+++ b/hts.c
@@ -44,6 +44,7 @@ DEALINGS IN THE SOFTWARE.  */
 #include "version.h"
 #include "hts_internal.h"
 #include "hfile_internal.h"
+#include "htslib/hts_os.h" // drand48
 
 #include "htslib/khash.h"
 #include "htslib/kseq.h"
diff --git a/hts_os.c b/hts_os.c
new file mode 100644
index 0000000..eb0a5ca
--- /dev/null
+++ b/hts_os.c
@@ -0,0 +1,35 @@
+/// @file hts_os.c
+/// Operating System specific tweaks, for compatibility with POSIX.
+/*
+   Copyright (C) 2017 Genome Research Ltd.
+
+    Author: James Bonfield <jkb at sanger.ac.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.  */
+
+// Windows (maybe more) lack a drand48 implementation.
+#ifndef HAVE_DRAND48
+#include "win/rand.c"
+#endif
+
+// // On Windows when using the MSYS or Cygwin terminals, isatty fails
+// #ifdef _WIN32
+// #define USE_FILEEXTD
+// #include "win/iscygpty.c"
+// #endif
diff --git a/htslib/hts_defs.h b/htslib/hts_defs.h
index 1602303..5a8d921 100644
--- a/htslib/hts_defs.h
+++ b/htslib/hts_defs.h
@@ -69,6 +69,18 @@ DEALINGS IN THE SOFTWARE.  */
 #define HTS_DEPRECATED(message)
 #endif
 
+// On mingw the "printf" format type doesn't work.  It needs "gnu_printf"
+// in order to check %lld and %z, otherwise it defaults to checking against
+// the Microsoft library printf format options despite linking against the
+// GNU posix implementation of printf.  The __MINGW_PRINTF_FORMAT macro
+// expands to printf or gnu_printf as required, but obviously may not
+// exist
+#ifdef __MINGW_PRINTF_FORMAT
+#define HTS_PRINTF_FMT __MINGW_PRINTF_FORMAT
+#else
+#define HTS_PRINTF_FMT printf
+#endif
+
 #if HTS_COMPILER_HAS(__format__) || HTS_GCC_AT_LEAST(3,0)
 #define HTS_FORMAT(type, idx, first) __attribute__((__format__ (type, idx, first)))
 #else
diff --git a/htslib/hts_os.h b/htslib/hts_os.h
new file mode 100644
index 0000000..edb23a2
--- /dev/null
+++ b/htslib/hts_os.h
@@ -0,0 +1,49 @@
+/// @file hts_os.h
+/// Operating System specific tweaks, for compatibility with POSIX.
+/*
+   Copyright (C) 2017 Genome Research Ltd.
+
+    Author: James Bonfield <jkb at sanger.ac.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.  */
+
+#ifndef HTSLIB_HTS_OS_H
+#define HTSLIB_HTS_OS_H
+
+extern void srand48(long seed);
+extern double drand48(void);
+extern long lrand48(void);
+
+#ifdef _WIN32
+/* Check if the fd is a cygwin/msys's pty. */
+extern int is_cygpty(int fd);
+#endif
+
+#if defined(__MINGW32__)
+#include <io.h>
+#define mkdir(filename,mode) mkdir((filename))
+#endif
+
+#ifdef _WIN32
+#include <stdlib.h>
+#define srandom srand
+#define random rand
+#endif
+
+#endif
diff --git a/tabix.c b/tabix.c
index 681f8a0..119f396 100644
--- a/tabix.c
+++ b/tabix.c
@@ -29,6 +29,7 @@ DEALINGS IN THE SOFTWARE.  */
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <strings.h>
 #include <getopt.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -69,7 +70,6 @@ static void error(const char *format, ...)
 int file_type(const char *fname)
 {
     int l = strlen(fname);
-    int strcasecmp(const char *s1, const char *s2);
     if (l>=7 && strcasecmp(fname+l-7, ".gff.gz") == 0) return IS_GFF;
     else if (l>=7 && strcasecmp(fname+l-7, ".bed.gz") == 0) return IS_BED;
     else if (l>=7 && strcasecmp(fname+l-7, ".sam.gz") == 0) return IS_SAM;
diff --git a/test/hfile.c b/test/hfile.c
index 358ac70..577b817 100644
--- a/test/hfile.c
+++ b/test/hfile.c
@@ -61,7 +61,7 @@ char *slurp(const char *filename)
 {
     char *text;
     struct stat sbuf;
-    size_t filesize, readsize;
+    size_t filesize;
     FILE *f = fopen(filename, "rb");
     if (f == NULL) fail("fopen(\"%s\", \"rb\")", filename);
     if (fstat(fileno(f), &sbuf) != 0) fail("fstat(\"%s\")", filename);
diff --git a/test/sam.c b/test/sam.c
index 736281d..dd83336 100644
--- a/test/sam.c
+++ b/test/sam.c
@@ -43,7 +43,7 @@ DEALINGS IN THE SOFTWARE.  */
 
 int status;
 
-static void HTS_FORMAT(printf, 1, 2) fail(const char *fmt, ...)
+static void HTS_FORMAT(HTS_PRINTF_FMT, 1, 2) fail(const char *fmt, ...)
 {
     va_list args;
 
diff --git a/test/tabix/test-tabix.sh b/test/tabix/test-tabix.sh
index 358a3dd..4a4b045 100755
--- a/test/tabix/test-tabix.sh
+++ b/test/tabix/test-tabix.sh
@@ -57,11 +57,12 @@ run_test() {
 	y="exit_code"
     elif [ "x$e" != "x" -a "$e" != "." ]
     then
-	if cmp -s _out.tmp "$e"
+    sed -n 's/.*/&/p' _out.tmp > _out.tmp2
+	if cmp -s _out.tmp2 "$e"
 	then
 	    # Output was as expected
 	    r="P"
-	    rm -f _out.tmp _err.tmp
+	    rm -f _out.tmp _out.tmp2 _err.tmp
 	else
 	    # Output differed
 	    r="F"
@@ -70,7 +71,7 @@ run_test() {
     else
 	# Expected zero exit code and got it.
 	r="P"
-	rm -f _out.tmp _err.tmp
+	rm -f _out.tmp _out.tmp2 _err.tmp
     fi
 
     if [ "$r" = "F" ]
diff --git a/test/test-bcf-sr.pl b/test/test-bcf-sr.pl
index 8f78acb..3102cdd 100755
--- a/test/test-bcf-sr.pl
+++ b/test/test-bcf-sr.pl
@@ -156,6 +156,7 @@ sub check_outputs
     {
         my ($pos, at vals) = split(/\t/,$line);
         chomp($vals[-1]);
+        $vals[-1] =~ s/\r$//;
         push @{$out{$pos}},join("\t", at vals);
     }
     close($fh) or error("close failed: $fname_bin");
@@ -173,6 +174,7 @@ sub check_outputs
     while (my $line=<$fh>)
     {
         chomp($line);
+        $line =~ s/\r$//;
         push @plines,$line;
     }
     close($fh) or error("close failed: $fname_perl");
@@ -181,8 +183,8 @@ sub check_outputs
     @plines = sort @plines;
     for (my $i=0; $i<@plines; $i++)
     {
-        if ( $blines[$i] ne $plines[$i] ) 
-        { 
+        if ( $blines[$i] ne $plines[$i] )
+        {
             #error("Different lines in $fname_bin vs $fname_perl:\n\t$blines[$i].\nvs\n\t$plines[$i].\n"); 
             error("Different lines in $fname_bin vs $fname_perl:\n\t".join("\n\t", at blines)."\nvs\n\t".join("\n\t", at plines)."\n"); 
         }
diff --git a/test/test.pl b/test/test.pl
index 261ca98..f168135 100755
--- a/test/test.pl
+++ b/test/test.pl
@@ -69,6 +69,23 @@ sub error
         "\n";
     exit 1;
 }
+
+sub cygpath {
+    my ($path) = @_;
+    $path = `cygpath -m $path`;
+    $path =~ s/\r?\n//;
+    return $path
+}
+
+sub safe_tempdir
+{
+    my $dir = tempdir(CLEANUP=>1);
+    if ($^O =~ /^msys/) {
+        $dir = cygpath($dir);
+    }
+    return $dir;
+}
+
 sub parse_params
 {
     my $opts = { keep_files=>0, nok=>0, nfailed=>0 };
@@ -81,11 +98,16 @@ sub parse_params
             'h|?|help' => \$help
             );
     if ( !$ret or $help ) { error(); }
-    $$opts{tmp} = $$opts{keep_files} ? $$opts{keep_files} : tempdir(CLEANUP=>1);
+    $$opts{tmp} = $$opts{keep_files} ? $$opts{keep_files} : safe_tempdir();
     if ( $$opts{keep_files} ) { cmd("mkdir -p $$opts{keep_files}"); }
     $$opts{path} = $FindBin::RealBin;
     $$opts{bin}  = $FindBin::RealBin;
     $$opts{bin}  =~ s{/test/?$}{};
+    if ($^O =~ /^msys/) {
+	$$opts{path} = cygpath($$opts{path});
+	$$opts{bin}  = cygpath($$opts{bin});
+    }
+
     return $opts;
 }
 sub _cmd
diff --git a/win/rand.c b/win/rand.c
new file mode 100644
index 0000000..c8d54ab
--- /dev/null
+++ b/win/rand.c
@@ -0,0 +1,98 @@
+/*  rand.c -- drand48 implementation from the FreeBSD source tree. */
+
+// This file is an amalgamation of the many small files in FreeBSD to do with
+// drand48 and friends implementations.
+// It comprises _rand48.c, rand48.h, srand48.c, drand48.c, erand48.c, lrand48.c
+
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+//#include <sys/cdefs.h>
+//__FBSDID("$FreeBSD: src/lib/libc/gen/_rand48.c,v 1.2 2002/03/22 21:52:05 obrien Exp $");
+
+#include <math.h>
+#include "win/rand.h"
+
+#define	RAND48_SEED_0	(0x330e)
+#define	RAND48_SEED_1	(0xabcd)
+#define	RAND48_SEED_2	(0x1234)
+#define	RAND48_MULT_0	(0xe66d)
+#define	RAND48_MULT_1	(0xdeec)
+#define	RAND48_MULT_2	(0x0005)
+#define	RAND48_ADD	(0x000b)
+
+unsigned short _rand48_seed[3] = {
+	RAND48_SEED_0,
+	RAND48_SEED_1,
+	RAND48_SEED_2
+};
+unsigned short _rand48_mult[3] = {
+	RAND48_MULT_0,
+	RAND48_MULT_1,
+	RAND48_MULT_2
+};
+unsigned short _rand48_add = RAND48_ADD;
+
+static void
+_dorand48(unsigned short xseed[3])
+{
+	unsigned long accu;
+	unsigned short temp[2];
+
+	accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
+	 (unsigned long) _rand48_add;
+	temp[0] = (unsigned short) accu;	/* lower 16 bits */
+	accu >>= sizeof(unsigned short) * 8;
+	accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
+	 (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
+	temp[1] = (unsigned short) accu;	/* middle 16 bits */
+	accu >>= sizeof(unsigned short) * 8;
+	accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
+	xseed[0] = temp[0];
+	xseed[1] = temp[1];
+	xseed[2] = (unsigned short) accu;
+}
+
+void
+srand48(long seed)
+{
+	_rand48_seed[0] = RAND48_SEED_0;
+	_rand48_seed[1] = (unsigned short) seed;
+	_rand48_seed[2] = (unsigned short) (seed >> 16);
+	_rand48_mult[0] = RAND48_MULT_0;
+	_rand48_mult[1] = RAND48_MULT_1;
+	_rand48_mult[2] = RAND48_MULT_2;
+	_rand48_add = RAND48_ADD;
+}
+
+double
+erand48(unsigned short xseed[3])
+{
+	_dorand48(xseed);
+	return ldexp((double) xseed[0], -48) +
+	       ldexp((double) xseed[1], -32) +
+	       ldexp((double) xseed[2], -16);
+}
+
+double
+drand48(void)
+{
+	return erand48(_rand48_seed);
+}
+
+long
+lrand48(void)
+{
+	_dorand48(_rand48_seed);
+	return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
+}
diff --git a/win/rand.h b/win/rand.h
new file mode 100644
index 0000000..1a36daa
--- /dev/null
+++ b/win/rand.h
@@ -0,0 +1,23 @@
+/*  rand.h -- drand48 implementation from the FreeBSD source tree. */
+
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#ifndef HTSLIB_HTS_RAND_H
+#define HTSLIB_HTS_RAND_H
+
+void srand48(long seed);
+double drand48(void);
+long lrand48(void);
+
+#endif /* HTSLIB_HTS_RAND_H */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/htslib.git



More information about the debian-med-commit mailing list