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

Generated by: LCOV version 1.14