| 1503 | } |
| 1504 | |
| 1505 | char *cbm_fqn_folder(CBMArena *a, const char *project, const char *rel_dir) { |
| 1506 | // project.dir1.dir2 |
| 1507 | size_t proj_len = strlen(project); |
| 1508 | size_t dir_len = strlen(rel_dir); |
| 1509 | size_t max_len = proj_len + SKIP_ONE + dir_len + SKIP_ONE; |
| 1510 | char *buf = (char *)cbm_arena_alloc(a, max_len); |
| 1511 | if (!buf) { |
| 1512 | return NULL; |
| 1513 | } |
| 1514 | |
| 1515 | char *out = buf; |
| 1516 | memcpy(out, project, proj_len); |
| 1517 | out += proj_len; |
| 1518 | |
| 1519 | if (dir_len > 0 && !(dir_len == SKIP_ONE && rel_dir[0] == '.')) { |
| 1520 | const char *start = rel_dir; |
| 1521 | const char *end_ptr = rel_dir + dir_len; |
| 1522 | while (start < end_ptr) { |
| 1523 | const char *slash = (const char *)memchr(start, '/', end_ptr - start); |
| 1524 | const char *part_end = slash ? slash : end_ptr; |
| 1525 | size_t part_len = (size_t)(part_end - start); |
| 1526 | if (part_len > 0) { |
| 1527 | *out++ = '.'; |
| 1528 | memcpy(out, start, part_len); |
| 1529 | out += part_len; |
| 1530 | } |
| 1531 | start = part_end + SKIP_ONE; |
| 1532 | } |
| 1533 | } |
| 1534 | *out = '\0'; |
| 1535 | return buf; |
| 1536 | } |
| 1537 | |
| 1538 | /* ── String literal classifier ──────────────────────────────────── */ |
| 1539 |
no test coverage detected