Print this page
Address Robert's feedback

@@ -10,23 +10,26 @@
  */
 
 /*
  * Copyright 2017 Jason King.
  */
-
+#include <ctype.h>
 #include <errno.h>
+#include <locale.h>
 #include <string.h>
 #include <setjmp.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/isa_defs.h>
 #include <sys/debug.h>
 #include "sysdemangle.h"
 #include "sysdemangle_int.h"
-#include "cpp.h"
+#include "cxx.h"
 
+#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
+#endif
 
 #define CPP_QUAL_CONST          (1U)
 #define CPP_QUAL_VOLATILE       (2U)
 #define CPP_QUAL_RESTRICT       (4U)
 

@@ -41,10 +44,11 @@
         unsigned        cpp_depth;
         boolean_t       cpp_parsed_ctor_dtor_cv;
         boolean_t       cpp_tag_templates;
         boolean_t       cpp_fix_forward_references;
         boolean_t       cpp_try_to_parse_template_args;
+        locale_t        cpp_loc;
 } cpp_db_t;
 
 #define CK(x)                                           \
         do {                                            \
                 if (!(x))                               \

@@ -53,12 +57,10 @@
 
 #define TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l))
 #define RLEN(f, l) ((size_t)((l) - (f)))
 #define NAMT(db, n) (nlen(db) - n)
 
-static inline boolean_t is_digit(int);
-static inline boolean_t is_upper(int);
 static inline boolean_t is_xdigit(int);
 
 static boolean_t nempty(cpp_db_t *);
 static size_t nlen(cpp_db_t *);
 static void nadd_l(cpp_db_t *, const char *, size_t);

@@ -74,11 +76,11 @@
 static void tsub(cpp_db_t *, size_t);
 static void tpush(cpp_db_t *);
 static void tpop(cpp_db_t *);
 static void tsave(cpp_db_t *, size_t);
 
-static void db_init(cpp_db_t *, sysdem_ops_t *);
+static boolean_t db_init(cpp_db_t *, sysdem_ops_t *);
 static void db_fini(cpp_db_t *);
 static void dump(cpp_db_t *, FILE *);
 
 static void demangle(const char *, const char *, cpp_db_t *);
 

@@ -89,20 +91,20 @@
 static const char *parse_dot_suffix(const char *, const char *, cpp_db_t *);
 static const char *parse_block_invoke(const char *, const char *, cpp_db_t *);
 static const char *parse_special_name(const char *, const char *, cpp_db_t *);
 static const char *parse_name(const char *, const char *, boolean_t *,
     cpp_db_t *);
-static const char *parse_call_offset(const char *, const char *);
-static const char *parse_number(const char *, const char *);
+static const char *parse_call_offset(const char *, const char *, locale_t);
+static const char *parse_number(const char *, const char *, locale_t);
 static const char *parse_nested_name(const char *, const char *, boolean_t *,
     cpp_db_t *);
 static const char *parse_local_name(const char *, const char *, boolean_t *,
     cpp_db_t *);
 static const char *parse_unscoped_name(const char *, const char *, cpp_db_t *);
 static const char *parse_template_args(const char *, const char *, cpp_db_t *);
 static const char *parse_substitution(const char *, const char *, cpp_db_t *);
-static const char *parse_discriminator(const char *, const char *);
+static const char *parse_discriminator(const char *, const char *, locale_t);
 static const char *parse_cv_qualifiers(const char *, const char *, unsigned *);
 static const char *parse_template_param(const char *, const char *, cpp_db_t *);
 static const char *parse_decltype(const char *, const char *, cpp_db_t *);
 static const char *parse_template_args(const char *, const char *, cpp_db_t *);
 static const char *parse_unqualified_name(const char *, const char *,

@@ -164,12 +166,12 @@
 {
         char *result = NULL;
         cpp_db_t db;
         size_t srclen = strlen(src);
 
-        db_init(&db, ops);
-
+        if (!db_init(&db, ops))
+                goto done;
         if (setjmp(db.cpp_jmp) != 0)
                 goto done;
 
         errno = 0;
         demangle(src, src + srclen, &db);

@@ -269,11 +271,11 @@
 }
 
 static const char *
 parse_dot_suffix(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last || first[0] != '.')
                 return (first);
 
         if (nempty(db))

@@ -291,11 +293,11 @@
  * _block_invoke_<digit>+
  */
 static const char *
 parse_block_invoke(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 13)
                 return (first);
 
         const char test[] = "_block_invoke";

@@ -308,16 +310,16 @@
         if (t == last)
                 goto done;
 
         if (t[0] == '_') {
                 /* need at least one digit */
-                if (t + 1 == last || !is_digit(t[1]))
+                if (t + 1 == last || !isdigit_l(t[1], db->cpp_loc))
                         return (first);
                 t += 2;
         }
 
-        while (t < last && is_digit(t[0]))
+        while (t < last && isdigit_l(t[0], db->cpp_loc))
                 t++;
 
 done:
         if (nempty(db))
                 return (first);

@@ -332,11 +334,11 @@
  *            ::= <special name>
  */
 static const char *
 parse_encoding(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         const char *t = NULL;

@@ -405,11 +407,11 @@
          * a bit of a hack, but a template substitution can apparently be
          * an empty string at the end of an argument list, so avoid
          * <...., >
          */
         if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0)
-                (void) name_pop(&db->cpp_name, NULL);
+                name_pop(&db->cpp_name, NULL);
 
         njoin(db, NAMT(db, n), ", ");
         nfmt(db, "({0})", NULL);
 
         str_t *s = TOP_L(db);

@@ -463,11 +465,11 @@
  *      extension ::= GR <object name> # reference temporary for object
  */
 static const char *
 parse_special_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = first;
         const char *t1 = NULL;
         size_t n = nlen(db);
 

@@ -493,14 +495,14 @@
                         nadd_l(db, "typeinfo name for", 0);
                         t = parse_type(first + 2, last, db);
                         break;
                 case 'c':
                         nadd_l(db, "covariant return thunk to", 0);
-                        t1 = parse_call_offset(first + 2, last);
+                        t1 = parse_call_offset(first + 2, last, db->cpp_loc);
                         if (t1 == t)
                                 return (first);
-                        t = parse_call_offset(t1, last);
+                        t = parse_call_offset(t1, last, db->cpp_loc);
                         if (t == t1)
                                 return (first);
                         t1 = parse_encoding(t, last, db);
                         if (t1 == t)
                                 return (first);

@@ -507,11 +509,11 @@
                         break;
                 case 'C':
                         t = parse_type(first + 2, last, db);
                         if (t == first + 2)
                                 return (first);
-                        t1 = parse_number(t, last);
+                        t1 = parse_number(t, last, db->cpp_loc);
                         if (*t1 != '_')
                                 return (first);
                         t = parse_type(t1 + 1, last, db);
                         if (t == t1 + 1 || nlen(db) < 2)
                                 return (first);

@@ -531,11 +533,11 @@
                                 nadd_l(db, "virtual thunk to", 0);
                         } else {
                                 nadd_l(db, "non-virtual thunk to", 0);
                         }
 
-                        t = parse_call_offset(first + 1, last);
+                        t = parse_call_offset(first + 1, last, db->cpp_loc);
                         if (t == first + 1)
                                 return (first);
                         t1 = parse_encoding(t, last, db);
                         if (t == t1)
                                 return (first);

@@ -578,13 +580,13 @@
  *
  * <v-offset>  ::= <offset number> _ <virtual offset number>
  *               # virtual base override, with vcall offset
  */
 static const char *
-parse_call_offset(const char *first, const char *last)
+parse_call_offset(const char *first, const char *last, locale_t loc)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
         const char *t1 = NULL;
 
         if (first == last)

@@ -591,21 +593,21 @@
                 return (first);
 
         if (first[0] != 'h' && first[0] != 'v')
                 return (first);
 
-        t = parse_number(first + 1, last);
+        t = parse_number(first + 1, last, loc);
         if (t == first + 1 || t == last || t[0] != '_')
                 return (first);
 
         /* skip _ */
         t++;
 
         if (first[0] == 'h')
                 return (t);
 
-        t1 = parse_number(t, last);
+        t1 = parse_number(t, last, loc);
         if (t == t1 || t1 == last || t1[0] != '_')
                 return (first);
 
         /* skip _ */
         t1++;

@@ -624,11 +626,11 @@
  */
 static const char *
 parse_name(const char *first, const char *last,
     boolean_t *ends_with_template_args, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = first;
         const char *t1 = NULL;
 
         if (last - first < 2)

@@ -687,11 +689,11 @@
 /* END CSTYLED */
 const char *
 parse_local_name(const char *first, const char *last,
     boolean_t *ends_with_template_args, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
         const char *t1 = NULL;
         const char *t2 = NULL;
 

@@ -700,22 +702,22 @@
 
         t = parse_encoding(first + 1, last, db);
         if (t == first + 1 || t == last || t[0] != 'E')
                 return (first);
 
-        ASSERT(!nempty(db));
+        VERIFY(!nempty(db));
 
         /* skip E */
         t++;
 
         if (t[0] == 's') {
                 nfmt(db, "{0:L}::string literal", "{0:R}");
-                return (parse_discriminator(t, last));
+                return (parse_discriminator(t, last, db->cpp_loc));
         }
 
         if (t[0] == 'd') {
-                t1 = parse_number(t + 1, last);
+                t1 = parse_number(t + 1, last, db->cpp_loc);
                 if (t1[0] != '_')
                         return (first);
                 t1++;
         } else {
                 t1 = t;

@@ -727,11 +729,11 @@
 
         nfmt(db, "{1:L}::{0}", "{1:R}");
 
         /* parsed, but ignored */
         if (t[0] != 'd')
-                t2 = parse_discriminator(t2, last);
+                t2 = parse_discriminator(t2, last, db->cpp_loc);
 
         return (t2);
 }
 
 /* BEGIN CSTYLED */

@@ -755,11 +757,11 @@
 /* END CSTYLED */
 static const char *
 parse_nested_name(const char *first, const char *last,
     boolean_t *ends_with_template_args, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last || first[0] != 'N')
                 return (first);
 
         unsigned cv = 0;

@@ -808,11 +810,11 @@
                                 return (first);
 
                         if (!more) {
                                 nfmt(db, "{0}", NULL);
                         } else {
-                                ASSERT3U(nlen(db), >, 1);
+                                VERIFY3U(nlen(db), >, 1);
                                 nfmt(db, "{1:L}::{0}", "{1:R}");
                                 save_top(db, 1);
                         }
 
                         more = B_TRUE;

@@ -826,11 +828,11 @@
                                 return (first);
 
                         if (!more) {
                                 nfmt(db, "{0}", NULL);
                         } else {
-                                ASSERT3U(nlen(db), >, 1);
+                                VERIFY3U(nlen(db), >, 1);
                                 nfmt(db, "{1:L}::{0}", "{1:R}");
                         }
 
                         save_top(db, 1);
                         more = B_TRUE;

@@ -846,11 +848,11 @@
                                 return (first);
 
                         if (!more) {
                                 nfmt(db, "{0}", NULL);
                         } else {
-                                ASSERT3U(nlen(db), >, 1);
+                                VERIFY3U(nlen(db), >, 1);
                                 nfmt(db, "{1:L}::{0}", "{1:R}");
                         }
 
                         save_top(db, 1);
                         more = B_TRUE;

@@ -868,11 +870,11 @@
 
                         t1 = parse_template_args(t, last, db);
                         if (t1 == t || t1 == last)
                                 return (first);
 
-                        ASSERT3U(nlen(db), >, 1);
+                        VERIFY3U(nlen(db), >, 1);
                         nfmt(db, "{1:L}{0}", "{1:R}");
                         save_top(db, 1);
                         t = t1;
                         component_ends_with_template_args = B_TRUE;
                         continue;

@@ -892,11 +894,11 @@
                         return (first);
 
                 if (!more) {
                         nfmt(db, "{0}", NULL);
                 } else {
-                        ASSERT3U(nlen(db), >, 1);
+                        VERIFY3U(nlen(db), >, 1);
                         nfmt(db, "{1:L}::{0}", "{1:R}");
                 }
 
                 save_top(db, 1);
                 more = B_TRUE;

@@ -929,11 +931,11 @@
  *                ::= LZ <encoding> E          # extension
  */
 static const char *
 parse_template_arg(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
         const char *t1 = NULL;
 
         if (first == last)

@@ -1129,11 +1131,11 @@
 #undef PN
 
 static const char *
 parse_expression(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         for (size_t i = 0; i < ARRAY_SIZE(expr_tbl); i++) {

@@ -1173,11 +1175,11 @@
 
 static const char *
 parse_binary_expr(const char *first, const char *last, const char *op,
     cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         size_t n = nlen(db);

@@ -1193,11 +1195,11 @@
                 return (first);
 
         if (NAMT(db, n) != 3)
                 return (first);
 
-        ASSERT3U(nlen(db), >, 2);
+        VERIFY3U(nlen(db), >, 2);
 
         nfmt(db, "({2}) {1} ({0})", NULL);
         if (strcmp(op, ">") == 0)
                 nfmt(db, "({0})", NULL);
 

@@ -1206,11 +1208,11 @@
 
 static const char *
 parse_prefix_expr(const char *first, const char *last, const char *op,
     cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         nadd_l(db, op, 0);

@@ -1218,20 +1220,20 @@
         const char *t = parse_expression(first + 2, last, db);
         if (t == first + 2) {
                 return (first);
         }
 
-        ASSERT3U(nlen(db), >, 1);
+        VERIFY3U(nlen(db), >, 1);
 
         nfmt(db, "{1}({0})", NULL);
         return (t);
 }
 
 static const char *
 parse_gs(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
 
         if (last - first < 4)
                 return (first);

@@ -1244,11 +1246,11 @@
                 return (first);
 
         if (t == first + 2)
                 return (first);
 
-        ASSERT3U(nlen(db), >, 0);
+        VERIFY3U(nlen(db), >, 0);
 
         nfmt(db, "::{0}", NULL);
         return (t);
 }
 

@@ -1260,28 +1262,28 @@
  * <initializer> ::= pi <expression>* E         # parenthesized initialization
  */
 static const char *
 parse_new_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         /* note [gs] is already handled by parse_gs() */
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'n');
-        ASSERT(first[1] == 'a' || first[1] == 'w');
+        VERIFY3U(first[0], ==, 'n');
+        VERIFY(first[1] == 'a' || first[1] == 'w');
 
         const char *t1 = first + 2;
         const char *t2 = NULL;
         size_t n = nlen(db);
 
         nadd_l(db, (first[1] == 'w') ? "new" : "new[]", 0);
 
         while (t1 != last && t1[0] != '_') {
                 t2 = parse_expression(t1, last, db);
-                ASSERT3P(t2, !=, NULL);
+                VERIFY3P(t2, !=, NULL);
                 if (t2 == t1)
                         return (first);
                 t1 = t2;
         }
         if (t1 == last)

@@ -1327,17 +1329,17 @@
 }
 
 static const char *
 parse_del_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'd');
-        ASSERT(first[1] == 'l' || first[1] == 'a');
+        VERIFY3U(first[0], ==, 'd');
+        VERIFY(first[1] == 'l' || first[1] == 'a');
 
         size_t n = nlen(db);
         const char *t = parse_expression(first + 2, last, db);
         if (t == first + 2 || NAMT(db, n) != 1)
                 return (first);

@@ -1347,13 +1349,13 @@
 }
 
 static const char *
 parse_idx_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
-        ASSERT3U(first[0], ==, 'i');
-        ASSERT3U(first[1], ==, 'x');
+        VERIFY3P(first, <=, last);
+        VERIFY3U(first[0], ==, 'i');
+        VERIFY3U(first[1], ==, 'x');
 
         size_t n = nlen(db);
         const char *t1 = parse_expression(first + 2, last, db);
         if (t1 == first + 2)
                 return (first);

@@ -1368,11 +1370,11 @@
 
 static const char *
 parse_ppmm_expr(const char *first, const char *last, const char *fmt,
     cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
         const char *t = NULL;

@@ -1394,32 +1396,32 @@
 }
 
 static const char *
 parse_mm_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
-        ASSERT3U(first[0], ==, 'm');
-        ASSERT3U(first[1], ==, 'm');
+        VERIFY3P(first, <=, last);
+        VERIFY3U(first[0], ==, 'm');
+        VERIFY3U(first[1], ==, 'm');
 
         return (parse_ppmm_expr(first, last, "({0})--", db));
 }
 
 static const char *
 parse_pp_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
-        ASSERT3U(first[0], ==, 'p');
-        ASSERT3U(first[0], ==, 'p');
+        VERIFY3U(first[0], ==, 'p');
+        VERIFY3U(first[0], ==, 'p');
 
         return (parse_ppmm_expr(first, last, "({0})++", db));
 }
 
 static const char *
 parse_trinary_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t1, *t2, *t3;
         size_t n = nlen(db);
 
         if (last - first < 2)

@@ -1443,11 +1445,11 @@
 }
 
 static const char *
 parse_noexcept_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         size_t n = nlen(db);

