I have been hunting down the last few pieces of code that made some obsolete claims about not being able to use C99 yet or needing to be compatible with pre-C99 or something like that. I found two obsolete comments and two places where we could now actually use the C99 functionality that the comment was anticipating.

At least according to my grepping, all the remaining mentions of "C99" are now up to date and relevant.
From 6ba9a93498de3f73c14706463c6ed2c47577f223 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Sun, 2 Nov 2025 21:12:53 +0100
Subject: [PATCH 1/4] Replace internal C function pg_hypot() by standard
 hypot()

The code comment said, "It is expected that this routine will
eventually be replaced with the C99 hypot() function.", so let's do
that now.
---
 src/backend/access/spgist/spgproc.c |  2 +-
 src/backend/utils/adt/geo_ops.c     | 76 ++---------------------------
 src/backend/utils/adt/geo_spgist.c  |  2 +-
 src/include/utils/geo_decls.h       |  8 ---
 4 files changed, 6 insertions(+), 82 deletions(-)

diff --git a/src/backend/access/spgist/spgproc.c 
b/src/backend/access/spgist/spgproc.c
index 660009291da..722c17ce2e5 100644
--- a/src/backend/access/spgist/spgproc.c
+++ b/src/backend/access/spgist/spgproc.c
@@ -51,7 +51,7 @@ point_box_distance(Point *point, BOX *box)
        else
                dy = 0.0;
 
-       return HYPOT(dx, dy);
+       return hypot(dx, dy);
 }
 
 /*
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 377a1b3f3ad..9101a720744 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1276,7 +1276,7 @@ line_distance(PG_FUNCTION_ARGS)
 
        PG_RETURN_FLOAT8(float8_div(fabs(float8_mi(l1->C,
                                                                                
           float8_mul(ratio, l2->C))),
-                                                               HYPOT(l1->A, 
l1->B)));
+                                                               hypot(l1->A, 
l1->B)));
 }
 
 /* line_interpt()
@@ -2001,7 +2001,7 @@ point_distance(PG_FUNCTION_ARGS)
 static inline float8
 point_dt(Point *pt1, Point *pt2)
 {
-       return HYPOT(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
+       return hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y));
 }
 
 Datum
@@ -5005,7 +5005,7 @@ circle_mul_pt(PG_FUNCTION_ARGS)
        result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
        point_mul_point(&result->center, &circle->center, point);
-       result->radius = float8_mul(circle->radius, HYPOT(point->x, point->y));
+       result->radius = float8_mul(circle->radius, hypot(point->x, point->y));
 
        PG_RETURN_CIRCLE_P(result);
 }
@@ -5020,7 +5020,7 @@ circle_div_pt(PG_FUNCTION_ARGS)
        result = (CIRCLE *) palloc(sizeof(CIRCLE));
 
        point_div_point(&result->center, &circle->center, point);
-       result->radius = float8_div(circle->radius, HYPOT(point->x, point->y));
+       result->radius = float8_div(circle->radius, hypot(point->x, point->y));
 
        PG_RETURN_CIRCLE_P(result);
 }
@@ -5492,71 +5492,3 @@ plist_same(int npts, Point *p1, Point *p2)
 
        return false;
 }
-
-
-/*-------------------------------------------------------------------------
- * Determine the hypotenuse.
- *
- * If required, x and y are swapped to make x the larger number. The
- * traditional formula of x^2+y^2 is rearranged to factor x outside the
- * sqrt. This allows computation of the hypotenuse for significantly
- * larger values, and with a higher precision than when using the naive
- * formula.  In particular, this cannot overflow unless the final result
- * would be out-of-range.
- *
- * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
- *                                      = x * sqrt( 1 + y^2/x^2 )
- *                                      = x * sqrt( 1 + y/x * y/x )
- *
- * It is expected that this routine will eventually be replaced with the
- * C99 hypot() function.
- *
- * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
- * case of hypot(inf,nan) results in INF, and not NAN.
- *-----------------------------------------------------------------------
- */
-float8
-pg_hypot(float8 x, float8 y)
-{
-       float8          yx,
-                               result;
-
-       /* Handle INF and NaN properly */
-       if (isinf(x) || isinf(y))
-               return get_float8_infinity();
-
-       if (isnan(x) || isnan(y))
-               return get_float8_nan();
-
-       /* Else, drop any minus signs */
-       x = fabs(x);
-       y = fabs(y);
-
-       /* Swap x and y if needed to make x the larger one */
-       if (x < y)
-       {
-               float8          temp = x;
-
-               x = y;
-               y = temp;
-       }
-
-       /*
-        * If y is zero, the hypotenuse is x.  This test saves a few cycles in
-        * such cases, but more importantly it also protects against
-        * divide-by-zero errors, since now x >= y.
-        */
-       if (y == 0.0)
-               return x;
-
-       /* Determine the hypotenuse */
-       yx = y / x;
-       result = x * sqrt(1.0 + (yx * yx));
-
-       if (unlikely(isinf(result)))
-               float_overflow_error();
-       if (unlikely(result == 0.0))
-               float_underflow_error();
-
-       return result;
-}
diff --git a/src/backend/utils/adt/geo_spgist.c 
b/src/backend/utils/adt/geo_spgist.c
index fec33e95372..4308a3065cd 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -390,7 +390,7 @@ pointToRectBoxDistance(Point *point, RectBox *rect_box)
        else
                dy = 0;
 
