LCOV - code coverage report
Current view: top level - u8stream/source/u8stream - universal_file_output_stream.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.67.0_covts Lines: 100.0 % 79 79
Test Date: 2025-11-06 17:22:08 Functions: 100.0 % 7 7

            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           16 : void universal_file_output_stream_init ( universal_file_output_stream_t *this_ )
      22              : {
      23           16 :     U8_TRACE_BEGIN();
      24              : 
      25           16 :     (*this_).output = NULL;
      26           16 :     universal_output_stream_private_init( &((*this_).output_stream), &universal_file_output_stream_private_if, this_ );
      27              : 
      28           16 :     U8_TRACE_END();
      29           16 : }
      30              : 
      31           15 : u8_error_t universal_file_output_stream_destroy( universal_file_output_stream_t *this_ )
      32              : {
      33           15 :     U8_TRACE_BEGIN();
      34           15 :     u8_error_t err = U8_ERROR_NONE;
      35              : 
      36           15 :     if ( (*this_).output != NULL )
      37              :     {
      38            4 :         err = universal_file_output_stream_close( this_ );
      39              :     }
      40           15 :     (*this_).output = NULL;
      41           15 :     universal_output_stream_private_destroy( &((*this_).output_stream) );
      42              : 
      43           15 :     U8_TRACE_END_ERR(err);
      44           15 :     return err;
      45              : }
      46              : 
      47           17 : u8_error_t universal_file_output_stream_open ( universal_file_output_stream_t *this_, const char *path )
      48              : {
      49           17 :     U8_TRACE_BEGIN();
      50           17 :     assert( path != NULL );
      51           17 :     u8_error_t err = U8_ERROR_NONE;
      52              : 
      53           17 :     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           17 :     (*this_).output = fopen( path, "w" );
      60           17 :     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           17 :     U8_TRACE_END_ERR(err);
      68           17 :     return err;
      69              : }
      70              : 
      71          113 : 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          113 :     u8_error_t err = U8_ERROR_NONE;
      75              : 
      76          113 :     if ( (*this_).output != NULL )
      77              :     {
      78          111 :         size_t written = 0;
      79          222 :         while (( written < length )&&( err == U8_ERROR_NONE ))
      80              :         {
      81          111 :             const size_t remaining = length - written;
      82              :             size_t out_count;
      83          111 :             out_count = fwrite( ((const char*)start)+written, 1, remaining, (*this_).output );
      84          111 :             assert( out_count != 0 );  /* this should not happen, but do not take this for granted */
      85          111 :             U8_FAULT_INJECT_COND_SET( U8_TEST_COND_FWRITE, out_count, 0 );
      86          111 :             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          110 :                 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          113 :     return err;
     105              : }
     106              : 
     107           13 : u8_error_t universal_file_output_stream_flush( universal_file_output_stream_t *this_ )
     108              : {
     109           13 :     U8_TRACE_BEGIN();
     110           13 :     u8_error_t err = U8_ERROR_NONE;
     111              : 
     112           13 :     if ( (*this_).output != NULL )
     113              :     {
     114           12 :         int flush_err = fflush( (*this_).output );
     115           12 :         assert( flush_err == 0 );  /* this should not happen, but do not take this for granted */
     116           12 :         U8_FAULT_INJECT_COND_SET( U8_TEST_COND_FFLUSH, flush_err, EOF );
     117           12 :         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           13 :     U8_TRACE_END_ERR(err);
     130           13 :     return err;
     131              : }
     132              : 
     133           17 : u8_error_t universal_file_output_stream_close( universal_file_output_stream_t *this_ )
     134              : {
     135           17 :     U8_TRACE_BEGIN();
     136           17 :     u8_error_t err = U8_ERROR_NONE;
     137              : 
     138           17 :     if ( (*this_).output != NULL )
     139              :     {
     140           15 :         int close_err = fclose( (*this_).output );
     141           15 :         assert( close_err == 0 );  /* this should not happen, but do not take this for granted */
     142           15 :         U8_FAULT_INJECT_COND_SET( U8_TEST_COND_FCLOSE, close_err, EOF );
     143           15 :         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           15 :         (*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           17 :     U8_TRACE_END_ERR(err);
     157           17 :     return err;
     158              : }
     159              : 
     160            3 : universal_output_stream_t* universal_file_output_stream_get_output_stream( universal_file_output_stream_t *this_ )
     161              : {
     162            3 :     U8_TRACE_BEGIN();
     163              : 
     164            3 :     universal_output_stream_t* result = &((*this_).output_stream);
     165              : 
     166            3 :     U8_TRACE_END();
     167            3 :     return result;
     168              : }
     169              : 
     170              : 
     171              : /*
     172              : Copyright 2020-2025 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 2.0-1