| 6554 | } |
| 6555 | |
| 6556 | int cbm_cmd_config(int argc, char **argv) { |
| 6557 | /* NULL argv with a nonzero argc previously slipped past this guard (the |
| 6558 | * inner `argv &&` shielded only the help comparison) and dereferenced |
| 6559 | * argv[0] below -- caught by the clang-analyzer lane. */ |
| 6560 | if (argc == 0 || !argv || strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0) { |
| 6561 | printf("Usage: codebase-memory-mcp config <command> [args]\n\n"); |
| 6562 | printf("Commands:\n"); |
| 6563 | printf(" list Show all config values\n"); |
| 6564 | printf(" get <key> Get a config value\n"); |
| 6565 | printf(" set <key> <val> Set a config value\n"); |
| 6566 | printf(" reset <key> Reset a key to default\n\n"); |
| 6567 | printf("Config keys:\n"); |
| 6568 | for (size_t i = 0; i < sizeof(CONFIG_KEYS) / sizeof(CONFIG_KEYS[0]); i++) { |
| 6569 | printf(" %-25s default=%-10s %s\n", CONFIG_KEYS[i].key, CONFIG_KEYS[i].default_value, |
| 6570 | CONFIG_KEYS[i].help); |
| 6571 | } |
| 6572 | return 0; |
| 6573 | } |
| 6574 | |
| 6575 | const char *home = cbm_get_home_dir(); |
| 6576 | if (!home) { |
| 6577 | (void)fprintf(stderr, "error: HOME not set (use USERPROFILE on Windows)\n"); |
| 6578 | return CLI_TRUE; |
| 6579 | } |
| 6580 | |
| 6581 | char cache_dir[CLI_BUF_1K]; |
| 6582 | snprintf(cache_dir, sizeof(cache_dir), "%s", cbm_resolve_cache_dir()); |
| 6583 | |
| 6584 | cbm_config_t *cfg = cbm_config_open(cache_dir); |
| 6585 | if (!cfg) { |
| 6586 | (void)fprintf(stderr, "error: cannot open config database\n"); |
| 6587 | return CLI_TRUE; |
| 6588 | } |
| 6589 | |
| 6590 | int rc = 0; |
| 6591 | if (strcmp(argv[0], "list") == 0 || strcmp(argv[0], "ls") == 0) { |
| 6592 | printf("Configuration:\n"); |
| 6593 | for (size_t i = 0; i < sizeof(CONFIG_KEYS) / sizeof(CONFIG_KEYS[0]); i++) { |
| 6594 | printf(" %-25s = %-10s\n", CONFIG_KEYS[i].key, |
| 6595 | cbm_config_get(cfg, CONFIG_KEYS[i].key, CONFIG_KEYS[i].default_value)); |
| 6596 | } |
| 6597 | } else if (strcmp(argv[0], "get") == 0) { |
| 6598 | if (argc < MIN_ARGC_GET) { |
| 6599 | (void)fprintf(stderr, "Usage: config get <key>\n"); |
| 6600 | rc = CLI_TRUE; |
| 6601 | } else { |
| 6602 | const config_key_def_t *def = config_key_lookup(argv[CLI_SKIP_ONE]); |
| 6603 | if (!def) { |
| 6604 | config_print_unknown_key(argv[CLI_SKIP_ONE]); |
| 6605 | rc = CLI_TRUE; |
| 6606 | } else { |
| 6607 | /* Stored value or the key's real default — the same fallback |
| 6608 | * the runtime readers use. `""` here was #1522's bug 2: every |
| 6609 | * unset key read as empty with exit 0. */ |
| 6610 | printf("%s\n", cbm_config_get(cfg, def->key, def->default_value)); |
| 6611 | } |
| 6612 | } |
| 6613 | } else if (strcmp(argv[0], "set") == 0) { |