@@ -1466,11 +1468,11 @@
  * sc <type> <expression>       # static_cast<type> (expression)
  */
 static const char *
 parse_cast_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         const char *fmt = NULL;

@@ -1489,31 +1491,31 @@
                 break;
         default:
                 return (first);
         }
 
-        ASSERT3U(first[1], ==, 'c');
+        VERIFY3U(first[1], ==, 'c');
 
         const char *t1 = parse_type(first + 2, last, db);
         if (t1 == first + 2)
                 return (first);
 
         const char *t2 = parse_expression(t1, last, db);
         if (t2 == t1)
                 return (first);
 
-        ASSERT3U(nlen(db), >, 1);
+        VERIFY3U(nlen(db), >, 1);
 
         nfmt(db, fmt, NULL);
         return (t2);
 }
 
 /* pt <expression> <expression>         # expr->name */
 static const char *
 parse_arrow_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 4)
                 return (first);
 
         size_t n = nlen(db);

@@ -1574,11 +1576,11 @@
  */
 /* END CSTYLED */
 static const char *
 parse_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         switch (first[0]) {

@@ -1741,14 +1743,14 @@
                         if (t != name->str_s + 9) {
                                 nfmt(db, "{1}<{0}>", NULL);
 
                                 str_pair_t save = {0};
 
-                                (void) name_pop(&db->cpp_name, &save);
+                                name_pop(&db->cpp_name, &save);
 
                                 /* get rid of 'objcproto' */
-                                (void) name_pop(&db->cpp_name, NULL);
+                                name_pop(&db->cpp_name, NULL);
                                 CK(name_add_str(&db->cpp_name, &save.strp_l,
                                     &save.strp_r));
                         } else {
                                 nfmt(db, "{1} {0}", NULL);
                         }

@@ -1839,11 +1841,11 @@
 }
 
 static const char *
 parse_qual_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
         const char *t1 = NULL;
         unsigned cv = 0;
 

