LCOV - code coverage report
Current view: top level - libs/rational/src - rational_provide.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 64 64
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 3 3
Branches: 100.0 % 36 36

             Branch data     Line data    Source code
       1                 :             : #include "rational.h"
       2                 :             : #include <stdio.h>
       3                 :             : 
       4                 :             : /**
       5                 :             :  * @brief Normalize one function Return value with global context
       6                 :             :  *
       7                 :             :  * @details The function normalizes @p status, normalizes global_return_status,
       8                 :             :  *          stores the normalized global status back, merges only GLOBAL bits
       9                 :             :  *          from global_return_status into @p status, and normalizes the final
      10                 :             :  *          result. Technical critical bits take precedence over SUCCESS.
      11                 :             :  *          NO takes precedence over YES when both binary answer flags are present
      12                 :             :  *
      13                 :             :  * @param status Status flags to normalize
      14                 :             :  * @return Normalized status flags
      15                 :             :  */
      16                 :     3010139 : Return rational_normalize_return(Return status)
      17                 :             : {
      18                 :             :         /* CRITICAL marks an internal or blocking problem.
      19                 :             :            Such a status cannot also be SUCCESS, even if SUCCESS was ORed in earlier */
      20         [ +  + ]:     3010139 :         if(CRITICAL & status)
      21                 :             :         {
      22                 :         497 :                 status &= ~SUCCESS;
      23                 :             :         }
      24                 :             : 
      25                 :             :         /* NO is the dominant binary answer.
      26                 :             :            If a check answered no, the final binary answer cannot also be yes.
      27                 :             :            If both binary answers are present, keep NO and drop YES */
      28         [ +  + ]:     3010139 :         if(NO & status)
      29                 :             :         {
      30                 :        8215 :                 status &= ~YES;
      31                 :             :         }
      32                 :             : 
      33                 :             :         /* Local status is not the only source of process state.
      34                 :             :            global_return_status carries context that may be set outside the current function.
      35                 :             :            Read it into a regular Return value, normalize that copy, store the cleaned copy back,
      36                 :             :            then merge only explicitly global bits into the function return */
      37                 :     3010139 :         Return global_status = atomic_load(&global_return_status);
      38                 :             : 
      39                 :             :         /* Global status follows the same contradiction rules as local status.
      40                 :             :            The normalized value is stored back so future returns see cleaned flags */
      41         [ +  + ]:     3010139 :         if(CRITICAL & global_status)
      42                 :             :         {
      43                 :           1 :                 global_status &= ~SUCCESS;
      44                 :             :         }
      45                 :             : 
      46         [ +  + ]:     3010139 :         if(NO & global_status)
      47                 :             :         {
      48                 :           2 :                 global_status &= ~YES;
      49                 :             :         }
      50                 :             : 
      51                 :             :         /* Keep the process-wide status normalized for the next function return */
      52                 :     3010139 :         atomic_store(&global_return_status,global_status);
      53                 :             : 
      54                 :             :         /* Only process-wide context bits may flow from global status to a return.
      55                 :             :            Binary answers and local-only flags must not leak between functions */
      56                 :     3010139 :         status |= (global_status & GLOBAL);
      57                 :             : 
      58                 :             :         /* Merging global context can introduce contradictions.
      59                 :             :            Normalize once more before returning the final function status */
      60         [ +  + ]:     3010139 :         if(CRITICAL & status)
      61                 :             :         {
      62                 :         497 :                 status &= ~SUCCESS;
      63                 :             :         }
      64                 :             : 
      65         [ +  + ]:     3010139 :         if(NO & status)
      66                 :             :         {
      67                 :        8215 :                 status &= ~YES;
      68                 :             :         }
      69                 :             : 
      70                 :     3010139 :         return(status);
      71                 :             : }
      72                 :             : 
      73                 :             : /**
      74                 :             :  * @brief Consume a yes/no Return answer and merge its technical status
      75                 :             :  *
      76                 :             :  * @details The returned status must contain a pending yes/no answer. The
      77                 :             :  *          function reads YES or NO, removes AWAITING and BOOLEAN from the
      78                 :             :  *          caller's local status, merges only the technical status bits, and
      79                 :             :  *          returns a regular C bool for direct use in conditions
      80                 :             :  *
      81                 :             :  * @param status Local caller status that accumulates technical return flags
      82                 :             :  * @param returned Return value produced by a check function
      83                 :             :  * @param func Name of the caller function for diagnostics
      84                 :             :  * @param line Source line of the ask() call for diagnostics
      85                 :             :  * @return true when @p returned contains a non-critical YES answer
      86                 :             :  */
      87                 :        4455 : bool rational_ask(
      88                 :             :         Return     *status,
      89                 :             :         Return     returned,
      90                 :             :         const char *func,
      91                 :             :         const int  line)
      92                 :             : {
      93                 :        4455 :         bool answer = false;
      94                 :             : 
      95         [ +  + ]:        4455 :         if(status == NULL)
      96                 :             :         {
      97                 :           1 :                 slog(ERROR,"%s:%d ask() received NULL status storage\n",func,line);
      98                 :             : 
      99                 :           1 :                 return(false);
     100                 :             :         }
     101                 :             : 
     102                 :        4454 :         returned = rational_normalize_return(returned);
     103                 :             : 
     104         [ +  + ]:        4454 :         if((AWAITING & returned) == 0)
     105                 :             :         {
     106                 :           1 :                 slog(ERROR,"%s:%d ask() expected a yes/no Return answer\n",func,line);
     107                 :           1 :                 *status = rational_normalize_return((*status & ~(AWAITING | BOOLEAN)) | FAILURE);
     108                 :             : 
     109                 :           1 :                 return(false);
     110                 :             :         }
     111                 :             : 
     112         [ +  + ]:        4453 :         if((BOOLEAN & returned) == 0)
     113                 :             :         {
     114                 :           1 :                 slog(ERROR,"%s:%d ask() received a pending Return answer without YES or NO\n",func,line);
     115                 :           1 :                 *status = rational_normalize_return((*status & ~(AWAITING | BOOLEAN)) | FAILURE);
     116                 :             : 
     117                 :           1 :                 return(false);
     118                 :             :         }
     119                 :             : 
     120   [ +  +  +  + ]:        4452 :         if((CRITICAL & returned) == 0 && (YES & returned))
     121                 :             :         {
     122                 :         345 :                 answer = true;
     123                 :             :         }
     124                 :             : 
     125                 :        8904 :         *status = rational_normalize_return(
     126                 :        4452 :                 (*status & ~(AWAITING | BOOLEAN))
     127                 :        4452 :                 | (returned & ~(AWAITING | BOOLEAN)));
     128                 :             : 
     129                 :        4452 :         return(answer);
     130                 :             : }
     131                 :             : 
     132                 :             : /// Converts Return status flags to a string
     133                 :         769 : const char *show_status(const Return status)
     134                 :             : {
     135                 :         769 :         const char *status_label = "UNKNOWN";
     136                 :             : 
     137                 :             :         /* Keep behavior explicit for the zero status value. */
     138         [ +  + ]:         769 :         if(status == OK)
     139                 :             :         {
     140                 :           1 :                 status_label = "OK";
     141                 :             :         } else {
     142                 :             :                 static char buffer[MAX_CHARACTERS];
     143                 :         768 :                 buffer[0] = '\0';
     144                 :             : 
     145                 :             :                 static const struct {
     146                 :             :                         Return flag;
     147                 :             :                         const char *name;
     148                 :             :                 } mapping[] = {
     149                 :             :                         {FAILURE,"FAILURE"},
     150                 :             :                         {SUCCESS,"SUCCESS"},
     151                 :             :                         {HALTED,"HALTED"},
     152                 :             :                         {WARNING,"WARNING"},
     153                 :             :                         {DONOTHING,"DONOTHING"},
     154                 :             :                         {INFO,"INFO"},
     155                 :             :                         {YES,"YES"},
     156                 :             :                         {NO,"NO"},
     157                 :             :                         {AWAITING,"AWAITING"},
     158                 :             :                         {0,NULL}
     159                 :             :                 };
     160                 :             : 
     161                 :         768 :                 size_t used = 0U;
     162                 :         768 :                 bool first = true;
     163                 :         768 :                 unsigned int remaining = (unsigned int)status;
     164                 :             : 
     165         [ +  + ]:        7662 :                 for(size_t i = 0U; mapping[i].name != NULL; i++)
     166                 :             :                 {
     167                 :        6896 :                         const unsigned int flag = (unsigned int)mapping[i].flag;
     168                 :             : 
     169         [ +  + ]:        6896 :                         if((remaining & flag) == 0U)
     170                 :             :                         {
     171                 :        6045 :                                 continue;
     172                 :             :                         }
     173                 :             : 
     174                 :         851 :                         const int written = snprintf(
     175                 :             :                                 buffer + used,
     176                 :             :                                 MAX_CHARACTERS - used,
     177                 :             :                                 "%s%s",
     178                 :             :                                 first ? "" : "|",
     179         [ +  + ]:         851 :                                 mapping[i].name);
     180                 :             : 
     181         [ +  + ]:         851 :                         if(written < 0)
     182                 :             :                         {
     183                 :           1 :                                 break;
     184                 :             :                         }
     185                 :             : 
     186         [ +  + ]:         850 :                         if((size_t)written >= (MAX_CHARACTERS - used))
     187                 :             :                         {
     188                 :           1 :                                 buffer[MAX_CHARACTERS - 1U] = '\0';
     189                 :           1 :                                 status_label = buffer;
     190                 :           1 :                                 first = false;
     191                 :           1 :                                 break;
     192                 :             :                         }
     193                 :             : 
     194                 :         849 :                         used += (size_t)written;
     195                 :         849 :                         first = false;
     196                 :         849 :                         remaining &= ~flag;
     197                 :             :                 }
     198                 :             : 
     199         [ +  + ]:         768 :                 if(first == false)
     200                 :             :                 {
     201                 :         766 :                         status_label = buffer;
     202                 :             :                 }
     203                 :             :         }
     204                 :         769 :         return(status_label);
     205                 :             : }
        

Generated by: LCOV version 2.0-1