LCOV - code coverage report
Current view: top level - u8stream/source/u8stream - universal_file_output_stream.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.57.0_covts Lines: 79 79 100.0 %
Date: 2024-04-07 11:14:42 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* File: universal_file_output_stream.c; Copyright and License: see below */
       2             : 
       3             : #include "u8stream/universal_file_output_stream.h"
       4             : #include "u8stream/universal_output_stream_if.h"
       5             : #include "u8_test_cond.h"
       6             : #include "u8/u8_fault_inject.h"
       7             : #include "u8/u8_trace.h"
       8             : #include "u8/u8_log.h"
       9             : #include <errno.h>
      10             : #include <string.h>
      11             : #include <stdbool.h>
      12             : #include <assert.h>
      13             : 
      14             : /* the vmt implementing the interface */
      15             : static const universal_output_stream_if_t universal_file_output_stream_private_if
      16             :     = {
      17             :         .write = (u8_error_t (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_file_output_stream_write,
      18             :         .flush = (u8_error_t (*)(universal_output_stream_impl_t*)) &universal_file_output_stream_flush
      19             :     };
      20             : 
      21          13 : void universal_file_output_stream_init ( universal_file_output_stream_t *this_ )
      22             : {
      23          13 :     U8_TRACE_BEGIN();
      24             : 
      25          13 :     (*this_).output = NULL;
      26          13 :     universal_output_stream_private_init( &((*this_).output_stream), &universal_file_output_stream_private_if, this_ );
      27             : 
      28          13 :     U8_TRACE_END();
      29          13 : }
      30             : 
      31          12 : u8_error_t universal_file_output_stream_destroy( universal_file_output_stream_t *this_ )
      32             : {
      33          12 :     U8_TRACE_BEGIN();
      34          12 :     u8_error_t err = U8_ERROR_NONE;
      35             : 
      36          12 :     if ( (*this_).output != NULL )
      37             :     {
      38           3 :         err = universal_file_output_stream_close( this_ );
      39             :     }
      40          12 :     (*this_).output = NULL;
      41          12 :     universal_output_stream_private_destroy( &((*this_).output_stream) );
      42             : 
      43          12 :     U8_TRACE_END_ERR(err);
      44          12 :     return err;
      45             : }
      46             : 
      47          14 : u8_error_t universal_file_output_stream_open ( universal_file_output_stream_t *this_, const char *path )
      48             : {
      49          14 :     U8_TRACE_BEGIN();
      50          14 :     assert( path != NULL );
      51          14 :     u8_error_t err = U8_ERROR_NONE;
      52             : 
      53          14 :     if ( (*this_).output != NULL )
      54             :     {
      55           1 :         U8_LOG_ERROR("cannot open a file that is already open.");
      56           1 :         err = U8_ERROR_WRONG_STATE;
      57           1 :         err |= universal_file_output_stream_close( this_ );
      58             :     }
      59          14 :     (*this_).output = fopen( path, "w" );
      60          14 :     if ( NULL == (*this_).output )
      61             :     {
      62             :         /* Note: This need not be an error, could be intentionally to avoid TOCTOU issues. */
      63           2 :         U8_LOG_EVENT_STR( "could not open file for writing:", strerror(errno) );
      64           2 :         err |= U8_ERROR_AT_FILE_WRITE;
      65             :     }
      66             : 
      67          14 :     U8_TRACE_END_ERR(err);
      68          14 :     return err;
      69             : }
      70             : 
      71          12 : u8_error_t universal_file_output_stream_write ( universal_file_output_stream_t *this_, const void *start, size_t length )
      72             : {
      73             :     /*U8_TRACE_BEGIN();*/
      74          12 :     u8_error_t err = U8_ERROR_NONE;
      75             : 
      76          12 :     if ( (*this_).output != NULL )
      77             :     {
      78          10 :         size_t written = 0;
      79          20 :         while (( written < length )&&( err == U8_ERROR_NONE ))
      80             :         {
      81          10 :             const size_t remaining = length - written;
      82             :             size_t out_count;
      83          10 :             out_count = fwrite( ((const char*)start)+written, 1, remaining, (*this_).output );
      84          10 :             assert( out_count != 0 );  /* this should not happen, but do not take this for granted */
      85          10 :             out_count = U8_FAULT_INJECT_COND( U8_TEST_COND_FWRITE, 0, out_count );
      86          10 :             if ( out_count == 0 )
      87             :             {
      88           1 :                 U8_LOG_ERROR_INT( "not all bytes could be written. missing:", remaining );
      89           1 :                 err = U8_ERROR_AT_FILE_WRITE;
      90             :             }
      91             :             else
      92             :             {
      93           9 :                 written += out_count;
      94             :             }
      95             :         }
      96             :     }
      97             :     else
      98             :     {
      99           2 :         U8_LOG_ERROR("cannot write to a file that is not open.");
     100           2 :         err = U8_ERROR_WRONG_STATE;
     101             :     }
     102             : 
     103             :     /*U8_TRACE_END_ERR(err);*/
     104          12 :     return err;
     105             : }
     106             : 
     107           3 : u8_error_t universal_file_output_stream_flush( universal_file_output_stream_t *this_ )
     108             : {
     109           3 :     U8_TRACE_BEGIN();
     110           3 :     u8_error_t err = U8_ERROR_NONE;
     111             : 
     112           3 :     if ( (*this_).output != NULL )
     113             :     {
     114           2 :         int flush_err = fflush( (*this_).output );
     115           2 :         assert( flush_err == 0 );  /* this should not happen, but do not take this for granted */
     116           2 :         flush_err = U8_FAULT_INJECT_COND( U8_TEST_COND_FFLUSH, EOF, flush_err );
     117           2 :         if ( 0 != flush_err )
     118             :         {
     119           1 :             U8_LOG_ERROR_INT("error at flushing file:",flush_err);
     120           1 :             err = U8_ERROR_AT_FILE_WRITE;
     121             :         }
     122             :     }
     123             :     else
     124             :     {
     125           1 :         U8_LOG_ERROR("cannot flush a file that is not open.");
     126           1 :         err = U8_ERROR_WRONG_STATE;
     127             :     }
     128             : 
     129           3 :     U8_TRACE_END_ERR(err);
     130           3 :     return err;
     131             : }
     132             : 
     133          14 : u8_error_t universal_file_output_stream_close( universal_file_output_stream_t *this_ )
     134             : {
     135          14 :     U8_TRACE_BEGIN();
     136          14 :     u8_error_t err = U8_ERROR_NONE;
     137             : 
     138          14 :     if ( (*this_).output != NULL )
     139             :     {
     140          12 :         int close_err = fclose( (*this_).output );
     141          12 :         assert( close_err == 0 );  /* this should not happen, but do not take this for granted */
     142          12 :         close_err = U8_FAULT_INJECT_COND( U8_TEST_COND_FCLOSE, EOF, close_err );
     143          12 :         if ( 0 != close_err )
     144             :         {
     145           1 :             U8_LOG_ERROR_INT("error at closing file:",close_err);
     146           1 :             err = U8_ERROR_AT_FILE_WRITE;
     147             :         }
     148          12 :         (*this_).output = NULL;
     149             :     }
     150             :     else
     151             :     {
     152           2 :         U8_LOG_ERROR("cannot close a file that is not open.");
     153           2 :         err = U8_ERROR_WRONG_STATE;
     154             :     }
     155             : 
     156          14 :     U8_TRACE_END_ERR(err);
     157          14 :     return err;
     158             : }
     159             : 
     160           1 : universal_output_stream_t* universal_file_output_stream_get_output_stream( universal_file_output_stream_t *this_ )
     161             : {
     162           1 :     U8_TRACE_BEGIN();
     163             : 
     164           1 :     universal_output_stream_t* result = &((*this_).output_stream);
     165             : 
     166           1 :     U8_TRACE_END();
     167           1 :     return result;
     168             : }
     169             : 
     170             : 
     171             : /*
     172             : Copyright 2020-2024 Andreas Warnke
     173             : 
     174             : Licensed under the Apache License, Version 2.0 (the "License");
     175             : you may not use this file except in compliance with the License.
     176             : You may obtain a copy of the License at
     177             : 
     178             :     http://www.apache.org/licenses/LICENSE-2.0
     179             : 
     180             : Unless required by applicable law or agreed to in writing, software
     181             : distributed under the License is distributed on an "AS IS" BASIS,
     182             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     183             : See the License for the specific language governing permissions and
     184             : limitations under the License.
     185             : */

Generated by: LCOV version 1.16