@@ -1914,11 +1916,11 @@
  * az <expression>      # alignof (a expression)
  */
 static const char *
 parse_alignof(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         const char *(*fn)(const char *, const char *, cpp_db_t *);

@@ -1939,16 +1941,16 @@
  * sz <expr>    # sizeof (a expression)
  */
 static const char *
 parse_sizeof(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
-        ASSERT3U(first[0], ==, 's');
+        VERIFY3U(first[0], ==, 's');
 
         const char *t = NULL;
         size_t n = nlen(db);
 
         switch (first[1]) {

@@ -1977,31 +1979,31 @@
  */
 /* END CSTYLED */
 static const char *
 parse_function_param(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3 || first[0] != 'f')
                 return (first);
 
         const char *t1 = first + 2;
         const char *t2 = NULL;
         unsigned cv = 0;
 
         if (first[1] == 'L') {
-                t2 = parse_number(t1, last);
+                t2 = parse_number(t1, last, db->cpp_loc);
                 if (t2 == last || t2[0] != 'p')
                         return (first);
                 t1 = t2;
         }
 
         if (first[1] != 'p')
                 return (first);
 
         t1 = parse_cv_qualifiers(t1, last, &cv);
-        t2 = parse_number(t1, last);
+        t2 = parse_number(t1, last, db->cpp_loc);
         if (t2 == last || t2[0] != '_')
                 return (first);
 
         if (t2 - t1 > 0)
                 nadd_l(db, t1, (size_t)(t2 - t1));

@@ -2017,17 +2019,17 @@
  * sZ <function-param>          # size of a function parameter pack
  */
 static const char *
 parse_sizeof_param_pack_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 's');
-        ASSERT3U(first[1], ==, 'Z');
+        VERIFY3U(first[0], ==, 's');
+        VERIFY3U(first[1], ==, 'Z');
 
         if (first[2] != 'T' && first[2] != 'f')
                 return (first);
 
         const char *t = NULL;

@@ -2051,17 +2053,17 @@
  * ti <type>                                            # typeid (type)
  */
 static const char *
 parse_typeid_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 't');
-        ASSERT(first[1] == 'e' || first[1] == 'i');
+        VERIFY3U(first[0], ==, 't');
+        VERIFY(first[1] == 'e' || first[1] == 'i');
 
         const char *t = NULL;
         size_t n = nlen(db);
 
         if (first[1] == 'e')

@@ -2081,17 +2083,17 @@
  * tw <expression>                                      # throw expression
  */
 static const char *
 parse_throw_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 't');