-       return HYPOT(dx, dy);
+       return hypot(dx, dy);
 }
 
 
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 8a9df75c93c..d4f7ea31f62 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -88,7 +88,6 @@ FPge(double A, double B)
 #define FPge(A,B)                              ((A) >= (B))
 #endif
 
-#define HYPOT(A, B)                            pg_hypot(A, B)
 
 /*---------------------------------------------------------------------
  * Point - (x,y)
@@ -275,11 +274,4 @@ CirclePGetDatum(const CIRCLE *X)
 #define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n))
 #define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x)
 
-
-/*
- * in geo_ops.c
- */
-
-extern float8 pg_hypot(float8 x, float8 y);
-
 #endif                                                 /* GEO_DECLS_H */
-- 
2.51.0

From 5eff322218b1bfa578686fd648592037640fa5a7 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Sun, 2 Nov 2025 21:14:12 +0100
Subject: [PATCH 2/4] Update comment related to C99

---
 src/bin/pg_dump/dumputils.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 10f6e27c0a0..57d36f386f0 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -26,8 +26,7 @@
  * localized, which means they may contain characters in various random
  * encodings; this has been seen to cause encoding errors when reading the
  * dump script.  Think not to get around that by using %z, because
- * (1) %z is not portable to pre-C99 systems, and
- * (2) %z doesn't actually act differently from %Z on Windows anyway.
+ * %z doesn't actually act differently from %Z on Windows.
  */
 #ifndef WIN32
 #define PGDUMP_STRFTIME_FMT  "%Y-%m-%d %H:%M:%S %Z"
-- 
2.51.0

From cd7e6fa5d2e0145bf961be55b3aed25faa3d7637 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 21 Nov 2025 13:59:28 +0100
Subject: [PATCH 3/4] Fix pg_isblank()

There was a pg_isblank() function that claimed to be a replacement for
the standard isblank() function, which was thought to be "not very
portable yet".  We can now assume that it's portable (it's in C99).

But pg_isblank() actually diverged from the standard isblank() by also
accepting '\r', while the standard one only accepts space and tab.
This was added to support parsing pg_hba.conf under Windows.  But the
hba parsing code now works completely differently and already handles
line endings before we get to pg_isblank().  The other user of
pg_isblank() is for ident protocol message parsing, which also handles
'\r' separately.  So this behavior is now obsolete and confusing.

