Line data Source code
1 : /**********************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: Implement VSI large file api for stdout
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "cpl_vsi.h"
15 :
16 : #include <cstddef>
17 : #include <cstdio>
18 : #include <cstring>
19 : #include <fcntl.h>
20 :
21 : #include "cpl_error.h"
22 : #include "cpl_vsi_virtual.h"
23 :
24 : #ifdef _WIN32
25 : #include <io.h>
26 : #endif
27 :
28 : static VSIWriteFunction pWriteFunction = fwrite;
29 : static FILE *pWriteStream = stdout;
30 :
31 : /************************************************************************/
32 : /* VSIStdoutSetRedirection() */
33 : /************************************************************************/
34 :
35 : /** Set an alternative write function and output file handle instead of
36 : * fwrite() / stdout.
37 : *
38 : * @param pFct Function with same signature as fwrite()
39 : * @param stream File handle on which to output. Passed to pFct.
40 : *
41 : */
42 0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
43 : {
44 0 : pWriteFunction = pFct;
45 0 : pWriteStream = stream;
46 0 : }
47 :
48 : //! @cond Doxygen_Suppress
49 :
50 : /************************************************************************/
51 : /* ==================================================================== */
52 : /* VSIStdoutFilesystemHandler */
53 : /* ==================================================================== */
54 : /************************************************************************/
55 :
56 : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
57 : {
58 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
59 :
60 : public:
61 1768 : VSIStdoutFilesystemHandler() = default;
62 :
63 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
64 : const char *pszAccess, bool bSetError,
65 : CSLConstList /* papszOptions */) override;
66 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
67 : int nFlags) override;
68 :
69 0 : bool SupportsRead(const char * /* pszPath */) override
70 : {
71 0 : return false;
72 : }
73 : };
74 :
75 : /************************************************************************/
76 : /* ==================================================================== */
77 : /* VSIStdoutHandle */
78 : /* ==================================================================== */
79 : /************************************************************************/
80 :
81 : class VSIStdoutHandle final : public VSIVirtualHandle
82 : {
83 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
84 :
85 : vsi_l_offset m_nOffset = 0;
86 : bool m_bError = false;
87 :
88 : public:
89 6 : VSIStdoutHandle() = default;
90 12 : ~VSIStdoutHandle() override = default;
91 :
92 : int Seek(vsi_l_offset nOffset, int nWhence) override;
93 : vsi_l_offset Tell() override;
94 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
95 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
96 :
97 0 : void ClearErr() override
98 : {
99 0 : m_bError = false;
100 0 : }
101 :
102 0 : int Error() override
103 : {
104 0 : return m_bError;
105 : }
106 :
107 0 : int Eof() override
108 : {
109 0 : return FALSE;
110 : }
111 :
112 : int Flush() override;
113 : int Close() override;
114 : };
115 :
116 : /************************************************************************/
117 : /* Seek() */
118 : /************************************************************************/
119 :
120 0 : int VSIStdoutHandle::Seek(vsi_l_offset nOffset, int nWhence)
121 :
122 : {
123 0 : if (nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR))
124 0 : return 0;
125 0 : if (nWhence == SEEK_SET && nOffset == Tell())
126 0 : return 0;
127 0 : CPLError(CE_Failure, CPLE_NotSupported, "Seek() unsupported on /vsistdout");
128 0 : return -1;
129 : }
130 :
131 : /************************************************************************/
132 : /* Tell() */
133 : /************************************************************************/
134 :
135 3 : vsi_l_offset VSIStdoutHandle::Tell()
136 : {
137 3 : return m_nOffset;
138 : }
139 :
140 : /************************************************************************/
141 : /* Flush() */
142 : /************************************************************************/
143 :
144 9 : int VSIStdoutHandle::Flush()
145 :
146 : {
147 9 : if (pWriteStream == stdout)
148 9 : return fflush(stdout);
149 : else
150 0 : return 0;
151 : }
152 :
153 : /************************************************************************/
154 : /* Read() */
155 : /************************************************************************/
156 :
157 0 : size_t VSIStdoutHandle::Read(void * /* pBuffer */, size_t nSize, size_t nCount)
158 : {
159 0 : if (nSize > 0 && nCount > 0)
160 : {
161 0 : CPLError(CE_Failure, CPLE_NotSupported,
162 : "Read() unsupported on /vsistdout");
163 0 : m_bError = true;
164 : }
165 0 : return 0;
166 : }
167 :
168 : /************************************************************************/
169 : /* Write() */
170 : /************************************************************************/
171 :
172 440 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
173 :
174 : {
175 440 : size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
176 440 : m_nOffset += nSize * nRet;
177 440 : return nRet;
178 : }
179 :
180 : /************************************************************************/
181 : /* Close() */
182 : /************************************************************************/
183 :
184 6 : int VSIStdoutHandle::Close()
185 :
186 : {
187 6 : return Flush();
188 : }
189 :
190 : /************************************************************************/
191 : /* ==================================================================== */
192 : /* VSIStdoutFilesystemHandler */
193 : /* ==================================================================== */
194 : /************************************************************************/
195 :
196 : /************************************************************************/
197 : /* Open() */
198 : /************************************************************************/
199 :
200 : VSIVirtualHandleUniquePtr
201 14 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
202 : const char *pszAccess, bool /* bSetError */,
203 : CSLConstList /* papszOptions */)
204 : {
205 14 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
206 : {
207 8 : CPLError(CE_Failure, CPLE_NotSupported,
208 : "Read or update mode not supported on /vsistdout");
209 8 : return nullptr;
210 : }
211 :
212 : #ifdef _WIN32
213 : if (strchr(pszAccess, 'b') != nullptr)
214 : setmode(fileno(stdout), O_BINARY);
215 : #endif
216 :
217 : return VSIVirtualHandleUniquePtr(
218 6 : std::make_unique<VSIStdoutHandle>().release());
219 : }
220 :
221 : /************************************************************************/
222 : /* Stat() */
223 : /************************************************************************/
224 :
225 30 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
226 : VSIStatBufL *pStatBuf, int /* nFlags */)
227 :
228 : {
229 30 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
230 :
231 30 : return -1;
232 : }
233 :
234 : /************************************************************************/
235 : /* ==================================================================== */
236 : /* VSIStdoutRedirectFilesystemHandler */
237 : /* ==================================================================== */
238 : /************************************************************************/
239 :
240 : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
241 : {
242 : public:
243 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
244 : const char *pszAccess, bool bSetError,
245 : CSLConstList /* papszOptions */) override;
246 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
247 : int nFlags) override;
248 :
249 1 : bool SupportsRead(const char * /* pszPath */) override
250 : {
251 1 : return false;
252 : }
253 : };
254 :
255 : /************************************************************************/
256 : /* ==================================================================== */
257 : /* VSIStdoutRedirectHandle */
258 : /* ==================================================================== */
259 : /************************************************************************/
260 :
261 : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
262 : {
263 : VSIVirtualHandle *m_poHandle = nullptr;
264 : bool m_bError = false;
265 :
266 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
267 :
268 : public:
269 : explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
270 : ~VSIStdoutRedirectHandle() override;
271 :
272 : int Seek(vsi_l_offset nOffset, int nWhence) override;
273 : vsi_l_offset Tell() override;
274 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
275 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
276 :
277 0 : void ClearErr() override
278 : {
279 0 : m_bError = false;
280 0 : }
281 :
282 0 : int Error() override
283 : {
284 0 : return m_bError;
285 : }
286 :
287 0 : int Eof() override
288 : {
289 0 : return FALSE;
290 : }
291 :
292 : int Flush() override;
293 : int Close() override;
294 : };
295 :
296 : /************************************************************************/
297 : /* VSIStdoutRedirectHandle() */
298 : /************************************************************************/
299 :
300 7 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
301 7 : : m_poHandle(poHandle)
302 : {
303 7 : }
304 :
305 : /************************************************************************/
306 : /* ~VSIStdoutRedirectHandle() */
307 : /************************************************************************/
308 :
309 14 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
310 : {
311 7 : delete m_poHandle;
312 14 : }
313 :
314 : /************************************************************************/
315 : /* Seek() */
316 : /************************************************************************/
317 :
318 0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
319 : {
320 0 : CPLError(CE_Failure, CPLE_NotSupported,
321 : "Seek() unsupported on /vsistdout_redirect");
322 0 : return -1;
323 : }
324 :
325 : /************************************************************************/
326 : /* Tell() */
327 : /************************************************************************/
328 :
329 272 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
330 : {
331 272 : return m_poHandle->Tell();
332 : }
333 :
334 : /************************************************************************/
335 : /* Flush() */
336 : /************************************************************************/
337 :
338 2 : int VSIStdoutRedirectHandle::Flush()
339 :
340 : {
341 2 : return m_poHandle->Flush();
342 : }
343 :
344 : /************************************************************************/
345 : /* Read() */
346 : /************************************************************************/
347 :
348 0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t nSize,
349 : size_t nCount)
350 : {
351 0 : if (nSize > 0 && nCount > 0)
352 : {
353 0 : CPLError(CE_Failure, CPLE_NotSupported,
354 : "Read() unsupported on /vsistdout");
355 0 : m_bError = true;
356 : }
357 0 : return 0;
358 : }
359 :
360 : /************************************************************************/
361 : /* Write() */
362 : /************************************************************************/
363 :
364 592 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
365 : size_t nCount)
366 :
367 : {
368 592 : return m_poHandle->Write(pBuffer, nSize, nCount);
369 : }
370 :
371 : /************************************************************************/
372 : /* Close() */
373 : /************************************************************************/
374 :
375 10 : int VSIStdoutRedirectHandle::Close()
376 :
377 : {
378 10 : return m_poHandle->Close();
379 : }
380 :
381 : /************************************************************************/
382 : /* ==================================================================== */
383 : /* VSIStdoutRedirectFilesystemHandler */
384 : /* ==================================================================== */
385 : /************************************************************************/
386 :
387 : /************************************************************************/
388 : /* Open() */
389 : /************************************************************************/
390 :
391 26 : VSIVirtualHandleUniquePtr VSIStdoutRedirectFilesystemHandler::Open(
392 : const char *pszFilename, const char *pszAccess, bool /* bSetError */,
393 : CSLConstList /* papszOptions */)
394 :
395 : {
396 26 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
397 : {
398 19 : CPLError(CE_Failure, CPLE_NotSupported,
399 : "Read or update mode not supported on /vsistdout_redirect");
400 19 : return nullptr;
401 : }
402 :
403 : auto poHandle = VSIFilesystemHandler::OpenStatic(
404 14 : pszFilename + strlen("/vsistdout_redirect/"), pszAccess);
405 7 : if (poHandle == nullptr)
406 0 : return nullptr;
407 :
408 : return VSIVirtualHandleUniquePtr(
409 14 : std::make_unique<VSIStdoutRedirectHandle>(poHandle.release())
410 7 : .release());
411 : }
412 :
413 : /************************************************************************/
414 : /* Stat() */
415 : /************************************************************************/
416 :
417 37 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
418 : VSIStatBufL *pStatBuf,
419 : int /* nFlags */)
420 : {
421 37 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
422 :
423 37 : return -1;
424 : }
425 :
426 : //! @endcond
427 :
428 : /************************************************************************/
429 : /* VSIInstallStdoutHandler() */
430 : /************************************************************************/
431 :
432 : /*!
433 : \brief Install /vsistdout/ file system handler
434 :
435 : A special file handler is installed that allows writing to the standard
436 : output stream.
437 :
438 : The file operations available are of course limited to Write().
439 :
440 : A variation of this file system exists as the /vsistdout_redirect/ file
441 : system handler, where the output function can be defined with
442 : VSIStdoutSetRedirection().
443 :
444 : \verbatim embed:rst
445 : See :ref:`/vsistdout/ documentation <vsistdout>`
446 : \endverbatim
447 :
448 : */
449 :
450 1768 : void VSIInstallStdoutHandler()
451 :
452 : {
453 1768 : VSIFileManager::InstallHandler("/vsistdout/",
454 1768 : new VSIStdoutFilesystemHandler);
455 1768 : VSIFileManager::InstallHandler("/vsistdout_redirect/",
456 1768 : new VSIStdoutRedirectFilesystemHandler);
457 1768 : }
|