-        ASSERT(first[1] == 'w' || first[1] == 'r');
+        VERIFY3U(first[0], ==, 't');
+        VERIFY(first[1] == 'w' || first[1] == 'r');
 
         if (first[1] == 'r') {
                 nadd_l(db, "throw", 0);
                 return (first + 2);
         }

@@ -2107,17 +2109,17 @@
 
 /* ds <expression> <expression>         # expr.*expr */
 static const char *
 parse_dot_star_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'd');
-        ASSERT3U(first[1], ==, 's');
+        VERIFY3U(first[0], ==, 'd');
+        VERIFY3U(first[1], ==, 's');
 
         size_t n = nlen(db);
         const char *t = parse_expression(first + 2, last, db);
         if (t == first + 2)
                 return (first);

@@ -2132,17 +2134,17 @@
 
 /* dt <expression> <unresolved-name>            # expr.name */
 static const char *
 parse_dot_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'd');
-        ASSERT3U(first[1], ==, 't');
+        VERIFY3U(first[0], ==, 'd');
+        VERIFY3U(first[1], ==, 't');
 
         const char *t = parse_expression(first + 2, last, db);
         if (t == first + 2)
                 return (first);
 

@@ -2156,17 +2158,17 @@
 
 /* cl <expression>+ E           # call */
 static const char *
 parse_call_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 4)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'c');
