| 919 | } |
| 920 | |
| 921 | CBMLanguage cbm_language_for_filename(const char *filename) { |
| 922 | if (!filename || !filename[0]) { |
| 923 | return CBM_LANG_COUNT; |
| 924 | } |
| 925 | |
| 926 | /* Check special filenames first */ |
| 927 | for (size_t i = 0; i < FILENAME_TABLE_SIZE; i++) { |
| 928 | if (strcmp(FILENAME_TABLE[i].filename, filename) == 0) { |
| 929 | return FILENAME_TABLE[i].language; |
| 930 | } |
| 931 | } |
| 932 | |
| 933 | /* DotEnv variant filenames (".env.local", ".env.production", …): the |
| 934 | * filename starts with ".env." but its last "extension" (e.g. ".local") |
| 935 | * is not a real language extension. Match the dotenv convention used by |
| 936 | * pass_envscan/pass_infrascan (".env" exact, ".env." prefix, "*.env" |
| 937 | * suffix) so file-index routing agrees with direct extraction. */ |
| 938 | if (strncmp(filename, ".env.", SLEN(".env.")) == 0) { |
| 939 | return CBM_LANG_DOTENV; |
| 940 | } |
| 941 | |
| 942 | /* Fall back to extension-based lookup. |
| 943 | * For compound extensions (e.g. ".blade.php") defined in the user config, |
| 944 | * scan from the first dot in the basename toward the last, checking user |
| 945 | * config at each position. Built-in extensions use the last dot only. */ |
| 946 | const char *last_dot = strrchr(filename, '.'); |
| 947 | if (!last_dot) { |
| 948 | return CBM_LANG_COUNT; |
| 949 | } |
| 950 | |
| 951 | /* Probe compound extensions (e.g. ".blade.php") from the first dot toward |
| 952 | * the last. Built-in compounds are checked first so e.g. Laravel Blade |
| 953 | * templates map to Blade rather than the single-extension fallback (PHP); |
| 954 | * user config can still add more (#258). */ |
| 955 | static const struct { |
| 956 | const char *ext; |
| 957 | CBMLanguage lang; |
| 958 | } COMPOUND_EXT_TABLE[] = { |
| 959 | {".blade.php", CBM_LANG_BLADE}, |
| 960 | }; |
| 961 | const cbm_userconfig_t *ucfg = cbm_get_user_lang_config(); |
| 962 | const char *p = strchr(filename, '.'); |
| 963 | while (p && p < last_dot) { |
| 964 | for (size_t i = 0; i < sizeof(COMPOUND_EXT_TABLE) / sizeof(COMPOUND_EXT_TABLE[0]); i++) { |
| 965 | if (strcmp(p, COMPOUND_EXT_TABLE[i].ext) == 0) { |
| 966 | return COMPOUND_EXT_TABLE[i].lang; |
| 967 | } |
| 968 | } |
| 969 | if (ucfg) { |
| 970 | CBMLanguage lang = cbm_userconfig_lookup(ucfg, p); |
| 971 | if (lang != CBM_LANG_COUNT) { |
| 972 | return lang; |
| 973 | } |
| 974 | } |
| 975 | p = strchr(p + SKIP_ONE, '.'); |
| 976 | } |
| 977 | |
| 978 | /* Standard single-extension lookup (built-ins + user overrides). */ |
no test coverage detected