| 5670 | /* ── Architecture aspect implementations ───────────────────────── */ |
| 5671 | |
| 5672 | static int arch_languages(cbm_store_t *s, const char *project, const char *path, |
| 5673 | cbm_architecture_info_t *out) { |
| 5674 | char norm[CBM_SZ_512]; |
| 5675 | char like[CBM_SZ_512]; |
| 5676 | bool scoped = arch_path_prepare(path, norm, sizeof(norm), like, sizeof(like)); |
| 5677 | char sqlbuf[ST_SQL_BUF]; |
| 5678 | const char *base = "SELECT file_path FROM nodes WHERE project=?1 AND label='File'"; |
| 5679 | if (scoped) { |
| 5680 | snprintf(sqlbuf, sizeof(sqlbuf), "%s%s", base, arch_path_scope_sql()); |
| 5681 | } else { |
| 5682 | snprintf(sqlbuf, sizeof(sqlbuf), "%s", base); |
| 5683 | } |
| 5684 | sqlite3_stmt *stmt = NULL; |
| 5685 | if (sqlite3_prepare_v2(s->db, sqlbuf, CBM_NOT_FOUND, &stmt, NULL) != SQLITE_OK) { |
| 5686 | store_set_error_sqlite(s, "arch_languages"); |
| 5687 | return CBM_STORE_ERR; |
| 5688 | } |
| 5689 | bind_text(stmt, SKIP_ONE, project); |
| 5690 | if (scoped) { |
| 5691 | arch_bind_path_scope(stmt, ST_COL_2, ST_COL_3, norm, like); |
| 5692 | } |
| 5693 | |
| 5694 | /* Count per language using a simple parallel array */ |
| 5695 | const char *lang_names[CBM_SZ_64]; |
| 5696 | int lang_counts[CBM_SZ_64]; |
| 5697 | int nlang = 0; |
| 5698 | |
| 5699 | int scan_rc20; |
| 5700 | while ((scan_rc20 = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 5701 | const char *fp = (const char *)sqlite3_column_text(stmt, 0); |
| 5702 | const char *ext = file_ext(fp); |
| 5703 | const char *lang = ext_to_lang(ext); |
| 5704 | if (!lang) { |
| 5705 | continue; |
| 5706 | } |
| 5707 | int found = ST_FOUND; |
| 5708 | for (int i = 0; i < nlang; i++) { |
| 5709 | if (strcmp(lang_names[i], lang) == 0) { |
| 5710 | found = i; |
| 5711 | break; |
| 5712 | } |
| 5713 | } |
| 5714 | if (found >= 0) { |
| 5715 | lang_counts[found]++; |
| 5716 | } else if (nlang < CBM_SZ_64) { |
| 5717 | lang_names[nlang] = lang; |
| 5718 | lang_counts[nlang] = SKIP_ONE; |
| 5719 | nlang++; |
| 5720 | } |
| 5721 | } |
| 5722 | if (scan_rc20 != SQLITE_DONE) { /* SCANCHK:20:stmt */ |
| 5723 | store_set_error_sqlite(s, "row scan aborted"); |
| 5724 | sqlite3_finalize(stmt); |
| 5725 | return CBM_STORE_ERR; |
| 5726 | } |
| 5727 | sqlite3_finalize(stmt); |
| 5728 | |
| 5729 | /* Sort by count descending (simple insertion sort) */ |
no test coverage detected