diff options
| author | Marcus Brinkmann <[email protected]> | 2007-09-06 22:41:11 +0000 | 
|---|---|---|
| committer | Marcus Brinkmann <[email protected]> | 2007-09-06 22:41:11 +0000 | 
| commit | becf580f6163889de683500957a0a7cfceb7ed47 (patch) | |
| tree | c3c9b04114345915dc05ca837d274aae4570d28f | |
| parent | 2007-09-03 Marcus Brinkmann <[email protected]> (diff) | |
| download | gpgme-becf580f6163889de683500957a0a7cfceb7ed47.tar.gz gpgme-becf580f6163889de683500957a0a7cfceb7ed47.zip | |
2007-09-07  Marcus Brinkmann  <[email protected]>
	* configure.ac: Check for C++, Qt and support --enable-w32-qt.
	* m4/pkg.m4: New file.
gpgme/
2007-09-07  Marcus Brinkmann  <[email protected]>
	* kdpipeiodevice.h, kdpipeiodevice.cpp, moc_kdpipeiodevice.cpp,
	kdpipeiodevice.moc, w32-qt-io.c: New files.
	* Makefile.am (ltlib_gpgme_extra): Rename to ltlib_gpgme_glib.
	(ltlib_gpgme_qt): New variable.
	(lib_LTLIBRARIES): Add $(ltlib_gpgme_qt).
	(libgpgme_qt_la_SOURCES): New variable.
	(AM_CPPFLAGS): Add @QT4_CORE_INCLUDES@
	(AM_CFLAGS): Add @QT4_CORE_CFLAGS@.
	(libgpgme_qt_la_LDFLAGS, libgpgme_qt_la_DEPENDENCIES)
	(libgpgme_qt_la_LIBADD): New variables.
	* sema.h (struct critsect_s): Rename "private" to "priv" to make
	C++ users happy.  Change users.
	* posix-sema.c (_gpgme_sema_cs_enter, _gpgme_sema_cs_leave)
	(_gpgme_sema_cs_destroy): Likewise.
	* w32-sema.c (critsect_init, _gpgme_sema_cs_enter)
	(_gpgme_sema_cs_leave, _gpgme_sema_cs_destroy): Likewise.
	* w32-glib-io.c (gpgme_get_giochannel): Change return type to
	void*.
	(gpgme_get_fdptr): New function.
	* w32-io.c (gpgme_get_fdptr): New function
	* gpgme.def: Add gpgme_get_fdptr.