-        ASSERT3U(first[1], ==, 'l');
+        VERIFY3U(first[0], ==, 'c');
+        VERIFY3U(first[1], ==, 'l');
 
         const char *t = first + 2;
         const char *t1 = NULL;
         size_t n = nlen(db);
 

@@ -2182,11 +2184,11 @@
                 return (first);
 
         njoin(db, amt - 1, ", ");
         nfmt(db, "{1}({0})", NULL);
 
-        ASSERT3U(t[0], ==, 'E');
+        VERIFY3U(t[0], ==, 'E');
         return (t + 1);
 }
 
 /* BEGIN CSTYLED */
 /*

@@ -2195,17 +2197,17 @@
  */
 /* END CSTYLED */
 static const char *
 parse_conv_expr(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'c');
-        ASSERT3U(first[1], ==, 'v');
+        VERIFY3U(first[0], ==, 'c');
+        VERIFY3U(first[1], ==, 'v');
 
         const char *t = NULL;
         const char *t1 = NULL;
         size_t n = nlen(db);
 

@@ -2252,11 +2254,11 @@
 
 /* <simple-id> ::= <source-name> [ <template-args> ] */
 static const char *
 parse_simple_id(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = parse_source_name(first, last, db);
         if (t == first)
                 return (t);
 

@@ -2274,11 +2276,11 @@
  *                   ::= <substitution>
  */
 static const char *
 parse_unresolved_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         const char *t = first;

@@ -2287,11 +2289,11 @@
         switch (first[0]) {
         case 'T':
                 t = parse_template_param(first, last, db);
                 if (t == first || NAMT(db, n) != 1) {
                         for (size_t i = 0; i < NAMT(db, n); i++)
-                                (void) name_pop(&db->cpp_name, NULL);
+                                name_pop(&db->cpp_name, NULL);
                         return (first);
                 }
                 save_top(db, 1);
                 return (t);
 

@@ -2324,17 +2326,17 @@
 
 /* sp <expression>              # pack expansion */
 static const char *
 parse_pack_expansion(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 's');
-        ASSERT3U(first[1], ==, 'p');
+        VERIFY3U(first[0], ==, 's');
+        VERIFY3U(first[1], ==, 'p');
 
         const char *t = parse_expression(first + 2, last, db);
         if (t == first +2)
                 return (first);
 

@@ -2347,11 +2349,11 @@
  * extension       ::= StL<unqualified-name>
  */
 static const char *
 parse_unscoped_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         const char *t = first;

@@ -2383,11 +2385,11 @@
  *                    ::= <unnamed-type-name>
  */
 const char *
 parse_unqualified_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         switch (*first) {

@@ -2422,11 +2424,11 @@
  *                      # Parameter types or "v" if the lambda has no parameters
  */
 static const char *
 parse_unnamed_type_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2 || first[0] != 'U')
                 return (first);
 
         if (first[1] != 't' && first[1] != 'l')

@@ -2434,11 +2436,12 @@
 
         const char *t1 = first + 2;
         const char *t2 = NULL;
 
         if (first[1] == 't') {
-                while (t1 != last && t1[0] != '_' && is_digit(t1[0]))
+                while (t1 != last && t1[0] != '_' &&
+                    isdigit_l(t1[0], db->cpp_loc))
                         t1++;
 
                 if (t1[0] != '_')
                         return (first);
 

@@ -2477,11 +2480,11 @@
         /* E */
         t1++;
 
         t2 = t1;
         while (t2 != last && t2[0] != '_') {
-                if (!is_digit(*t2++))
+                if (!isdigit_l(*t2++, db->cpp_loc))
                         return (first);
         }
 
         if (t2[0] != '_')
                 return (first);

@@ -2570,11 +2573,11 @@
                         }
                 }
         }
 
 out:
-        ASSERT3P(end, >=, start);
+        VERIFY3P(end, >=, start);
 
         if (end - start < 2) {
                 nadd_l(db, "", 0);
                 return;
         }

@@ -2584,11 +2587,11 @@
                         start++;
                         break;
                 }
         }
 
