🌐 AI搜索 & 代理 主页
Skip to content

Commit f8715ec

Browse files
committed
Support "j" length modifier in snprintf.c.
POSIX has for a long time defined the "j" length modifier for printf conversions as meaning the size of intmax_t or uintmax_t. We got away without supporting that so far, because we were not using intmax_t anywhere. However, commit e6be843 re-introduced upstream's use of intmax_t and PRIdMAX into zic.c. It emerges that on some platforms (at least FreeBSD and macOS), <inttypes.h> defines PRIdMAX as "jd", so that snprintf.c falls over if that is used. (We hadn't noticed yet because it would only be apparent if bad data is fed to zic, resulting in an error report, and even then the only visible symptom is a missing line number in the error message.) We could revert that decision from our copy of zic.c, but on the whole it seems better to update snprintf.c to support this standard modifier. There might well be extensions, now or in future, that expect it to work. I did this in the lazy man's way of translating "j" to either "l" or "ll" depending on a compile-time sizeof() check, just as was done long ago to support "z" for size_t. One could imagine promoting intmax_t to have full support in snprintf.c, for example converting fmtint()'s value argument and internal arithmetic to use [u]intmax_t not [unsigned] long long. But that'd be more work and I'm hesitant to do it anyway: if there are any platforms out there where intmax_t is actually wider than "long long", this would doubtless result in a noticeable speed penalty to snprintf(). Let's not go there until we have positive evidence that there's a reason to, and some way to measure what size of penalty we're taking. Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/3210703.1765236740@sss.pgh.pa.us
1 parent 3cb5808 commit f8715ec

File tree

5 files changed

+57
-0
lines changed

5 files changed

+57
-0
lines changed

configure

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16853,6 +16853,39 @@ cat >>confdefs.h <<_ACEOF
1685316853
_ACEOF
1685416854

1685516855

16856+
# The cast to long int works around a bug in the HP C Compiler
16857+
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
16858+
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
16859+
# This bug is HP SR number 8606223364.
16860+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of intmax_t" >&5
16861+
$as_echo_n "checking size of intmax_t... " >&6; }
16862+
if ${ac_cv_sizeof_intmax_t+:} false; then :
16863+
$as_echo_n "(cached) " >&6
16864+
else
16865+
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (intmax_t))" "ac_cv_sizeof_intmax_t" "$ac_includes_default"; then :
16866+
16867+
else
16868+
if test "$ac_cv_type_intmax_t" = yes; then
16869+
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
16870+
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
16871+
as_fn_error 77 "cannot compute sizeof (intmax_t)
16872+
See \`config.log' for more details" "$LINENO" 5; }
16873+
else
16874+
ac_cv_sizeof_intmax_t=0
16875+
fi
16876+
fi
16877+
16878+
fi
16879+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_intmax_t" >&5
16880+
$as_echo "$ac_cv_sizeof_intmax_t" >&6; }
16881+
16882+
16883+
16884+
cat >>confdefs.h <<_ACEOF
16885+
#define SIZEOF_INTMAX_T $ac_cv_sizeof_intmax_t
16886+
_ACEOF
16887+
16888+
1685616889

1685716890
# Determine memory alignment requirements for the basic C data types.
1685816891

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,6 +1983,7 @@ AC_CHECK_SIZEOF([void *])
19831983
AC_CHECK_SIZEOF([size_t])
19841984
AC_CHECK_SIZEOF([long])
19851985
AC_CHECK_SIZEOF([long long])
1986+
AC_CHECK_SIZEOF([intmax_t])
19861987

19871988
# Determine memory alignment requirements for the basic C data types.
19881989

meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,8 @@ cdata.set('SIZEOF_LONG', cc.sizeof('long', args: test_c_args))
17761776
cdata.set('SIZEOF_LONG_LONG', cc.sizeof('long long', args: test_c_args))
17771777
cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
17781778
cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1779+
cdata.set('SIZEOF_INTMAX_T', cc.sizeof('intmax_t', args: test_c_args,
1780+
prefix: '#include <stdint.h>'))
17791781

17801782

17811783
# Check if __int128 is a working 128 bit integer type, and if so

src/include/pg_config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,9 @@
645645
RELSEG_SIZE requires an initdb. */
646646
#undef RELSEG_SIZE
647647

648+
/* The size of `intmax_t', as computed by sizeof. */
649+
#undef SIZEOF_INTMAX_T
650+
648651
/* The size of `long', as computed by sizeof. */
649652
#undef SIZEOF_LONG
650653

src/port/snprintf.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,15 @@ dopr(PrintfTarget *target, const char *format, va_list args)
563563
else
564564
longflag = 1;
565565
goto nextch2;
566+
case 'j':
567+
#if SIZEOF_INTMAX_T == SIZEOF_LONG
568+
longflag = 1;
569+
#elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
570+
longlongflag = 1;
571+
#else
572+
#error "cannot find integer type of the same size as intmax_t"
573+
#endif
574+
goto nextch2;
566575
case 'z':
567576
#if SIZEOF_SIZE_T == SIZEOF_LONG
568577
longflag = 1;
@@ -826,6 +835,15 @@ find_arguments(const char *format, va_list args,
826835
else
827836
longflag = 1;
828837
goto nextch1;
838+
case 'j':
839+
#if SIZEOF_INTMAX_T == SIZEOF_LONG
840+
longflag = 1;
841+
#elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
842+
longlongflag = 1;
843+
#else
844+
#error "cannot find integer type of the same size as intmax_t"
845+
#endif
846+
goto nextch1;
829847
case 'z':
830848
#if SIZEOF_SIZE_T == SIZEOF_LONG
831849
longflag = 1;

0 commit comments

Comments
 (0)