LCOV - code coverage report
Current view: top level - port - cpl_vsil_stdout.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 55 97 56.7 %
Date: 2025-10-22 13:51:22 Functions: 21 33 63.6 %

          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 : }

Generated by: LCOV version 1.14