LCOV - code coverage report
Current view: top level - src - pl_string.h (source / functions) Hit Total Coverage
Test: Code coverage Lines: 39 39 100.0 %
Date: 2025-03-29 09:04:10 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 44 62 71.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of libplacebo.
       3                 :            :  *
       4                 :            :  * libplacebo is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Lesser General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2.1 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * libplacebo is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 :            :  * GNU Lesser General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Lesser General Public
      15                 :            :  * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
      16                 :            :  */
      17                 :            : 
      18                 :            : #pragma once
      19                 :            : 
      20                 :            : #include "common.h"
      21                 :            : 
      22                 :            : PL_API_BEGIN
      23                 :            : 
      24                 :            : typedef struct pl_str {
      25                 :            :     uint8_t *buf;
      26                 :            :     size_t len;
      27                 :            : } pl_str;
      28                 :            : 
      29                 :            : // For formatting with "%.*s"
      30                 :            : #define PL_STR_FMT(str) (int)((str).len), ((str).buf ? (char *)((str).buf) : "")
      31                 :            : 
      32                 :            : static inline pl_str pl_str0(const char *str)
      33                 :            : {
      34                 :         14 :     return (pl_str) {
      35                 :            :         .buf = (uint8_t *) str,
      36   [ +  -  +  -  :     121567 :         .len = str ? strlen(str) : 0,
          +  -  +  -  +  
                      - ]
      37                 :            :     };
      38                 :            : }
      39                 :            : 
      40                 :            : // Macro version of pl_str0, for constants
      41                 :            : #define PL_STR0(str) ((pl_str) { (uint8_t *) (str), (str) ? strlen(str) : 0 })
      42                 :            : 
      43                 :            : static inline pl_str pl_strdup(void *alloc, pl_str str)
      44                 :            : {
      45                 :            :     return (pl_str) {
      46         [ +  - ]:         10 :         .buf = (uint8_t *) (str.len ? pl_memdup(alloc, str.buf, str.len) : NULL),
      47                 :            :         .len = str.len,
      48                 :            :     };
      49                 :            : }
      50                 :            : 
      51                 :            : // Always returns a valid string
      52                 :            : static inline char *pl_strdup0(void *alloc, pl_str str)
      53                 :            : {
      54   [ +  -  +  -  :        101 :     return pl_strndup0(alloc, str.len ? (char *) str.buf : "", str.len);
          +  -  +  -  +  
                      - ]
      55                 :            : }
      56                 :            : 
      57                 :            : // Adds a trailing \0 for convenience, even if `append` is an empty string
      58                 :            : void pl_str_append(void *alloc, pl_str *str, pl_str append);
      59                 :            : 
      60                 :            : // Like `pl_str_append` but for raw memory, omits trailing \0
      61                 :            : void pl_str_append_raw(void *alloc, pl_str *str, const void *ptr, size_t size);
      62                 :            : 
      63                 :            : // Locale-sensitive string functions
      64                 :            : char *pl_asprintf(void *parent, const char *fmt, ...)
      65                 :            :     PL_PRINTF(2, 3);
      66                 :            : char *pl_vasprintf(void *parent, const char *fmt, va_list ap)
      67                 :            :     PL_PRINTF(2, 0);
      68                 :            : void pl_str_append_asprintf(void *alloc, pl_str *str, const char *fmt, ...)
      69                 :            :     PL_PRINTF(3, 4);
      70                 :            : void pl_str_append_vasprintf(void *alloc, pl_str *str, const char *fmt, va_list va)
      71                 :            :     PL_PRINTF(3, 0);
      72                 :            : int pl_str_sscanf(pl_str str, const char *fmt, ...);
      73                 :            : 
      74                 :            : // Locale-invariant versions of append_(v)asprintf
      75                 :            : //
      76                 :            : // NOTE: These only support a small handful of modifiers. Check `format.c`
      77                 :            : // for a list. Calling them on an invalid string will abort!
      78                 :            : void pl_str_append_asprintf_c(void *alloc, pl_str *str, const char *fmt, ...)
      79                 :            :     PL_PRINTF(3, 4);
      80                 :            : void pl_str_append_vasprintf_c(void *alloc, pl_str *str, const char *fmt, va_list va)
      81                 :            :     PL_PRINTF(3, 0);
      82                 :            : 
      83                 :            : // Variant of the above which takes arguments directly from a pointer in memory,
      84                 :            : // reading them incrementally (tightly packed). Returns the amount of bytes
      85                 :            : // read from `args`, as determined by the following table:
      86                 :            : //
      87                 :            : // %c: sizeof(char)
      88                 :            : // %d, %u: sizeof(int)
      89                 :            : // %f: sizeof(double)
      90                 :            : // %lld, %llu: sizeof(long long int)
      91                 :            : // %zu: sizeof(size_t)
      92                 :            : // %s: \0 terminated string
      93                 :            : // %.*s: sizeof(int) + that many bytes (no \0 terminator)
      94                 :            : size_t pl_str_append_memprintf_c(void *alloc, pl_str *str, const char *fmt,
      95                 :            :                                  const void *args)
      96                 :            :     PL_PRINTF(3, 0);
      97                 :            : 
      98                 :            : // Locale-invariant number printing
      99                 :            : int pl_str_print_hex(char *buf, size_t len, unsigned short n);
     100                 :            : int pl_str_print_int(char *buf, size_t len, int n);
     101                 :            : int pl_str_print_uint(char *buf, size_t len, unsigned int n);
     102                 :            : int pl_str_print_int64(char *buf, size_t len, int64_t n);
     103                 :            : int pl_str_print_uint64(char *buf, size_t len, uint64_t n);
     104                 :            : int pl_str_print_float(char *buf, size_t len, float n);
     105                 :            : int pl_str_print_double(char *buf, size_t len, double n);
     106                 :            : 
     107                 :            : // Locale-invariant number parsing
     108                 :            : bool pl_str_parse_hex(pl_str str, unsigned short *out);
     109                 :            : bool pl_str_parse_int(pl_str str, int *out);
     110                 :            : bool pl_str_parse_uint(pl_str str, unsigned int *out);
     111                 :            : bool pl_str_parse_int64(pl_str str, int64_t *out);
     112                 :            : bool pl_str_parse_uint64(pl_str str, uint64_t *out);
     113                 :            : bool pl_str_parse_float(pl_str str, float *out);
     114                 :            : bool pl_str_parse_double(pl_str str, double *out);
     115                 :            : 
     116                 :            : // Variants of string.h functions
     117                 :            : int pl_strchr(pl_str str, int c);
     118                 :            : size_t pl_strspn(pl_str str, const char *accept);
     119                 :            : size_t pl_strcspn(pl_str str, const char *reject);
     120                 :            : 
     121                 :            : // Strip leading/trailing whitespace
     122                 :            : pl_str pl_str_strip(pl_str str);
     123                 :            : 
     124                 :            : // Generic functions for cutting up strings
     125                 :            : static inline pl_str pl_str_take(pl_str str, size_t len)
     126                 :            : {
     127                 :        592 :     if (len < str.len)
     128                 :            :         str.len = len;
     129                 :            :     return str;
     130                 :            : }
     131                 :            : 
     132                 :            : static inline pl_str pl_str_drop(pl_str str, size_t len)
     133                 :            : {
     134   [ +  +  +  +  :      41973 :     if (len >= str.len)
             +  +  +  + ]
     135                 :            :         return (pl_str) { .buf = NULL, .len = 0 };
     136                 :            : 
     137                 :      41050 :     str.buf += len;
     138                 :      41050 :     str.len -= len;
     139                 :      41050 :     return str;
     140                 :            : }
     141                 :            : 
     142                 :            : // Find a substring in another string, and return its index (or -1)
     143                 :            : int pl_str_find(pl_str haystack, pl_str needle);
     144                 :            : 
     145                 :            : // String splitting functions. These return the part of the string before
     146                 :            : // the separator, and optionally the rest (in `out_rest`).
     147                 :            : //
     148                 :            : // Note that the separator is not included as part of either string.
     149                 :            : pl_str pl_str_split_char(pl_str str, char sep, pl_str *out_rest);
     150                 :            : pl_str pl_str_split_str(pl_str str, pl_str sep, pl_str *out_rest);
     151                 :            : 
     152                 :            : // Like `pl_str_split_char`, but splits on any char in `seps`
     153                 :            : pl_str pl_str_split_chars(pl_str str, const char *seps, pl_str *out_rest);
     154                 :            : 
     155                 :            : static inline pl_str pl_str_getline(pl_str str, pl_str *out_rest)
     156                 :            : {
     157                 :        263 :     return pl_str_split_char(str, '\n', out_rest);
     158                 :            : }
     159                 :            : 
     160                 :            : // Decode a string containing hexadecimal data. All whitespace will be silently
     161                 :            : // ignored. When successful, this allocates a new array to store the output.
     162                 :            : bool pl_str_decode_hex(void *alloc, pl_str hex, pl_str *out);
     163                 :            : 
     164                 :      17315 : static inline bool pl_str_equals(pl_str str1, pl_str str2)
     165                 :            : {
     166         [ +  + ]:      17315 :     if (str1.len != str2.len)
     167                 :            :         return false;
     168   [ +  +  +  + ]:        758 :     if (str1.buf == str2.buf || !str1.len)
     169                 :            :         return true;
     170                 :        679 :     return memcmp(str1.buf, str2.buf, str1.len) == 0;
     171                 :            : }
     172                 :            : 
     173                 :            : static inline bool pl_str_startswith(pl_str str, pl_str prefix)
     174                 :            : {
     175         [ +  - ]:        190 :     if (!prefix.len)
     176                 :            :         return true;
     177   [ +  +  +  + ]:       1104 :     if (str.len < prefix.len)
     178                 :            :         return false;
     179                 :        187 :     return memcmp(str.buf, prefix.buf, prefix.len) == 0;
     180                 :            : }
     181                 :            : 
     182                 :        266 : static inline bool pl_str_endswith(pl_str str, pl_str suffix)
     183                 :            : {
     184         [ +  + ]:        266 :     if (!suffix.len)
     185                 :            :         return true;
     186         [ +  + ]:        264 :     if (str.len < suffix.len)
     187                 :            :         return false;
     188                 :        120 :     return memcmp(str.buf + str.len - suffix.len, suffix.buf, suffix.len) == 0;
     189                 :            : }
     190                 :            : 
     191         [ +  - ]:        968 : static inline bool pl_str_eatstart(pl_str *str, pl_str prefix)
     192                 :            : {
     193         [ +  + ]:        927 :     if (!pl_str_startswith(*str, prefix))
     194                 :            :         return false;
     195                 :            : 
     196                 :        409 :     str->buf += prefix.len;
     197                 :        409 :     str->len -= prefix.len;
     198                 :        409 :     return true;
     199                 :            : }
     200                 :            : 
     201                 :            : static inline bool pl_str_eatend(pl_str *str, pl_str suffix)
     202                 :            : {
     203         [ +  + ]:        263 :     if (!pl_str_endswith(*str, suffix))
     204                 :            :         return false;
     205                 :            : 
     206                 :         31 :     str->len -= suffix.len;
     207                 :         31 :     return true;
     208                 :            : }
     209                 :            : 
     210                 :            : // Convenience wrappers for the above which save the use of a pl_str0
     211         [ +  - ]:         49 : static inline pl_str pl_str_split_str0(pl_str str, const char *sep, pl_str *out_rest)
     212                 :            : {
     213                 :         49 :     return pl_str_split_str(str, pl_str0(sep), out_rest);
     214                 :            : }
     215                 :            : 
     216         [ +  - ]:        136 : static inline bool pl_str_startswith0(pl_str str, const char *prefix)
     217                 :            : {
     218                 :        136 :     return pl_str_startswith(str, pl_str0(prefix));
     219                 :            : }
     220                 :            : 
     221                 :            : static inline bool pl_str_endswith0(pl_str str, const char *suffix)
     222                 :            : {
     223                 :            :     return pl_str_endswith(str, pl_str0(suffix));
     224                 :            : }
     225                 :            : 
     226         [ +  - ]:      17249 : static inline bool pl_str_equals0(pl_str str1, const char *str2)
     227                 :            : {
     228                 :      17249 :     return pl_str_equals(str1, pl_str0(str2));
     229                 :            : }
     230                 :            : 
     231         [ +  - ]:        968 : static inline bool pl_str_eatstart0(pl_str *str, const char *prefix)
     232                 :            : {
     233                 :        968 :     return pl_str_eatstart(str, pl_str0(prefix));
     234                 :            : }
     235                 :            : 
     236         [ +  - ]:        263 : static inline bool pl_str_eatend0(pl_str *str, const char *prefix)
     237                 :            : {
     238                 :        263 :     return pl_str_eatend(str, pl_str0(prefix));
     239                 :            : }
     240                 :            : 
     241                 :            : // String building helpers, used to lazily construct a string by appending a
     242                 :            : // series of string templates which can be executed on-demand into a final
     243                 :            : // output buffer.
     244                 :            : typedef struct pl_str_builder_t *pl_str_builder;
     245                 :            : 
     246                 :            : // Returns the number of bytes consumed from `args`. Be warned that the pointer
     247                 :            : // given will not necessarily be aligned to the type you need it as, so make
     248                 :            : // sure to use `memcpy` or some other method of safely loading arbitrary data
     249                 :            : // from memory.
     250                 :            : typedef size_t (*pl_str_template)(void *alloc, pl_str *buf, const uint8_t *args);
     251                 :            : 
     252                 :            : pl_str_builder pl_str_builder_alloc(void *alloc);
     253                 :            : void pl_str_builder_free(pl_str_builder *builder);
     254                 :            : 
     255                 :            : // Resets string builder without destroying buffer
     256                 :            : void pl_str_builder_reset(pl_str_builder builder);
     257                 :            : 
     258                 :            : // Returns a representative hash of the string builder's output, without
     259                 :            : // actually executing it. Note that this is *not* the same as a pl_str_hash of
     260                 :            : // the string builder's output.
     261                 :            : //
     262                 :            : // Note also that the output of this may not survive a process restart because
     263                 :            : // of position-independent code and address randomization moving around the
     264                 :            : // locatons of template functions, so special care must be taken not to
     265                 :            : // compare such hashes across process invocations.
     266                 :            : uint64_t pl_str_builder_hash(const pl_str_builder builder);
     267                 :            : 
     268                 :            : // Executes a string builder, dispatching all templates. The resulting string
     269                 :            : // is guaranteed to be \0-terminated, as a minor convenience.
     270                 :            : //
     271                 :            : // Calling any other `pl_str_builder_*` function on this builder causes the
     272                 :            : // contents of the returned string to become undefined.
     273                 :            : pl_str pl_str_builder_exec(pl_str_builder builder);
     274                 :            : 
     275                 :            : // Append a template and its arguments to a string builder
     276                 :            : void pl_str_builder_append(pl_str_builder builder, pl_str_template tmpl,
     277                 :            :                            const void *args, size_t args_size);
     278                 :            : 
     279                 :            : // Append an entire other `pl_str_builder` onto `builder`
     280                 :            : void pl_str_builder_concat(pl_str_builder builder, const pl_str_builder append);
     281                 :            : 
     282                 :            : // Append a constant string. This will only record &str into the buffer, which
     283                 :            : // may have a number of unwanted consequences if the memory pointed at by
     284                 :            : // `str` mutates at any point in time in the future, or if `str` is not
     285                 :            : // at a stable location in memory.
     286                 :            : //
     287                 :            : // This is intended for strings which are compile-time constants.
     288                 :            : void pl_str_builder_const_str(pl_str_builder builder, const char *str);
     289                 :            : 
     290                 :            : // Append a string. This will make a full copy of `str`
     291                 :            : void pl_str_builder_str(pl_str_builder builder, const pl_str str);
     292                 :            : #define pl_str_builder_str0(b, str) pl_str_builder_str(b, pl_str0(str))
     293                 :            : 
     294                 :            : // Append a string printf-style. This will preprocess `fmt` to determine the
     295                 :            : // number and type of arguments. Supports the same format conversion characters
     296                 :            : // as `pl_str_append_asprintf_c`.
     297                 :            : void pl_str_builder_printf_c(pl_str_builder builder, const char *fmt, ...)
     298                 :            :     PL_PRINTF(2, 3);
     299                 :            : 
     300                 :            : void pl_str_builder_vprintf_c(pl_str_builder builder, const char *fmt, va_list ap)
     301                 :            :     PL_PRINTF(2, 0);
     302                 :            : 
     303                 :            : // Helper macro to specialize `pl_str_builder_printf_c` to
     304                 :            : // `pl_str_builder_const_str` if it contains no format characters.
     305                 :            : #define pl_str_builder_addf(builder, ...) do                                    \
     306                 :            : {                                                                               \
     307                 :            :     if (_contains_fmt_chars(__VA_ARGS__)) {                                     \
     308                 :            :         pl_str_builder_printf_c(builder, __VA_ARGS__);                          \
     309                 :            :     } else {                                                                    \
     310                 :            :         pl_str_builder_const_str(builder, _get_fmt(__VA_ARGS__));               \
     311                 :            :     }                                                                           \
     312                 :            : } while (0)
     313                 :            : 
     314                 :            : // Helper macros to deal with the non-portability of __VA_OPT__(,)
     315                 :            : #define _contains_fmt_chars(fmt, ...)   (strchr(fmt, '%'))
     316                 :            : #define _get_fmt(fmt, ...)              fmt
     317                 :            : 
     318                 :            : PL_API_END

Generated by: LCOV version 1.16