Branch data Line data Source code
1 : : // Copyright 2019-2026 David Robillard <d@drobilla.net> 2 : : // SPDX-License-Identifier: ISC 3 : : 4 : : #include "number_utils.h" 5 : : 6 : : #include "char_utils.h" 7 : : #include "int_math.h" 8 : : #include "result.h" 9 : : 10 : : #include <exess/exess.h> 11 : : 12 : : #include <assert.h> 13 : : #include <string.h> 14 : : 15 : : EXESS_NONBLOCKING size_t 16 : 261213 : read_sign(int* const sign, const char* const str) 17 : : { 18 [ + + ]: 261213 : if (*str == '-') { 19 : 54413 : *sign = -1; 20 : 54413 : return 1U; 21 : : } 22 : : 23 : 206800 : *sign = 1; 24 [ + + ]: 206800 : return (*str == '+') ? 1U : 0U; 25 : : } 26 : : 27 : : EXESS_NONBLOCKING ExessResult 28 : 28469 : read_two_digit_number(uint8_t* const out, 29 : : const uint8_t min_value, 30 : : const uint8_t max_value, 31 : : const char* const str) 32 : : { 33 : : // Read digits 34 : 28469 : size_t i = 0; 35 [ + + + + ]: 85383 : for (; i < 2 && is_digit(str[i]); ++i) { 36 : 56914 : *out = (uint8_t)((*out * 10) + (str[i] - '0')); 37 : : } 38 : : 39 : : // Ensure there are exactly the expected number of digits 40 [ + + ]: 28469 : if (i != 2) { 41 : 16 : return RESULT(EXESS_EXPECTED_DIGIT, i); 42 : : } 43 : : 44 : : // Ensure value is in range 45 [ + + + + ]: 28453 : if (*out < min_value || *out > max_value) { 46 : 19 : return RESULT(EXESS_OUT_OF_RANGE, i); 47 : : } 48 : : 49 : 28434 : return RESULT(EXESS_SUCCESS, i); 50 : : } 51 : : 52 : : EXESS_NONBLOCKING size_t 53 : 27308 : write_two_digit_number(const uint8_t value, 54 : : const size_t buf_size, 55 : : char* const buf, 56 : : const size_t i) 57 : : { 58 [ + + ]: 27308 : if (i + 1 < buf_size) { 59 [ + + ]: 26992 : buf[i] = (char)((value >= 10) ? ('0' + (value / 10)) : '0'); 60 : 26992 : buf[i + 1] = (char)('0' + (value % 10)); 61 : : } 62 : : 63 : 27308 : return 2; 64 : : } 65 : : 66 : : EXESS_NONBLOCKING size_t 67 : 8233 : write_zeros(const size_t n, 68 : : const size_t buf_size, 69 : : char* const buf, 70 : : const size_t i) 71 : : { 72 [ - + ]: 8233 : assert(i + n < buf_size); 73 : : (void)buf_size; 74 : 8233 : memset(buf + i, '0', n); 75 : 8233 : return n; 76 : : } 77 : : 78 : : EXESS_NONBLOCKING ExessResult 79 : 206337 : read_digits(uint64_t* const out, const char* const str) 80 : : { 81 : : // Ensure the first character is a digit 82 : 206337 : size_t i = 0; 83 [ + + ]: 206337 : if (!is_digit(str[i])) { 84 : 150 : return RESULT(EXESS_EXPECTED_DIGIT, i); 85 : : } 86 : : 87 : : // Skip leading zeros 88 [ + + ]: 206400 : while (str[i] == '0') { 89 : 213 : ++i; 90 : : } 91 : : 92 : : // Read digits 93 [ + + ]: 1328000 : for (; is_digit(str[i]); ++i) { 94 : 1121816 : const uint64_t next = (*out * 10U) + (uint64_t)(str[i] - '0'); 95 [ + + ]: 1121816 : if (next < *out) { 96 : 3 : *out = 0; 97 : 3 : return RESULT(EXESS_OUT_OF_RANGE, i); 98 : : } 99 : : 100 : 1121813 : *out = next; 101 : : } 102 : : 103 : 206184 : return RESULT(EXESS_SUCCESS, i); 104 : : } 105 : : 106 : : EXESS_NONBLOCKING ExessResult 107 : 216328 : write_digits(const uint64_t value, 108 : : const size_t buf_size, 109 : : char* const buf, 110 : : const size_t i) 111 : : { 112 : 216328 : const uint8_t n_digits = exess_num_digits(value); 113 [ + + ]: 216328 : if (i + n_digits >= buf_size) { 114 : 6247 : return RESULT(EXESS_NO_SPACE, n_digits); 115 : : } 116 : : 117 : : // Point s to the end 118 : 210081 : char* s = buf + i + n_digits - 1U; 119 : : 120 : : // Write integer part (right to left) 121 : 210081 : uint64_t remaining = value; 122 : : do { 123 : 1197896 : *s-- = (char)('0' + (remaining % 10)); 124 [ + + ]: 1197896 : } while ((remaining /= 10) > 0); 125 : : 126 : 210081 : return RESULT(EXESS_SUCCESS, n_digits); 127 : : }