| 15 | }; |
| 16 | |
| 17 | char *cbm_path_join(CBMArena *a, const char *base, const char *name) { |
| 18 | if (!base || !name) { |
| 19 | return NULL; |
| 20 | } |
| 21 | size_t blen = strlen(base); |
| 22 | size_t nlen = strlen(name); |
| 23 | |
| 24 | /* Handle empty components */ |
| 25 | if (blen == 0) { |
| 26 | return cbm_arena_strdup(a, name); |
| 27 | } |
| 28 | if (nlen == 0) { |
| 29 | return cbm_arena_strdup(a, base); |
| 30 | } |
| 31 | |
| 32 | /* Strip trailing slash from base */ |
| 33 | while (blen > 0 && base[blen - SKIP_ONE] == '/') { |
| 34 | blen--; |
| 35 | } |
| 36 | /* Strip leading slash from name */ |
| 37 | while (nlen > 0 && *name == '/') { |
| 38 | name++; |
| 39 | nlen--; |
| 40 | } |
| 41 | |
| 42 | if (blen == 0) { |
| 43 | return cbm_arena_strndup(a, name, nlen); |
| 44 | } |
| 45 | if (nlen == 0) { |
| 46 | return cbm_arena_strndup(a, base, blen); |
| 47 | } |
| 48 | |
| 49 | char *result = (char *)cbm_arena_alloc(a, blen + SKIP_ONE + nlen + SKIP_ONE); |
| 50 | if (!result) { |
| 51 | return NULL; |
| 52 | } |
| 53 | memcpy(result, base, blen); |
| 54 | result[blen] = '/'; |
| 55 | memcpy(result + blen + SKIP_ONE, name, nlen); |
| 56 | result[blen + SKIP_ONE + nlen] = '\0'; |
| 57 | return result; |
| 58 | } |
| 59 | |
| 60 | char *cbm_path_join_n(CBMArena *a, const char **parts, int n) { |
| 61 | if (n <= 0 || !parts) { |
no test coverage detected