LCOV - code coverage report
Current view: top level - port - cpl_vsil_stdout.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 54 96 56.2 %
Date: 2024-11-21 22:18:42 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             : #if HAVE_FCNTL_H
      20             : #include <fcntl.h>
      21             : #endif
      22             : 
      23             : #include "cpl_error.h"
      24             : #include "cpl_vsi_virtual.h"
      25             : 
      26             : #ifdef _WIN32
      27             : #include <io.h>
      28             : #include <fcntl.h>
      29             : #endif
      30             : 
      31             : static VSIWriteFunction pWriteFunction = fwrite;
      32             : static FILE *pWriteStream = stdout;
      33             : 
      34             : /************************************************************************/
      35             : /*                        VSIStdoutSetRedirection()                     */
      36             : /************************************************************************/
      37             : 
      38             : /** Set an alternative write function and output file handle instead of
      39             :  *  fwrite() / stdout.
      40             :  *
      41             :  * @param pFct Function with same signature as fwrite()
      42             :  * @param stream File handle on which to output. Passed to pFct.
      43             :  *
      44             :  * @since GDAL 2.0
      45             :  */
      46           0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
      47             : {
      48           0 :     pWriteFunction = pFct;
      49           0 :     pWriteStream = stream;
      50           0 : }
      51             : 
      52             : //! @cond Doxygen_Suppress
      53             : 
      54             : /************************************************************************/
      55             : /* ==================================================================== */
      56             : /*                       VSIStdoutFilesystemHandler                     */
      57             : /* ==================================================================== */
      58             : /************************************************************************/
      59             : 
      60             : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
      61             : {
      62             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
      63             : 
      64             :   public:
      65        1304 :     VSIStdoutFilesystemHandler() = default;
      66             : 
      67             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
      68             :                            bool bSetError,
      69             :                            CSLConstList /* papszOptions */) override;
      70             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
      71             :              int nFlags) override;
      72             : 
      73           0 :     bool SupportsRead(const char * /* pszPath */) override
      74             :     {
      75           0 :         return false;
      76             :     }
      77             : };
      78             : 
      79             : /************************************************************************/
      80             : /* ==================================================================== */
      81             : /*                        VSIStdoutHandle                               */
      82             : /* ==================================================================== */
      83             : /************************************************************************/
      84             : 
      85             : class VSIStdoutHandle final : public VSIVirtualHandle
      86             : {
      87             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
      88             : 
      89             :     vsi_l_offset m_nOffset = 0;
      90             :     bool m_bError = false;
      91             : 
      92             :   public:
      93           3 :     VSIStdoutHandle() = default;
      94           6 :     ~VSIStdoutHandle() override = default;
      95             : 
      96             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
      97             :     vsi_l_offset Tell() override;
      98             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
      99             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     100             : 
     101           0 :     void ClearErr() override
     102             :     {
     103           0 :         m_bError = false;
     104           0 :     }
     105             : 
     106           0 :     int Error() override
     107             :     {
     108           0 :         return m_bError;
     109             :     }
     110             : 
     111           0 :     int Eof() override
     112             :     {
     113           0 :         return FALSE;
     114             :     }
     115             : 
     116             :     int Flush() override;
     117             :     int Close() override;
     118             : };
     119             : 
     120             : /************************************************************************/
     121             : /*                                Seek()                                */
     122             : /************************************************************************/
     123             : 
     124           0 : int VSIStdoutHandle::Seek(vsi_l_offset nOffset, int nWhence)
     125             : 
     126             : {
     127           0 :     if (nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR))
     128           0 :         return 0;
     129           0 :     if (nWhence == SEEK_SET && nOffset == Tell())
     130           0 :         return 0;
     131           0 :     CPLError(CE_Failure, CPLE_NotSupported, "Seek() unsupported on /vsistdout");
     132           0 :     return -1;
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                                Tell()                                */
     137             : /************************************************************************/
     138             : 
     139           1 : vsi_l_offset VSIStdoutHandle::Tell()
     140             : {
     141           1 :     return m_nOffset;
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                               Flush()                                */
     146             : /************************************************************************/
     147             : 
     148           4 : int VSIStdoutHandle::Flush()
     149             : 
     150             : {
     151           4 :     if (pWriteStream == stdout)
     152           4 :         return fflush(stdout);
     153             :     else
     154           0 :         return 0;
     155             : }
     156             : 
     157             : /************************************************************************/
     158             : /*                                Read()                                */
     159             : /************************************************************************/
     160             : 
     161           0 : size_t VSIStdoutHandle::Read(void * /* pBuffer */, size_t nSize, size_t nCount)
     162             : {
     163           0 :     if (nSize > 0 && nCount > 0)
     164             :     {
     165           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     166             :                  "Read() unsupported on /vsistdout");
     167           0 :         m_bError = true;
     168             :     }
     169           0 :     return 0;
     170             : }
     171             : 
     172             : /************************************************************************/
     173             : /*                               Write()                                */
     174             : /************************************************************************/
     175             : 
     176          20 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
     177             : 
     178             : {
     179          20 :     size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
     180          20 :     m_nOffset += nSize * nRet;
     181          20 :     return nRet;
     182             : }
     183             : 
     184             : /************************************************************************/
     185             : /*                               Close()                                */
     186             : /************************************************************************/
     187             : 
     188           3 : int VSIStdoutHandle::Close()
     189             : 
     190             : {
     191           3 :     return Flush();
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /* ==================================================================== */
     196             : /*                       VSIStdoutFilesystemHandler                     */
     197             : /* ==================================================================== */
     198             : /************************************************************************/
     199             : 
     200             : /************************************************************************/
     201             : /*                                Open()                                */
     202             : /************************************************************************/
     203             : 
     204             : VSIVirtualHandle *
     205           5 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
     206             :                                  const char *pszAccess, bool /* bSetError */,
     207             :                                  CSLConstList /* papszOptions */)
     208             : {
     209           5 :     if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
     210             :     {
     211           2 :         CPLError(CE_Failure, CPLE_NotSupported,
     212             :                  "Read or update mode not supported on /vsistdout");
     213           2 :         return nullptr;
     214             :     }
     215             : 
     216             : #ifdef _WIN32
     217             :     if (strchr(pszAccess, 'b') != nullptr)
     218             :         setmode(fileno(stdout), O_BINARY);
     219             : #endif
     220             : 
     221           3 :     return new VSIStdoutHandle;
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                                Stat()                                */
     226             : /************************************************************************/
     227             : 
     228          10 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
     229             :                                      VSIStatBufL *pStatBuf, int /* nFlags */)
     230             : 
     231             : {
     232          10 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     233             : 
     234          10 :     return -1;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /* ==================================================================== */
     239             : /*                   VSIStdoutRedirectFilesystemHandler                 */
     240             : /* ==================================================================== */
     241             : /************************************************************************/
     242             : 
     243             : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
     244             : {
     245             :   public:
     246             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     247             :                            bool bSetError,
     248             :                            CSLConstList /* papszOptions */) override;
     249             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     250             :              int nFlags) override;
     251             : 
     252           1 :     bool SupportsRead(const char * /* pszPath */) override
     253             :     {
     254           1 :         return false;
     255             :     }
     256             : };
     257             : 
     258             : /************************************************************************/
     259             : /* ==================================================================== */
     260             : /*                        VSIStdoutRedirectHandle                       */
     261             : /* ==================================================================== */
     262             : /************************************************************************/
     263             : 
     264             : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
     265             : {
     266             :     VSIVirtualHandle *m_poHandle = nullptr;
     267             :     bool m_bError = false;
     268             : 
     269             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
     270             : 
     271             :   public:
     272             :     explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
     273             :     ~VSIStdoutRedirectHandle() override;
     274             : 
     275             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     276             :     vsi_l_offset Tell() override;
     277             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     278             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     279             : 
     280           0 :     void ClearErr() override
     281             :     {
     282           0 :         m_bError = false;
     283           0 :     }
     284             : 
     285           0 :     int Error() override
     286             :     {
     287           0 :         return m_bError;
     288             :     }
     289             : 
     290           0 :     int Eof() override
     291             :     {
     292           0 :         return FALSE;
     293             :     }
     294             : 
     295             :     int Flush() override;
     296             :     int Close() override;
     297             : };
     298             : 
     299             : /************************************************************************/
     300             : /*                        VSIStdoutRedirectHandle()                    */
     301             : /************************************************************************/
     302             : 
     303           6 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
     304           6 :     : m_poHandle(poHandle)
     305             : {
     306           6 : }
     307             : 
     308             : /************************************************************************/
     309             : /*                        ~VSIStdoutRedirectHandle()                    */
     310             : /************************************************************************/
     311             : 
     312          12 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
     313             : {
     314           6 :     delete m_poHandle;
     315          12 : }
     316             : 
     317             : /************************************************************************/
     318             : /*                                Seek()                                */
     319             : /************************************************************************/
     320             : 
     321           0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
     322             : {
     323           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     324             :              "Seek() unsupported on /vsistdout_redirect");
     325           0 :     return -1;
     326             : }
     327             : 
     328             : /************************************************************************/
     329             : /*                                Tell()                                */
     330             : /************************************************************************/
     331             : 
     332         271 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
     333             : {
     334         271 :     return m_poHandle->Tell();
     335             : }
     336             : 
     337             : /************************************************************************/
     338             : /*                               Flush()                                */
     339             : /************************************************************************/
     340             : 
     341           1 : int VSIStdoutRedirectHandle::Flush()
     342             : 
     343             : {
     344           1 :     return m_poHandle->Flush();
     345             : }
     346             : 
     347             : /************************************************************************/
     348             : /*                                Read()                                */
     349             : /************************************************************************/
     350             : 
     351           0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t nSize,
     352             :                                      size_t nCount)
     353             : {
     354           0 :     if (nSize > 0 && nCount > 0)
     355             :     {
     356           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     357             :                  "Read() unsupported on /vsistdout");
     358           0 :         m_bError = true;
     359             :     }
     360           0 :     return 0;
     361             : }
     362             : 
     363             : /************************************************************************/
     364             : /*                               Write()                                */
     365             : /************************************************************************/
     366             : 
     367         567 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
     368             :                                       size_t nCount)
     369             : 
     370             : {
     371         567 :     return m_poHandle->Write(pBuffer, nSize, nCount);
     372             : }
     373             : 
     374             : /************************************************************************/
     375             : /*                               Close()                                */
     376             : /************************************************************************/
     377             : 
     378           6 : int VSIStdoutRedirectHandle::Close()
     379             : 
     380             : {
     381           6 :     return m_poHandle->Close();
     382             : }
     383             : 
     384             : /************************************************************************/
     385             : /* ==================================================================== */
     386             : /*                 VSIStdoutRedirectFilesystemHandler                   */
     387             : /* ==================================================================== */
     388             : /************************************************************************/
     389             : 
     390             : /************************************************************************/
     391             : /*                                Open()                                */
     392             : /************************************************************************/
     393             : 
     394          21 : VSIVirtualHandle *VSIStdoutRedirectFilesystemHandler::Open(
     395             :     const char *pszFilename, const char *pszAccess, bool /* bSetError */,
     396             :     CSLConstList /* papszOptions */)
     397             : 
     398             : {
     399          21 :     if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
     400             :     {
     401          15 :         CPLError(CE_Failure, CPLE_NotSupported,
     402             :                  "Read or update mode not supported on /vsistdout_redirect");
     403          15 :         return nullptr;
     404             :     }
     405             : 
     406           6 :     VSIVirtualHandle *poHandle = reinterpret_cast<VSIVirtualHandle *>(
     407             :         VSIFOpenL(pszFilename + strlen("/vsistdout_redirect/"), pszAccess));
     408           6 :     if (poHandle == nullptr)
     409           0 :         return nullptr;
     410             : 
     411           6 :     return new VSIStdoutRedirectHandle(poHandle);
     412             : }
     413             : 
     414             : /************************************************************************/
     415             : /*                                Stat()                                */
     416             : /************************************************************************/
     417             : 
     418          24 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
     419             :                                              VSIStatBufL *pStatBuf,
     420             :                                              int /* nFlags */)
     421             : {
     422          24 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     423             : 
     424          24 :     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        1304 : void VSIInstallStdoutHandler()
     453             : 
     454             : {
     455        1304 :     VSIFileManager::InstallHandler("/vsistdout/",
     456        1304 :                                    new VSIStdoutFilesystemHandler);
     457        1304 :     VSIFileManager::InstallHandler("/vsistdout_redirect/",
     458        1304 :                                    new VSIStdoutRedirectFilesystemHandler);
     459        1304 : }

Generated by: LCOV version 1.14