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