| 1490 | } |
| 1491 | |
| 1492 | char *cbm_fqn_folder(CBMArena *a, const char *project, const char *rel_dir) { |
| 1493 | // project.dir1.dir2 |
| 1494 | size_t proj_len = strlen(project); |
| 1495 | size_t dir_len = strlen(rel_dir); |
| 1496 | size_t max_len = proj_len + SKIP_ONE + dir_len + SKIP_ONE; |
| 1497 | char *buf = (char *)cbm_arena_alloc(a, max_len); |
| 1498 | if (!buf) { |
| 1499 | return NULL; |
| 1500 | } |
| 1501 | |
| 1502 | char *out = buf; |
| 1503 | memcpy(out, project, proj_len); |
| 1504 | out += proj_len; |
| 1505 | |
| 1506 | if (dir_len > 0 && !(dir_len == SKIP_ONE && rel_dir[0] == '.')) { |
| 1507 | const char *start = rel_dir; |
| 1508 | const char *end_ptr = rel_dir + dir_len; |
| 1509 | while (start < end_ptr) { |
| 1510 | const char *slash = (const char *)memchr(start, '/', end_ptr - start); |
| 1511 | const char *part_end = slash ? slash : end_ptr; |
| 1512 | size_t part_len = (size_t)(part_end - start); |
| 1513 | if (part_len > 0) { |
| 1514 | *out++ = '.'; |
| 1515 | memcpy(out, start, part_len); |
| 1516 | out += part_len; |
| 1517 | } |
| 1518 | start = part_end + SKIP_ONE; |
| 1519 | } |
| 1520 | } |
| 1521 | *out = '\0'; |
| 1522 | return buf; |
| 1523 | } |
| 1524 | |
| 1525 | /* ── String literal classifier ──────────────────────────────────── */ |
| 1526 |
no test coverage detected