From: Nick Bowler Date: Thu, 18 Jan 2024 05:17:06 +0000 (-0500) Subject: libcdecl: Replace uintmax_t with unsigned (long) long. X-Git-Tag: v1.3~29 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/486349a83f783742b9d148447c6119eb76d4ead0 libcdecl: Replace uintmax_t with unsigned (long) long. Using uintmax_t in a public header file is problematic. The most obvious problem is that we need to include either or to get it, and the current unconditional inclusion of breaks on e.g., HP-UX 11 which only has The less obvious problem is that uintmax_t can depend on compiler configuration, e.g., the Sun compiler for a 32-bit host provides a 32-bit uintmax_t in C89 mode. Instead, just change it to "unsigned long long" if supported, otherwise "unsigned long". It is very likely to be binary compatible with prior releases, since as far as I am aware prior releases don't actually build on any implementation where it would not be the case. --- diff --git a/Makefile.am b/Makefile.am index 1aa6a56..cb50bfc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,7 +39,7 @@ noinst_DATA = $(MOFILES) nodist_include_HEADERS = src/config/cdecl.h src/config/cdecl.h: config.h src/cdecl.h $(DX_BASEDIR)/scripts/bake-config.awk - $(AM_V_at) $(AWK) -f $(DX_BASEDIR)/scripts/bake-config.awk \ + $(AM_V_GEN) $(AWK) -f $(DX_BASEDIR)/scripts/bake-config.awk \ config.h $(srcdir)/src/cdecl.h >$@-t $(AM_V_at) mv -f $@-t $@ EXTRA_DIST += $(DX_BASEDIR)/scripts/bake-config.awk diff --git a/common b/common index aaaaceb..2f638e5 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit aaaacebf1f04c364803f308c3b3e9670e216da09 +Subproject commit 2f638e51e602982648087e00c788a4751f1a4a8c diff --git a/configure.ac b/configure.ac index 435eaf9..62715e8 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,7 @@ AM_PROG_CC_C_O gl_EARLY AC_HEADER_ASSERT +AC_TYPE_UNSIGNED_LONG_LONG_INT AC_C_FLEXIBLE_ARRAY_MEMBER AC_C_INLINE DX_C_FOR_DECLARATIONS diff --git a/doc/libcdecl.3 b/doc/libcdecl.3 index 4a882a0..725566b 100644 --- a/doc/libcdecl.3 +++ b/doc/libcdecl.3 @@ -1,4 +1,4 @@ -.Dd December 3, 2023 +.Dd January 17, 2024 .Dt LIBCDECL \&3 "Cdecl99 Developer's Manual" .Os cdecl99 .Sh NAME @@ -29,8 +29,7 @@ see the manual page. .Pp .Nm -is intended to be portable to any system with a working C implementation that -at least makes an effort to support C99. +is intended to be portable to any system with a standard C compiler. The library is thread-safe when appropriate facilities exist and are enabled at build time. .Sh NAMESPACE @@ -248,9 +247,10 @@ member is non-null, then it points to the first element of a singly-linked list of type qualifiers. .Ss Array Declarators .Bd -literal -offset indent +typedef unsigned long long cdecl_uintmax; /* depends on configuration */ struct cdecl_array { char *vla; - uintmax_t length; + cdecl_uintmax length; }; .Ed .Pp @@ -265,6 +265,19 @@ Otherwise, if .Va length is positive, then this is an array declarator with the specified length. Otherwise, this is an incomplete array declarator. +.Pp +If the library was configured using a compiler which does not support +.Vt unsigned long long , +then the +.Vt cdecl_uintmax +type is defined as +.Vt unsigned long +instead. +Prior versions of +.Nm +used +.Vt uintmax_t +directly. .Ss Function Declarators .Bd -literal -offset indent typedef _Bool cdecl_bool; /* depends on configuration */ @@ -439,7 +452,7 @@ is non-zero, the resulting string is '\\0' terminated even if it was truncated. .Sh AUTHORS Nick Bowler .Sh COPYRIGHT -Copyright \(co 2011\(en2012, 2021, 2023 Nick Bowler +Copyright \(co 2011\(en2012, 2021, 2023\(en2024 Nick Bowler .Pp Permission is granted to copy, distribute and/or modify this manual under the terms of the GNU General Public License as published by the Free Software diff --git a/src/cdecl-internal.h b/src/cdecl-internal.h index b586dd4..dc8d1f0 100644 --- a/src/cdecl-internal.h +++ b/src/cdecl-internal.h @@ -83,7 +83,7 @@ struct output_state { size_t cdecl__advance(struct output_state *dst, size_t amount); size_t cdecl__emit(struct output_state *dst, const char *src); -size_t cdecl__emit_uint(struct output_state *dst, uintmax_t val); +size_t cdecl__emit_uint(struct output_state *dst, cdecl_uintmax val); size_t cdecl__strlcpy(char *dst, const char *src, size_t len); const char *cdecl__emit_specs(struct output_state *dst, diff --git a/src/cdecl.h b/src/cdecl.h index 63034f4..952b0aa 100644 --- a/src/cdecl.h +++ b/src/cdecl.h @@ -1,5 +1,5 @@ /* - * Copyright © 2011, 2021, 2023 Nick Bowler + * Copyright © 2011, 2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,8 +18,7 @@ #ifndef CDECL_H_ #define CDECL_H_ -#include -#include +#include /* for size_t */ #if __GNUC__ # define CDECL__INLINE __inline @@ -34,6 +33,12 @@ typedef _Bool cdecl_bool; typedef signed char cdecl_bool; #endif +#if HAVE_UNSIGNED_LONG_LONG_INT +typedef unsigned long long cdecl_uintmax; +#else +typedef unsigned long cdecl_uintmax; +#endif + /* Declaration specifier kinds. */ enum { CDECL_SPEC_TYPE = 256, @@ -98,7 +103,7 @@ struct cdecl { } pointer; struct cdecl_array { char *vla; - uintmax_t length; + cdecl_uintmax length; } array; struct cdecl_function { struct cdecl *parameters; diff --git a/src/cdecl99.c b/src/cdecl99.c index 3eb7cc1..1d8dff0 100644 --- a/src/cdecl99.c +++ b/src/cdecl99.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/src/declare.c b/src/declare.c index 5c11381..c5a1f23 100644 --- a/src/declare.c +++ b/src/declare.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "cdecl.h" diff --git a/src/error.c b/src/error.c index a2d705a..94987af 100644 --- a/src/error.c +++ b/src/error.c @@ -180,7 +180,7 @@ void cdecl__err(const char *fmt, const char *arg) retry: rc = fmt_err(state, fmt, arg); if (rc >= state->nstr) { - assert(try++ == 0 && rc < SIZE_MAX / 4); + assert(try++ == 0 && rc < (size_t)-1 / 4); state = alloc_err_state(state, (size_t)(rc+1u) * 3 / 2); if (!state) diff --git a/src/execute.gperf b/src/execute.gperf index a45413d..51443ba 100644 --- a/src/execute.gperf +++ b/src/execute.gperf @@ -1,6 +1,6 @@ %{ /* - * Copyright © 2021, 2023 Nick Bowler + * Copyright © 2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "cdecl99.h" diff --git a/src/fix-yytname.awk b/src/fix-yytname.awk index 8a417b3..4f46871 100755 --- a/src/fix-yytname.awk +++ b/src/fix-yytname.awk @@ -1,6 +1,6 @@ #!/bin/awk -f # -# Copyright © 2023 Nick Bowler +# Copyright © 2023-2024 Nick Bowler # # Hackjob to improve the horrible yytname array generated by Bison. # @@ -95,7 +95,7 @@ in_table { # At the end of the yytname definition, output our replacement function. in_table && $0 ~ /^};/ { print "#if !defined(UINT_LEAST8_MAX) || !defined(UINT_LEAST16_MAX)"; - print "# include "; + print "# include "; print "#endif"; print "#ifndef assert"; print "# include "; diff --git a/src/intconv.h b/src/intconv.h index 17644f2..6cc7819 100644 --- a/src/intconv.h +++ b/src/intconv.h @@ -1,5 +1,5 @@ /* - * Copyright © 2023 Nick Bowler + * Copyright © 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ #include #include -#include enum { INTCONV_OCTAL = 8, INTCONV_DECIMAL = 10, INTCONV_HEXADECIMAL = 16 }; @@ -28,14 +27,14 @@ enum { INTCONV_OCTAL = 8, INTCONV_DECIMAL = 10, INTCONV_HEXADECIMAL = 16 }; * Multiply *v by base, which must be one of the above enumeration constants, * and add digit, updating *v with the result. * - * If the result does not fit in uintmax_t, then 0 is returned. Otherwise, + * If the result does not fit in cdecl_uintmax, then 0 is returned. Otherwise, * a non-zero result is returned. */ -static inline bool intconv_shift(uintmax_t *v, unsigned base, unsigned digit) +static inline bool intconv_shift(cdecl_uintmax *v, unsigned base, unsigned digit) { - uintmax_t old_v = *v; + cdecl_uintmax old_v = *v; - if (old_v > (uintmax_t)-1 / base) + if (old_v > (cdecl_uintmax)-1 / base) return false; old_v *= base; diff --git a/src/output.c b/src/output.c index c0438e6..634b79e 100644 --- a/src/output.c +++ b/src/output.c @@ -1,6 +1,6 @@ /* * Helper functions for outputting text. - * Copyright © 2011, 2021, 2023 Nick Bowler + * Copyright © 2011, 2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ */ #include #include +#include #include #include "cdecl.h" @@ -55,29 +56,15 @@ size_t cdecl__emit(struct output_state *dst, const char *src) return cdecl__advance(dst, rc); } -/* - * 31 decimal digits is enough for values up to 2^102 - 1. - * 63 decimal digits is enough for values up to 2^209 - 1. - * - * We can't portably write numbers this large in preprocessor conditionals, - * but since the maximum values of unsigned integer types are always one - * less than a power of two, we can use a sequence of small shifts to infer - * the bounds. - * - * All known implementations have 64-bit uintmax_t. Leave some headroom - * to support a possible future implementatons with 128-bit uintmax_t. - */ enum { -#if (UINTMAX_MAX >> 27 >> 27 >> 26 >> 26) == 0 - MAX_UINT_DIGITS = 31 -#elif (UINTMAX_MAX >> 27 >> 26 >> 26 >> 26 >> 26 >> 26 >> 26 >> 26) == 0 - MAX_UINT_DIGITS = 63 -#else -# error UINTMAX_MAX is too large, please report a bug. -#endif + /* + * upper bound on number of decimal digits required to convert + * cdecl_uintmax. + */ + MAX_UINT_DIGITS = (CHAR_BIT * sizeof (cdecl_uintmax) + 2)/3 }; -size_t cdecl__emit_uint(struct output_state *dst, uintmax_t val) +size_t cdecl__emit_uint(struct output_state *dst, cdecl_uintmax val) { char buf[MAX_UINT_DIGITS + 1], *p = &buf[sizeof buf]; diff --git a/src/parse.y b/src/parse.y index 8abc21a..80801c3 100644 --- a/src/parse.y +++ b/src/parse.y @@ -32,7 +32,6 @@ #include #include "scan.h" -#include "cdecl.h" #include "cdecl-internal.h" #include "errmsg.h" @@ -120,6 +119,7 @@ static size_t yytnamerr_copy(char *dst, const char *src) %code requires { #include #include +#include "cdecl.h" } %code provides { @@ -129,7 +129,7 @@ const char *cdecl__token_name(unsigned token); } %union { - uintmax_t uintval; + cdecl_uintmax uintval; unsigned spectype; bool boolval; struct cdecl_declspec *declspec; diff --git a/src/scan.l b/src/scan.l index f7e1b03..5d460ed 100644 --- a/src/scan.l +++ b/src/scan.l @@ -183,7 +183,7 @@ IDENT [_[:alpha:]][-_[:alnum:]]* [1-9][0-9]* { intconv_base = INTCONV_DECIMAL; goto int_parse; } 0[Xx][[:xdigit:]]+ { unsigned char d; - uintmax_t v; + cdecl_uintmax v; yytext += 2; intconv_base = INTCONV_HEXADECIMAL; diff --git a/t/declgen.c b/t/declgen.c index 630ab90..9824c40 100644 --- a/t/declgen.c +++ b/t/declgen.c @@ -1,6 +1,6 @@ /* * Generate random C declarations for testing. - * Copyright © 2012, 2021-2023 Nick Bowler + * Copyright © 2012, 2021-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -288,10 +288,10 @@ gen_declspecs(struct test_rng *rng, unsigned flags) return gen_randomize_specs(rng, s); } -static uintmax_t gen_uintmax(struct test_rng *rng) +static cdecl_uintmax gen_uintmax(struct test_rng *rng) { + cdecl_uintmax ret = 0; unsigned char tmp; - uintmax_t ret = 0; size_t i; for (i = 0; i < sizeof ret; i++) { diff --git a/t/rng.c b/t/rng.c index e442d99..a827b2e 100644 --- a/t/rng.c +++ b/t/rng.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -75,11 +74,11 @@ static unsigned long long splitmix64(unsigned long long *state) #if !TEST_RNG_NO_EXTERNAL_API struct test_rng *test_rng_alloc(const char *seed_str) { + test_uintmax limit, seed_val; unsigned long long seed; - uintmax_t limit, seed_val; struct test_rng *rng; - limit = (uintmax_t)0xffffffff; + limit = 0xffffffff; limit |= (limit << 16 << 16); if (!test_strtoumax(&seed_val, seed_str, limit)) { diff --git a/t/test.h b/t/test.h index 2e7882d..32b4e8c 100644 --- a/t/test.h +++ b/t/test.h @@ -30,6 +30,16 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) +/* + * The test_uintmax typedef is interchangeable with cdecl_uintmax defined in + * , but we may want to avoid including that header for some tests. + */ +#if HAVE_UNSIGNED_LONG_LONG_INT +typedef unsigned long long test_uintmax; +#else +typedef unsigned long test_uintmax; +#endif + struct cdecl_declspec; struct option; struct cdecl; @@ -41,11 +51,11 @@ void print_error(const char *fmt, ...); void *malloc_nofail(size_t size); void *realloc_nofail(void *ptr, size_t size); -bool test_strtoumax(uintmax_t *out, const char *s, uintmax_t limit); +bool test_strtoumax(test_uintmax *out, const char *s, test_uintmax limit); static inline bool test_strtoul(unsigned long *val, const char *str) { - uintmax_t v; + test_uintmax v; bool rc; rc = test_strtoumax(&v, str, (unsigned long)-1); diff --git a/t/testlib.c b/t/testlib.c index dd9e073..c417839 100644 --- a/t/testlib.c +++ b/t/testlib.c @@ -76,11 +76,11 @@ static unsigned intconv_base(const char **str) return INTCONV_DECIMAL; } -bool test_strtoumax(uintmax_t *out, const char *s, uintmax_t limit) +bool test_strtoumax(cdecl_uintmax *out, const char *s, cdecl_uintmax limit) { static const char idx[] = "0123456789abcdef0123456789ABCDEF"; unsigned base = intconv_base(&s); - uintmax_t v; + cdecl_uintmax v; char *c, d; for (v = 0; (d = *s++);) {