1 /***************************************************************************
2                             qgsgrassdatafile.cpp
3                              -------------------
4     begin                : June, 2015
5     copyright            : (C) 2015 Radim Blazek
6     email                : radim.blazek@gmail.com
7  ***************************************************************************/
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 #include "qgsgrassdatafile.h"
17 
18 #ifdef Q_OS_UNIX
19 #include <sys/select.h>
20 #endif
21 
QgsGrassDataFile(QObject * parent)22 QgsGrassDataFile::QgsGrassDataFile( QObject *parent )
23   : QFile( parent )
24 {
25 }
26 
open(FILE * fh)27 bool QgsGrassDataFile::open( FILE *fh )
28 {
29   bool ret = QFile::open( fh, QIODevice::ReadOnly | QIODevice::Unbuffered );
30   if ( ret )
31   {
32     mFh = fh;
33   }
34   return ret;
35 }
36 
readData(char * data,qint64 len)37 qint64 QgsGrassDataFile::readData( char *data, qint64 len )
38 {
39   qint64 readSoFar = 0;
40   forever
41   {
42     // QFile::readData should return -1 when pipe is closed, but it does not
43     // and error is not set (at least with QProcess::closeWriteChannel).
44     // In fact, qfsfileengine_unix.cpp QFSFileEnginePrivate::nativeRead returns -1
45     // if (readBytes == 0 && !feof(fh)).
46     //
47     // feof(stdin) works (tested on Linux) but it is impossible to get FILE* from QFile
48     // ( fdopen(handle(),"rb") returns FILE*, but it doesn't have eof set until read() is used on it)
49     // => store FILE* in open()
50 
51     qint64 read = QFile::readData( data + readSoFar, len - readSoFar );
52     if ( read == -1 )
53     {
54       return -1;
55     }
56     readSoFar += read;
57 
58     //fprintf(stderr, "len = %d readSoFar = %d feof = %d", static_cast<int>(len), static_cast<int>(readSoFar), static_cast<int>(feof(mFh))  );
59     if ( readSoFar == len )
60     {
61       break;
62     }
63     if ( feof( mFh ) )
64     {
65       return -1;
66     }
67     // Should we select()? QFile has no waitForReadyRead() implementation.
68     // QFile::readData() seems to be blocking until there are data on Linux if pipe was not closed.
69     // If pipe was closed, QFile::readData() does not block and returns 0 (instead of -1) but
70     // we catch closed pipe above (feof) so select probably is not necessary, normally (on Linux) it is not reached.
71     // TODO: verify what happens on Windows and possibly port select().
72 #ifdef Q_OS_UNIX
73     if ( read == 0 )
74     {
75       fd_set readFds;
76       FD_ZERO( &readFds );
77       struct timeval tv;
78       tv.tv_sec = 0;
79       tv.tv_usec = 10000; // we could also wait for ever
80       int sel = select( 0, &readFds, nullptr, nullptr, &tv );
81       Q_UNUSED( sel )
82       //fprintf(stderr, "sel = %d", sel);
83     }
84 #endif
85   }
86   return readSoFar;
87 }
88