LCOV - code coverage report
Current view: top level - src - timezone.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 59 59 100.0 %
Date: 2026-07-14 21:28:07 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 52 52 100.0 %

           Branch data     Line data    Source code
       1                 :            : // Copyright 2019-2026 David Robillard <d@drobilla.net>
       2                 :            : // SPDX-License-Identifier: ISC
       3                 :            : 
       4                 :            : #include "timezone.h"
       5                 :            : #include "number_utils.h"
       6                 :            : #include "result.h"
       7                 :            : #include "write_utils.h"
       8                 :            : 
       9                 :            : #include <exess/exess.h>
      10                 :            : 
      11                 :            : #include <stdint.h>
      12                 :            : #include <stdlib.h>
      13                 :            : 
      14                 :            : EXESS_NONBLOCKING ExessTimezone
      15                 :        130 : exess_timezone(const int8_t hours, const int8_t minutes)
      16                 :            : {
      17   [ +  +  +  + ]:        130 :   if (hours < -14 || hours > 14) {
      18                 :          2 :     return EXESS_TIMEZONE_LOCAL;
      19                 :            :   }
      20                 :            : 
      21   [ +  +  +  +  :        128 :   if (hours < 0 && minutes != 0 && minutes != -15 && minutes != -30 &&
          +  +  +  +  +  
                      + ]
      22                 :            :       minutes != -45) {
      23                 :          2 :     return EXESS_TIMEZONE_LOCAL;
      24                 :            :   }
      25                 :            : 
      26   [ +  +  +  +  :        126 :   if (hours > 0 && minutes != 0 && minutes != 15 && minutes != 30 &&
          +  +  +  +  +  
                      + ]
      27                 :            :       minutes != 45) {
      28                 :          2 :     return EXESS_TIMEZONE_LOCAL;
      29                 :            :   }
      30                 :            : 
      31                 :        124 :   return (int8_t)((4 * hours) + (minutes / 15));
      32                 :            : }
      33                 :            : 
      34                 :            : EXESS_NONBLOCKING ExessResult
      35                 :       6350 : read_optional_timezone(ExessTimezone* const out, const char* const str)
      36                 :            : {
      37                 :       6350 :   *out = EXESS_TIMEZONE_LOCAL;
      38                 :            : 
      39                 :            :   // Handle UTC special case
      40                 :       6350 :   size_t i = 0;
      41         [ +  + ]:       6350 :   if (str[i] == 'Z') {
      42                 :        155 :     *out = 0;
      43                 :        155 :     return RESULT(EXESS_SUCCESS, i + 1);
      44                 :            :   }
      45                 :            : 
      46                 :            :   // Read leading sign
      47                 :       6195 :   int sign = 1;
      48         [ +  + ]:       6195 :   if (str[i] == '-') {
      49                 :       2204 :     sign = -1;
      50         [ +  + ]:       3991 :   } else if (str[i] != '+') {
      51                 :       1691 :     return RESULT(EXESS_SUCCESS, i);
      52                 :            :   }
      53                 :            : 
      54                 :       4504 :   ++i;
      55                 :            : 
      56                 :            :   // Read hour digits
      57                 :       4504 :   uint8_t     hh = 0U;
      58                 :       4504 :   ExessResult r  = read_two_digit_number(&hh, 0U, 14U, str + i);
      59         [ +  + ]:       4504 :   if (r.status) {
      60                 :          8 :     return RESULT(r.status, i + r.count);
      61                 :            :   }
      62                 :            : 
      63                 :       4496 :   i += 2U;
      64                 :            : 
      65                 :            :   // Check colon
      66         [ +  + ]:       4496 :   if (str[i] != ':') {
      67                 :          1 :     return RESULT(EXESS_EXPECTED_COLON, i);
      68                 :            :   }
      69                 :            : 
      70                 :       4495 :   ++i;
      71                 :            : 
      72                 :            :   // Read minute digits
      73                 :       4495 :   uint8_t mm = 0U;
      74                 :       4495 :   r          = read_two_digit_number(&mm, 0U, 59U, str + i);
      75         [ +  + ]:       4495 :   if (r.status) {
      76                 :          4 :     return RESULT(r.status, i + r.count);
      77                 :            :   }
      78                 :            : 
      79                 :       4491 :   i += 2U;
      80                 :            : 
      81                 :            :   // Calculate signed hour and minute
      82                 :       4491 :   const int8_t hour   = (int8_t)(sign * hh);
      83                 :       4491 :   const int8_t minute = (int8_t)(sign * mm);
      84         [ +  + ]:       4491 :   if (minute % 15) {
      85                 :          1 :     return RESULT(EXESS_UNSUPPORTED, i);
      86                 :            :   }
      87                 :            : 
      88                 :            :   // Convert to quarter hours
      89                 :       4490 :   const int8_t quarters = (int8_t)((4 * hour) + (minute / 15));
      90   [ +  +  +  + ]:       4490 :   if (quarters < -56 || quarters > 56) {
      91                 :          2 :     return RESULT(EXESS_OUT_OF_RANGE, i);
      92                 :            :   }
      93                 :            : 
      94                 :       4488 :   *out = quarters;
      95                 :       4488 :   return RESULT(EXESS_SUCCESS, i);
      96                 :            : }
      97                 :            : 
      98                 :            : EXESS_NONBLOCKING ExessResult
      99                 :       6177 : write_timezone(const ExessTimezone value,
     100                 :            :                const size_t        buf_size,
     101                 :            :                char* const         buf,
     102                 :            :                size_t              o)
     103                 :            : {
     104         [ +  + ]:       6177 :   if (value == EXESS_TIMEZONE_LOCAL) {
     105                 :       1629 :     return RESULT(EXESS_SUCCESS, 0);
     106                 :            :   }
     107                 :            : 
     108   [ +  +  +  + ]:       4548 :   if (value < -56 || value > 56) {
     109                 :          4 :     return RESULT(EXESS_BAD_VALUE, 0);
     110                 :            :   }
     111                 :            : 
     112         [ +  + ]:       4544 :   if (value == 0) {
     113                 :         82 :     write_char('Z', buf_size, buf, o);
     114                 :         82 :     return RESULT(EXESS_SUCCESS, 1);
     115                 :            :   }
     116                 :            : 
     117                 :       4462 :   const uint8_t abs_quarters = (uint8_t)abs(value);
     118                 :       4462 :   const uint8_t abs_hour     = abs_quarters / 4;
     119                 :       4462 :   const uint8_t abs_minute   = (uint8_t)(15U * (abs_quarters % 4U));
     120                 :            : 
     121                 :       4462 :   size_t n = 0;
     122         [ +  + ]:       4462 :   n += write_char(value < 0 ? '-' : '+', buf_size, buf, o + n);
     123                 :       4462 :   n += write_two_digit_number(abs_hour, buf_size, buf, o + n);
     124                 :       4462 :   n += write_char(':', buf_size, buf, o + n);
     125                 :       4462 :   n += write_two_digit_number(abs_minute, buf_size, buf, o + n);
     126                 :            : 
     127                 :       4462 :   return RESULT(EXESS_SUCCESS, n);
     128                 :            : }

Generated by: LCOV version 1.16