/* Copyright (C) 1995-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <langinfo.h>
#include <locale.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#ifndef STRING_TYPE
# define STRING_TYPE char
# define USTRING_TYPE unsigned char
# define STRXFRM __strxfrm_l
# define STRLEN strlen
# define STPNCPY __stpncpy
# define WEIGHT_H "../locale/weight.h"
# define SUFFIX MB
# define L(arg) arg
#endif
#define CONCAT(a,b) CONCAT1(a,b)
#define CONCAT1(a,b) a##b
/* Maximum string size that is calculated with cached indices. Right now this
is an arbitrary value open to optimizations. SMALL_STR_SIZE * 4 has to be
lower than __MAX_ALLOCA_CUTOFF. Keep localedata/xfrm-test.c in sync. */
#define SMALL_STR_SIZE 4095
#include "../locale/localeinfo.h"
#include WEIGHT_H
/* Group locale data for shorter parameter lists. */
typedef struct
{
uint32_t nrules;
unsigned char *rulesets;
USTRING_TYPE *weights;
int32_t *table;
USTRING_TYPE *extra;
int32_t *indirect;
} locale_data_t;
#ifndef WIDE_CHAR_VERSION
/* We need UTF-8 encoding of numbers. */
static int
utf8_encode (char *buf, int val)
{
int retval;
if (val < 0x80)
{
*buf++ = (char) val;
retval = 1;
}
else
{
int step;
for (step = 2; step < 6; ++step)
if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
break;
retval = step;
*buf = (unsigned char) (~0xff >> step);
--step;
do
{
buf[step] = 0x80 | (val & 0x3f);
val >>= 6;
}
while (--step > 0);
*buf |= val;
}
return retval;
}
#endif
/* Find next weight and rule index. Inlined since called for every char. */
static __always_inline size_t
find_idx (const USTRING_TYPE **us, int32_t *weight_idx,
unsigned char *rule_idx, const locale_data_t *l_data, const int pass)
{
int32_t tmp = findidx (l_data->table, l_data->indirect, l_data->extra, us,
-1);
*rule_idx = tmp >> 24;
int32_t idx = tmp & 0xffffff