2005-05-01 04:19:56 +08:00
|
|
|
#include "cache.h"
|
|
|
|
|
2009-08-31 10:26:46 +08:00
|
|
|
static const char *usage_msg = "\n"
|
2016-06-21 05:10:29 +08:00
|
|
|
" test-date relative [time_t]...\n"
|
2016-06-21 05:11:59 +08:00
|
|
|
" test-date show:<format> [time_t]...\n"
|
2009-08-31 10:26:46 +08:00
|
|
|
" test-date parse [date]...\n"
|
t0006 & t5000: prepare for 64-bit timestamps
Git's source code refers to timestamps as unsigned longs. On 32-bit
platforms, as well as on Windows, unsigned long is not large enough to
capture dates that are "absurdly far in the future".
It is perfectly valid by the C standard, of course, for the `long` data
type to refer to 32-bit integers. That is why the `time_t` data type
exists: so that it can be 64-bit even if `long` is 32-bit. Git's source
code simply uses an incorrect data type for timestamps, is all.
The earlier quick fix 6b9c38e14cd (t0006: skip "far in the future" test
when unsigned long is not long enough, 2016-07-11) papered over this
issue simply by skipping the respective test cases on platforms where
they would fail due to the data type in use.
This quick fix, however, tests for *long* to be 64-bit or not. What we
need, though, is a test that says whether *whatever data type we use for
timestamps* is 64-bit or not.
The same quick fix was used to handle the similar problem where Git's
source code uses `unsigned long` to represent size, instead of `size_t`,
conflating the two issues.
So let's just add another prerequisite to test specifically whether
timestamps are represented by a 64-bit data type or not. Later, after we
switch to a larger data type, we can flip that prerequisite to test
`time_t` instead of `long`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-21 04:52:13 +08:00
|
|
|
" test-date approxidate [date]...\n"
|
2017-04-21 04:58:21 +08:00
|
|
|
" test-date is64bit\n"
|
|
|
|
" test-date time_t-is64bit\n";
|
2009-08-31 10:26:46 +08:00
|
|
|
|
2016-07-20 04:22:19 +08:00
|
|
|
static void show_relative_dates(const char **argv, struct timeval *now)
|
2005-05-01 04:19:56 +08:00
|
|
|
{
|
2012-04-23 20:30:23 +08:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2009-08-31 10:26:46 +08:00
|
|
|
|
|
|
|
for (; *argv; argv++) {
|
|
|
|
time_t t = atoi(*argv);
|
2012-04-23 20:30:23 +08:00
|
|
|
show_date_relative(t, 0, now, &buf);
|
|
|
|
printf("%s -> %s\n", *argv, buf.buf);
|
2009-08-31 10:26:46 +08:00
|
|
|
}
|
2012-04-23 20:30:23 +08:00
|
|
|
strbuf_release(&buf);
|
2009-08-31 10:26:46 +08:00
|
|
|
}
|
2005-05-01 04:19:56 +08:00
|
|
|
|
2016-07-20 04:22:19 +08:00
|
|
|
static void show_dates(const char **argv, const char *format)
|
2016-06-21 05:11:59 +08:00
|
|
|
{
|
|
|
|
struct date_mode mode;
|
|
|
|
|
|
|
|
parse_date_format(format, &mode);
|
|
|
|
for (; *argv; argv++) {
|
2016-07-20 04:22:19 +08:00
|
|
|
char *arg;
|
2016-06-21 05:11:59 +08:00
|
|
|
time_t t;
|
|
|
|
int tz;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not use our normal timestamp parsing here, as the point
|
|
|
|
* is to test the formatting code in isolation.
|
|
|
|
*/
|
2017-04-21 18:45:44 +08:00
|
|
|
t = parse_timestamp(*argv, &arg, 10);
|
2016-06-21 05:11:59 +08:00
|
|
|
while (*arg == ' ')
|
|
|
|
arg++;
|
|
|
|
tz = atoi(arg);
|
|
|
|
|
|
|
|
printf("%s -> %s\n", *argv, show_date(t, tz, &mode));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
add an extra level of indirection to main()
There are certain startup tasks that we expect every git
process to do. In some cases this is just to improve the
quality of the program (e.g., setting up gettext()). In
others it is a requirement for using certain functions in
libgit.a (e.g., system_path() expects that you have called
git_extract_argv0_path()).
Most commands are builtins and are covered by the git.c
version of main(). However, there are still a few external
commands that use their own main(). Each of these has to
remember to include the correct startup sequence, and we are
not always consistent.
Rather than just fix the inconsistencies, let's make this
harder to get wrong by providing a common main() that can
run this standard startup.
We basically have two options to do this:
- the compat/mingw.h file already does something like this by
adding a #define that replaces the definition of main with a
wrapper that calls mingw_startup().
The upside is that the code in each program doesn't need
to be changed at all; it's rewritten on the fly by the
preprocessor.
The downside is that it may make debugging of the startup
sequence a bit more confusing, as the preprocessor is
quietly inserting new code.
- the builtin functions are all of the form cmd_foo(),
and git.c's main() calls them.
This is much more explicit, which may make things more
obvious to somebody reading the code. It's also more
flexible (because of course we have to figure out _which_
cmd_foo() to call).
The downside is that each of the builtins must define
cmd_foo(), instead of just main().
This patch chooses the latter option, preferring the more
explicit approach, even though it is more invasive. We
introduce a new file common-main.c, with the "real" main. It
expects to call cmd_main() from whatever other objects it is
linked against.
We link common-main.o against anything that links against
libgit.a, since we know that such programs will need to do
this setup. Note that common-main.o can't actually go inside
libgit.a, as the linker would not pick up its main()
function automatically (it has no callers).
The rest of the patch is just adjusting all of the various
external programs (mostly in t/helper) to use cmd_main().
I've provided a global declaration for cmd_main(), which
means that all of the programs also need to match its
signature. In particular, many functions need to switch to
"const char **" instead of "char **" for argv. This effect
ripples out to a few other variables and functions, as well.
This makes the patch even more invasive, but the end result
is much better. We should be treating argv strings as const
anyway, and now all programs conform to the same signature
(which also matches the way builtins are defined).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-01 13:58:58 +08:00
|
|
|
static void parse_dates(const char **argv, struct timeval *now)
|
2009-08-31 10:26:46 +08:00
|
|
|
{
|
2014-08-27 15:57:08 +08:00
|
|
|
struct strbuf result = STRBUF_INIT;
|
|
|
|
|
2009-08-31 10:26:46 +08:00
|
|
|
for (; *argv; argv++) {
|
2010-07-06 15:54:33 +08:00
|
|
|
unsigned long t;
|
2010-07-04 18:48:35 +08:00
|
|
|
int tz;
|
2005-05-01 04:19:56 +08:00
|
|
|
|
2014-08-27 15:57:08 +08:00
|
|
|
strbuf_reset(&result);
|
|
|
|
parse_date(*argv, &result);
|
2017-04-21 18:45:48 +08:00
|
|
|
if (sscanf(result.buf, "%"PRItime" %d", &t, &tz) == 2)
|
2010-07-04 18:48:35 +08:00
|
|
|
printf("%s -> %s\n",
|
convert "enum date_mode" into a struct
In preparation for adding date modes that may carry extra
information beyond the mode itself, this patch converts the
date_mode enum into a struct.
Most of the conversion is fairly straightforward; we pass
the struct as a pointer and dereference the type field where
necessary. Locations that declare a date_mode can use a "{}"
constructor. However, the tricky case is where we use the
enum labels as constants, like:
show_date(t, tz, DATE_NORMAL);
Ideally we could say:
show_date(t, tz, &{ DATE_NORMAL });
but of course C does not allow that. Likewise, we cannot
cast the constant to a struct, because we need to pass an
actual address. Our options are basically:
1. Manually add a "struct date_mode d = { DATE_NORMAL }"
definition to each caller, and pass "&d". This makes
the callers uglier, because they sometimes do not even
have their own scope (e.g., they are inside a switch
statement).
2. Provide a pre-made global "date_normal" struct that can
be passed by address. We'd also need "date_rfc2822",
"date_iso8601", and so forth. But at least the ugliness
is defined in one place.
3. Provide a wrapper that generates the correct struct on
the fly. The big downside is that we end up pointing to
a single global, which makes our wrapper non-reentrant.
But show_date is already not reentrant, so it does not
matter.
This patch implements 3, along with a minor macro to keep
the size of the callers sane.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-26 00:55:02 +08:00
|
|
|
*argv, show_date(t, tz, DATE_MODE(ISO8601)));
|
2010-07-04 18:48:35 +08:00
|
|
|
else
|
|
|
|
printf("%s -> bad\n", *argv);
|
2009-08-31 10:26:46 +08:00
|
|
|
}
|
2014-08-27 15:57:08 +08:00
|
|
|
strbuf_release(&result);
|
2009-08-31 10:26:46 +08:00
|
|
|
}
|
2005-11-15 16:07:04 +08:00
|
|
|
|
add an extra level of indirection to main()
There are certain startup tasks that we expect every git
process to do. In some cases this is just to improve the
quality of the program (e.g., setting up gettext()). In
others it is a requirement for using certain functions in
libgit.a (e.g., system_path() expects that you have called
git_extract_argv0_path()).
Most commands are builtins and are covered by the git.c
version of main(). However, there are still a few external
commands that use their own main(). Each of these has to
remember to include the correct startup sequence, and we are
not always consistent.
Rather than just fix the inconsistencies, let's make this
harder to get wrong by providing a common main() that can
run this standard startup.
We basically have two options to do this:
- the compat/mingw.h file already does something like this by
adding a #define that replaces the definition of main with a
wrapper that calls mingw_startup().
The upside is that the code in each program doesn't need
to be changed at all; it's rewritten on the fly by the
preprocessor.
The downside is that it may make debugging of the startup
sequence a bit more confusing, as the preprocessor is
quietly inserting new code.
- the builtin functions are all of the form cmd_foo(),
and git.c's main() calls them.
This is much more explicit, which may make things more
obvious to somebody reading the code. It's also more
flexible (because of course we have to figure out _which_
cmd_foo() to call).
The downside is that each of the builtins must define
cmd_foo(), instead of just main().
This patch chooses the latter option, preferring the more
explicit approach, even though it is more invasive. We
introduce a new file common-main.c, with the "real" main. It
expects to call cmd_main() from whatever other objects it is
linked against.
We link common-main.o against anything that links against
libgit.a, since we know that such programs will need to do
this setup. Note that common-main.o can't actually go inside
libgit.a, as the linker would not pick up its main()
function automatically (it has no callers).
The rest of the patch is just adjusting all of the various
external programs (mostly in t/helper) to use cmd_main().
I've provided a global declaration for cmd_main(), which
means that all of the programs also need to match its
signature. In particular, many functions need to switch to
"const char **" instead of "char **" for argv. This effect
ripples out to a few other variables and functions, as well.
This makes the patch even more invasive, but the end result
is much better. We should be treating argv strings as const
anyway, and now all programs conform to the same signature
(which also matches the way builtins are defined).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-01 13:58:58 +08:00
|
|
|
static void parse_approxidate(const char **argv, struct timeval *now)
|
2009-08-31 10:26:46 +08:00
|
|
|
{
|
|
|
|
for (; *argv; argv++) {
|
|
|
|
time_t t;
|
|
|
|
t = approxidate_relative(*argv, now);
|
convert "enum date_mode" into a struct
In preparation for adding date modes that may carry extra
information beyond the mode itself, this patch converts the
date_mode enum into a struct.
Most of the conversion is fairly straightforward; we pass
the struct as a pointer and dereference the type field where
necessary. Locations that declare a date_mode can use a "{}"
constructor. However, the tricky case is where we use the
enum labels as constants, like:
show_date(t, tz, DATE_NORMAL);
Ideally we could say:
show_date(t, tz, &{ DATE_NORMAL });
but of course C does not allow that. Likewise, we cannot
cast the constant to a struct, because we need to pass an
actual address. Our options are basically:
1. Manually add a "struct date_mode d = { DATE_NORMAL }"
definition to each caller, and pass "&d". This makes
the callers uglier, because they sometimes do not even
have their own scope (e.g., they are inside a switch
statement).
2. Provide a pre-made global "date_normal" struct that can
be passed by address. We'd also need "date_rfc2822",
"date_iso8601", and so forth. But at least the ugliness
is defined in one place.
3. Provide a wrapper that generates the correct struct on
the fly. The big downside is that we end up pointing to
a single global, which makes our wrapper non-reentrant.
But show_date is already not reentrant, so it does not
matter.
This patch implements 3, along with a minor macro to keep
the size of the callers sane.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-26 00:55:02 +08:00
|
|
|
printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601)));
|
2009-08-31 10:26:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
add an extra level of indirection to main()
There are certain startup tasks that we expect every git
process to do. In some cases this is just to improve the
quality of the program (e.g., setting up gettext()). In
others it is a requirement for using certain functions in
libgit.a (e.g., system_path() expects that you have called
git_extract_argv0_path()).
Most commands are builtins and are covered by the git.c
version of main(). However, there are still a few external
commands that use their own main(). Each of these has to
remember to include the correct startup sequence, and we are
not always consistent.
Rather than just fix the inconsistencies, let's make this
harder to get wrong by providing a common main() that can
run this standard startup.
We basically have two options to do this:
- the compat/mingw.h file already does something like this by
adding a #define that replaces the definition of main with a
wrapper that calls mingw_startup().
The upside is that the code in each program doesn't need
to be changed at all; it's rewritten on the fly by the
preprocessor.
The downside is that it may make debugging of the startup
sequence a bit more confusing, as the preprocessor is
quietly inserting new code.
- the builtin functions are all of the form cmd_foo(),
and git.c's main() calls them.
This is much more explicit, which may make things more
obvious to somebody reading the code. It's also more
flexible (because of course we have to figure out _which_
cmd_foo() to call).
The downside is that each of the builtins must define
cmd_foo(), instead of just main().
This patch chooses the latter option, preferring the more
explicit approach, even though it is more invasive. We
introduce a new file common-main.c, with the "real" main. It
expects to call cmd_main() from whatever other objects it is
linked against.
We link common-main.o against anything that links against
libgit.a, since we know that such programs will need to do
this setup. Note that common-main.o can't actually go inside
libgit.a, as the linker would not pick up its main()
function automatically (it has no callers).
The rest of the patch is just adjusting all of the various
external programs (mostly in t/helper) to use cmd_main().
I've provided a global declaration for cmd_main(), which
means that all of the programs also need to match its
signature. In particular, many functions need to switch to
"const char **" instead of "char **" for argv. This effect
ripples out to a few other variables and functions, as well.
This makes the patch even more invasive, but the end result
is much better. We should be treating argv strings as const
anyway, and now all programs conform to the same signature
(which also matches the way builtins are defined).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-01 13:58:58 +08:00
|
|
|
int cmd_main(int argc, const char **argv)
|
2009-08-31 10:26:46 +08:00
|
|
|
{
|
|
|
|
struct timeval now;
|
|
|
|
const char *x;
|
|
|
|
|
|
|
|
x = getenv("TEST_DATE_NOW");
|
|
|
|
if (x) {
|
|
|
|
now.tv_sec = atoi(x);
|
|
|
|
now.tv_usec = 0;
|
2005-05-01 04:19:56 +08:00
|
|
|
}
|
2009-08-31 10:26:46 +08:00
|
|
|
else
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
|
|
|
|
argv++;
|
|
|
|
if (!*argv)
|
|
|
|
usage(usage_msg);
|
2016-06-21 05:10:29 +08:00
|
|
|
if (!strcmp(*argv, "relative"))
|
|
|
|
show_relative_dates(argv+1, &now);
|
2016-06-21 05:11:59 +08:00
|
|
|
else if (skip_prefix(*argv, "show:", &x))
|
|
|
|
show_dates(argv+1, x);
|
2009-08-31 10:26:46 +08:00
|
|
|
else if (!strcmp(*argv, "parse"))
|
|
|
|
parse_dates(argv+1, &now);
|
|
|
|
else if (!strcmp(*argv, "approxidate"))
|
|
|
|
parse_approxidate(argv+1, &now);
|
t0006 & t5000: prepare for 64-bit timestamps
Git's source code refers to timestamps as unsigned longs. On 32-bit
platforms, as well as on Windows, unsigned long is not large enough to
capture dates that are "absurdly far in the future".
It is perfectly valid by the C standard, of course, for the `long` data
type to refer to 32-bit integers. That is why the `time_t` data type
exists: so that it can be 64-bit even if `long` is 32-bit. Git's source
code simply uses an incorrect data type for timestamps, is all.
The earlier quick fix 6b9c38e14cd (t0006: skip "far in the future" test
when unsigned long is not long enough, 2016-07-11) papered over this
issue simply by skipping the respective test cases on platforms where
they would fail due to the data type in use.
This quick fix, however, tests for *long* to be 64-bit or not. What we
need, though, is a test that says whether *whatever data type we use for
timestamps* is 64-bit or not.
The same quick fix was used to handle the similar problem where Git's
source code uses `unsigned long` to represent size, instead of `size_t`,
conflating the two issues.
So let's just add another prerequisite to test specifically whether
timestamps are represented by a 64-bit data type or not. Later, after we
switch to a larger data type, we can flip that prerequisite to test
`time_t` instead of `long`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-21 04:52:13 +08:00
|
|
|
else if (!strcmp(*argv, "is64bit"))
|
|
|
|
return sizeof(unsigned long) == 8 ? 0 : 1;
|
2017-04-21 04:58:21 +08:00
|
|
|
else if (!strcmp(*argv, "time_t-is64bit"))
|
|
|
|
return sizeof(time_t) == 8 ? 0 : 1;
|
2009-08-31 10:26:46 +08:00
|
|
|
else
|
|
|
|
usage(usage_msg);
|
2005-05-01 04:19:56 +08:00
|
|
|
return 0;
|
|
|
|
}
|