core/text/cstring_fit.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * @file cstring_fit.h | ||
| 3 | * @brief Comparing a string against a fixed buffer it is about to be copied into. | ||
| 4 | * | ||
| 5 | * @ingroup lib_core | ||
| 6 | */ | ||
| 7 | #pragma once | ||
| 8 | #include <stdbool.h> | ||
| 9 | #include <stddef.h> | ||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | /** | ||
| 13 | * @addtogroup lib_core | ||
| 14 | * @{ | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** | ||
| 18 | * @brief Copy a string into a fixed buffer, keeping only what fits and always terminating it. | ||
| 19 | * | ||
| 20 | * The cut counts bytes, so a character that takes more than one byte can be split at it. The fonts | ||
| 21 | * carry only the characters a face shows, which a character past ASCII is not, so it draws as a box | ||
| 22 | * whether it is cut or whole, and walking back to a character boundary would cost bytes for nothing. | ||
| 23 | * | ||
| 24 | * @param dst The buffer to write into. | ||
| 25 | * @param src The string to copy, or NULL to empty the buffer. | ||
| 26 | * @param size The buffer's size, terminator included. | ||
| 27 | */ | ||
| 28 | 21 | static inline void cstring_fit(char *dst, const char *src, size_t size) | |
| 29 | { | ||
| 30 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 20 times.
|
21 | if (size == 0) |
| 31 | { | ||
| 32 | 1 | return; | |
| 33 | } | ||
| 34 | |||
| 35 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 19 times.
|
20 | if (!src) |
| 36 | { | ||
| 37 | 1 | dst[0] = '\0'; | |
| 38 | 1 | return; | |
| 39 | } | ||
| 40 | |||
| 41 | 19 | strncpy(dst, src, size - 1); | |
| 42 | 19 | dst[size - 1] = '\0'; | |
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * @brief Whether copying @p value into a buffer would leave it reading exactly as it does now. | ||
| 47 | * | ||
| 48 | * The copy keeps only what fits, so the incoming string is measured the same way. Comparing it in | ||
| 49 | * full instead would call a value longer than the buffer a change every single time, which for a | ||
| 50 | * settings field means re-reacting to a setting nobody touched. | ||
| 51 | * | ||
| 52 | * @param current What the buffer holds now. | ||
| 53 | * @param value The string that would be copied in. Must not be NULL. | ||
| 54 | * @param size The buffer's size, terminator included. | ||
| 55 | * @return True when the copy would leave the buffer unchanged. | ||
| 56 | */ | ||
| 57 | 8 | static inline bool cstring_fit_same(const char *current, const char *value, size_t size) | |
| 58 | { | ||
| 59 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
|
8 | if (size == 0) |
| 60 | { | ||
| 61 | 1 | return true; // nowhere to put it, so nothing about the buffer can move | |
| 62 | } | ||
| 63 | |||
| 64 | 7 | size_t room = size - 1; | |
| 65 | 7 | size_t incoming = strlen(value); | |
| 66 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (incoming > room) |
| 67 | { | ||
| 68 | 2 | incoming = room; | |
| 69 | } | ||
| 70 | |||
| 71 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
|
7 | return strlen(current) == incoming && strncmp(current, value, incoming) == 0; |
| 72 | } | ||
| 73 | |||
| 74 | /** @} */ | ||
| 75 |