LCOV - code coverage report
Current view: top level - port - cpl_vsil_stdout.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 54 82 65.9 %
Date: 2024-04-28 21:03:45 Functions: 21 29 72.4 %

          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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "cpl_vsi.h"
      31             : 
      32             : #include <cstddef>
      33             : #include <cstdio>
      34             : #include <cstring>
      35             : #if HAVE_FCNTL_H
      36             : #include <fcntl.h>
      37             : #endif
      38             : 
      39             : #include "cpl_error.h"
      40             : #include "cpl_vsi_virtual.h"
      41             : 
      42             : #ifdef _WIN32
      43             : #include <io.h>
      44             : #include <fcntl.h>
      45             : #endif
      46             : 
      47             : static VSIWriteFunction pWriteFunction = fwrite;
      48             : static FILE *pWriteStream = stdout;
      49             : 
      50             : /************************************************************************/
      51             : /*                        VSIStdoutSetRedirection()                     */
      52             : /************************************************************************/
      53             : 
      54             : /** Set an alternative write function and output file handle instead of
      55             :  *  fwrite() / stdout.
      56             :  *
      57             :  * @param pFct Function with same signature as fwrite()
      58             :  * @param stream File handle on which to output. Passed to pFct.
      59             :  *
      60             :  * @since GDAL 2.0
      61             :  */
      62           0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
      63             : {
      64           0 :     pWriteFunction = pFct;
      65           0 :     pWriteStream = stream;
      66           0 : }
      67             : 
      68             : //! @cond Doxygen_Suppress
      69             : 
      70             : /************************************************************************/
      71             : /* ==================================================================== */
      72             : /*                       VSIStdoutFilesystemHandler                     */
      73             : /* ==================================================================== */
      74             : /************************************************************************/
      75             : 
      76             : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
      77             : {
      78             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
      79             : 
      80             :   public:
      81        1225 :     VSIStdoutFilesystemHandler() = default;
      82             : 
      83             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
      84             :                            bool bSetError,
      85             :                            CSLConstList /* papszOptions */) override;
      86             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
      87             :              int nFlags) override;
      88             : 
      89           0 :     bool SupportsRead(const char * /* pszPath */) override
      90             :     {
      91           0 :         return false;
      92             :     }
      93             : };
      94             : 
      95             : /************************************************************************/
      96             : /* ==================================================================== */
      97             : /*                        VSIStdoutHandle                               */
      98             : /* ==================================================================== */
      99             : /************************************************************************/
     100             : 
     101             : class VSIStdoutHandle final : public VSIVirtualHandle
     102             : {
     103             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
     104             : 
     105             :     vsi_l_offset m_nOffset = 0;
     106             : 
     107             :   public:
     108           3 :     VSIStdoutHandle() = default;
     109           6 :     ~VSIStdoutHandle() override = default;
     110             : 
     111             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     112             :     vsi_l_offset Tell() override;
     113             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     114             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     115             :     int Eof() override;
     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 */,
     162             :                              size_t /* nCount */)
     163             : {
     164           0 :     CPLError(CE_Failure, CPLE_NotSupported, "Read() unsupported on /vsistdout");
     165           0 :     return 0;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                               Write()                                */
     170             : /************************************************************************/
     171             : 
     172          20 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
     173             : 
     174             : {
     175          20 :     size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
     176          20 :     m_nOffset += nSize * nRet;
     177          20 :     return nRet;
     178             : }
     179             : 
     180             : /************************************************************************/
     181             : /*                                Eof()                                 */
     182             : /************************************************************************/
     183             : 
     184           0 : int VSIStdoutHandle::Eof()
     185             : 
     186             : {
     187           0 :     return 0;
     188             : }
     189             : 
     190             : /************************************************************************/
     191             : /*                               Close()                                */
     192             : /************************************************************************/
     193             : 
     194           3 : int VSIStdoutHandle::Close()
     195             : 
     196             : {
     197           3 :     return Flush();
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /* ==================================================================== */
     202             : /*                       VSIStdoutFilesystemHandler                     */
     203             : /* ==================================================================== */
     204             : /************************************************************************/
     205             : 
     206             : /************************************************************************/
     207             : /*                                Open()                                */
     208             : /************************************************************************/
     209             : 
     210             : VSIVirtualHandle *
     211           5 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
     212             :                                  const char *pszAccess, bool /* bSetError */,
     213             :                                  CSLConstList /* papszOptions */)
     214             : {
     215           5 :     if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
     216             :     {
     217           2 :         CPLError(CE_Failure, CPLE_NotSupported,
     218             :                  "Read or update mode not supported on /vsistdout");
     219           2 :         return nullptr;
     220             :     }
     221             : 
     222             : #ifdef _WIN32
     223             :     if (strchr(pszAccess, 'b') != nullptr)
     224             :         setmode(fileno(stdout), O_BINARY);
     225             : #endif
     226             : 
     227           3 :     return new VSIStdoutHandle;
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                                Stat()                                */
     232             : /************************************************************************/
     233             : 
     234          10 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
     235             :                                      VSIStatBufL *pStatBuf, int /* nFlags */)
     236             : 
     237             : {
     238          10 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     239             : 
     240          10 :     return -1;
     241             : }
     242             : 
     243             : /************************************************************************/
     244             : /* ==================================================================== */
     245             : /*                   VSIStdoutRedirectFilesystemHandler                 */
     246             : /* ==================================================================== */
     247             : /************************************************************************/
     248             : 
     249             : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
     250             : {
     251             :   public:
     252             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     253             :                            bool bSetError,
     254             :                            CSLConstList /* papszOptions */) override;
     255             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     256             :              int nFlags) override;
     257             : 
     258           1 :     bool SupportsRead(const char * /* pszPath */) override
     259             :     {
     260           1 :         return false;
     261             :     }
     262             : };
     263             : 
     264             : /************************************************************************/
     265             : /* ==================================================================== */
     266             : /*                        VSIStdoutRedirectHandle                       */
     267             : /* ==================================================================== */
     268             : /************************************************************************/
     269             : 
     270             : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
     271             : {
     272             :     VSIVirtualHandle *m_poHandle = nullptr;
     273             : 
     274             :     CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
     275             : 
     276             :   public:
     277             :     explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
     278             :     ~VSIStdoutRedirectHandle() override;
     279             : 
     280             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     281             :     vsi_l_offset Tell() override;
     282             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     283             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     284             :     int Eof() override;
     285             :     int Flush() override;
     286             :     int Close() override;
     287             : };
     288             : 
     289             : /************************************************************************/
     290             : /*                        VSIStdoutRedirectHandle()                    */
     291             : /************************************************************************/
     292             : 
     293           6 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
     294           6 :     : m_poHandle(poHandle)
     295             : {
     296           6 : }
     297             : 
     298             : /************************************************************************/
     299             : /*                        ~VSIStdoutRedirectHandle()                    */
     300             : /************************************************************************/
     301             : 
     302          12 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
     303             : {
     304           6 :     delete m_poHandle;
     305          12 : }
     306             : 
     307             : /************************************************************************/
     308             : /*                                Seek()                                */
     309             : /************************************************************************/
     310             : 
     311           0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
     312             : {
     313           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     314             :              "Seek() unsupported on /vsistdout_redirect");
     315           0 :     return -1;
     316             : }
     317             : 
     318             : /************************************************************************/
     319             : /*                                Tell()                                */
     320             : /************************************************************************/
     321             : 
     322         271 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
     323             : {
     324         271 :     return m_poHandle->Tell();
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                               Flush()                                */
     329             : /************************************************************************/
     330             : 
     331           1 : int VSIStdoutRedirectHandle::Flush()
     332             : 
     333             : {
     334           1 :     return m_poHandle->Flush();
     335             : }
     336             : 
     337             : /************************************************************************/
     338             : /*                                Read()                                */
     339             : /************************************************************************/
     340             : 
     341           0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t /* nSize */,
     342             :                                      size_t /* nCount */)
     343             : {
     344           0 :     CPLError(CE_Failure, CPLE_NotSupported,
     345             :              "Read() unsupported on /vsistdout_redirect");
     346           0 :     return 0;
     347             : }
     348             : 
     349             : /************************************************************************/
     350             : /*                               Write()                                */
     351             : /************************************************************************/
     352             : 
     353         567 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
     354             :                                       size_t nCount)
     355             : 
     356             : {
     357         567 :     return m_poHandle->Write(pBuffer, nSize, nCount);
     358             : }
     359             : 
     360             : /************************************************************************/
     361             : /*                                Eof()                                 */
     362             : /************************************************************************/
     363             : 
     364           0 : int VSIStdoutRedirectHandle::Eof()
     365             : 
     366             : {
     367           0 :     return m_poHandle->Eof();
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                               Close()                                */
     372             : /************************************************************************/
     373             : 
     374           6 : int VSIStdoutRedirectHandle::Close()
     375             : 
     376             : {
     377           6 :     return m_poHandle->Close();
     378             : }
     379             : 
     380             : /************************************************************************/
     381             : /* ==================================================================== */
     382             : /*                 VSIStdoutRedirectFilesystemHandler                   */
     383             : /* ==================================================================== */
     384             : /************************************************************************/
     385             : 
     386             : /************************************************************************/
     387             : /*                                Open()                                */
     388             : /************************************************************************/
     389             : 
     390          21 : VSIVirtualHandle *VSIStdoutRedirectFilesystemHandler::Open(
     391             :     const char *pszFilename, const char *pszAccess, bool /* bSetError */,
     392             :     CSLConstList /* papszOptions */)
     393             : 
     394             : {
     395          21 :     if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
     396             :     {
     397          15 :         CPLError(CE_Failure, CPLE_NotSupported,
     398             :                  "Read or update mode not supported on /vsistdout_redirect");
     399          15 :         return nullptr;
     400             :     }
     401             : 
     402           6 :     VSIVirtualHandle *poHandle = reinterpret_cast<VSIVirtualHandle *>(
     403             :         VSIFOpenL(pszFilename + strlen("/vsistdout_redirect/"), pszAccess));
     404           6 :     if (poHandle == nullptr)
     405           0 :         return nullptr;
     406             : 
     407           6 :     return new VSIStdoutRedirectHandle(poHandle);
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                                Stat()                                */
     412             : /************************************************************************/
     413             : 
     414          24 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
     415             :                                              VSIStatBufL *pStatBuf,
     416             :                                              int /* nFlags */)
     417             : {
     418          24 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     419             : 
     420          24 :     return -1;
     421             : }
     422             : 
     423             : //! @endcond
     424             : 
     425             : /************************************************************************/
     426             : /*                       VSIInstallStdoutHandler()                      */
     427             : /************************************************************************/
     428             : 
     429             : /*!
     430             :  \brief Install /vsistdout/ file system handler
     431             : 
     432             :  A special file handler is installed that allows writing to the standard
     433             :  output stream.
     434             : 
     435             :  The file operations available are of course limited to Write().
     436             : 
     437             :  A variation of this file system exists as the /vsistdout_redirect/ file
     438             :  system handler, where the output function can be defined with
     439             :  VSIStdoutSetRedirection().
     440             : 
     441             :  \verbatim embed:rst
     442             :  See :ref:`/vsistdout/ documentation <vsistdout>`
     443             :  \endverbatim
     444             : 
     445             :  @since GDAL 1.8.0
     446             :  */
     447             : 
     448        1225 : void VSIInstallStdoutHandler()
     449             : 
     450             : {
     451        1225 :     VSIFileManager::InstallHandler("/vsistdout/",
     452        1225 :                                    new VSIStdoutFilesystemHandler);
     453        1225 :     VSIFileManager::InstallHandler("/vsistdout_redirect/",
     454        1225 :                                    new VSIStdoutRedirectFilesystemHandler);
     455        1225 : }

Generated by: LCOV version 1.14