| -rw-r--r-- | ChangeLog | 7 | ||||
| -rw-r--r-- | configure.ac | 8 | ||||
| -rw-r--r-- | gpgme/ChangeLog | 24 | ||||
| -rw-r--r-- | gpgme/Makefile.am | 42 | ||||
| -rw-r--r-- | gpgme/gpgme.def | 2 | ||||
| -rw-r--r-- | gpgme/kdpipeiodevice.cpp | 760 | ||||
| -rw-r--r-- | gpgme/kdpipeiodevice.h | 66 | ||||
| -rw-r--r-- | gpgme/kdpipeiodevice.moc | 132 | ||||
| -rw-r--r-- | gpgme/moc_kdpipeiodevice.cpp | 60 | ||||
| -rw-r--r-- | gpgme/posix-sema.c | 10 | ||||
| -rw-r--r-- | gpgme/sema.h | 6 | ||||
| -rw-r--r-- | gpgme/w32-glib-io.c | 13 | ||||
| -rw-r--r-- | gpgme/w32-io.c | 10 | ||||
| -rw-r--r-- | gpgme/w32-qt-io.cpp | 609 | ||||
| -rw-r--r-- | gpgme/w32-sema.c | 22 | ||||
| -rw-r--r-- | m4/pkg.m4 | 157 | 
16 files changed, 1898 insertions, 30 deletions
| @@ -1,3 +1,8 @@ +2007-09-07  Marcus Brinkmann  <[email protected]> + +	* configure.ac: Check for C++, Qt and support --enable-w32-qt. +	* m4/pkg.m4: New file. +  2007-08-21  Marcus Brinkmann  <[email protected]>  	* configure.ac (--enable-w32-glib): Use --enableval, not @@ -775,7 +780,7 @@  	* autogen.sh: Added option --build-w32. - Copyright 2001, 2002, 2003, 2004, 2005 g10 Code GmbH + Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 g10 Code GmbH   This file is free software; as a special exception the author gives   unlimited permission to copy and/or distribute it, with or without diff --git a/configure.ac b/configure.ac index 923792c0..a21aaa9b 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,7 @@ AH_VERBATIM([_REENTRANT],  #endif])  AC_PROG_CC +AC_PROG_CXX  AC_SUBST(LIBGPGME_LT_CURRENT)  AC_SUBST(LIBGPGME_LT_AGE) @@ -162,6 +163,13 @@ AC_ARG_ENABLE(w32-glib,  	    build_w32_glib=$enableval)  AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = yes) +build_w32_qt=no +PKG_CHECK_MODULES(QT4_CORE, QtCore) +AC_ARG_ENABLE(w32-qt, +	    AC_HELP_STRING([--enable-w32-qt], [build GPGME Qt for W32]), +	    build_w32_qt=$enableval) +AM_CONDITIONAL(BUILD_W32_QT, test "$build_w32_qt" = yes) +  AM_CONDITIONAL(HAVE_PTH, test "$have_pth" = "yes")  AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes") diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 29f496d1..7d3ae586 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,27 @@ +2007-09-07  Marcus Brinkmann  <[email protected]> + +	* kdpipeiodevice.h, kdpipeiodevice.cpp, moc_kdpipeiodevice.cpp, +	kdpipeiodevice.moc, w32-qt-io.c: New files. +	* Makefile.am (ltlib_gpgme_extra): Rename to ltlib_gpgme_glib. +	(ltlib_gpgme_qt): New variable. +	(lib_LTLIBRARIES): Add $(ltlib_gpgme_qt). +	(libgpgme_qt_la_SOURCES): New variable. +	(AM_CPPFLAGS): Add @QT4_CORE_INCLUDES@ +	(AM_CFLAGS): Add @QT4_CORE_CFLAGS@. +	(libgpgme_qt_la_LDFLAGS, libgpgme_qt_la_DEPENDENCIES) +	(libgpgme_qt_la_LIBADD): New variables. +	* sema.h (struct critsect_s): Rename "private" to "priv" to make +	C++ users happy.  Change users. +	* posix-sema.c (_gpgme_sema_cs_enter, _gpgme_sema_cs_leave) +	(_gpgme_sema_cs_destroy): Likewise. +	* w32-sema.c (critsect_init, _gpgme_sema_cs_enter) +	(_gpgme_sema_cs_leave, _gpgme_sema_cs_destroy): Likewise. +	* w32-glib-io.c (gpgme_get_giochannel): Change return type to +	void*. +	(gpgme_get_fdptr): New function. +	* w32-io.c (gpgme_get_fdptr): New function +	* gpgme.def: Add gpgme_get_fdptr. +  2007-08-22  Marcus Brinkmann  <[email protected]>  	* w32-io.c (_gpgme_io_write): Return early if COUNT is zero. diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 9c6254fd..df233bba 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -1,5 +1,5 @@  # Copyright (C) 2000 Werner Koch (dd9jn) -# Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH +# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH  #   # This file is part of GPGME.  #  @@ -40,12 +40,18 @@ ltlib_gpgme_pth =  endif  if BUILD_W32_GLIB -ltlib_gpgme_extra = libgpgme-glib.la +ltlib_gpgme_glib = libgpgme-glib.la  else -ltlib_gpgme_extra = +ltlib_gpgme_glib =  endif -lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_extra) \ +if BUILD_W32_QT +ltlib_gpgme_qt = libgpgme-qt.la +else +ltlib_gpgme_qt = +endif + +lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \  	$(ltlib_gpgme_pthread) $(ltlib_gpgme_pth)  if HAVE_LD_VERSION_SCRIPT @@ -107,10 +113,24 @@ if BUILD_W32_GLIB  libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c  endif +if BUILD_W32_QT +libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \ +	kdpipeiodevice.h kdpipeiodevice.cpp moc_kdpipeiodevice.cpp \ +	kdpipeiodevice.moc + +# These are built sources (normally). +# moc_kdpipeiodevice.cpp: kdpipeiodevice.h +#	$(MOC4) -o $@ $< +# +# kdpipeiodevice.moc: kdpipeiodevice.cpp +#	$(MOC4) -o $@ $< +endif +  # We use a global CFLAGS and CPPFLAGS setting for all library  # versions, because then every object file is only compiled once. -AM_CPPFLAGS = $(assuan_cppflags) @GPG_ERROR_CFLAGS@ @PTH_CPPFLAGS@ -AM_CFLAGS = @PTH_CFLAGS@ @GLIB_CFLAGS@ +AM_CPPFLAGS = $(assuan_cppflags) @GPG_ERROR_CFLAGS@ @PTH_CPPFLAGS@ \ +	@QT4_CORE_CFLAGS@ +AM_CFLAGS = @PTH_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@  if HAVE_W32_SYSTEM @@ -181,6 +201,16 @@ libgpgme_glib_la_LIBADD = $(assuan_libobjs) @LTLIBOBJS@ \  	@GPG_ERROR_LIBS@ @GLIB_LIBS@ @NETLIBS@  endif +if BUILD_W32_QT +libgpgme_qt_la_LDFLAGS = $(gpgme_res_ldflag) $(no_undefined) \ +	$(export_symbols) $(libgpgme_version_script_cmd) -version-info \ +	@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_qt_la_DEPENDENCIES = $(assuan_libobjs) \ +	@LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) +libgpgme_qt_la_LIBADD = $(assuan_libobjs) @LTLIBOBJS@ \ +	@GPG_ERROR_LIBS@ @QT4_CORE_LIB@ @NETLIBS@ +endif +  status-table.h : gpgme.h  	$(srcdir)/mkstatus < $(srcdir)/gpgme.h > status-table.h diff --git a/gpgme/gpgme.def b/gpgme/gpgme.def index f4aa1b5a..bb2caf26 100644 --- a/gpgme/gpgme.def +++ b/gpgme/gpgme.def @@ -154,5 +154,7 @@ EXPORTS      gpgme_free				  @120      gpgme_get_giochannel		  @121 +    gpgme_get_fdptr			  @122 +  ; END diff --git a/gpgme/kdpipeiodevice.cpp b/gpgme/kdpipeiodevice.cpp new file mode 100644 index 00000000..f4acebee --- /dev/null +++ b/gpgme/kdpipeiodevice.cpp @@ -0,0 +1,760 @@ +/* +  Copyright (C) 2007 Klar�lvdalens Datakonsult AB + +  KDPipeIODevice is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. + +  KDPipeIODevice 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 Library General Public License for more details. + +  You should have received a copy of the GNU Library General Public License +  along with KDPipeIODevice; see the file COPYING.LIB.  If not, write to the +  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +  Boston, MA 02110-1301, USA. +*/ + +#include "kdpipeiodevice.h" + +#include <QtCore> + +#include <cassert> +#include <memory> +#include <algorithm> + +#ifdef Q_OS_WIN32 +# define NOMINMAX +# include <windows.h> +# include <io.h> +#else +# include <unistd.h> +# include <errno.h> +#endif + +#ifndef KDAB_CHECK_THIS +# define KDAB_CHECK_CTOR (void)1 +# define KDAB_CHECK_DTOR KDAB_CHECK_CTOR +# define KDAB_CHECK_THIS KDAB_CHECK_CTOR +#endif + +#define LOCKED( d ) const QMutexLocker locker( &d->mutex ) +#define synchronized( d ) if ( int i = 0 ) {} else for ( const QMutexLocker locker( &d->mutex ) ; !i ; ++i ) + +const unsigned int BUFFER_SIZE = 4096; +const bool ALLOW_QIODEVICE_BUFFERING = true; + +// comment to get trace output: +#define qDebug if(1){}else qDebug + +namespace { +class Reader : public QThread { +    Q_OBJECT +public: +    Reader( int fd, Qt::HANDLE handle ); +    ~Reader(); + +    qint64 readData( char * data, qint64 maxSize ); + +    unsigned int bytesInBuffer() const { +        return ( wptr + sizeof buffer - rptr ) % sizeof buffer ; +    } + +    bool bufferFull() const { +        return bytesInBuffer() == sizeof buffer - 1; +    } + +    bool bufferEmpty() const { +	return bytesInBuffer() == 0; +    } + +    bool bufferContains( char ch ) { +	const unsigned int bib = bytesInBuffer(); +	for ( unsigned int i = rptr ; i < rptr + bib ; ++i ) +	    if ( buffer[i%sizeof buffer] == ch ) +		return true; +	return false; +    } +	 +Q_SIGNALS: +    void readyRead(); + +protected: +    /* reimp */ void run(); + +private: +    int fd; +    Qt::HANDLE handle; +public: +    QMutex mutex; +    QWaitCondition bufferNotFullCondition; +    QWaitCondition bufferNotEmptyCondition; +    QWaitCondition hasStarted; +    bool cancel; +    bool eof; +    bool error; +    bool eofShortCut; +    int errorCode; +private: +    unsigned int rptr, wptr; +    char buffer[BUFFER_SIZE+1]; // need to keep one byte free to detect empty state +}; + + +Reader::Reader( int fd_, Qt::HANDLE handle_ ) +    : QThread(), +      fd( fd_ ), +      handle( handle_ ), +      mutex(), +      bufferNotFullCondition(), +      bufferNotEmptyCondition(), +      hasStarted(), +      cancel( false ), +      eof( false ), +      error( false ), +      eofShortCut( false ), +      errorCode( 0 ), +      rptr( 0 ), wptr( 0 ) +{ +     +} + +Reader::~Reader() {} + + +class Writer : public QThread { +    Q_OBJECT +public: +    Writer( int fd, Qt::HANDLE handle ); +    ~Writer(); + +    qint64 writeData( const char * data, qint64 size ); + +    unsigned int bytesInBuffer() const { return numBytesInBuffer; } + +    bool bufferFull() const { +        return numBytesInBuffer == sizeof buffer; +    } + +    bool bufferEmpty() const { +	return numBytesInBuffer == 0; +    } + +Q_SIGNALS: +    void bytesWritten( qint64 ); + +protected: +    /* reimp */ void run(); + +private: +    int fd; +    Qt::HANDLE handle; +public: +    QMutex mutex; +    QWaitCondition bufferEmptyCondition; +    QWaitCondition bufferNotEmptyCondition; +    QWaitCondition hasStarted; +    bool cancel; +    bool error; +    int errorCode; +private: +    unsigned int numBytesInBuffer; +    char buffer[BUFFER_SIZE]; +}; +} + +Writer::Writer( int fd_, Qt::HANDLE handle_ ) +    : QThread(), +      fd( fd_ ), +      handle( handle_ ), +      mutex(), +      bufferEmptyCondition(), +      bufferNotEmptyCondition(), +      hasStarted(), +      cancel( false ), +      error( false ), +      errorCode( 0 ), +      numBytesInBuffer( 0 ) +{ + +} + +Writer::~Writer() {} + + +class KDPipeIODevice::Private { +    friend class ::KDPipeIODevice; +    KDPipeIODevice * const q; +public: +    explicit Private( KDPipeIODevice * qq ); +    ~Private(); + +    bool doOpen( int, Qt::HANDLE, OpenMode ); + +private: +    int fd; +    Qt::HANDLE handle; +    Reader * reader; +    Writer * writer; +}; + +KDPipeIODevice::Private::Private( KDPipeIODevice * qq ) +    : q( qq ), +      fd( -1 ), +      handle( 0 ), +      reader( 0 ), +      writer( 0 ) +{ + +} + + +KDPipeIODevice::Private::~Private() {} + + +KDPipeIODevice::KDPipeIODevice( QObject * p ) +    : QIODevice( p ), d( new Private( this ) ) +{ +    KDAB_CHECK_CTOR; +} + +KDPipeIODevice::KDPipeIODevice( int fd, OpenMode mode, QObject * p ) +    : QIODevice( p ), d( new Private( this ) ) +{ +    KDAB_CHECK_CTOR; +    open( fd, mode ); +} + +KDPipeIODevice::KDPipeIODevice( Qt::HANDLE handle, OpenMode mode, QObject * p ) +    : QIODevice( p ), d( new Private( this ) ) +{ +    KDAB_CHECK_CTOR; +    open( handle, mode ); +} + +KDPipeIODevice::~KDPipeIODevice() { KDAB_CHECK_DTOR; +    if ( isOpen() ) +	close(); +    delete d; d = 0; +} + + +bool KDPipeIODevice::open( int fd, OpenMode mode ) { KDAB_CHECK_THIS; + +#ifdef Q_OS_WIN32 +    return d->doOpen( fd, (HANDLE)_get_osfhandle( fd ), mode ); +#else +    return d->doOpen( fd, 0, mode ); +#endif + +} + +bool KDPipeIODevice::open( Qt::HANDLE h, OpenMode mode ) { KDAB_CHECK_THIS; + +#ifdef Q_OS_WIN32 +    return d->doOpen( 0, h, mode ); +#else +    Q_UNUSED( h ); +    Q_UNUSED( mode ); +    assert( !"KDPipeIODevice::open( Qt::HANDLE, OpenMode ) should never be called except on Windows." ); +#endif + +} + +bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode_ ) { + +    if ( q->isOpen() || fd_ < 0 ) +	return false; + +#ifdef Q_OS_WIN32 +    if ( !handle_ ) +	return false; +#endif + +    if ( !(mode_ & ReadWrite) ) +	return false; // need to have at least read -or- write + +    fd = fd_; +    handle = handle_; + +    std::auto_ptr<Reader> reader_; +    std::auto_ptr<Writer> writer_; + +    if ( mode_ & ReadOnly ) { +	reader_.reset( new Reader( fd_, handle_ ) ); +	LOCKED( reader_ ); +	reader_->start( QThread::HighestPriority ); +	if ( !reader_->hasStarted.wait( &reader_->mutex, 1000 ) ) +	    return false; +	connect( reader_.get(), SIGNAL(readyRead()), q, SIGNAL(readyRead()), Qt::QueuedConnection ); +    } +    if ( mode_ & WriteOnly ) { +	writer_.reset( new Writer( fd_, handle_ ) ); +	LOCKED( writer_ ); +	writer_->start( QThread::HighestPriority ); +	if ( !writer_->hasStarted.wait( &writer_->mutex, 1000 ) ) +	    return false; +	connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)), Qt::QueuedConnection ); +    } + +    // commit to *this: +    fd = fd_; +    handle = handle_; +    reader = reader_.release(); +    writer = writer_.release(); + +    q->setOpenMode( mode_|Unbuffered ); + +    return true; +} + +int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS; +    return d->fd; +} + +Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS; +    return d->handle; +} + +qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS; +    const qint64 base = QIODevice::bytesAvailable(); +    if ( d->reader ) +	synchronized( d->reader ) return base + d->reader->bytesInBuffer(); +    return base; +} + +qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; +    const qint64 base = QIODevice::bytesToWrite(); +    if ( d->writer ) +	synchronized( d->writer ) return base + d->writer->bytesInBuffer(); +    return base; +} + +bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS; +    if ( QIODevice::canReadLine() ) +	return true; +    if ( d->reader ) +	synchronized( d->reader ) return d->reader->bufferContains( '\n' ); +    return true; +} + +bool KDPipeIODevice::isSequential() const { +    return true; +} + +bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS; +    if ( !QIODevice::atEnd() ) { +	qDebug( "KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", static_cast<long>(bytesAvailable()) ); +	return false; +    } +    if ( !isOpen() ) +	return true; +    if ( d->reader->eofShortCut ) +	return true; +    LOCKED( d->reader ); +    const bool eof = ( d->reader->error || d->reader->eof ) && d->reader->bufferEmpty(); +    if ( !eof ) { +	if ( !d->reader->error && !d->reader->eof ) +	    qDebug( "KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof" ); +	if ( !d->reader->bufferEmpty() ) +	    qDebug( "KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()" ); +    } +    return eof; +} + +bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS; +    Writer * const w = d->writer; +    if ( !w ) +	return true; +    LOCKED( w ); +    return w->bufferEmpty() || w->error || w->bufferEmptyCondition.wait( &w->mutex, msecs ) ; +} + +bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS; +    if ( ALLOW_QIODEVICE_BUFFERING ) { +	if ( bytesAvailable() > 0 ) +	    return true; +    } +    Reader * const r = d->reader; +    if ( !r || r->eofShortCut ) +	return true; +    LOCKED( r ); +    return r->bytesInBuffer() != 0 || r->eof || r->error || r->bufferNotEmptyCondition.wait( &r->mutex, msecs ) ; +} + +qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS; + +    qDebug( "KDPipeIODevice::readData: data=%p, maxSize=%lld", data, maxSize ); + +    Reader * const r = d->reader; + +    assert( r ); +    //assert( r->isRunning() ); // wrong (might be eof, error) +    assert( data || maxSize == 0 ); +    assert( maxSize >= 0 ); + +    if ( r->eofShortCut ) { +	qDebug( "KDPipeIODevice::readData: hit eofShortCut, returning 0" ); +	return 0; +    } + +    if ( maxSize < 0 ) +	maxSize = 0; + +    if ( ALLOW_QIODEVICE_BUFFERING ) { +	if ( bytesAvailable() > 0 ) +	    maxSize = std::min( maxSize, bytesAvailable() ); // don't block +    } + +    LOCKED( r ); +    if ( /* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof ) { // ### block on maxSize == 0? +	qDebug( "KDPipeIODevice::readData: waiting for bufferNotEmptyCondition" ); +	r->bufferNotEmptyCondition.wait( &r->mutex ); +    } + +    if ( r->bufferEmpty() ) { +	qDebug( "KDPipeIODevice::readData: got empty buffer, signal eof" ); +	// woken with an empty buffer must mean either EOF or error: +	assert( r->eof || r->error ); +	r->eofShortCut = true; +	return r->eof ? 0 : -1 ; +    } + +    qDebug( "KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", maxSize ); +    const qint64 bytesRead = r->readData( data, maxSize ); +    qDebug( "KDPipeIODevice::readData: read %lld bytes", bytesRead ); +    return bytesRead; +} + +qint64 Reader::readData( char * data, qint64 maxSize ) { + +    qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ; +    if ( numRead > maxSize ) +	numRead = maxSize; + +    qDebug( "KDPipeIODevice::readData: data=%p, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", +	    data, maxSize, rptr, wptr, bytesInBuffer(), numRead ); + +    std::memcpy( data, buffer + rptr, numRead ); + +    rptr = ( rptr + numRead ) % sizeof buffer ; + +    if ( !bufferFull() ) { +	qDebug( "KDPipeIODevice::readData: signal bufferNotFullCondition" ); +	bufferNotFullCondition.wakeAll(); +    } + +    return numRead; +} + +qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS; + +    Writer * const w = d->writer; + +    assert( w ); +    assert( w->error || w->isRunning() ); +    assert( data || size == 0 ); +    assert( size >= 0 ); + +    LOCKED( w ); + +    while ( !w->error && !w->bufferEmpty() ) +	w->bufferEmptyCondition.wait( &w->mutex ); + +    if ( w->error ) +	return -1; + +    assert( w->bufferEmpty() ); + +    return w->writeData( data, size ); +} + +qint64 Writer::writeData( const char * data, qint64 size ) { + +    assert( bufferEmpty() ); + +    if ( size > static_cast<qint64>( sizeof buffer ) ) +	size = sizeof buffer; + +    std::memcpy( buffer, data, size ); +     +    numBytesInBuffer = size; + +    if ( !bufferEmpty() ) +	bufferNotEmptyCondition.wakeAll(); + +    return size; +} + +void KDPipeIODevice::close() { KDAB_CHECK_THIS; + +    if ( !isOpen() ) +	return; + +    // tell clients we're about to close: +    emit aboutToClose(); + +    if ( d->writer && bytesToWrite() > 0 ) +	waitForBytesWritten( -1 ); + +    assert( bytesToWrite() == 0 ); + +    if ( Reader * & r = d->reader ) { +	synchronized( r ) { +	    // tell thread to cancel: +	    r->cancel = true; +	    // and wake it, so it can terminate: +	    r->bufferNotFullCondition.wakeAll(); +	} +	r->wait(); +	delete r; r = 0; +    } +    if ( Writer * & w = d->writer ) { +	synchronized( w ) { +	    // tell thread to cancel: +	    w->cancel = true; +	    // and wake it, so it can terminate: +	    w->bufferNotEmptyCondition.wakeAll(); +	} +	w->wait(); +	delete w; w = 0; +    } + +#ifdef Q_OS_WIN32 +    CloseHandle( d->handle ); +#else +    ::close( d->fd ); +#endif + +    setOpenMode( NotOpen ); +    d->fd = -1; +    d->handle = 0; +} + +void Reader::run() { + +    LOCKED( this ); + +    // too bad QThread doesn't have that itself; a signal isn't enough +    hasStarted.wakeAll(); + +    qDebug( "Reader::run: started" ); + +    while ( true ) { + +	while ( !cancel && bufferFull() ) { +	    bufferNotEmptyCondition.wakeAll(); +	    qDebug( "Reader::run: buffer is full, going to sleep" ); +	    bufferNotFullCondition.wait( &mutex ); +	    qDebug( "Reader::run: woke up" ); +	} + +	if ( cancel ) { +	    qDebug( "Reader::run: detected cancel" ); +	    goto leave; +	} + +	if ( rptr == wptr ) // optimize for larger chunks in case the buffer is empty +	    rptr = wptr = 0; + +	unsigned int numBytes = ( rptr + sizeof buffer - wptr - 1 ) % sizeof buffer; +	if ( numBytes > sizeof buffer - wptr ) +	    numBytes = sizeof buffer - wptr; + +	qDebug( "Reader::run: rptr=%d, wptr=%d -> numBytes=%d", rptr, wptr, numBytes ); + +	assert( numBytes > 0 ); + +	qDebug( "Reader::run: trying to read %d bytes", numBytes ); +#ifdef Q_OS_WIN32 +	DWORD numRead; +	mutex.unlock(); +	const bool ok = ReadFile( handle, buffer + wptr, numBytes, &numRead, 0 ); +	mutex.lock(); +	if ( !ok ) { +	    errorCode = static_cast<int>( GetLastError() ); +	    if ( errorCode == ERROR_BROKEN_PIPE ) { +		qDebug( "Reader::run: got eof" ); +		eof = true; +	    } else { +		qDebug( "Reader::run: got error: %d", errorCode ); +		error = true; +	    } +	    goto leave; +	} +#else +	qint64 numRead; +	mutex.unlock(); +	do { +	    numRead = ::read( fd, buffer + wptr, numBytes ); +	} while ( numRead == -1 && errno == EINTR ); +	mutex.lock(); + +	if ( numRead < 0 ) { +	    errorCode = errno; +	    error = true; +	    qDebug( "Reader::run: got error: %d", errorCode ); +	    goto leave; +	} +#endif +	qDebug( "Reader::run: read %ld bytes", static_cast<long>(numRead) ); +	if ( numRead == 0 ) { +	    qDebug( "Reader::run: eof detected" ); +	    eof = true; +	    goto leave; +	} + +	if ( cancel ) { +	    qDebug( "Reader::run: detected cancel" ); +	    goto leave; +	} +	qDebug( "Reader::run: buffer before: rptr=%4d, wptr=%4d", rptr, wptr ); +	wptr = ( wptr + numRead ) % sizeof buffer; +	qDebug( "Reader::run: buffer after:  rptr=%4d, wptr=%4d", rptr, wptr ); +	if ( !bufferEmpty() ) { +	    qDebug( "Reader::run: buffer no longer empty, waking everyone" ); +	    bufferNotEmptyCondition.wakeAll(); +	    emit readyRead(); +	} +    } + leave: +    qDebug( "Reader::run: terminating" ); +    bufferNotEmptyCondition.wakeAll(); +    emit readyRead(); +} + +void Writer::run() { + +    LOCKED( this ); + +    // too bad QThread doesn't have that itself; a signal isn't enough +    hasStarted.wakeAll(); + +    qDebug( "Writer::run: started" ); + +    while ( true ) { + +	while ( !cancel && bufferEmpty() ) { +	    bufferEmptyCondition.wakeAll(); +	    qDebug( "Writer::run: buffer is empty, going to sleep" ); +	    bufferNotEmptyCondition.wait( &mutex ); +	    qDebug( "Writer::run: woke up" ); +	} + +	if ( cancel ) { +	    qDebug( "Writer::run: detected cancel" ); +	    goto leave; +	} + +	assert( numBytesInBuffer > 0 ); + +	qDebug( "Writer::run: Trying to write %u bytes", numBytesInBuffer ); +	qint64 totalWritten = 0; +	do {  +	    mutex.unlock(); +#ifdef Q_OS_WIN32 +	    DWORD numWritten; +	    if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) { +		mutex.lock(); +		errorCode = static_cast<int>( GetLastError() ); +		qDebug( "Writer::run: got error code: %d", errorCode ); +		error = true; +		goto leave; +	    } +#else +	    qint64 numWritten; +	    do { +		numWritten = ::write( fd, buffer + totalWritten, numBytesInBuffer - totalWritten ); +	    } while ( numWritten == -1 && errno == EINTR ); + +	    if ( numWritten < 0 ) { +		mutex.lock(); +		errorCode = errno; +		qDebug( "Writer::run: got error code: %d", errorCode ); +		error = true; +		goto leave; +	    } +#endif +	    totalWritten += numWritten; +	    mutex.lock(); +	} while ( totalWritten < numBytesInBuffer ); + +	qDebug( "Writer::run: wrote %lld bytes", totalWritten ); + +	numBytesInBuffer = 0; +	bufferEmptyCondition.wakeAll(); +	emit bytesWritten( totalWritten ); +    } + leave: +    qDebug( "Writer::run: terminating" ); +    numBytesInBuffer = 0; +    bufferEmptyCondition.wakeAll(); +    emit bytesWritten( 0 ); +} + +// static  +std::pair<KDPipeIODevice*,KDPipeIODevice*> KDPipeIODevice::makePairOfConnectedPipes() { +    KDPipeIODevice * read = 0; +    KDPipeIODevice * write = 0; +#ifdef Q_OS_WIN32 +    HANDLE rh; +    HANDLE wh; +    SECURITY_ATTRIBUTES sa; +    memset( &sa, 0, sizeof(sa) ); +    sa.nLength = sizeof(sa); +    sa.bInheritHandle = TRUE; +	if ( CreatePipe( &rh, &wh, &sa, BUFFER_SIZE ) ) { +	read = new KDPipeIODevice; +	read->open( rh, ReadOnly ); +	write = new KDPipeIODevice; +	write->open( wh, WriteOnly ); +    } +#else +    int fds[2]; +    if ( pipe( fds ) == 0 ) { +	read = new KDPipeIODevice; +	read->open( fds[0], ReadOnly ); +	write = new KDPipeIODevice; +	write->open( fds[1], WriteOnly ); +    } +#endif +    return std::make_pair( read, write ); +} + +#ifdef KDAB_DEFINE_CHECKS +KDAB_DEFINE_CHECKS( KDPipeIODevice ) { +    if ( !isOpen() ) { +	assert( openMode() == NotOpen ); +	assert( !d->reader ); +	assert( !d->writer ); +#ifdef Q_OS_WIN32 +	assert( !d->handle ); +#else +	assert( d->fd < 0 ); +#endif +    } else { +	assert( openMode() != NotOpen ); +	assert( openMode() & ReadWrite ); +	if ( openMode() & ReadOnly ) { +	    assert( d->reader ); +	    synchronized( d->reader ) +		assert( d->reader->eof || d->reader->error || d->reader->isRunning() ); +	} +	if ( openMode() & WriteOnly ) { +	    assert( d->writer ); +	    synchronized( d->writer ) +		assert( d->writer->error || d->writer->isRunning() ); +	} +#ifdef Q_OS_WIN32 +	assert( d->handle ); +#else +	assert( d->fd >= 0 ); +#endif +    } +} +#endif // KDAB_DEFINE_CHECKS + +#include "moc_kdpipeiodevice.cpp" +#include "kdpipeiodevice.moc" diff --git a/gpgme/kdpipeiodevice.h b/gpgme/kdpipeiodevice.h new file mode 100644 index 00000000..ce2873f9 --- /dev/null +++ b/gpgme/kdpipeiodevice.h @@ -0,0 +1,66 @@ +/* +  Copyright (C) 2007 Klar�lvdalens Datakonsult AB + +  KDPipeIODevice is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. + +  KDPipeIODevice 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 Library General Public License for more details. + +  You should have received a copy of the GNU Library General Public License +  along with KDPipeIODevice; see the file COPYING.LIB.  If not, write to the +  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +  Boston, MA 02110-1301, USA. +*/ + +#ifndef __KDTOOLSCORE_KDPIPEIODEVICE_H__ +#define __KDTOOLSCORE_KDPIPEIODEVICE_H__ + +#include <QIODevice> + +#include <utility> + +//#include "checker.h" + +class KDPipeIODevice : public QIODevice { +    Q_OBJECT +    //KDAB_MAKE_CHECKABLE( KDPipeIODevice ) +public: +    explicit KDPipeIODevice( QObject * parent=0 ); +    explicit KDPipeIODevice( int fd, OpenMode=ReadOnly, QObject * parent=0 ); +    explicit KDPipeIODevice( Qt::HANDLE handle, OpenMode=ReadOnly, QObject * parent=0 ); +    ~KDPipeIODevice(); + +    static std::pair<KDPipeIODevice*, KDPipeIODevice*> makePairOfConnectedPipes(); + +    bool open( int fd, OpenMode mode=ReadOnly ); +    bool open( Qt::HANDLE handle, OpenMode mode=ReadOnly ); + +    Qt::HANDLE handle() const; +    int descriptor() const; + +    /* reimp */ qint64 bytesAvailable() const; +    /* reimp */ qint64 bytesToWrite() const; +    /* reimp */ bool canReadLine() const; +    /* reimp */ void close(); +    /* reimp */ bool isSequential() const; +    /* reimp */ bool atEnd() const; + +    /* reimp */ bool waitForBytesWritten( int msecs ); +    /* reimp */ bool waitForReadyRead( int msecs ); + +protected: +    /* reimp */ qint64 readData( char * data, qint64 maxSize ); +    /* reimp */ qint64 writeData( const char * data, qint64 maxSize ); + +private: +    class Private; +    Private * d; +}; + +#endif /* __KDTOOLSCORE_KDPIPEIODEVICE_H__ */ + diff --git a/gpgme/kdpipeiodevice.moc b/gpgme/kdpipeiodevice.moc new file mode 100644 index 00000000..e00d0bce --- /dev/null +++ b/gpgme/kdpipeiodevice.moc @@ -0,0 +1,132 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'kdpipeiodevice.cpp' +** +** Created: Mon Aug 27 15:17:18 2007 +**      by: The Qt Meta Object Compiler version 59 (Qt 4.3.0) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'kdpipeiodevice.cpp' doesn't include <QObject>." +#elif Q_MOC_OUTPUT_REVISION != 59 +#error "This file was generated using the moc from 4.3.0. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +static const uint qt_meta_data_Reader[] = { + + // content: +       1,       // revision +       0,       // classname +       0,    0, // classinfo +       1,   10, // methods +       0,    0, // properties +       0,    0, // enums/sets + + // signals: signature, parameters, type, tag, flags +       8,    7,    7,    7, 0x05, + +       0        // eod +}; + +static const char qt_meta_stringdata_Reader[] = { +    "Reader\0\0readyRead()\0" +}; + +const QMetaObject Reader::staticMetaObject = { +    { &QThread::staticMetaObject, qt_meta_stringdata_Reader, +      qt_meta_data_Reader, 0 } +}; + +const QMetaObject *Reader::metaObject() const +{ +    return &staticMetaObject; +} + +void *Reader::qt_metacast(const char *_clname) +{ +    if (!_clname) return 0; +    if (!strcmp(_clname, qt_meta_stringdata_Reader)) +	return static_cast<void*>(const_cast< Reader*>(this)); +    return QThread::qt_metacast(_clname); +} + +int Reader::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ +    _id = QThread::qt_metacall(_c, _id, _a); +    if (_id < 0) +        return _id; +    if (_c == QMetaObject::InvokeMetaMethod) { +        switch (_id) { +        case 0: readyRead(); break; +        } +        _id -= 1; +    } +    return _id; +} + +// SIGNAL 0 +void Reader::readyRead() +{ +    QMetaObject::activate(this, &staticMetaObject, 0, 0); +} +static const uint qt_meta_data_Writer[] = { + + // content: +       1,       // revision +       0,       // classname +       0,    0, // classinfo +       1,   10, // methods +       0,    0, // properties +       0,    0, // enums/sets + + // signals: signature, parameters, type, tag, flags +       8,    7,    7,    7, 0x05, + +       0        // eod +}; + +static const char qt_meta_stringdata_Writer[] = { +    "Writer\0\0bytesWritten(qint64)\0" +}; + +const QMetaObject Writer::staticMetaObject = { +    { &QThread::staticMetaObject, qt_meta_stringdata_Writer, +      qt_meta_data_Writer, 0 } +}; + +const QMetaObject *Writer::metaObject() const +{ +    return &staticMetaObject; +} + +void *Writer::qt_metacast(const char *_clname) +{ +    if (!_clname) return 0; +    if (!strcmp(_clname, qt_meta_stringdata_Writer)) +	return static_cast<void*>(const_cast< Writer*>(this)); +    return QThread::qt_metacast(_clname); +} + +int Writer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ +    _id = QThread::qt_metacall(_c, _id, _a); +    if (_id < 0) +        return _id; +    if (_c == QMetaObject::InvokeMetaMethod) { +        switch (_id) { +        case 0: bytesWritten((*reinterpret_cast< qint64(*)>(_a[1]))); break; +        } +        _id -= 1; +    } +    return _id; +} + +// SIGNAL 0 +void Writer::bytesWritten(qint64 _t1) +{ +    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; +    QMetaObject::activate(this, &staticMetaObject, 0, _a); +} diff --git a/gpgme/moc_kdpipeiodevice.cpp b/gpgme/moc_kdpipeiodevice.cpp new file mode 100644 index 00000000..eac7b23a --- /dev/null +++ b/gpgme/moc_kdpipeiodevice.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'kdpipeiodevice.h' +** +** Created: Mon Aug 27 15:17:18 2007 +**      by: The Qt Meta Object Compiler version 59 (Qt 4.3.0) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "kdpipeiodevice.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'kdpipeiodevice.h' doesn't include <QObject>." +#elif Q_MOC_OUTPUT_REVISION != 59 +#error "This file was generated using the moc from 4.3.0. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +static const uint qt_meta_data_KDPipeIODevice[] = { + + // content: +       1,       // revision +       0,       // classname +       0,    0, // classinfo +       0,    0, // methods +       0,    0, // properties +       0,    0, // enums/sets + +       0        // eod +}; + +static const char qt_meta_stringdata_KDPipeIODevice[] = { +    "KDPipeIODevice\0" +}; + +const QMetaObject KDPipeIODevice::staticMetaObject = { +    { &QIODevice::staticMetaObject, qt_meta_stringdata_KDPipeIODevice, +      qt_meta_data_KDPipeIODevice, 0 } +}; + +const QMetaObject *KDPipeIODevice::metaObject() const +{ +    return &staticMetaObject; +} + +void *KDPipeIODevice::qt_metacast(const char *_clname) +{ +    if (!_clname) return 0; +    if (!strcmp(_clname, qt_meta_stringdata_KDPipeIODevice)) +	return static_cast<void*>(const_cast< KDPipeIODevice*>(this)); +    return QIODevice::qt_metacast(_clname); +} + +int KDPipeIODevice::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ +    _id = QIODevice::qt_metacall(_c, _id, _a); +    if (_id < 0) +        return _id; +    return _id; +} diff --git a/gpgme/posix-sema.c b/gpgme/posix-sema.c index fa2b8d37..4ec3abb0 100644 --- a/gpgme/posix-sema.c +++ b/gpgme/posix-sema.c @@ -1,6 +1,6 @@  /* posix-sema.c      Copyright (C) 2001 Werner Koch (dd9jn) -   Copyright (C) 2001, 2002, 2004 g10 Code GmbH +   Copyright (C) 2001, 2002, 2004, 2007 g10 Code GmbH     This file is part of GPGME. @@ -45,18 +45,18 @@ _gpgme_sema_subsystem_init ()  void  _gpgme_sema_cs_enter (struct critsect_s *s)  { -  _gpgme_ath_mutex_lock (&s->private); +  _gpgme_ath_mutex_lock (&s->priv);  }  void  _gpgme_sema_cs_leave (struct critsect_s *s)  { -  _gpgme_ath_mutex_unlock (&s->private); +  _gpgme_ath_mutex_unlock (&s->priv);  }  void  _gpgme_sema_cs_destroy (struct critsect_s *s)  { -  _gpgme_ath_mutex_destroy (&s->private); -  s->private = NULL; +  _gpgme_ath_mutex_destroy (&s->priv); +  s->priv = NULL;  } diff --git a/gpgme/sema.h b/gpgme/sema.h index 0ee20742..7d3870e9 100644 --- a/gpgme/sema.h +++ b/gpgme/sema.h @@ -1,6 +1,6 @@  /* sema.h - Definitions for semaphores.     Copyright (C) 2000 Werner Koch (dd9jn) -   Copyright (C) 2001, 2003, 2004 g10 Code GmbH +   Copyright (C) 2001, 2003, 2004, 2007 g10 Code GmbH     This file is part of GPGME. @@ -25,7 +25,7 @@  struct critsect_s  {    const char *name; -  void *private; +  void *priv;  };  #define DEFINE_GLOBAL_LOCK(name) \ @@ -39,7 +39,7 @@ struct critsect_s    do					\      {					\        (a).name = #a;			\ -      (a).private = NULL;		\ +      (a).priv = NULL;			\      }					\    while (0)  #define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name)) diff --git a/gpgme/w32-glib-io.c b/gpgme/w32-glib-io.c index 232ed533..a0301b67 100644 --- a/gpgme/w32-glib-io.c +++ b/gpgme/w32-glib-io.c @@ -97,14 +97,23 @@ find_channel (int fd, int create)    return giochannel_table[fd];  } -/* Look up the giochannel for "file descriptor" FD.  */ -GIOChannel * + +/* Compatibility interface.  Obsolete.  */ +void *  gpgme_get_giochannel (int fd)  {    return find_channel (fd, 0);  } +/* Look up the giochannel for "file descriptor" FD.  */ +void * +gpgme_get_fdptr (int fd) +{ +  return find_channel (fd, 0); +} + +  /* Write the printable version of FD to the buffer BUF of length     BUFLEN.  The printable version is the representation on the command     line that the child process expects.  */ diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index dfdf45e5..a4a42569 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -1403,9 +1403,9 @@ _gpgme_io_dup (int fd)  } -/* The following interface is only useful for GPGME Glib.  */ +/* The following interface is only useful for GPGME Glib and Qt.  */ -/* Look up the giochannel for file descriptor FD.  */ +/* Compatibility interface, obsolete.  */  void *  gpgme_get_giochannel (int fd)  { @@ -1413,3 +1413,9 @@ gpgme_get_giochannel (int fd)  } +/* Look up the giochannel or qiodevice for file descriptor FD.  */ +void * +gpgme_get_fdptr (int fd) +{ +  return NULL; +} diff --git a/gpgme/w32-qt-io.cpp b/gpgme/w32-qt-io.cpp new file mode 100644 index 00000000..91170667 --- /dev/null +++ b/gpgme/w32-qt-io.cpp @@ -0,0 +1,609 @@ +/* w32-glib-io.c - W32 Glib I/O functions +   Copyright (C) 2000 Werner Koch (dd9jn) +   Copyright (C) 2001, 2002, 2004, 2005, 2007 g10 Code GmbH + +   This file is part of GPGME. +  +   GPGME is free software; you can redistribute it and/or modify it +   under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of +   the License, or (at your option) any later version. +    +   GPGME 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 +   Lesser General Public License for more details. +    +   You should have received a copy of the GNU Lesser General Public +   License along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +   02111-1307, USA.  */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <windows.h> +#include <io.h> + +#include "kdpipeiodevice.h" + +extern "C" +{ +#include "util.h" +#include "priv-io.h" +#include "sema.h" +#include "debug.h" +} + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY	_O_BINARY +#else +#define O_BINARY	0 +#endif +#endif + + +/* This file is an ugly hack to get GPGME working with Qt on Windows +   targets.  On Windows, you can not select() on file descriptors. +   The only way to check if there is something to read is to read +   something.  This means that GPGME can not let Qt check for data +   without letting Qt also handle the data on Windows targets. + +   The ugly consequence is that we need to work on QIODevices in +   GPGME, creating a Qt dependency.  Also, we need to export an +   interface for the application to get at GPGME's QIODevices.  There +   is no good way to abstract all this with callbacks, because the +   whole thing is also interconnected with the creation of pipes and +   child processes. + +   The following rule applies only to this I/O backend: + +   * ALL operations must use the user defined event loop.  GPGME can +   not anymore provide its own event loop.  This is mostly a sanity +   requirement: Although we have in theory all information we need to +   make the GPGME W32 code for select still work, it would be a big +   complication and require changes throughout GPGME. + +   Eventually, we probably have to bite the bullet and make some +   really nice callback interfaces to let the user control all this at +   a per-context level.  */ + + +#define MAX_SLAFD 256 + +QIODevice *iodevice_table[MAX_SLAFD]; + + +static QIODevice * +find_channel (int fd, int create) +{ +  if (fd < 0 || fd >= MAX_SLAFD) +    return NULL; + +  if (create && !iodevice_table[fd]) +    iodevice_table[fd] = new KDPipeIODevice +      (fd, QIODevice::ReadOnly|QIODevice::Unbuffered); + +  return iodevice_table[fd]; +} + + +/* Write the printable version of FD to the buffer BUF of length +   BUFLEN.  The printable version is the representation on the command +   line that the child process expects.  */ +int +_gpgme_io_fd2str (char *buf, int buflen, int fd) +{ +  return snprintf (buf, buflen, "%ld", (long) _get_osfhandle (fd)); +} + + +void +_gpgme_io_subsystem_init (void) +{ +} + + +static struct +{ +  _gpgme_close_notify_handler_t handler; +  void *value; +} notify_table[MAX_SLAFD]; + + +int +_gpgme_io_read (int fd, void *buffer, size_t count) +{ +  int saved_errno = 0; +  qint64 nread; +  QIODevice *chan; +  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd, +	      "buffer=%p, count=%u", buffer, count); + +  chan = find_channel (fd, 0); +  if (!chan) +    { +      TRACE_LOG ("no channel registered"); +      errno = EINVAL; +      return TRACE_SYSRES (-1); +    } +  TRACE_LOG1 ("channel %p", chan); + +  { +//  GError *err = NULL; +//  status = g_io_channel_read_chars (chan, (gchar *) buffer, +//				      count, &nread, &err); +    nread = chan->read( buffer, count ); +    if ( nread < 0 ) { +        TRACE_LOG1 ("err %s", qPrintable( chan->errorString() ) ); +        saved_errno = EIO; +        nread = -1; +    } +  } + +  TRACE_LOGBUF (buffer, nread); + +  errno = saved_errno; +  return TRACE_SYSRES (nread); +} + + +int +_gpgme_io_write (int fd, const void *buffer, size_t count) +{ +  qint64 nwritten; +  QIODevice *chan; +  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd, +	      "buffer=%p, count=%u", buffer, count); +  TRACE_LOGBUF (buffer, count); + +  chan = find_channel (fd, 0); +  if (!chan) +    { +      TRACE_LOG ("fd %d: no channel registered"); +      errno = EINVAL; +      return -1; +    } + +  nwritten = chan->write( buffer, count ); + +  if (nwritten < 0) +    { +      nwritten = -1; +      errno = EIO; +      return TRACE_SYSRES(-1) +    } +  errno = 0; +  return TRACE_SYSRES (nwritten); +} + + +int +_gpgme_io_pipe (int filedes[2], int inherit_idx) +{ +  QIODevice *chan; +  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, +	      "inherit_idx=%i (GPGME uses it for %s)", +	      inherit_idx, inherit_idx ? "writing" : "reading"); + +#define PIPEBUF_SIZE  4096 +  if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1) +    return TRACE_SYSRES (-1); + +  /* Make one end inheritable. */ +  if (inherit_idx == 0) +    { +      int new_read; + +      new_read = _dup (filedes[0]); +      _close (filedes[0]); +      filedes[0] = new_read; + +      if (new_read < 0) +	{ +	  _close (filedes[1]); +	  return TRACE_SYSRES (-1); +	} +    } +  else if (inherit_idx == 1) +    { +      int new_write; + +      new_write = _dup (filedes[1]); +      _close (filedes[1]); +      filedes[1] = new_write; + +      if (new_write < 0) +	{ +	  _close (filedes[0]); +	  return TRACE_SYSRES (-1); +	} +    } + +  /* Now we have a pipe with the right end inheritable.  The other end +     should have a giochannel.  */ +  chan = find_channel (filedes[1 - inherit_idx], 1); +  if (!chan) +    { +      int saved_errno = errno; +      _close (filedes[0]); +      _close (filedes[1]); +      errno = saved_errno; +      return TRACE_SYSRES (-1); +    } + +  return TRACE_SUC5 ("read=0x%x/%p, write=0x%x/%p, channel=%p", +	  filedes[0], (HANDLE) _get_osfhandle (filedes[0]), +	  filedes[1], (HANDLE) _get_osfhandle (filedes[1]), +	  chan); +} + + +int +_gpgme_io_close (int fd) +{ +  QIODevice *chan; +  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd); + +  if (fd < 0 || fd >= MAX_SLAFD) +    { +      errno = EBADF; +      return TRACE_SYSRES (-1); +    } + +  /* First call the notify handler.  */ +  if (notify_table[fd].handler) +    { +      notify_table[fd].handler (fd, notify_table[fd].value); +      notify_table[fd].handler = NULL; +      notify_table[fd].value = NULL; +    } + +  /* Then do the close.  */     +  chan = iodevice_table[fd]; +  if (chan) +    { +      chan->close(); +      delete chan; +      iodevice_table[fd] = NULL; +    } +  else +    _close (fd); + +  return 0; +} + + +int +_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler, +			    void *value) +{ +  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd, +	      "close_handler=%p/%p", handler, value); + +  assert (fd != -1); + +  if (fd < 0 || fd >= (int) DIM (notify_table)) +    { +      errno = EINVAL; +      return TRACE_SYSRES (-1); +    } +  notify_table[fd].handler = handler; +  notify_table[fd].value = value; +  return TRACE_SYSRES (0); +} + + +int +_gpgme_io_set_nonblocking (int fd) +{ +  /* Qt always uses non-blocking IO, except for files, maybe, but who +     uses that?  */ +  TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd); + +  return TRACE_SYSRES (0); +} + + +static char * +build_commandline (char **argv) +{ +  int i; +  int n = 0; +  char *buf; +  char *p; +   +  /* We have to quote some things because under Windows the program +     parses the commandline and does some unquoting.  We enclose the +     whole argument in double-quotes, and escape literal double-quotes +     as well as backslashes with a backslash.  We end up with a +     trailing space at the end of the line, but that is harmless.  */ +  for (i = 0; argv[i]; i++) +    { +      p = argv[i]; +      /* The leading double-quote.  */ +      n++; +      while (*p) +	{ +	  /* An extra one for each literal that must be escaped.  */ +	  if (*p == '\\' || *p == '"') +	    n++; +	  n++; +	  p++; +	} +      /* The trailing double-quote and the delimiter.  */ +      n += 2; +    } +  /* And a trailing zero.  */ +  n++; + +  buf = p = malloc (n); +  if (!buf) +    return NULL; +  for (i = 0; argv[i]; i++) +    { +      char *argvp = argv[i]; + +      *(p++) = '"'; +      while (*argvp) +	{ +	  if (*argvp == '\\' || *argvp == '"') +	    *(p++) = '\\'; +	  *(p++) = *(argvp++); +	} +      *(p++) = '"'; +      *(p++) = ' '; +    } +  *(p++) = 0; + +  return buf; +} + + +int +_gpgme_io_spawn (const char *path, char **argv, +		 struct spawn_fd_item_s *fd_child_list, +		 struct spawn_fd_item_s *fd_parent_list) +{ +  SECURITY_ATTRIBUTES sec_attr; +  PROCESS_INFORMATION pi = +    { +      NULL,      /* returns process handle */ +      0,         /* returns primary thread handle */ +      0,         /* returns pid */ +      0         /* returns tid */ +    }; +  STARTUPINFO si; +  char *envblock = NULL; +  int cr_flags = CREATE_DEFAULT_ERROR_MODE +    | GetPriorityClass (GetCurrentProcess ()); +  int i; +  char *arg_string; +  int duped_stdin = 0; +  int duped_stderr = 0; +  HANDLE hnul = INVALID_HANDLE_VALUE; +  /* FIXME.  */ +  int debug_me = 0; +  TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, +	      "path=%s", path); +  i = 0; +  while (argv[i]) +    { +      TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]); +      i++; +    } +   +  memset (&sec_attr, 0, sizeof sec_attr); +  sec_attr.nLength = sizeof sec_attr; +  sec_attr.bInheritHandle = FALSE; +   +  arg_string = build_commandline (argv); +  if (!arg_string) +    return TRACE_SYSRES (-1); +   +  memset (&si, 0, sizeof si); +  si.cb = sizeof (si); +  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; +  si.wShowWindow = debug_me? SW_SHOW : SW_HIDE; +  si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); +  si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); +  si.hStdError = GetStdHandle (STD_ERROR_HANDLE); +   +  for (i = 0; fd_child_list[i].fd != -1; i++) +    { +      if (fd_child_list[i].dup_to == 0) +	{ +	  si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd); +	  TRACE_LOG2 ("using 0x%x/%p for stdin", fd_child_list[i].fd, +		      _get_osfhandle (fd_child_list[i].fd)); +	  duped_stdin = 1; +        } +      else if (fd_child_list[i].dup_to == 1) +	{ +	  si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd); +	  TRACE_LOG2 ("using 0x%x/%p for stdout", fd_child_list[i].fd, +		      _get_osfhandle (fd_child_list[i].fd)); +	} +      else if (fd_child_list[i].dup_to == 2) +	{ +	  si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd); +	  TRACE_LOG2 ("using 0x%x/%p for stderr", fd_child_list[i].fd, +		      _get_osfhandle (fd_child_list[i].fd)); +	  duped_stderr = 1; +        } +    } +   +  if (!duped_stdin || !duped_stderr) +    { +      SECURITY_ATTRIBUTES sa; +       +      memset (&sa, 0, sizeof sa); +      sa.nLength = sizeof sa; +      sa.bInheritHandle = TRUE; +      hnul = CreateFile ("nul", +			 GENERIC_READ|GENERIC_WRITE, +			 FILE_SHARE_READ|FILE_SHARE_WRITE, +			 &sa, +			 OPEN_EXISTING, +			 FILE_ATTRIBUTE_NORMAL, +			 NULL); +      if (hnul == INVALID_HANDLE_VALUE) +	{ +	  TRACE_LOG1 ("CreateFile (\"nul\") failed: ec=%d", +		      (int) GetLastError ()); +	  free (arg_string); +	  /* FIXME: Should translate the error code.  */ +	  errno = EIO; +	  return TRACE_SYSRES (-1); +        } +      /* Make sure that the process has a connected stdin.  */ +      if (!duped_stdin) +	{ +	  si.hStdInput = hnul; +	  TRACE_LOG1 ("using 0x%x for dummy stdin", (int) hnul); +	} +      /* We normally don't want all the normal output.  */ +      if (!duped_stderr) +	{ +	  si.hStdError = hnul; +	  TRACE_LOG1 ("using %d for dummy stderr", (int)hnul); +	} +    } +   +  cr_flags |= CREATE_SUSPENDED; +  cr_flags |= DETACHED_PROCESS; +  if (!CreateProcessA (path, +		       arg_string, +		       &sec_attr,     /* process security attributes */ +		       &sec_attr,     /* thread security attributes */ +		       TRUE,          /* inherit handles */ +		       cr_flags,      /* creation flags */ +		       envblock,      /* environment */ +		       NULL,          /* use current drive/directory */ +		       &si,           /* startup information */ +		       &pi))          /* returns process information */ +    { +      TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); +      free (arg_string); +      /* FIXME: Should translate the error code.  */ +      errno = EIO; +      return TRACE_SYSRES (-1); +    } +   +  /* Close the /dev/nul handle if used.  */ +  if (hnul != INVALID_HANDLE_VALUE) +    { +      if (!CloseHandle (hnul)) +	TRACE_LOG1 ("CloseHandle (hnul) failed: ec=%d (ignored)", +		    (int) GetLastError ()); +    } +   +  /* Close the other ends of the pipes.  */ +  for (i = 0; fd_parent_list[i].fd != -1; i++) +    _gpgme_io_close (fd_parent_list[i].fd); +   +  TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, " +	      "dwProcessID=%d, dwThreadId=%d", +	      pi.hProcess, pi.hThread,  +	      (int) pi.dwProcessId, (int) pi.dwThreadId); +   +  if (ResumeThread (pi.hThread) < 0) +    TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ()); +   +  if (!CloseHandle (pi.hThread)) +    TRACE_LOG1 ("CloseHandle of thread failed: ec=%d", +		(int) GetLastError ()); + +  TRACE_SUC1 ("process=%p", pi.hProcess); +  return 0; +} + + +/* Select on the list of fds.  Returns: -1 = error, 0 = timeout or +   nothing to select, > 0 = number of signaled fds.  */ +int +_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ +  int i; +  int count; +  /* Use a 1s timeout.  */ + +  void *dbg_help = NULL; +  TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds, +	      "nfds=%u, nonblock=%u", nfds, nonblock); + +  // we only implement the special case of nonblock == true +  assert( nonblock ); + +  count = 0; + +  TRACE_SEQ (dbg_help, "select on [ "); +  for (i = 0; i < nfds; i++) +    { +      if (fds[i].fd == -1) +        { +          fds[i].signaled = 0; +        } +      else if (fds[i].frozen) +        { +          TRACE_ADD1 (dbg_help, "f0x%x ", fds[i].fd); +          fds[i].signaled = 0; +        } +      else if (fds[i].for_read ) +        { +          const QIODevice * const chan = find_channel (fds[i].fd, 0); +          assert (chan); +          fds[i].signaled = chan->bytesAvailable() > 0 ? 1 : 0 ; +          TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd); +          count++; +        } +      else if (fds[i].for_write) +        { +          const QIODevice * const chan = find_channel (fds[i].fd, 0); +          assert (chan); +          fds[i].signaled = chan->bytesToWrite() > 0 ? 0 : 1 ; +          TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd); +          count++; +        } +    } +  TRACE_END (dbg_help, "]");  + +  return TRACE_SYSRES (count); +} + + +int +_gpgme_io_dup (int fd) +{ +  return _dup (fd); +} + + +/* Look up the qiodevice for file descriptor FD.  */ +extern "C" +void * +gpgme_get_fdptr (int fd) +{ +  return find_channel (fd, 0); +} + + +/* Obsolete compatibility interface.  */ +extern "C" +void * +gpgme_get_giochannel (int fd) +{ +  return NULL; +} + diff --git a/gpgme/w32-sema.c b/gpgme/w32-sema.c index c20f1a7b..5228cc7c 100644 --- a/gpgme/w32-sema.c +++ b/gpgme/w32-sema.c @@ -1,6 +1,6 @@  /* w32-sema.c      Copyright (C) 2001 Werner Koch (dd9jn) -   Copyright (C) 2001, 2002, 2004 g10 Code GmbH +   Copyright (C) 2001, 2002, 2004, 2007 g10 Code GmbH     This file is part of GPGME. @@ -65,7 +65,7 @@ critsect_init (struct critsect_s *s)      /* first test whether it is really not initialized */      EnterCriticalSection (&init_lock); -    if ( s->private ) { +    if ( s->priv ) {          LeaveCriticalSection (&init_lock);          return;      } @@ -76,7 +76,7 @@ critsect_init (struct critsect_s *s)          sema_fatal ("out of core while creating critical section lock");      }      InitializeCriticalSection (mp); -    s->private = mp; +    s->priv = mp;      LeaveCriticalSection (&init_lock);  } @@ -91,25 +91,25 @@ _gpgme_sema_subsystem_init ()  void  _gpgme_sema_cs_enter ( struct critsect_s *s )  { -    if (!s->private) +    if (!s->priv)          critsect_init (s); -    EnterCriticalSection ( (CRITICAL_SECTION*)s->private ); +    EnterCriticalSection ( (CRITICAL_SECTION*)s->priv );  }  void  _gpgme_sema_cs_leave (struct critsect_s *s)  { -    if (!s->private) +    if (!s->priv)          critsect_init (s); -    LeaveCriticalSection ((CRITICAL_SECTION*)s->private); +    LeaveCriticalSection ((CRITICAL_SECTION*)s->priv);  }  void  _gpgme_sema_cs_destroy ( struct critsect_s *s )  { -    if (s && s->private) { -        DeleteCriticalSection ((CRITICAL_SECTION*)s->private); -        free (s->private); -        s->private = NULL; +    if (s && s->priv) { +        DeleteCriticalSection ((CRITICAL_SECTION*)s->priv); +        free (s->priv); +        s->priv = NULL;      }  } diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 00000000..c29b6c05 --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,157 @@ +# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*- +#  +# Copyright © 2004 Scott James Remnant <[email protected]>. +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then +	AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then +	_pkg_min_version=m4_default([$1], [0.9.0]) +	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) +	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then +		AC_MSG_RESULT([yes]) +	else +		AC_MSG_RESULT([no]) +		PKG_CONFIG="" +	fi +		 +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists.  Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ +    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then +  m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else +  $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then +    if test -n "$$1"; then +        pkg_cv_[]$1="$$1" +    else +        PKG_CHECK_EXISTS([$3], +                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], +			 [pkg_failed=yes]) +    fi +else +	pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then +        _pkg_short_errors_supported=yes +else +        _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then +        _PKG_SHORT_ERRORS_SUPPORTED +        if test $_pkg_short_errors_supported = yes; then +	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` +        else  +	        $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` +        fi +	# Put the nasty error message in config.log where it belongs +	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + +	ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], +		[AC_MSG_RESULT([no]) +                $4]) +elif test $pkg_failed = untried; then +	ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old.  Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])], +		[$4]) +else +	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS +	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS +        AC_MSG_RESULT([yes]) +	ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES | 
