Coverage Report

Created: 2025-11-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wxwidgets/include/wx/private/streamtempinput.h
Line
Count
Source
1
///////////////////////////////////////////////////////////////////////////////
2
// Name:        wx/private/streamtempinput.h
3
// Purpose:     defines wxStreamTempInputBuffer which is used by Unix and MSW
4
//              implementations of wxExecute; this file is only used by the
5
//              library and never by the user code
6
// Author:      Vadim Zeitlin
7
// Modified by: Rob Bresalier
8
// Created:     2013-05-04
9
// Copyright:   (c) 2002 Vadim Zeitlin <vadim@wxwidgets.org>
10
// Licence:     wxWindows licence
11
///////////////////////////////////////////////////////////////////////////////
12
13
#ifndef _WX_PRIVATE_STREAMTEMPINPUT_H
14
#define _WX_PRIVATE_STREAMTEMPINPUT_H
15
16
#include "wx/private/pipestream.h"
17
18
// ----------------------------------------------------------------------------
19
// wxStreamTempInputBuffer
20
// ----------------------------------------------------------------------------
21
22
/*
23
   wxStreamTempInputBuffer is a hack which we need to solve the problem of
24
   executing a child process synchronously with IO redirecting: when we do
25
   this, the child writes to a pipe we open to it but when the pipe buffer
26
   (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to
27
   read data from it because the child blocks in its write() until then and if
28
   it blocks we are never going to return from wxExecute() so we dead lock.
29
30
   So here is the fix: we now read the output as soon as it appears into a temp
31
   buffer (wxStreamTempInputBuffer object) and later just stuff it back into
32
   the stream when the process terminates. See supporting code in wxExecute()
33
   itself as well.
34
35
   Note that this is horribly inefficient for large amounts of output (count
36
   the number of times we copy the data around) and so a better API is badly
37
   needed! However it's not easy to devise a way to do this keeping backwards
38
   compatibility with the existing wxExecute(wxEXEC_SYNC)...
39
*/
40
class wxStreamTempInputBuffer
41
{
42
public:
43
0
    wxStreamTempInputBuffer() = default;
44
45
    // call to associate a stream with this buffer, otherwise nothing happens
46
    // at all
47
    void Init(wxPipeInputStream *stream)
48
0
    {
49
0
        wxASSERT_MSG( !m_stream, wxS("Can only initialize once") );
50
51
0
        m_stream = stream;
52
0
    }
53
54
    // check for input on our stream and cache it in our buffer if any
55
    //
56
    // return true if anything was done
57
    bool Update()
58
0
    {
59
0
        if ( !m_stream || !m_stream->CanRead() )
60
0
            return false;
61
62
        // realloc in blocks of 4Kb: this is the default (and minimal) buffer
63
        // size of the Unix pipes so it should be the optimal step
64
        //
65
        // NB: don't use "static int" in this inline function, some compilers
66
        //     (e.g. IBM xlC) don't like it
67
0
        enum { incSize = 4096 };
68
69
0
        void *buf = realloc(m_buffer, m_size + incSize);
70
0
        if ( !buf )
71
0
            return false;
72
73
0
        m_buffer = buf;
74
0
        m_stream->Read((char *)m_buffer + m_size, incSize);
75
0
        m_size += m_stream->LastRead();
76
77
0
        return true;
78
0
    }
79
80
    // check if can continue reading from the stream, this is used to disable
81
    // the callback once we can't read anything more
82
    bool Eof() const
83
0
    {
84
        // If we have no stream, always return true as we can't read any more.
85
0
        return !m_stream || m_stream->Eof();
86
0
    }
87
88
    // read everything remaining until the EOF, this should only be called once
89
    // the child process terminates and we know that no more data is coming
90
    bool ReadAll()
91
0
    {
92
0
        while ( !Eof() )
93
0
        {
94
0
            if ( !Update() )
95
0
                return false;
96
0
        }
97
98
0
        return true;
99
0
    }
100
101
    // dtor puts the data buffered during this object lifetime into the
102
    // associated stream
103
    ~wxStreamTempInputBuffer()
104
0
    {
105
0
        if ( m_buffer )
106
0
        {
107
0
            m_stream->Ungetch(m_buffer, m_size);
108
0
            free(m_buffer);
109
0
        }
110
0
    }
111
112
0
    const void *GetBuffer() const { return m_buffer; }
113
114
0
    size_t GetSize() const { return m_size; }
115
116
private:
117
    // the stream we're buffering, if nullptr we don't do anything at all
118
    wxPipeInputStream *m_stream = nullptr;
119
120
    // the buffer of size m_size (nullptr if m_size == 0)
121
    void *m_buffer = nullptr;
122
123
    // the size of the buffer
124
    size_t m_size = 0;
125
126
    wxDECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer);
127
};
128
129
#endif // _WX_PRIVATE_STREAMTEMPINPUT_H