Using uintmax_t in a public header file is problematic. The most
obvious problem is that we need to include either <inttypes.h> or
<stdint.h> to get it, and the current unconditional inclusion of
<stdint.h> breaks on e.g., HP-UX 11 which only has <inttypes.h>
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.
19 files changed:
nodist_include_HEADERS = src/config/cdecl.h
src/config/cdecl.h: config.h src/cdecl.h $(DX_BASEDIR)/scripts/bake-config.awk
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
config.h $(srcdir)/src/cdecl.h >$@-t
$(AM_V_at) mv -f $@-t $@
EXTRA_DIST += $(DX_BASEDIR)/scripts/bake-config.awk
-Subproject commit aaaacebf1f04c364803f308c3b3e9670e216da09
+Subproject commit 2f638e51e602982648087e00c788a4751f1a4a8c
gl_EARLY
AC_HEADER_ASSERT
gl_EARLY
AC_HEADER_ASSERT
+AC_TYPE_UNSIGNED_LONG_LONG_INT
AC_C_FLEXIBLE_ARRAY_MEMBER
AC_C_INLINE
DX_C_FOR_DECLARATIONS
AC_C_FLEXIBLE_ARRAY_MEMBER
AC_C_INLINE
DX_C_FOR_DECLARATIONS
.Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
.Os cdecl99
.Sh NAME
.Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
.Os cdecl99
.Sh NAME
-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
The library is thread-safe when appropriate facilities exist and are enabled at
build time.
.Sh NAMESPACE
of type qualifiers.
.Ss Array Declarators
.Bd -literal -offset indent
of type qualifiers.
.Ss Array Declarators
.Bd -literal -offset indent
+typedef unsigned long long cdecl_uintmax; /* depends on configuration */
struct cdecl_array {
char *vla;
struct cdecl_array {
char *vla;
.Va length
is positive, then this is an array declarator with the specified length.
Otherwise, this is an incomplete array declarator.
.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 */
.Ss Function Declarators
.Bd -literal -offset indent
typedef _Bool cdecl_bool; /* depends on configuration */
.Sh AUTHORS
Nick Bowler <nbowler@draconx.ca>
.Sh COPYRIGHT
.Sh AUTHORS
Nick Bowler <nbowler@draconx.ca>
.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
.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
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__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,
size_t cdecl__strlcpy(char *dst, const char *src, size_t len);
const char *cdecl__emit_specs(struct output_state *dst,
- * 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
*
* 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
#ifndef CDECL_H_
#define CDECL_H_
#ifndef CDECL_H_
#define CDECL_H_
-#include <stddef.h>
-#include <stdint.h>
+#include <stddef.h> /* for size_t */
#if __GNUC__
# define CDECL__INLINE __inline
#if __GNUC__
# define CDECL__INLINE __inline
typedef signed char cdecl_bool;
#endif
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,
/* Declaration specifier kinds. */
enum {
CDECL_SPEC_TYPE = 256,
} pointer;
struct cdecl_array {
char *vla;
} pointer;
struct cdecl_array {
char *vla;
} array;
struct cdecl_function {
struct cdecl *parameters;
} array;
struct cdecl_function {
struct cdecl *parameters;
#include <locale.h>
#include <assert.h>
#include <stdarg.h>
#include <locale.h>
#include <assert.h>
#include <stdarg.h>
#include <getopt.h>
#include <gettext.h>
#include <getopt.h>
#include <gettext.h>
#include <config.h>
#include <stdio.h>
#include <stdbool.h>
#include <config.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include "cdecl.h"
#include <assert.h>
#include "cdecl.h"
retry:
rc = fmt_err(state, fmt, arg);
if (rc >= state->nstr) {
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)
state = alloc_err_state(state, (size_t)(rc+1u) * 3 / 2);
if (!state)
- * 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
*
* 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
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "cdecl99.h"
#include <assert.h>
#include "cdecl99.h"
-# Copyright © 2023 Nick Bowler
+# Copyright © 2023-2024 Nick Bowler
#
# Hackjob to improve the horrible yytname array generated by Bison.
#
#
# Hackjob to improve the horrible yytname array generated by Bison.
#
# At the end of the yytname definition, output our replacement function.
in_table && $0 ~ /^};/ {
print "#if !defined(UINT_LEAST8_MAX) || !defined(UINT_LEAST16_MAX)";
# 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 <stdint.h>";
+ print "# include <inttypes.h>";
print "#endif";
print "#ifndef assert";
print "# include <assert.h>";
print "#endif";
print "#ifndef assert";
print "# include <assert.h>";
- * 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
*
* 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
#include <string.h>
#include <stdbool.h>
#include <string.h>
#include <stdbool.h>
enum { INTCONV_OCTAL = 8, INTCONV_DECIMAL = 10, INTCONV_HEXADECIMAL = 16 };
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.
*
* 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.
*/
* 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)
+ cdecl_uintmax old_v = *v;
- if (old_v > (uintmax_t)-1 / base)
+ if (old_v > (cdecl_uintmax)-1 / base)
return false;
old_v *= base;
return false;
old_v *= base;
/*
* Helper functions for outputting text.
/*
* 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
*
* 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
*/
#include <config.h>
#include <stdio.h>
*/
#include <config.h>
#include <stdio.h>
#include <assert.h>
#include "cdecl.h"
#include <assert.h>
#include "cdecl.h"
return cdecl__advance(dst, rc);
}
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.
- */
-#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];
{
char buf[MAX_UINT_DIGITS + 1], *p = &buf[sizeof buf];
#include <stdbool.h>
#include "scan.h"
#include <stdbool.h>
#include "scan.h"
#include "cdecl-internal.h"
#include "errmsg.h"
#include "cdecl-internal.h"
#include "errmsg.h"
%code requires {
#include <inttypes.h>
#include <stdbool.h>
%code requires {
#include <inttypes.h>
#include <stdbool.h>
unsigned spectype;
bool boolval;
struct cdecl_declspec *declspec;
unsigned spectype;
bool boolval;
struct cdecl_declspec *declspec;
[1-9][0-9]* { intconv_base = INTCONV_DECIMAL; goto int_parse; }
0[Xx][[:xdigit:]]+ {
unsigned char d;
[1-9][0-9]* { intconv_base = INTCONV_DECIMAL; goto int_parse; }
0[Xx][[:xdigit:]]+ {
unsigned char d;
yytext += 2;
intconv_base = INTCONV_HEXADECIMAL;
yytext += 2;
intconv_base = INTCONV_HEXADECIMAL;
/*
* Generate random C declarations for testing.
/*
* 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
*
* 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
return gen_randomize_specs(rng, s);
}
return gen_randomize_specs(rng, s);
}
-static uintmax_t gen_uintmax(struct test_rng *rng)
+static cdecl_uintmax gen_uintmax(struct test_rng *rng)
size_t i;
for (i = 0; i < sizeof ret; i++) {
size_t i;
for (i = 0; i < sizeof ret; i++) {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <errno.h>
#include <limits.h>
#if !TEST_RNG_NO_EXTERNAL_API
struct test_rng *test_rng_alloc(const char *seed_str)
{
#if !TEST_RNG_NO_EXTERNAL_API
struct test_rng *test_rng_alloc(const char *seed_str)
{
+ test_uintmax limit, seed_val;
- uintmax_t limit, seed_val;
- limit = (uintmax_t)0xffffffff;
limit |= (limit << 16 << 16);
if (!test_strtoumax(&seed_val, seed_str, limit)) {
limit |= (limit << 16 << 16);
if (!test_strtoumax(&seed_val, seed_str, limit)) {
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#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
+ * <cdecl.h>, 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;
struct cdecl_declspec;
struct option;
struct cdecl;
void *malloc_nofail(size_t size);
void *realloc_nofail(void *ptr, size_t size);
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)
{
static inline bool test_strtoul(unsigned long *val, const char *str)
{
bool rc;
rc = test_strtoumax(&v, str, (unsigned long)-1);
bool rc;
rc = test_strtoumax(&v, str, (unsigned long)-1);
return INTCONV_DECIMAL;
}
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);
{
static const char idx[] = "0123456789abcdef0123456789ABCDEF";
unsigned base = intconv_base(&s);
char *c, d;
for (v = 0; (d = *s++);) {
char *c, d;
for (v = 0; (d = *s++);) {