| 5577 | /* ── Architecture aspect implementations ───────────────────────── */ |
| 5578 | |
| 5579 | static int arch_languages(cbm_store_t *s, const char *project, const char *path, |
| 5580 | cbm_architecture_info_t *out) { |
| 5581 | char norm[CBM_SZ_512]; |
| 5582 | char like[CBM_SZ_512]; |
| 5583 | bool scoped = arch_path_prepare(path, norm, sizeof(norm), like, sizeof(like)); |
| 5584 | char sqlbuf[ST_SQL_BUF]; |
| 5585 | const char *base = "SELECT file_path FROM nodes WHERE project=?1 AND label='File'"; |
| 5586 | if (scoped) { |
| 5587 | snprintf(sqlbuf, sizeof(sqlbuf), "%s%s", base, arch_path_scope_sql()); |
| 5588 | } else { |
| 5589 | snprintf(sqlbuf, sizeof(sqlbuf), "%s", base); |
| 5590 | } |
| 5591 | sqlite3_stmt *stmt = NULL; |
| 5592 | if (sqlite3_prepare_v2(s->db, sqlbuf, CBM_NOT_FOUND, &stmt, NULL) != SQLITE_OK) { |
| 5593 | store_set_error_sqlite(s, "arch_languages"); |
| 5594 | return CBM_STORE_ERR; |
| 5595 | } |
| 5596 | bind_text(stmt, SKIP_ONE, project); |
| 5597 | if (scoped) { |
| 5598 | arch_bind_path_scope(stmt, ST_COL_2, ST_COL_3, norm, like); |
| 5599 | } |
| 5600 | |
| 5601 | /* Count per language using a simple parallel array */ |
| 5602 | const char *lang_names[CBM_SZ_64]; |
| 5603 | int lang_counts[CBM_SZ_64]; |
| 5604 | int nlang = 0; |
| 5605 | |
| 5606 | int scan_rc20; |
| 5607 | while ((scan_rc20 = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 5608 | const char *fp = (const char *)sqlite3_column_text(stmt, 0); |
| 5609 | const char *ext = file_ext(fp); |
| 5610 | const char *lang = ext_to_lang(ext); |
| 5611 | if (!lang) { |
| 5612 | continue; |
| 5613 | } |
| 5614 | int found = ST_FOUND; |
| 5615 | for (int i = 0; i < nlang; i++) { |
| 5616 | if (strcmp(lang_names[i], lang) == 0) { |
| 5617 | found = i; |
| 5618 | break; |
| 5619 | } |
| 5620 | } |
| 5621 | if (found >= 0) { |
| 5622 | lang_counts[found]++; |
| 5623 | } else if (nlang < CBM_SZ_64) { |
| 5624 | lang_names[nlang] = lang; |
| 5625 | lang_counts[nlang] = SKIP_ONE; |
| 5626 | nlang++; |
| 5627 | } |
| 5628 | } |
| 5629 | if (scan_rc20 != SQLITE_DONE) { /* SCANCHK:20:stmt */ |
| 5630 | store_set_error_sqlite(s, "row scan aborted"); |
| 5631 | sqlite3_finalize(stmt); |
| 5632 | return CBM_STORE_ERR; |
| 5633 | } |
| 5634 | sqlite3_finalize(stmt); |
| 5635 | |
| 5636 | /* Sort by count descending (simple insertion sort) */ |
no test coverage detected