-        ASSERT3P(end, >=, start);
+        VERIFY3P(end, >=, start);
 
         nadd_l(db, start, (size_t)(end - start));
 }
 
 /*

@@ -2602,11 +2605,11 @@
  *   extension      ::= D5    # ?
  */
 static const char *
 parse_ctor_dtor_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2 || nempty(db) || str_length(TOP_L(db)) == 0)
                 return (first);
 
         switch (first[0]) {

@@ -2645,13 +2648,13 @@
 
 static const char *
 parse_integer_literal(const char *first, const char *last, const char *fmt,
     cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
-        const char *t = parse_number(first, last);
+        const char *t = parse_number(first, last, db->cpp_loc);
         const char *start = first;
 
         if (t == first || t == last || t[0] != 'E')
                 return (first);
 

@@ -2678,12 +2681,12 @@
 };
 
 static const char *
 parse_floating_literal(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
-        ASSERT(first[0] == 'f' || first[0] == 'd' || first[0] == 'e');
+        VERIFY3P(first, <=, last);
+        VERIFY(first[0] == 'f' || first[0] == 'd' || first[0] == 'e');
 
         const struct float_data_s *fd = NULL;
 
         for (size_t i = 0; i < ARRAY_SIZE(float_info); i++) {
                 if (float_info[i].type != first[0])

@@ -2730,24 +2733,24 @@
 #if defined(_BIG_ENDIAN)
         for (t = first + 1; t != last; t++, e++) {
                 if (!is_xdigit(t[0]))
                         return (first);
 
-                unsigned d1 = is_digit(t[0]) ? t[0] - '0' : t[0] - 'a' + 10;
+                unsigned d1 = isdigit_l(t[0], db->cpp_loc) ? t[0] - '0' : t[0] - 'a' + 10;
                 t++;
-                unsigned d0 = is_digit(t[0]) ? t[0] - '0' : t[0] - 'a' + 10;
+                unsigned d0 = isdigit_l(t[0], db->cpp_loc) ? t[0] - '0' : t[0] - 'a' + 10;
 
                 *e = (d1 << 4) + d0;
         }
 #elif defined(_LITTLE_ENDIAN)
         for (t = last - 1; t > first; t--, e++) {
                 if (!is_xdigit(t[0]))
                         return (first);
 
-                unsigned d0 = is_digit(t[0]) ? t[0] - '0' : t[0] - 'a' + 10;
+                unsigned d0 = isdigit_l(t[0], db->cpp_loc) ? t[0] - '0' : t[0] - 'a' + 10;
                 t--;
-                unsigned d1 = is_digit(t[0]) ? t[0] - '0' : t[0] - 'a' + 10;
+                unsigned d1 = isdigit_l(t[0], db->cpp_loc) ? t[0] - '0' : t[0] - 'a' + 10;
 
                 *e = (d1 << 4) + d0;
         }
         t = last;
 #else

@@ -2824,11 +2827,11 @@
 };
 
 static const char *
 parse_expr_primary(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 4 || first[0] != 'L')
                 return (first);
 
         const char *t = NULL;

@@ -2888,11 +2891,11 @@
 
                 if (t[0] == 'E')
                         return (t + 1);
 
                 const char *n;
-                for (n = t; n != last && is_digit(n[0]); n++)
+                for (n = t; n != last && isdigit_l(n[0], db->cpp_loc); n++)
                         ;
                 if (n == last || nempty(db) || n[0] != 'E')
                         return (first);
                 if (n == t)
                         return (t);

@@ -3011,11 +3014,11 @@
 };
 
 static const char *
 parse_operator_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         for (size_t i = 0; i < ARRAY_SIZE(op_tbl); i++) {

@@ -3036,11 +3039,11 @@
                 nfmt(db, "operator\"\" {0}", NULL);
                 return (t);
         }
 
         if (first[0] == 'v') {
-                if (!is_digit(first[1]))
+                if (!isdigit_l(first[1], db->cpp_loc))
                         return (first);
 
                 t = parse_source_name(first + 2, last, db);
                 if (t == first + 2)
                         return (first);

@@ -3109,11 +3112,11 @@
 };
 
 static const char *
 parse_builtin_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         size_t i;

@@ -3145,23 +3148,23 @@
 
         return (first);
 }
 
 static const char *
-parse_base36(const char *first, const char *last, size_t *val)
+parse_base36(const char *first, const char *last, size_t *val, locale_t loc)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t;
 
         for (t = first, *val = 0; t != last; t++) {
-                if (!is_digit(t[0]) && !is_upper(t[0]))
+                if (!isdigit_l(t[0], loc) && !isupper_l(t[0], loc))
                         return (t);
 
                 *val *= 36;
 
-                if (is_digit(t[0]))
+                if (isdigit_l(t[0], loc))
                         *val += t[0] - '0';
                 else
                         *val += t[0] - 'A' + 10;
         }
         return (t);

@@ -3177,11 +3180,11 @@
 };
 
 static const char *
 parse_substitution(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last || last - first < 2)
                 return (first);
 
         if (first[0] != 'S')

@@ -3196,11 +3199,11 @@
 
         const char *t = first + 1;
         size_t n = 0;
 
         if (t[0] != '_') {
-                t = parse_base36(first + 1, last, &n);
+                t = parse_base36(first + 1, last, &n, db->cpp_loc);
                 if (t == first + 1 || t[0] != '_')
                         return (first);
 
                 /*
                  * S_ == substitution 0,

@@ -3214,27 +3217,27 @@
                 return (first);
 
         sub(db, n);
 
         /* skip _ */
-        ASSERT3U(t[0], ==, '_');
+        VERIFY3U(t[0], ==, '_');
 
         return (t + 1);
 }
 
 static const char *
 parse_source_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         const char *t = NULL;
         size_t n = 0;
 
