From: Junio C Hamano <gitster@pobox.com>
To: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Cc: git@vger.kernel.org, "Derrick Stolee" <derrickstolee@github.com>,
"Elijah Newren" <newren@gmail.com>, "Jeff King" <peff@peff.net>,
"Taylor Blau" <me@ttaylorr.com>,
"SZEDER Gábor" <szeder.dev@gmail.com>,
"Glen Choo" <chooglen@google.com>,
"Calvin Wan" <calvinwan@google.com>,
"Emily Shaffer" <emilyshaffer@google.com>,
raymond@heliax.dev, zweiss@equinix.com
Subject: Re: [PATCH v4 3/9] config API: add and use a "git_config_get()" family of functions
Date: Thu, 02 Feb 2023 15:56:33 -0800 [thread overview]
Message-ID: <xmqqv8kjpqoe.fsf@gitster.g> (raw)
In-Reply-To: <patch-v4-3.9-998b11ae4bc-20230202T131155Z-avarab@gmail.com> ("Ævar Arnfjörð Bjarmason"'s message of "Thu, 2 Feb 2023 14:27:15 +0100")
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> We already have the basic "git_config_get_value()" function and its
> "repo_*" and "configset" siblings to get a given "key" and assign the
> last key found to a provided "value".
>
> But some callers don't care about that value, but just want to use the
> return value of the "get_value()" function to check whether the key
> exist (or another non-zero return value).
>
> The immediate motivation for this is that a subsequent commit will
> need to change all callers of the "*_get_value_multi()" family of
> functions. In two cases here we (ab)used it to check whether we had
> any values for the given key, but didn't care about the return value.
So, the idea is that
if (!git_config_get_string(key, &discard))
free(discard);
else
... the key is missing ...
becomes
if (git_config_get(key))
... the key is missing ...
In other words, git_config_get() returns 0 only when the key is
used, and non-zero return signals that the key is not used?
Similarly, get_value_multi() was an interface to get to the
value_list associated to the given key, and was abused like
if (git_config_get_value_multi(key))
... the key exists ...
which will become
if (!git_config_get(key))
... the key exists ...
right?
> /* Set maintenance strategy, if unset */
> - if (!git_config_get_string("maintenance.strategy", &config_value))
> - free(config_value);
> - else
> + if (git_config_get("maintenance.strategy"))
> git_config_set("maintenance.strategy", "incremental");
OK. config_get() says "true" meaning the key is missing.
> - if (!argc && git_config_get_value_multi("submodule.active"))
> + if (!argc && !git_config_get("submodule.active"))
> module_list_active(&list);
OK.
> @@ -2743,7 +2743,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
> * If there are no path args and submodule.active is set then,
> * by default, only initialize 'active' modules.
> */
> - if (!argc && git_config_get_value_multi("submodule.active"))
> + if (!argc && !git_config_get("submodule.active"))
> module_list_active(&list);
OK.
> @@ -3185,7 +3184,7 @@ static void configure_added_submodule(struct add_data *add_data)
> * is_submodule_active(), since that function needs to find
> * out the value of "submodule.active" again anyway.
> */
> - if (!git_config_get_string_tmp("submodule.active", &val)) {
> + if (!git_config_get("submodule.active")) {
string_tmp() variant is to retrieve borrowed value, and it returns 0
when there is a value. If it is a valueless true, we get -1 back
with an error message. What does the updated version do in the
valueless true case?
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index f51c40f1e1e..6ba42d4ad20 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -338,7 +337,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
> to_file, "core.bare", NULL, "true", 0))
> error(_("failed to unset '%s' in '%s'"),
> "core.bare", to_file);
> - if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
> + if (!git_configset_get(&cs, "core.worktree") &&
OK.
> diff --git a/config.c b/config.c
> index 00090a32fc3..b88da70c664 100644
> --- a/config.c
> +++ b/config.c
> @@ -2289,23 +2289,28 @@ void read_very_early_config(config_fn_t cb, void *data)
> config_with_options(cb, data, NULL, &opts);
> }
>
> -static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
> +static int configset_find_element(struct config_set *cs, const char *key,
> + struct config_set_element **dest)
> {
> struct config_set_element k;
> struct config_set_element *found_entry;
> char *normalized_key;
> + int ret;
> +
> /*
> * `key` may come from the user, so normalize it before using it
> * for querying entries from the hashmap.
> */
> - if (git_config_parse_key(key, &normalized_key, NULL))
> - return NULL;
> + ret = git_config_parse_key(key, &normalized_key, NULL);
> + if (ret)
> + return ret;
>
> hashmap_entry_init(&k.ent, strhash(normalized_key));
> k.key = normalized_key;
> found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
> free(normalized_key);
> - return found_entry;
> + *dest = found_entry;
> + return 0;
OK, so we used to return NULL when the key is not parseable, and
otherwise we returned the config_set_element we found for the key,
or NULL if there is no such element. Now we return error code as
the return value and allow the caller to peek the element via *dest
parameter.
So, from the caller's point of view (dest != NULL) is how it checks
if the key is used. The function returning 0 is a sign that the key
passed to it is healthy. OK.
> @@ -2314,8 +2319,11 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
> struct string_list_item *si;
> struct configset_list_item *l_item;
> struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
> + int ret;
>
> - e = configset_find_element(cs, key);
> + ret = configset_find_element(cs, key, &e);
> + if (ret)
> + return ret;
The function never returned any meaningful error, so the callers may
not be prepared to see such an error return. But now we at least
notice an error at this level.
> @@ -2425,8 +2433,25 @@ int git_configset_get_value(struct config_set *cs, const char *key, const char *
>
> const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
> {
> - struct config_set_element *e = configset_find_element(cs, key);
> - return e ? &e->value_list : NULL;
> + struct config_set_element *e;
> +
> + if (configset_find_element(cs, key, &e))
> + return NULL;
> + else if (!e)
> + return NULL;
> + return &e->value_list;
> +}
OK. !e means "we got a healthy key and peeking into the hash table,
there wasn't any entry for the key", and that is reported with NULL.
Do we evern return a string list with .nr == 0, I wonder. Having to
deal with such a list would make the caller's job more complex, but
perhaps we are not allowing the code to shrink value_list.nr to
avoid such a situation?
> +int git_configset_get(struct config_set *cs, const char *key)
> +{
> + struct config_set_element *e;
> + int ret;
> +
> + if ((ret = configset_find_element(cs, key, &e)))
> + return ret;
> + else if (!e)
> + return 1;
> + return 0;
> }
OK. So 0 return from the function means there is a value (or more)
for a given key. Good.
> diff --git a/config.h b/config.h
> index ef9eade6414..04c5e594015 100644
> --- a/config.h
> +++ b/config.h
> @@ -471,9 +471,12 @@ void git_configset_clear(struct config_set *cs);
>
> /*
> * These functions return 1 if not found, and 0 if found, leaving the found
> - * value in the 'dest' pointer.
> + * value in the 'dest' pointer (if any).
> */
Now the returned non-zero values are no longer 1 alone, no?
Whatever lower-level functions use to signal an error is propagated
up with the
if ((ret = func())
return ret;
pattern.
next prev parent reply other threads:[~2023-02-02 23:56 UTC|newest]
Thread overview: 134+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-26 15:35 [PATCH 00/10] config API: make "multi" safe, fix numerous segfaults Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 01/10] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2022-10-26 18:49 ` SZEDER Gábor
2022-10-26 19:33 ` Ævar Arnfjörð Bjarmason
2022-10-27 19:27 ` Junio C Hamano
2022-10-26 15:35 ` [PATCH 02/10] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 03/10] config API: mark *_multi() with RESULT_MUST_BE_USED Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 04/10] string-list API: mark "struct_string_list" to "for_each_string_list" const Ævar Arnfjörð Bjarmason
2022-10-27 19:32 ` Junio C Hamano
2022-10-27 23:04 ` Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 05/10] string-list API: make has_string() and list_lookup() "const" Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 06/10] builtin/gc.c: use "unsorted_string_list_has_string()" where appropriate Ævar Arnfjörð Bjarmason
2022-10-27 19:37 ` Junio C Hamano
2022-10-27 23:25 ` Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 07/10] config API: add and use "lookup_value" functions Ævar Arnfjörð Bjarmason
2022-10-27 19:42 ` Junio C Hamano
2022-10-26 15:35 ` [PATCH 08/10] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2022-10-27 19:43 ` Junio C Hamano
2022-10-26 15:35 ` [PATCH 09/10] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2022-10-27 19:49 ` Junio C Hamano
2022-10-27 19:52 ` Junio C Hamano
2022-10-27 23:44 ` Ævar Arnfjörð Bjarmason
2022-10-28 19:16 ` Junio C Hamano
2022-10-31 18:22 ` Ævar Arnfjörð Bjarmason
2022-10-26 15:35 ` [PATCH 10/10] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2022-10-27 20:12 ` [PATCH 00/10] config API: make "multi" safe, fix numerous segfaults Junio C Hamano
2022-11-01 23:05 ` [PATCH v2 0/9] " Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 1/9] for-each-repo tests: test bad --config keys Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 2/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 3/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2022-11-01 23:05 ` [PATCH v2 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2022-11-02 0:49 ` [PATCH v2 0/9] config API: make "multi" safe, fix numerous segfaults Taylor Blau
2022-11-25 9:50 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
2022-11-25 9:50 ` [PATCH v3 1/9] for-each-repo tests: test bad --config keys Ævar Arnfjörð Bjarmason
2022-11-25 9:50 ` [PATCH v3 2/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-01-19 0:15 ` Glen Choo
2022-11-25 9:50 ` [PATCH v3 3/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-01-19 0:28 ` Glen Choo
2022-11-25 9:50 ` [PATCH v3 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2022-11-25 9:50 ` [PATCH v3 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-01-19 0:50 ` Glen Choo
2022-11-25 9:50 ` [PATCH v3 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2022-11-25 9:50 ` [PATCH v3 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-01-19 0:51 ` Glen Choo
2022-11-25 9:50 ` [PATCH v3 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-01-19 1:03 ` Glen Choo
2022-11-25 9:50 ` [PATCH v3 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-01-19 0:10 ` [PATCH v3 0/9] config API: make "multi" safe, fix numerous segfaults Glen Choo
2023-02-02 13:27 ` [PATCH v4 " Ævar Arnfjörð Bjarmason
2023-02-02 13:27 ` [PATCH v4 1/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-02-03 1:22 ` Junio C Hamano
2023-02-06 8:31 ` Glen Choo
2023-02-02 13:27 ` [PATCH v4 2/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-02-02 23:12 ` Junio C Hamano
2023-02-06 10:40 ` Glen Choo
2023-02-06 12:31 ` Ævar Arnfjörð Bjarmason
2023-02-06 16:23 ` Glen Choo
2023-02-02 13:27 ` [PATCH v4 3/9] config API: add and use a "git_config_get()" family of functions Ævar Arnfjörð Bjarmason
2023-02-02 23:56 ` Junio C Hamano [this message]
2023-02-07 10:29 ` Ævar Arnfjörð Bjarmason
2023-02-06 12:36 ` Glen Choo
2023-02-06 12:37 ` Glen Choo
2023-02-07 11:52 ` Ævar Arnfjörð Bjarmason
2023-02-02 13:27 ` [PATCH v4 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2023-02-03 21:52 ` Junio C Hamano
2023-02-02 13:27 ` [PATCH v4 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-02-02 13:27 ` [PATCH v4 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2023-02-06 12:56 ` Glen Choo
2023-02-02 13:27 ` [PATCH v4 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-02-02 13:27 ` [PATCH v4 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-02-06 13:04 ` Glen Choo
2023-02-02 13:27 ` [PATCH v4 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 00/10] config API: make "multi" safe, fix segfaults, propagate "ret" Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 01/10] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 02/10] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-02-09 4:00 ` Glen Choo
2023-02-07 16:10 ` [PATCH v5 03/10] config API: add and use a "git_config_get()" family of functions Ævar Arnfjörð Bjarmason
2023-02-09 8:24 ` Glen Choo
2023-02-09 10:11 ` Ævar Arnfjörð Bjarmason
2023-02-09 10:59 ` Ævar Arnfjörð Bjarmason
2023-02-09 16:53 ` Glen Choo
2023-02-07 16:10 ` [PATCH v5 04/10] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 05/10] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 06/10] config API: don't lose the git_*get*() return values Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 07/10] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 08/10] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 09/10] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-02-07 16:10 ` [PATCH v5 10/10] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-02-07 17:38 ` [PATCH v5 00/10] config API: make "multi" safe, fix segfaults, propagate "ret" Junio C Hamano
2023-03-07 18:09 ` [PATCH v6 0/9] " Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 1/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 2/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 3/9] config API: add and use a "git_config_get()" family of functions Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-03-07 18:09 ` [PATCH v6 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-03-08 0:48 ` [PATCH v6 0/9] config API: make "multi" safe, fix segfaults, propagate "ret" Glen Choo
2023-03-08 9:06 ` [PATCH v7 " Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 1/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 2/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 3/9] config API: add and use a "git_config_get()" family of functions Ævar Arnfjörð Bjarmason
2023-03-09 18:53 ` Glen Choo
2023-03-14 11:21 ` Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-03-09 19:01 ` Glen Choo
2023-03-08 9:06 ` [PATCH v7 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-03-08 9:06 ` [PATCH v7 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-03-09 19:08 ` [PATCH v7 0/9] config API: make "multi" safe, fix segfaults, propagate "ret" Glen Choo
2023-03-09 20:46 ` Junio C Hamano
2023-03-28 14:04 ` [PATCH v8 " Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 1/9] config tests: cover blind spots in git_die_config() tests Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 2/9] config tests: add "NULL" tests for *_get_value_multi() Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 3/9] config API: add and use a "git_config_get()" family of functions Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 4/9] versioncmp.c: refactor config reading next commit Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 5/9] config API: have *_multi() return an "int" and take a "dest" Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 6/9] for-each-repo: error on bad --config Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 7/9] config API users: test for *_get_value_multi() segfaults Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 8/9] config API: add "string" version of *_value_multi(), fix segfaults Ævar Arnfjörð Bjarmason
2023-03-28 14:04 ` [PATCH v8 9/9] for-each-repo: with bad config, don't conflate <path> and <cmd> Ævar Arnfjörð Bjarmason
2023-04-07 15:51 ` SZEDER Gábor
2023-03-28 16:58 ` [PATCH v8 0/9] config API: make "multi" safe, fix segfaults, propagate "ret" Glen Choo
2023-03-28 17:02 ` Junio C Hamano
2023-03-29 22:17 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqqv8kjpqoe.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=avarab@gmail.com \
--cc=calvinwan@google.com \
--cc=chooglen@google.com \
--cc=derrickstolee@github.com \
--cc=emilyshaffer@google.com \
--cc=git@vger.kernel.org \
--cc=me@ttaylorr.com \
--cc=newren@gmail.com \
--cc=peff@peff.net \
--cc=raymond@heliax.dev \
--cc=szeder.dev@gmail.com \
--cc=zweiss@equinix.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).