For some of the memory leak fixes I've got queued up the first step is
often to migrate the relevant code to using modern initializer
patterns. I.e. using an *_INIT macro, initializing on the stack not
the heap when possible etc.
I found that for some of those I'd start with a migration to
designated initializers, but if we're doing that we might as well do
(almost) all of them.
This series does /most/ of that, the remaining parts are things that
would conflict with other in-flight changes, i.e. this merges cleanly
with "seen". We can clean up any stray stragglers some other time.
See
https://lore.kernel.org/git/cover-0.5-00000000000-20210701T104855Z-avarab@gmail.com/
for a predecessor series which already landed as bd4232fac33 (Merge
branch 'ab/struct-init', 2021-07-16).
Ævar Arnfjörð Bjarmason (5):
submodule-config.h: remove unused SUBMODULE_INIT macro
*.[ch] *_INIT macros: use { 0 } for a "zero out" idiom
*.h _INIT macros: don't specify fields equal to 0
*.h: move some *_INIT to designated initializers
cbtree.h: define cb_init() in terms of CBTREE_INIT
add-interactive.c | 8 +++++--
builtin/submodule--helper.c | 21 ++++++++++---------
cache.h | 4 +++-
cbtree.h | 5 +++--
checkout.c | 2 +-
.../git-credential-gnome-keyring.c | 2 +-
.../libsecret/git-credential-libsecret.c | 2 +-
diff.c | 4 ++--
entry.h | 2 +-
lockfile.h | 2 +-
object-store.h | 2 +-
object.h | 2 +-
oid-array.h | 2 +-
path.h | 5 +----
ref-filter.c | 2 +-
remote.c | 2 +-
revision.c | 2 +-
sequencer.h | 4 +++-
shallow.h | 4 +++-
simple-ipc.h | 6 +-----
strbuf.h | 2 +-
strvec.h | 4 +++-
submodule-config.h | 4 ----
submodule.c | 8 ++++---
submodule.h | 4 +++-
t/helper/test-run-command.c | 6 ++++--
transport.h | 4 +++-
27 files changed, 63 insertions(+), 52 deletions(-)
--
2.33.0.1294.g2bdf2798764
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change change code that provided N zero'd fields to just
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
builtin/submodule--helper.c | 16 ++++++++--------
checkout.c | 2 +-
.../gnome-keyring/git-credential-gnome-keyring.c | 2 +-
.../libsecret/git-credential-libsecret.c | 2 +-
diff.c | 4 ++--
entry.h | 2 +-
lockfile.h | 2 +-
object-store.h | 2 +-
object.h | 2 +-
oid-array.h | 2 +-
path.h | 5 +----
ref-filter.c | 2 +-
remote.c | 2 +-
revision.c | 2 +-
14 files changed, 22 insertions(+), 25 deletions(-)
This macro was added and used in c68f8375760 (implement fetching of
moved submodules, 2017-10-16) but its last user went away in
be76c212823 (fetch: ensure submodule objects fetched, 2018-12-06).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
submodule-config.h | 4 ----
1 file changed, 4 deletions(-)
Change the initialization of "struct strbuf" changed in
cbc0f81d96f (strbuf: use designated initializers in STRBUF_INIT,
2017-07-10) to omit specifying "alloc" and "len", as we do with other
"alloc" and "len" (or "nr") in similar structs.
Let's likewise omit the explicit initialization of all fields in the
"struct ipc_client_connect_option" struct added in
59c7b88198a (simple-ipc: add win32 implementation, 2021-03-15).
Finally, start incrementally changing the same pattern in
"t/helper/test-run-command.c". This change was part of an earlier
on-list version[1] of c90be786da9 (test-tool run-command: fix
flip-flop init pattern, 2021-09-11).
1. https://lore.kernel.org/git/patch-1.1-0aa4523ab6e-20210909T130849Z-avarab@gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
simple-ipc.h | 6 +-----
strbuf.h | 2 +-
t/helper/test-run-command.c | 2 +-
3 files changed, 3 insertions(+), 7 deletions(-)
Use the same pattern for cb_init() as the one established in the
recent refactoring of other such patterns in
5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT
macro, 2021-07-01).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cbtree.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
Move various *_INIT macros to use designated initializers. This helps
readability. I've only picked those leftover macros that were not
touched by another in-flight series of mine which changed others, but
also how initialization was done.
In the case of SUBMODULE_ALTERNATE_SETUP_INIT I've left an explicit
initialization of "error_mode", even though
SUBMODULE_ALTERNATE_ERROR_IGNORE itself is defined as "0". Let's not
peek under the hood and assume that enum fields we know the value of
will stay at "0".
The change to "TESTSUITE_INIT" in "t/helper/test-run-command.c" was
part of an earlier on-list version[1] of c90be786da9 (test-tool
run-command: fix flip-flop init pattern, 2021-09-11).
1. https://lore.kernel.org/git/patch-1.1-0aa4523ab6e-20210909T130849Z-avarab@gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
add-interactive.c | 8 ++++++--
builtin/submodule--helper.c | 5 +++--
cache.h | 4 +++-
sequencer.h | 4 +++-
shallow.h | 4 +++-
strvec.h | 4 +++-
submodule.c | 8 +++++---
submodule.h | 4 +++-
t/helper/test-run-command.c | 6 ++++--
transport.h | 4 +++-
10 files changed, 36 insertions(+), 15 deletions(-)
From: Eric Sunshine <hidden> Date: 2021-09-27 02:28:38
On Sun, Sep 26, 2021 at 8:40 PM Ævar Arnfjörð Bjarmason
[off-list ref] wrote:
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change change code that provided N zero'd fields to just
s/change change/change/
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
Hi Ævar
On 27/09/2021 01:39, Ævar Arnfjörð Bjarmason wrote:
quoted hunk
Use the same pattern for cb_init() as the one established in the
recent refactoring of other such patterns in
5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT
macro, 2021-07-01).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cbtree.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
Hi Ævar
On 27/09/2021 01:39, Ævar Arnfjörð Bjarmason wrote:
quoted
Use the same pattern for cb_init() as the one established in the
recent refactoring of other such patterns in
5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT
macro, 2021-07-01).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cbtree.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
Slightly off topic but would this be a good site for a compound
literal test balloon?
*t = (struct cb_tree){ 0 };
Compound literals are in C99 and seem to have been supported by MSVC
since 2013 [1].
I think that's a good thing to test out, FWIW I've also tested it on the
IBM xlc, Oracle SunCC and HP/UX's aCC, they all seem to accept it.
But I'd prefer just doing that in some general follow-up to bd4232fac33
(Merge branch 'ab/struct-init', 2021-07-16), i.e. let's just use the
init pattern it established here.
This macro was added and used in c68f8375760 (implement fetching of
moved submodules, 2017-10-16) but its last user went away in
be76c212823 (fetch: ensure submodule objects fetched, 2018-12-06).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
submodule-config.h | 4 ----
1 file changed, 4 deletions(-)
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change code that provided N zero'd fields to just
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
builtin/submodule--helper.c | 16 ++++++++--------
checkout.c | 2 +-
.../gnome-keyring/git-credential-gnome-keyring.c | 2 +-
.../libsecret/git-credential-libsecret.c | 2 +-
diff.c | 4 ++--
lockfile.h | 2 +-
object-store.h | 2 +-
object.h | 2 +-
oid-array.h | 2 +-
path.h | 5 +----
ref-filter.c | 2 +-
remote.c | 2 +-
revision.c | 2 +-
13 files changed, 21 insertions(+), 24 deletions(-)
Change the initialization of "struct strbuf" changed in
cbc0f81d96f (strbuf: use designated initializers in STRBUF_INIT,
2017-07-10) to omit specifying "alloc" and "len", as we do with other
"alloc" and "len" (or "nr") in similar structs.
Let's likewise omit the explicit initialization of all fields in the
"struct ipc_client_connect_option" struct added in
59c7b88198a (simple-ipc: add win32 implementation, 2021-03-15).
Do the same for a few other initializers, e.g. STRVEC_INIT and
CACHE_DEF_INIT.
Finally, start incrementally changing the same pattern in
"t/helper/test-run-command.c". This change was part of an earlier
on-list version[1] of c90be786da9 (test-tool run-command: fix
flip-flop init pattern, 2021-09-11).
1. https://lore.kernel.org/git/patch-1.1-0aa4523ab6e-20210909T130849Z-avarab@gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cache.h | 2 +-
simple-ipc.h | 6 +-----
strbuf.h | 2 +-
strvec.h | 2 +-
submodule.h | 2 +-
t/helper/test-run-command.c | 2 +-
trace.h | 2 +-
7 files changed, 7 insertions(+), 11 deletions(-)
Move various *_INIT macros to use designated initializers. This helps
readability. I've only picked those leftover macros that were not
touched by another in-flight series of mine which changed others, but
also how initialization was done.
In the case of SUBMODULE_ALTERNATE_SETUP_INIT I've left an explicit
initialization of "error_mode", even though
SUBMODULE_ALTERNATE_ERROR_IGNORE itself is defined as "0". Let's not
peek under the hood and assume that enum fields we know the value of
will stay at "0".
The change to "TESTSUITE_INIT" in "t/helper/test-run-command.c" was
part of an earlier on-list version[1] of c90be786da9 (test-tool
run-command: fix flip-flop init pattern, 2021-09-11).
1. https://lore.kernel.org/git/patch-1.1-0aa4523ab6e-20210909T130849Z-avarab@gmail.com/
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
add-interactive.c | 8 ++++++--
builtin/submodule--helper.c | 5 +++--
cache.h | 4 +++-
entry.h | 2 +-
list.h | 5 ++++-
sequencer.h | 4 +++-
shallow.h | 4 +++-
strvec.h | 4 +++-
submodule.c | 8 +++++---
submodule.h | 4 +++-
t/helper/test-run-command.c | 6 ++++--
trace.h | 2 +-
transport.h | 4 +++-
13 files changed, 42 insertions(+), 18 deletions(-)
@@ -46,7 +46,10 @@ struct list_head {#define INIT_LIST_HEAD(ptr) \(ptr)->next=(ptr)->prev=(ptr)-#define LIST_HEAD_INIT(name) { &(name), &(name) }+#define LIST_HEAD_INIT(name) { \+.next=&(name),\+.prev=&(name),\+}/* Add new element at the head of the list. */staticinlinevoidlist_add(structlist_head*newp,structlist_head*head)
Use the same pattern for cb_init() as the one established in the
recent refactoring of other such patterns in
5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT
macro, 2021-07-01).
It has been pointed out[1] that we could perhaps use this C99
replacement of using a compound literal for all of these:
*t = (struct cb_tree){ 0 };
But let's just stick to the existing pattern established in
5726a6b4012 for now, we can leave another weather balloon for some
other time.
1. http://lore.kernel.org/git/ef724a3a-a4b8-65d3-c928-13a7d78f189a@gmail.com
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cbtree.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
From: Jeff King <hidden> Date: 2021-09-27 23:24:52
On Mon, Sep 27, 2021 at 02:54:25PM +0200, Ævar Arnfjörð Bjarmason wrote:
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change code that provided N zero'd fields to just
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
I seem to recall we've had some linter complaints about using "0" to
initialize a pointer, but I think these days it's OK, per:
- 1c96642326 (sparse: allow '{ 0 }' to be used without warnings,
2020-05-22)
and
- https://lore.kernel.org/git/18bd6127-be72-b7b7-8e2a-17bbe7214a2e@ramsayjones.plus.com/
I think this is a good step, as the long lists are unwieldy and difficult to
keep up to date without actually providing any readability or functional
value.
-Peff
From: Jeff King <hidden> Date: 2021-09-27 23:34:13
On Mon, Sep 27, 2021 at 02:54:24PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted hunk
This macro was added and used in c68f8375760 (implement fetching of
moved submodules, 2017-10-16) but its last user went away in
be76c212823 (fetch: ensure submodule objects fetched, 2018-12-06).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
submodule-config.h | 4 ----
1 file changed, 4 deletions(-)
I was a bit surprised by this one, just because we generally prefer the
builtin initializers to init functions. And even if we are only using
the latter, I like the move to implementing it in terms of the former.
But this struct is extra funny, as now it will have neither. It comes
only from submodule_from_name() or submodule_from_path(), which in turn
are building up from config and the initialization in
lookup_or_create_by_name(). And keeping those two in sync is potentially
error-prone.
So this whole "make a submodule struct on the stack" thing is pretty odd
in the first place, and I'm happy to see this initializer going away.
-Peff
This could be
static const struct cb_tree blank = CBTREE_INIT;
*nod*...
[...]
...but to both this & the above my reply in the side-thread at
https://lore.kernel.org/git/87h7e61duk.fsf@evledraar.gmail.com/
applies. I.e. this is just following a pattern I got from Jeff King &
used in bd4232fac33 (Merge branch 'ab/struct-init', 2021-07-16).
I'm not sure how a compiler would react to the "static const" thing. I
tested the compiler output for the "auto" struct case you've written
here, and at least gcc and clang are smart enough to just initialize the
pointed-to struct directly, with no extra copy.
For a "static const" I'm not sure if they'd end up with the same code,
or if they'd allocate a struct in the data segment and just memcpy()
into place. A non-const static would perhaps push it in the direction of the
data/memcpy thing, though the compiler should be well aware that the
struct is never changed nor aliased, and thus we're always writing the
INIT values.
I suspect the performance is not that different either way (the big
thing to avoid is initializing an auto struct on the fly and then
copying from it, but this is a pretty easy optimization for compilers to
get right).
quoted
quoted
+ memcpy(t, &blank, sizeof(*t));
Is
*t = blank;
not a thing in C?
It would be fine to use struct assignment here, and should be equivalent
in most compilers. They know about memcpy() and will inline it as
appropriate.
I think some C programmers tend to prefer memcpy() just because that's
how they think. It also wasn't legal in old K&R compilers, but as far as
I know was in C89.
You have to take care with assignment of flex-structs, of course, but
you also have to do so with memcpy(), too. :)
FWIW with "const" in general I don't use it as much as I'd personally
prefer, see e.g. [1] for one recent discussion, but maybe there wouldn't
be any push-back in this case...
This isn't a parameter, so I don't think that discussion applies. _If_
you are going to make it a static, I think a const makes sense here (but
probably does nothing beyond signaling your intention, because the
compiler can see that it is never modified), but I wouldn't bother with
either.
-Peff
On Mon, Sep 27, 2021 at 02:54:25PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change code that provided N zero'd fields to just
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
I seem to recall we've had some linter complaints about using "0" to
initialize a pointer, but I think these days it's OK, per:
- 1c96642326 (sparse: allow '{ 0 }' to be used without warnings,
2020-05-22)
and
- https://lore.kernel.org/git/18bd6127-be72-b7b7-8e2a-17bbe7214a2e@ramsayjones.plus.com/
I think this is a good step, as the long lists are unwieldy and difficult to
keep up to date without actually providing any readability or functional
value.
[+CC Luc Van Oostenryck [off-list ref]]
It seems like we should just revert 1c96642326, looking at the history
of sparse.git there's:
- 537e3e2d (univ-init: conditionally accept { 0 } without warnings, 2020-05-18)
Followed by git.git's 1c96642326 a few days later, but then in sparse.git:
- 41f651b4 (univ-init: set default to -Wno-universal-initializer, 2020-05-29)
I.e. a few days after the workaround in git.git the upstream repo
changed the default. The 537e3e2d isn't in any release of sparse that
41f651b4 isn't in, they both first appeared in v0.6.2.
So us having -Wno-universal-initializer only seems useful if you're
using some old commit in sparse.git.
Having written the above I found
https://lore.kernel.org/git/20200530162432.a7fitzjc53hsn2ej@ltop.local/;
i.e. sparse's maintainer pretty much saying the same thing.
From: Jeff King <hidden> Date: 2021-09-28 00:46:18
On Tue, Sep 28, 2021 at 02:25:16AM +0200, Ævar Arnfjörð Bjarmason wrote:
It seems like we should just revert 1c96642326, looking at the history
of sparse.git there's:
- 537e3e2d (univ-init: conditionally accept { 0 } without warnings, 2020-05-18)
Followed by git.git's 1c96642326 a few days later, but then in sparse.git:
- 41f651b4 (univ-init: set default to -Wno-universal-initializer, 2020-05-29)
I.e. a few days after the workaround in git.git the upstream repo
changed the default. The 537e3e2d isn't in any release of sparse that
41f651b4 isn't in, they both first appeared in v0.6.2.
So us having -Wno-universal-initializer only seems useful if you're
using some old commit in sparse.git.
Having written the above I found
https://lore.kernel.org/git/20200530162432.a7fitzjc53hsn2ej@ltop.local/;
i.e. sparse's maintainer pretty much saying the same thing.
Yeah, that seems reasonable. If somebody has an old version of sparse
they'll presumably see actual "don't use 0 to initialize a pointer"
warnings, as opposed to "hey, I don't understand -Wno-universal-initializer".
But either way, they should upgrade.
-Peff
From: Ramsay Jones <hidden> Date: 2021-09-28 01:44:44
On 28/09/2021 01:25, Ævar Arnfjörð Bjarmason wrote:
On Mon, Sep 27 2021, Jeff King wrote:
quoted
On Mon, Sep 27, 2021 at 02:54:25PM +0200, Ævar Arnfjörð Bjarmason wrote:
quoted
In C it isn't required to specify that all members of a struct are
zero'd out to 0, NULL or '\0', just providing a "{ 0 }" will
accomplish that.
Let's also change code that provided N zero'd fields to just
provide one, and change e.g. "{ NULL }" to "{ 0 }" for
consistency. I.e. even if the first member is a pointer let's use "0"
instead of "NULL". The point of using "0" consistently is to pick one,
and to not have the reader wonder why we're not using the same pattern
everywhere.
I seem to recall we've had some linter complaints about using "0" to
initialize a pointer, but I think these days it's OK, per:
- 1c96642326 (sparse: allow '{ 0 }' to be used without warnings,
2020-05-22)
and
- https://lore.kernel.org/git/18bd6127-be72-b7b7-8e2a-17bbe7214a2e@ramsayjones.plus.com/
I think this is a good step, as the long lists are unwieldy and difficult to
keep up to date without actually providing any readability or functional
value.
[+CC Luc Van Oostenryck [off-list ref]]
It seems like we should just revert 1c96642326, looking at the history
of sparse.git there's:
- 537e3e2d (univ-init: conditionally accept { 0 } without warnings, 2020-05-18)
Followed by git.git's 1c96642326 a few days later, but then in sparse.git:
- 41f651b4 (univ-init: set default to -Wno-universal-initializer, 2020-05-29)
I.e. a few days after the workaround in git.git the upstream repo
changed the default. The 537e3e2d isn't in any release of sparse that
41f651b4 isn't in, they both first appeared in v0.6.2.
So us having -Wno-universal-initializer only seems useful if you're
using some old commit in sparse.git.
Having written the above I found
https://lore.kernel.org/git/20200530162432.a7fitzjc53hsn2ej@ltop.local/;
i.e. sparse's maintainer pretty much saying the same thing.
Yes, this has been on my TODO list pretty much since commit 41f651b4, but
it wasn't a priority. ;-)
ATB,
Ramsay Jones
This could be
static const struct cb_tree blank = CBTREE_INIT;
*nod*...
[...]
...but to both this & the above my reply in the side-thread at
https://lore.kernel.org/git/87h7e61duk.fsf@evledraar.gmail.com/
applies. I.e. this is just following a pattern I got from Jeff King &
used in bd4232fac33 (Merge branch 'ab/struct-init', 2021-07-16).
I'm not sure how a compiler would react to the "static const" thing. I
tested the compiler output for the "auto" struct case you've written
here, and at least gcc and clang are smart enough to just initialize the
pointed-to struct directly, with no extra copy.
Good! Then a deviation from established patterns is not warranted.
-- Hannes
On 27/09/2021 12:00, Ævar Arnfjörð Bjarmason wrote:
On Mon, Sep 27 2021, Phillip Wood wrote:
quoted
Hi Ævar
On 27/09/2021 01:39, Ævar Arnfjörð Bjarmason wrote:
quoted
Use the same pattern for cb_init() as the one established in the
recent refactoring of other such patterns in
5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT
macro, 2021-07-01).
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
cbtree.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
Slightly off topic but would this be a good site for a compound
literal test balloon?
*t = (struct cb_tree){ 0 };
Compound literals are in C99 and seem to have been supported by MSVC
since 2013 [1].
I think that's a good thing to test out, FWIW I've also tested it on the
IBM xlc, Oracle SunCC and HP/UX's aCC, they all seem to accept it.
Thanks for taking the time to test those other systems, it's good to
know they support compound literals
But I'd prefer just doing that in some general follow-up to bd4232fac33
(Merge branch 'ab/struct-init', 2021-07-16), i.e. let's just use the
init pattern it established here.
I agree it makes sense to introduce it as a separate series. I'm not
sure if there is a pressing need for them but it is the sort of thing
that is occasionally useful.
Best Wishes
Phillip