-        for (t = first; t != last && is_digit(t[0]); t++) {
+        for (t = first; t != last && isdigit_l(t[0], db->cpp_loc); t++) {
                 /* make sure we don't overflow */
                 size_t nn = n * 10;
                 if (nn < n)
                         return (first);
 

@@ -3266,23 +3269,23 @@
  *                         ::= p # AltiVec vector pixel
  */
 static const char *
 parse_vector_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'D');
-        ASSERT3U(first[1], ==, 'v');
+        VERIFY3U(first[0], ==, 'D');
+        VERIFY3U(first[1], ==, 'v');
 
         const char *t = first + 2;
         const char *t1 = NULL;
 
-        if (is_digit(first[2]) && first[2] != '0') {
-                t1 = parse_number(t, last);
+        if (isdigit_l(first[2], db->cpp_loc) && first[2] != '0') {
+                t1 = parse_number(t, last, db->cpp_loc);
                 if (t1 == last || t1 + 1 == last || t1[0] != '_')
                         return (first);
 
                 nadd_l(db, t, (size_t)(t1 - t));
 

@@ -3327,16 +3330,16 @@
  */
 /* END CSTYLED */
 static const char *
 parse_decltype(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 4)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'D');
+        VERIFY3U(first[0], ==, 'D');
 
         if (first[1] != 't' && first[1] != 'T')
                 return (first);
 
         size_t n = nlen(db);

@@ -3355,23 +3358,23 @@
  *              ::= A [<dimension expression>] _ <element type>
  */
 static const char *
 parse_array_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
-        ASSERT3U(first[0], ==, 'A');
+        VERIFY3P(first, <=, last);
+        VERIFY3U(first[0], ==, 'A');
 
         if (last - first < 3)
                 return (first);
 
         const char *t = first + 1;
         const char *t1 = NULL;
         size_t n = nlen(db);
 
         if (t[0] != '_') {
-                if (is_digit(t[0]) && t[0] != '0') {
-                        t1 = parse_number(t, last);
+                if (isdigit_l(t[0], db->cpp_loc) && t[0] != '0') {
+                        t1 = parse_number(t, last, db->cpp_loc);
                         if (t1 == last)
                                 return (first);
 
                         nadd_l(db, t, (size_t)(t1 - t));
                 } else {

@@ -3386,11 +3389,11 @@
                 t = t1;
         } else {
                 nadd_l(db, "", 0);
         }
 
-        ASSERT3U(t[0], ==, '_');
+        VERIFY3U(t[0], ==, '_');
 
         t1 = parse_type(t + 1, last, db);
         if (t1 == t + 1 || NAMT(db, n) != 2)
                 return (first);
 

@@ -3408,16 +3411,16 @@
 
 /* <pointer-to-member-type> ::= M <class type> <member type> */
 static const char *
 parse_pointer_to_member_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 3)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'M');
+        VERIFY3U(first[0], ==, 'M');
 
         const char *t1 = first + 1;
         const char *t2 = NULL;
         size_t n = nlen(db);
 

@@ -3457,11 +3460,11 @@
  */
 /* END CSTYLED */
 static const char *
 parse_unresolved_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         const char *t = first;

@@ -3505,11 +3508,11 @@
 
                         nfmt(db, "{1:L}{0}", "{1:R}");
                         t = t2;
                 }
 
-                ASSERT3U(NAMT(db, n), ==, 1);
+                VERIFY3U(NAMT(db, n), ==, 1);
 
                 while (t[0] != 'E') {
                         size_t nn = nlen(db);
                         t2 = parse_unresolved_qualifier_level(t, last, db);
                         if (t == t2 || t == last || NAMT(db, nn) != 1)

@@ -3577,11 +3580,11 @@
 /* <unresolved-qualifier-level> ::= <simple-id> */
 static const char *
 parse_unresolved_qualifier_level(const char *first, const char *last,
     cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
         return (parse_simple_id(first, last, db));
 }
 
 /* BEGIN CSTYLED */
 /*

@@ -3595,11 +3598,11 @@
  */
 /* END CSTYLED */
 static const char *
 parse_base_unresolved_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
         const char *t = NULL;

@@ -3644,11 +3647,11 @@
  *                   ::= <simple-id>            # e.g., ~A<2*N>
  */
 static const char *
 parse_destructor_name(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         const char *t = parse_unresolved_type(first, last, db);

@@ -3670,16 +3673,16 @@
  * <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
  */
 static const char *
 parse_function_type(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2)
                 return (first);
 
-        ASSERT3U(first[0], ==, 'F');
+        VERIFY3U(first[0], ==, 'F');
 
         const char *t = first + 1;
 
         /* extern "C" */
         if (t[0] == 'Y')

@@ -3746,20 +3749,20 @@
  *                  ::= T <parameter-2 non-negative number> _
  */
 static const char *
 parse_template_param(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2 || first[0] != 'T')
                 return (first);
 
         const char *t = first + 1;
         size_t idx = 0;
 
         while (t != last && t[0] != '_') {
-                if (!is_digit(t[0]))
+                if (!isdigit_l(t[0], db->cpp_loc))
                         return (first);
 
                 idx *= 10;
                 idx += t[0] - '0';
                 t++;

@@ -3766,11 +3769,11 @@
         }
 
         if (t == last)
                 return (first);
 
-        ASSERT3U(t[0], ==, '_');
+        VERIFY3U(t[0], ==, '_');
 
         /*
          * T_ -> idx 0
          * T0 -> idx 1
          * T1 -> idx 2

@@ -3800,11 +3803,11 @@
  *     extension, the abi says <template-arg>+
  */
 static const char *
 parse_template_args(const char *first, const char *last, cpp_db_t *db)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (last - first < 2 || first[0] != 'I')
                 return (first);
 
         if (db->cpp_tag_templates)

@@ -3836,15 +3839,15 @@
          * ugly, but if the last thing pushed was an empty string,
          * get rid of it so we dont get "<..., >"
          */
         if (NAMT(db, n) > 1 &&
             str_pair_len(name_top(&db->cpp_name)) == 0)
-                (void) name_pop(&db->cpp_name, NULL);
+                name_pop(&db->cpp_name, NULL);
 
         njoin(db, NAMT(db, n), ", ");
 
-        ASSERT3U(nlen(db), >, 0);
+        VERIFY3U(nlen(db), >, 0);
 
         /* make sure we don't bitshift ourselves into oblivion */
         str_t *top = TOP_L(db);
         if (str_length(top) > 0 &&
             top->str_s[top->str_len - 1] == '>')

@@ -3860,21 +3863,21 @@
  * <discriminator> := _ <non-negative number>      # when number < 10
  *                 := __ <non-negative number> _   # when number >= 10
  *  extension      := decimal-digit+               # at the end of string
  */
 static const char *
-parse_discriminator(const char *first, const char *last)
+parse_discriminator(const char *first, const char *last, locale_t loc)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = NULL;
 
         if (first == last)
                 return (first);
 
-        if (is_digit(first[0])) {
-                for (t = first; t != last && is_digit(t[0]); t++)
+        if (isdigit_l(first[0], loc)) {
+                for (t = first; t != last && isdigit_l(t[0], loc); t++)
                         ;
 
                 /* not at the end of the string */
                 if (t != last)
                         return (first);

@@ -3883,17 +3886,17 @@
         } else if (first[0] != '_' || first + 1 == last) {
                 return (first);
         }
 
         t = first + 1;
-        if (is_digit(t[0]))
+        if (isdigit_l(t[0], loc))
                 return (t + 1);
 
         if (t[0] != '_' || t + 1 == last)
                 return (first);
 
-        for (t++; t != last && is_digit(t[0]); t++)
+        for (t++; t != last && isdigit_l(t[0], loc); t++)
                 ;
         if (t == last || t[0] != '_')
                 return (first);
 
         return (t);

@@ -3901,11 +3904,11 @@
 
 /* <CV-qualifiers> ::= [r] [V] [K] */
 const char *
 parse_cv_qualifiers(const char *first, const char *last, unsigned *cv)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         if (first == last)
                 return (first);
 
         *cv = 0;

@@ -3927,51 +3930,37 @@
 
 /*
  * <number> ::= [n] <non-negative decimal integer>
  */
 static const char *
-parse_number(const char *first, const char *last)
+parse_number(const char *first, const char *last, locale_t loc)
 {
-        ASSERT3P(first, <=, last);
+        VERIFY3P(first, <=, last);
 
         const char *t = first;
 
-        if (first == last || (first[0] != 'n' && !is_digit(first[0])))
+        if (first == last || (first[0] != 'n' && !isdigit_l(first[0], loc)))
                 return (first);
 
         if (t[0] == 'n')
                 t++;
 
         if (t[0] == '0')
                 return (t + 1);
 
-        while (is_digit(t[0]))
+        while (isdigit_l(t[0], loc))
                 t++;
 
         return (t);
 }
 
 /*
- * we only ever use ASCII versions of these
+ * Like isxdigit(3C), except we can only accept lower case letters as
+ * that's only what is allowed when [de]mangling floating point constants into
+ * their hex representation.
  */
 static inline boolean_t
-is_digit(int c)
-{
-        if (c < '0' || c > '9')
-                return (B_FALSE);
-        return (B_TRUE);
-}
-
-static inline boolean_t
-is_upper(int c)
-{
-        if (c < 'A' || c > 'Z')
-                return (B_FALSE);
-        return (B_TRUE);
-}
-
-static inline boolean_t
 is_xdigit(int c)
 {
         if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
                 return (B_TRUE);
         return (B_FALSE);

@@ -4055,11 +4044,11 @@
 tsave(cpp_db_t *db, size_t amt)
 {
         CK(templ_save(&db->cpp_name, amt, &db->cpp_templ));
 }
 
-static void
+static boolean_t
 db_init(cpp_db_t *db, sysdem_ops_t *ops)
 {
         (void) memset(db, 0, sizeof (*db));
         db->cpp_ops = ops;
         name_init(&db->cpp_name, ops);

@@ -4066,18 +4055,21 @@
         sub_init(&db->cpp_subs, ops);
         templ_init(&db->cpp_templ, ops);
         db->cpp_tag_templates = B_TRUE;
         db->cpp_try_to_parse_template_args = B_TRUE;
         tpush(db);
+        db->cpp_loc = newlocale(LC_CTYPE_MASK, "C", 0);
+        return ((db->cpp_loc != NULL) ? B_TRUE : B_FALSE);
 }
 
 static void
 db_fini(cpp_db_t *db)
 {
         name_fini(&db->cpp_name);
         sub_fini(&db->cpp_subs);
         templ_fini(&db->cpp_templ);
+        freelocale(db->cpp_loc);
         (void) memset(db, 0, sizeof (*db));
 }
 
 static void
 print_sp(const str_pair_t *sp, FILE *out)

@@ -4105,11 +4097,11 @@
         }
 
         (void) fputc('\n', out);
 }
 
-
+/* Print a base-36 number (for substitutions) */
 static char *
 base36(char *buf, size_t val)
 {
         char tmp[16] = { 0 };
         char *p = tmp;