LCOV - code coverage report
Current view: top level - src - timezone.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 61 61 100.0 %
Date: 2026-08-20 23:47:58 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 54 54 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                 :       6555 : read_optional_timezone(ExessTimezone* const out,
      36                 :            :                        const char* const    str,
      37                 :            :                        ExessResult          r)
      38                 :            : {
      39                 :       6555 :   *out = EXESS_TIMEZONE_LOCAL;
      40                 :            : 
      41         [ +  + ]:       6555 :   if (r.status) {
      42                 :         56 :     return r;
      43                 :            :   }
      44                 :            : 
      45                 :            :   // Handle UTC special case
      46                 :       6499 :   size_t i = r.count;
      47         [ +  + ]:       6499 :   if (str[i] == 'Z') {
      48                 :        188 :     *out = 0;
      49                 :        188 :     return RESULT(EXESS_SUCCESS, i + 1);
      50                 :            :   }
      51                 :            : 
      52                 :            :   // Read leading sign
      53                 :       6311 :   int sign = 1;
      54         [ +  + ]:       6311 :   if (str[i] == '-') {
      55                 :       2212 :     sign = -1;
      56         [ +  + ]:       4099 :   } else if (str[i] != '+') {
      57                 :       1761 :     return RESULT(EXESS_SUCCESS, i);
      58                 :            :   }
      59                 :            : 
      60                 :       4550 :   ++i;
      61                 :            : 
      62                 :            :   // Read hour digits
      63                 :       4550 :   uint8_t hh = 0U;
      64                 :       4550 :   r          = read_two_digit_number(&hh, 0U, 14U, str + i);
      65         [ +  + ]:       4550 :   if (r.status) {
      66                 :          8 :     return RESULT(r.status, i + r.count);
      67                 :            :   }
      68                 :            : 
      69                 :       4542 :   i += 2U;
      70                 :            : 
      71                 :            :   // Check colon
      72         [ +  + ]:       4542 :   if (str[i] != ':') {
      73                 :          1 :     return RESULT(EXESS_EXPECTED_COLON, i);
      74                 :            :   }
      75                 :            : 
      76                 :       4541 :   ++i;
      77                 :            : 
      78                 :            :   // Read minute digits
      79                 :       4541 :   uint8_t mm = 0U;
      80                 :       4541 :   r          = read_two_digit_number(&mm, 0U, 59U, str + i);
      81         [ +  + ]:       4541 :   if (r.status) {
      82                 :          4 :     return RESULT(r.status, i + r.count);
      83                 :            :   }
      84                 :            : 
      85                 :       4537 :   i += 2U;
      86                 :            : 
      87                 :            :   // Calculate signed hour and minute
      88                 :       4537 :   const int8_t hour   = (int8_t)(sign * hh);
      89                 :       4537 :   const int8_t minute = (int8_t)(sign * mm);
      90         [ +  + ]:       4537 :   if (minute % 15) {
      91                 :          1 :     return RESULT(EXESS_UNSUPPORTED, i);
      92                 :            :   }
      93                 :            : 
      94                 :            :   // Convert to quarter hours
      95                 :       4536 :   const int8_t quarters = (int8_t)((4 * hour) + (minute / 15));
      96   [ +  +  +  + ]:       4536 :   if (quarters < -56 || quarters > 56) {
      97                 :          2 :     return RESULT(EXESS_OUT_OF_RANGE, i);
      98                 :            :   }
      99                 :            : 
     100                 :       4534 :   *out = quarters;
     101                 :       4534 :   return RESULT(EXESS_SUCCESS, i);
     102                 :            : }
     103                 :            : 
     104                 :            : EXESS_NONBLOCKING ExessResult
     105                 :       6284 : write_timezone(const ExessTimezone value,
     106                 :            :                const size_t        buf_size,
     107                 :            :                char* const         buf,
     108                 :            :                const ExessResult   r)
     109                 :            : {
     110                 :       6284 :   size_t o = r.count;
     111                 :            : 
     112         [ +  + ]:       6284 :   if (value == EXESS_TIMEZONE_LOCAL) {
     113                 :       1645 :     return end_write(r.status, buf_size, buf, o);
     114                 :            :   }
     115                 :            : 
     116   [ +  +  +  + ]:       4639 :   if (value < -56 || value > 56) {
     117                 :          4 :     return end_write(EXESS_BAD_VALUE, buf_size, buf, o);
     118                 :            :   }
     119                 :            : 
     120         [ +  + ]:       4635 :   if (value == 0) {
     121                 :        131 :     write_char('Z', buf_size, buf, o);
     122                 :        131 :     return end_write(r.status, buf_size, buf, o + 1U);
     123                 :            :   }
     124                 :            : 
     125                 :       4504 :   const uint8_t abs_quarters = (uint8_t)abs(value);
     126                 :       4504 :   const uint8_t abs_hour     = abs_quarters / 4;
     127                 :       4504 :   const uint8_t abs_minute   = (uint8_t)(15U * (abs_quarters % 4U));
     128                 :            : 
     129         [ +  + ]:       4504 :   o += write_char(value < 0 ? '-' : '+', buf_size, buf, o);
     130                 :       4504 :   o += write_two_digit_number(abs_hour, buf_size, buf, o);
     131                 :       4504 :   o += write_char(':', buf_size, buf, o);
     132                 :       4504 :   o += write_two_digit_number(abs_minute, buf_size, buf, o);
     133                 :            : 
     134                 :       4504 :   return end_write(EXESS_SUCCESS, buf_size, buf, o);
     135                 :            : }

Generated by: LCOV version 1.16