To improve clarity, I separated those concerns.  The ident parsing now
gets its own function that hardcodes the whitespace characters
mentioned by the relevant RFC.  The hba parsing uses the standard
isblank().  pg_isblank() is removed.
---
 src/backend/libpq/auth.c | 17 +++++++++++++----
 src/backend/libpq/hba.c  | 15 ++-------------
 src/include/libpq/hba.h  |  1 -
 3 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index ec4dbacf015..5854a2433bb 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -1580,6 +1580,15 @@ pg_SSPI_make_upn(char *accountname,
  *----------------------------------------------------------------
  */
 
+/*
+ * Per RFC 1413, space and tab are whitespace in ident messages.
+ */
+static bool
+is_ident_whitespace(const char c)
+{
+       return c == ' ' || c == '\t';
+}
+
 /*
  *     Parse the string "*ident_response" as a response from a query to an 
Ident
  *     server.  If it's a normal response indicating a user name, return true
@@ -1613,14 +1622,14 @@ interpret_ident_response(const char *ident_response,
                        int                     i;              /* Index into 
*response_type */
 
                        cursor++;                       /* Go over colon */
-                       while (pg_isblank(*cursor))
+                       while (is_ident_whitespace(*cursor))
                                cursor++;               /* skip blanks */
                        i = 0;
-                       while (*cursor != ':' && *cursor != '\r' && 
!pg_isblank(*cursor) &&
+                       while (*cursor != ':' && *cursor != '\r' && 
!is_ident_whitespace(*cursor) &&
                                   i < (int) (sizeof(response_type) - 1))
                                response_type[i++] = *cursor++;
                        response_type[i] = '\0';
-                       while (pg_isblank(*cursor))
+                       while (is_ident_whitespace(*cursor))
                                cursor++;               /* skip blanks */
                        if (strcmp(response_type, "USERID") != 0)
                                return false;
@@ -1643,7 +1652,7 @@ interpret_ident_response(const char *ident_response,
                                        else
                                        {
                                                cursor++;       /* Go over 
colon */
-                                               while (pg_isblank(*cursor))
+                                               while 
(is_ident_whitespace(*cursor))
                                                        cursor++;       /* skip 
blanks */
                                                /* Rest of line is user name.  
Copy it over. */
                                                i = 0;
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 97a3586000b..787aee49d24 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -138,17 +138,6 @@ static int regexec_auth_token(const char *match, AuthToken 
*token,
 static void tokenize_error_callback(void *arg);
 
 
-/*
- * isblank() exists in the ISO C99 spec, but it's not very portable yet,
- * so provide our own version.
- */
-bool
-pg_isblank(const char c)
-{
-       return c == ' ' || c == '\t' || c == '\r';
-}
-
-
 /*
  * Grab one token out of the string pointed to by *lineptr.
  *
@@ -198,7 +187,7 @@ next_token(char **lineptr, StringInfo buf,
        *terminating_comma = false;
 
        /* Move over any whitespace and commas preceding the next token */
-       while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
+       while ((c = (*(*lineptr)++)) != '\0' && (isblank((unsigned char) c) || 
c == ','))
                ;
 
        /*
@@ -206,7 +195,7 @@ next_token(char **lineptr, StringInfo buf,
         * unquoted whitespace.
         */
        while (c != '\0' &&
-                  (!pg_isblank(c) || in_quote))
+                  (!isblank((unsigned char) c) || in_quote))
        {
                /* skip comments to EOL */
                if (c == '#' && !in_quote)
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index e3748d3c8c9..7b93ba4a709 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -181,7 +181,6 @@ extern int  check_usermap(const char *usermap_name,
                                                  bool case_insensitive);
 extern HbaLine *parse_hba_line(TokenizedAuthLine *tok_line, int elevel);
 extern IdentLine *parse_ident_line(TokenizedAuthLine *tok_line, int elevel);
-extern bool pg_isblank(const char c);
 extern FILE *open_auth_file(const char *filename, int elevel, int depth,
                                                        char **err_msg);
 extern void free_auth_file(FILE *file, int depth);
-- 
2.51.0

From be5395ae0ecbadcaa0015064b0f7325236211c33 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 21 Nov 2025 14:02:39 +0100
Subject: [PATCH 4/4] Remove obsolete comment

This comment should probably have been moved to pg_locale_libc.c in
commit 66ac94cdc79 (2024), but upon closer examination it was already
completely obsolete then.

The first part of the comment has been obsolete since commit
85feb77aa09 (2017), which required that the system provides the
required wide-character functions.

The second part has been obsolete since commit e9931bfb751 (2024),
which eliminated code paths depending on the global LC_CTYPE setting.
---
 src/backend/utils/adt/formatting.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/src/backend/utils/adt/formatting.c 
b/src/backend/utils/adt/formatting.c
index 5f7b3114da7..5bfeda2ffde 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1616,16 +1616,6 @@ str_numth(char *dest, const char *num, enum TH_Case type)
  *                     upper/lower/initcap functions
  *****************************************************************************/
 
-/*
- * If the system provides the needed functions for wide-character manipulation
- * (which are all standardized by C99), then we implement upper/lower/initcap
- * using wide-character functions, if necessary.  Otherwise we use the
- * traditional <ctype.h> functions, which of course will not work as desired
- * in multibyte character sets.  Note that in either case we are effectively
- * assuming that the database character encoding matches the encoding implied
- * by LC_CTYPE.
- */
-
 /*
  * collation-aware, wide-character-aware lower function
  *
-- 
2.51.0

Reply via email to