Diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Report a word where cgitrc expects a number
atoi reads "yes" or "true" as 0, so repo.hide=yes, or cgit.hide true
in a scanned repository's git config, silently did nothing. The values
keep that meaning, since honouring them now would hide repositories on
upgrade, but each one is logged with its file and line.
Diffstat (limited to 'source')
| -rw-r--r-- | source/cgit.c | 134 | |
| -rw-r--r-- | source/config.c | 44 | |
| -rw-r--r-- | source/config.h | 20 | |
| -rw-r--r-- | source/scan-tree.c | 8 |
4 files changed, 136 insertions, 70 deletions
diff --git a/source/cgit.c b/source/cgit.c index 17a79a2..180cd82 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -590,77 +590,77 @@ static void apply_config(const char *name, const char *value) else if (!strcmp(name, "virtual-root")) ctx.cfg.virtual_root = ensure_end(value, '/'); else if (!strcmp(name, "enable-plain-email")) - ctx.cfg.enable_plain_email = atoi(value); + ctx.cfg.enable_plain_email = config_int(name, value); else if (!strcmp(name, "enable-header")) - ctx.cfg.enable_header = atoi(value); + ctx.cfg.enable_header = config_int(name, value); else if (!strcmp(name, "snapshots")) ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); else if (!strcmp(name, "trust-scan-config")) - ctx.cfg.trust_scan_config = atoi(value); + ctx.cfg.trust_scan_config = config_int(name, value); else if (!strcmp(name, "enable-follow-links")) - ctx.cfg.enable_follow_links = atoi(value); + ctx.cfg.enable_follow_links = config_int(name, value); else if (!strcmp(name, "enable-http-clone")) - ctx.cfg.enable_http_clone = atoi(value); + ctx.cfg.enable_http_clone = config_int(name, value); else if (!strcmp(name, "enable-index-links")) - ctx.cfg.enable_index_links = atoi(value); + ctx.cfg.enable_index_links = config_int(name, value); else if (!strcmp(name, "enable-index-owner")) - ctx.cfg.enable_index_owner = atoi(value); + ctx.cfg.enable_index_owner = config_int(name, value); else if (!strcmp(name, "enable-blame")) - ctx.cfg.enable_blame = atoi(value); + ctx.cfg.enable_blame = config_int(name, value); else if (!strcmp(name, "enable-commit-graph")) - ctx.cfg.enable_commit_graph = atoi(value); + ctx.cfg.enable_commit_graph = config_int(name, value); else if (!strcmp(name, "enable-gitmodules-links")) - ctx.cfg.enable_gitmodules_links = atoi(value); + ctx.cfg.enable_gitmodules_links = config_int(name, value); else if (!strcmp(name, "enable-log-filecount")) - ctx.cfg.enable_log_filecount = atoi(value); + ctx.cfg.enable_log_filecount = config_int(name, value); else if (!strcmp(name, "enable-log-linecount")) - ctx.cfg.enable_log_linecount = atoi(value); + ctx.cfg.enable_log_linecount = config_int(name, value); else if (!strcmp(name, "enable-mailmap")) - ctx.cfg.enable_mailmap = atoi(value); + ctx.cfg.enable_mailmap = config_int(name, value); else if (!strcmp(name, "enable-relative-dates")) - ctx.cfg.enable_relative_dates = atoi(value); + ctx.cfg.enable_relative_dates = config_int(name, value); else if (!strcmp(name, "enable-remote-branches")) - ctx.cfg.enable_remote_branches = atoi(value); + ctx.cfg.enable_remote_branches = config_int(name, value); else if (!strcmp(name, "enable-subject-links")) - ctx.cfg.enable_subject_links = atoi(value); + ctx.cfg.enable_subject_links = config_int(name, value); else if (!strcmp(name, "enable-commit-trailers")) - ctx.cfg.enable_commit_trailers = atoi(value); + ctx.cfg.enable_commit_trailers = config_int(name, value); else if (!strcmp(name, "enable-html-serving")) - ctx.cfg.enable_html_serving = atoi(value); + ctx.cfg.enable_html_serving = config_int(name, value); else if (!strcmp(name, "enable-tree-linenumbers")) - ctx.cfg.enable_tree_linenumbers = atoi(value); + ctx.cfg.enable_tree_linenumbers = config_int(name, value); else if (!strcmp(name, "enable-version-info")) - ctx.cfg.enable_version_info = atoi(value); + ctx.cfg.enable_version_info = config_int(name, value); else if (!strcmp(name, "enable-tree-group-dirs")) - ctx.cfg.enable_tree_group_dirs = atoi(value); + ctx.cfg.enable_tree_group_dirs = config_int(name, value); else if (!strcmp(name, "enable-git-config")) - ctx.cfg.enable_git_config = atoi(value); + ctx.cfg.enable_git_config = config_int(name, value); else if (!strcmp(name, "enable-cache-list")) - ctx.cfg.enable_cache_list = atoi(value); + ctx.cfg.enable_cache_list = config_int(name, value); else if (!strcmp(name, "max-stats")) ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "cache-size")) - ctx.cfg.cache_size = atoi(value); + ctx.cfg.cache_size = config_int(name, value); else if (!strcmp(name, "cache-root")) ctx.cfg.cache_root = cgit_strdup_first_line(cgit_expand_macros(value)); else if (!strcmp(name, "cache-index-ttl")) - ctx.cfg.cache_index_ttl = atoi(value); + ctx.cfg.cache_index_ttl = config_int(name, value); else if (!strcmp(name, "cache-summary-ttl")) - ctx.cfg.cache_summary_ttl = atoi(value); + ctx.cfg.cache_summary_ttl = config_int(name, value); else if (!strcmp(name, "cache-scan-ttl")) - ctx.cfg.cache_scan_ttl = atoi(value); + ctx.cfg.cache_scan_ttl = config_int(name, value); else if (!strcmp(name, "cache-static-ttl")) - ctx.cfg.cache_static_ttl = atoi(value); + ctx.cfg.cache_static_ttl = config_int(name, value); else if (!strcmp(name, "cache-dynamic-ttl")) - ctx.cfg.cache_dynamic_ttl = atoi(value); + ctx.cfg.cache_dynamic_ttl = config_int(name, value); else if (!strcmp(name, "cache-about-ttl")) - ctx.cfg.cache_about_ttl = atoi(value); + ctx.cfg.cache_about_ttl = config_int(name, value); else if (!strcmp(name, "cache-snapshot-ttl")) - ctx.cfg.cache_snapshot_ttl = atoi(value); + ctx.cfg.cache_snapshot_ttl = config_int(name, value); else if (!strcmp(name, "cache-max-slot-size")) - ctx.cfg.cache_max_slot_size = atoi(value); + ctx.cfg.cache_max_slot_size = config_int(name, value); else if (!strcmp(name, "case-sensitive-sort")) - ctx.cfg.case_sensitive_sort = atoi(value); + ctx.cfg.case_sensitive_sort = config_int(name, value); else if (!strcmp(name, "about-filter")) ctx.cfg.about_filter = cgit_new_filter(value, ABOUT); else if (!strcmp(name, "commit-filter")) @@ -672,29 +672,29 @@ static void apply_config(const char *name, const char *value) else if (!strcmp(name, "auth-filter")) ctx.cfg.auth_filter = cgit_new_filter(value, AUTH); else if (!strcmp(name, "embedded")) - ctx.cfg.embedded = atoi(value); + ctx.cfg.embedded = config_int(name, value); else if (!strcmp(name, "max-atom-items")) - ctx.cfg.max_atom_items = atoi(value); + ctx.cfg.max_atom_items = config_int(name, value); else if (!strcmp(name, "max-message-length")) - ctx.cfg.max_msg_len = atoi(value); + ctx.cfg.max_msg_len = config_int(name, value); else if (!strcmp(name, "max-repodesc-length")) - ctx.cfg.max_repodesc_len = atoi(value); + ctx.cfg.max_repodesc_len = config_int(name, value); else if (!strcmp(name, "max-blob-size")) - ctx.cfg.max_blob_size = atoi(value); + ctx.cfg.max_blob_size = config_int(name, value); else if (!strcmp(name, "max-diff-files")) - ctx.cfg.max_diff_files = atoi(value); + ctx.cfg.max_diff_files = config_int(name, value); else if (!strcmp(name, "max-diff-lines")) - ctx.cfg.max_diff_lines = atoi(value); + ctx.cfg.max_diff_lines = config_int(name, value); else if (!strcmp(name, "max-ref-count")) - ctx.cfg.max_ref_count = atoi(value); + ctx.cfg.max_ref_count = config_int(name, value); else if (!strcmp(name, "max-repo-count")) { - ctx.cfg.max_repo_count = atoi(value); + ctx.cfg.max_repo_count = config_int(name, value); if (ctx.cfg.max_repo_count <= 0) ctx.cfg.max_repo_count = INT_MAX; } else if (!strcmp(name, "max-commit-count")) - ctx.cfg.max_commit_count = atoi(value); + ctx.cfg.max_commit_count = config_int(name, value); else if (!strcmp(name, "max-patch-count")) - ctx.cfg.max_patch_count = atoi(value); + ctx.cfg.max_patch_count = config_int(name, value); else if (!strcmp(name, "project-list")) ctx.cfg.project_list = cgit_strdup_first_line(cgit_expand_macros(value)); else if (!strcmp(name, "scan-path")) { @@ -706,31 +706,31 @@ static void apply_config(const char *name, const char *value) // it may have moved, and a repo key after it belongs to nothing. ctx.repo = NULL; } else if (!strcmp(name, "scan-hidden-path")) - ctx.cfg.scan_hidden_path = atoi(value); + ctx.cfg.scan_hidden_path = config_int(name, value); else if (!strcmp(name, "section-from-path")) - ctx.cfg.section_from_path = atoi(value); + ctx.cfg.section_from_path = config_int(name, value); else if (!strcmp(name, "repository-sort")) ctx.cfg.repository_sort = cgit_strdup_first_line(value); else if (!strcmp(name, "section-sort")) - ctx.cfg.section_sort = atoi(value); + ctx.cfg.section_sort = config_int(name, value); else if (!strcmp(name, "source-filter")) ctx.cfg.source_filter = cgit_new_filter(value, SOURCE); else if (!strcmp(name, "summary-log")) - ctx.cfg.summary_log = atoi(value); + ctx.cfg.summary_log = config_int(name, value); else if (!strcmp(name, "summary-branches")) - ctx.cfg.summary_branches = atoi(value); + ctx.cfg.summary_branches = config_int(name, value); else if (!strcmp(name, "summary-tags")) - ctx.cfg.summary_tags = atoi(value); + ctx.cfg.summary_tags = config_int(name, value); else if (!strcmp(name, "side-by-side-diffs")) - ctx.cfg.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED; + ctx.cfg.difftype = config_int(name, value) ? DIFF_SSDIFF : DIFF_UNIFIED; else if (!strcmp(name, "age-file")) ctx.cfg.agefile = cgit_strdup_first_line(value); else if (!strcmp(name, "mimetype-file")) ctx.cfg.mimetype_file = cgit_strdup_first_line(value); else if (!strcmp(name, "rename-limit")) - ctx.cfg.renamelimit = atoi(value); + ctx.cfg.renamelimit = config_int(name, value); else if (!strcmp(name, "remove-suffix")) - ctx.cfg.remove_suffix = atoi(value); + ctx.cfg.remove_suffix = config_int(name, value); else if (!strcmp(name, "robots")) ctx.cfg.robots = cgit_strdup_first_line(value); else if (!strcmp(name, "clone-prefix")) @@ -738,7 +738,7 @@ static void apply_config(const char *name, const char *value) else if (!strcmp(name, "clone-url")) ctx.cfg.clone_url = cgit_strdup_first_line(value); else if (!strcmp(name, "local-time")) - ctx.cfg.local_time = atoi(value); + ctx.cfg.local_time = config_int(name, value); else if (!strcmp(name, "date-format")) parse_date_setting(value, &ctx.cfg.date_mode); else if (!strcmp(name, "commit-sort")) { @@ -1296,27 +1296,27 @@ void cgit_repo_config(struct cgit_repo *repo, const char *name, const char *valu else if (!strcmp(name, "snapshots")) repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); else if (!strcmp(name, "enable-blame")) - repo->enable_blame = atoi(value); + repo->enable_blame = config_int(name, value); else if (!strcmp(name, "enable-commit-graph")) - repo->enable_commit_graph = atoi(value); + repo->enable_commit_graph = config_int(name, value); else if (!strcmp(name, "enable-follow-links")) - repo->enable_follow_links = atoi(value); + repo->enable_follow_links = config_int(name, value); else if (!strcmp(name, "enable-gitmodules-links")) - repo->enable_gitmodules_links = atoi(value); + repo->enable_gitmodules_links = config_int(name, value); else if (!strcmp(name, "enable-log-filecount")) - repo->enable_log_filecount = atoi(value); + repo->enable_log_filecount = config_int(name, value); else if (!strcmp(name, "enable-log-linecount")) - repo->enable_log_linecount = atoi(value); + repo->enable_log_linecount = config_int(name, value); else if (!strcmp(name, "enable-mailmap")) - repo->enable_mailmap = atoi(value); + repo->enable_mailmap = config_int(name, value); else if (!strcmp(name, "enable-remote-branches")) - repo->enable_remote_branches = atoi(value); + repo->enable_remote_branches = config_int(name, value); else if (!strcmp(name, "enable-subject-links")) - repo->enable_subject_links = atoi(value); + repo->enable_subject_links = config_int(name, value); else if (!strcmp(name, "enable-commit-trailers")) - repo->enable_commit_trailers = atoi(value); + repo->enable_commit_trailers = config_int(name, value); else if (!strcmp(name, "enable-html-serving")) - repo->enable_html_serving = atoi(value); + repo->enable_html_serving = config_int(name, value); else if (!strcmp(name, "branch-sort")) { if (!strcmp(value, "age")) repo->branch_sort = 1; @@ -1345,9 +1345,9 @@ void cgit_repo_config(struct cgit_repo *repo, const char *name, const char *valu else if (!strcmp(name, "logo-link")) repo->logo_link = cgit_strdup_first_line(value); else if (!strcmp(name, "hide")) - repo->hide = atoi(value); + repo->hide = config_int(name, value); else if (!strcmp(name, "ignore")) - repo->ignore = atoi(value); + repo->ignore = config_int(name, value); else if (!strcmp(name, "about-filter")) repo->about_filter = cgit_new_filter(value, ABOUT); else if (!strcmp(name, "commit-filter")) diff --git a/source/config.c b/source/config.c index ca7c688..bfd31b6 100644 --- a/source/config.c +++ b/source/config.c @@ -11,6 +11,12 @@ #define MAX_INCLUDE_NESTING 8 +struct config_origin config_origin; + +// The newlines read so far from the file being parsed, which place each entry +// on its line. +static int lines_read; + /* * Folds away a carriage return that sits right before a newline so a file * saved with DOS line endings parses the same as one saved with Unix endings. @@ -26,6 +32,8 @@ static int next_char(FILE *f) c = '\r'; } } + if (c == '\n') + lines_read++; return c; } @@ -52,7 +60,7 @@ static int next_content_char(FILE *f) } } -static int read_entry(FILE *f, struct strbuf *name, struct strbuf *value) +static int read_entry(FILE *f, struct strbuf *name, struct strbuf *value, int *line) { int c; @@ -63,6 +71,7 @@ static int read_entry(FILE *f, struct strbuf *name, struct strbuf *value) if (c == EOF) return 0; + *line = lines_read + 1; strbuf_reset(name); while (c != '=' && c != '\n' && c != EOF) { strbuf_addch(name, c); @@ -88,6 +97,10 @@ static int read_entry(FILE *f, struct strbuf *name, struct strbuf *value) int config_file_parse(const char *filename, config_file_value_fn fn) { static int nesting; + // An include is parsed from inside a line of the file that names it, + // which carries on from that line once the include is done. + struct config_origin outer = config_origin; + int outer_lines_read = lines_read; struct strbuf name = STRBUF_INIT; struct strbuf value = STRBUF_INIT; FILE *f; @@ -99,15 +112,42 @@ int config_file_parse(const char *filename, config_file_value_fn fn) return 0; if (!(f = fopen(filename, "r"))) return errno; + config_origin.file = filename; + lines_read = 0; nesting++; - while (read_entry(f, &name, &value)) + while (read_entry(f, &name, &value, &config_origin.line)) fn(name.buf, value.buf); // A directory opens like a file and fails only once it is read. if (ferror(f)) err = errno; nesting--; fclose(f); + config_origin = outer; + lines_read = outer_lines_read; strbuf_release(&name); strbuf_release(&value); return err; } + +int config_int(const char *name, const char *value) +{ + int number = atoi(value); + char *end; + + // Space may follow the digits strtol finds, but nothing else. + strtol(value, &end, 10); + while (end != value && isspace(*end)) + end++; + if (end != value && !*end) + return number; + // The first line alone, since a git config value can hold a newline + // that would forge a log line of its own. + if (config_origin.file) + fprintf(stderr, "[cgit] Reading %s=%.*s in %s line %d as %d, since it is not a whole number\n", + name, (int)strcspn(value, "\n"), value, config_origin.file, + config_origin.line, number); + else + fprintf(stderr, "[cgit] Reading %s=%.*s as %d, since it is not a whole number\n", + name, (int)strcspn(value, "\n"), value, number); + return number; +} diff --git a/source/config.h b/source/config.h index 30cf74d..b6dfa2b 100644 --- a/source/config.h +++ b/source/config.h @@ -10,9 +10,29 @@ typedef void (*config_file_value_fn)(const char *name, const char *value); /* + * Where the setting being applied was written, for a warning about it to name. + * The file is NULL while no config file is being read. + */ +struct config_origin { + const char *file; + int line; +}; + +extern struct config_origin config_origin; + +/* * Returns 0, or an errno value when filename could not be opened or read. A * missing file is ordinary for some callers, so reporting one is left to them. + * filename has to stay as it is until the parse returns, since a warning about + * a setting in the file names it. */ extern int config_file_parse(const char *filename, config_file_value_fn fn); +/* + * Read value as atoi does, which is what a number in cgitrc has always meant, + * and warn on stderr when it is not a plain whole number, since atoi turns a + * word such as "yes" into 0 without a sound. + */ +extern int config_int(const char *name, const char *value); + #endif // CGIT_CONFIG_H diff --git a/source/scan-tree.c b/source/scan-tree.c index 91db419..6c1f854 100644 --- a/source/scan-tree.c +++ b/source/scan-tree.c @@ -75,13 +75,18 @@ static int trusted_key(const char *name, const char *value) } static int apply_gitconfig(const char *key, const char *value, - const struct config_context *cfg_ctx UNUSED, void *cb UNUSED) + const struct config_context *cfg_ctx, void *cb UNUSED) { + // The scan runs from inside a line of cgitrc, which a warning about + // this value must not be pinned to. + struct config_origin outer = config_origin; const char *name; // A key with no value is legal git config and nothing here can use it. if (!value) return 0; + config_origin.file = cfg_ctx->kvi->filename; + config_origin.line = cfg_ctx->kvi->linenr; if (!strcmp(key, "gitweb.owner")) cgit_repo_config(current_repo, "owner", value); else if (!strcmp(key, "gitweb.description")) @@ -90,6 +95,7 @@ static int apply_gitconfig(const char *key, const char *value, cgit_repo_config(current_repo, "section", value); else if (skip_prefix(key, "cgit.", &name) && trusted_key(name, value)) cgit_repo_config(current_repo, name, value); + config_origin = outer; return 0; } |
