Blame string/strxfrm_l.c

Packit Service 82fcde
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Written by Ulrich Drepper <drepper@gnu.org>, 1995.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <langinfo.h>
Packit Service 82fcde
#include <locale.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef STRING_TYPE
Packit Service 82fcde
# define STRING_TYPE char
Packit Service 82fcde
# define USTRING_TYPE unsigned char
Packit Service 82fcde
# define STRXFRM __strxfrm_l
Packit Service 82fcde
# define STRLEN strlen
Packit Service 82fcde
# define STPNCPY __stpncpy
Packit Service 82fcde
# define WEIGHT_H "../locale/weight.h"
Packit Service 82fcde
# define SUFFIX	MB
Packit Service 82fcde
# define L(arg) arg
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#define CONCAT(a,b) CONCAT1(a,b)
Packit Service 82fcde
#define CONCAT1(a,b) a##b
Packit Service 82fcde
Packit Service 82fcde
/* Maximum string size that is calculated with cached indices.  Right now this
Packit Service 82fcde
   is an arbitrary value open to optimizations.  SMALL_STR_SIZE * 4 has to be
Packit Service 82fcde
   lower than __MAX_ALLOCA_CUTOFF.  Keep localedata/xfrm-test.c in sync.  */
Packit Service 82fcde
#define SMALL_STR_SIZE 4095
Packit Service 82fcde
Packit Service 82fcde
#include "../locale/localeinfo.h"
Packit Service 82fcde
#include WEIGHT_H
Packit Service 82fcde
Packit Service 82fcde
/* Group locale data for shorter parameter lists.  */
Packit Service 82fcde
typedef struct
Packit Service 82fcde
{
Packit Service 82fcde
  uint_fast32_t nrules;
Packit Service 82fcde
  unsigned char *rulesets;
Packit Service 82fcde
  USTRING_TYPE *weights;
Packit Service 82fcde
  int32_t *table;
Packit Service 82fcde
  USTRING_TYPE *extra;
Packit Service 82fcde
  int32_t *indirect;
Packit Service 82fcde
} locale_data_t;
Packit Service 82fcde
Packit Service 82fcde
#ifndef WIDE_CHAR_VERSION
Packit Service 82fcde
Packit Service 82fcde
/* We need UTF-8 encoding of numbers.  */
Packit Service 82fcde
static int
Packit Service 82fcde
utf8_encode (char *buf, int val)
Packit Service 82fcde
{
Packit Service 82fcde
  int retval;
Packit Service 82fcde
Packit Service 82fcde
  if (val < 0x80)
Packit Service 82fcde
    {
Packit Service 82fcde
      *buf++ = (char) val;
Packit Service 82fcde
      retval = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      int step;
Packit Service 82fcde
Packit Service 82fcde
      for (step = 2; step < 6; ++step)
Packit Service 82fcde
	if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
Packit Service 82fcde
	  break;
Packit Service 82fcde
      retval = step;
Packit Service 82fcde
Packit Service 82fcde
      *buf = (unsigned char) (~0xff >> step);
Packit Service 82fcde
      --step;
Packit Service 82fcde
      do
Packit Service 82fcde
	{
Packit Service 82fcde
	  buf[step] = 0x80 | (val & 0x3f);
Packit Service 82fcde
	  val >>= 6;
Packit Service 82fcde
	}
Packit Service 82fcde
      while (--step > 0);
Packit Service 82fcde
      *buf |= val;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return retval;
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Find next weight and rule index.  Inlined since called for every char.  */
Packit Service 82fcde
static __always_inline size_t
Packit Service 82fcde
find_idx (const USTRING_TYPE **us, int32_t *weight_idx,
Packit Service 82fcde
	  unsigned char *rule_idx, const locale_data_t *l_data, const int pass)
Packit Service 82fcde
{
Packit Service 82fcde
  int32_t tmp = findidx (l_data->table, l_data->indirect, l_data->extra, us,
Packit Service 82fcde
			 -1);
Packit Service 82fcde
  *rule_idx = tmp >> 24;
Packit Service 82fcde
  int32_t idx = tmp & 0xffffff;
Packit Service 82fcde
  size_t len = l_data->weights[idx++];
Packit Service 82fcde
Packit Service 82fcde
  /* Skip over indices of previous levels.  */
Packit Service 82fcde
  for (int i = 0; i < pass; i++)
Packit Service 82fcde
    {
Packit Service 82fcde
      idx += len;
Packit Service 82fcde
      len = l_data->weights[idx++];
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  *weight_idx = idx;
Packit Service 82fcde
  return len;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
find_position (const USTRING_TYPE *us, const locale_data_t *l_data,
Packit Service 82fcde
	       const int pass)
Packit Service 82fcde
{
Packit Service 82fcde
  int32_t weight_idx;
Packit Service 82fcde
  unsigned char rule_idx;
Packit Service 82fcde
  const USTRING_TYPE *usrc = us;
Packit Service 82fcde
Packit Service 82fcde
  find_idx (&usrc, &weight_idx, &rule_idx, l_data, pass);
Packit Service 82fcde
  return l_data->rulesets[rule_idx * l_data->nrules + pass] & sort_position;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Do the transformation.  */
Packit Service 82fcde
static size_t
Packit Service 82fcde
do_xfrm (const USTRING_TYPE *usrc, STRING_TYPE *dest, size_t n,
Packit Service 82fcde
	 const locale_data_t *l_data)
Packit Service 82fcde
{
Packit Service 82fcde
  int32_t weight_idx;
Packit Service 82fcde
  unsigned char rule_idx;
Packit Service 82fcde
  uint_fast32_t pass;
Packit Service 82fcde
  size_t needed = 0;
Packit Service 82fcde
  size_t last_needed;
Packit Service 82fcde
Packit Service 82fcde
  /* Now the passes over the weights.  */
Packit Service 82fcde
  for (pass = 0; pass < l_data->nrules; ++pass)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t backw_len = 0;
Packit Service 82fcde
      last_needed = needed;
Packit Service 82fcde
      const USTRING_TYPE *cur = usrc;
Packit Service 82fcde
      const USTRING_TYPE *backw_start = NULL;
Packit Service 82fcde
Packit Service 82fcde
       /* We assume that if a rule has defined `position' in one section
Packit Service 82fcde
         this is true for all of them.  */
Packit Service 82fcde
      int position = find_position (cur, l_data, pass);
Packit Service 82fcde
Packit Service 82fcde
      if (position == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  while (*cur != L('\0'))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      const USTRING_TYPE *pos = cur;
Packit Service 82fcde
	      size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data,
Packit Service 82fcde
				     pass);
Packit Service 82fcde
	      int rule = l_data->rulesets[rule_idx * l_data->nrules + pass];
Packit Service 82fcde
Packit Service 82fcde
	      if ((rule & sort_forward) != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Handle the pushed backward sequence.  */
Packit Service 82fcde
		  if (backw_start != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      for (size_t i = backw_len; i > 0; )
Packit Service 82fcde
			{
Packit Service 82fcde
			  int32_t weight_idx;
Packit Service 82fcde
			  unsigned char rule_idx;
Packit Service 82fcde
			  size_t len = find_idx (&backw_start, &weight_idx,
Packit Service 82fcde
						 &rule_idx, l_data, pass);
Packit Service 82fcde
			  if (needed + i < n)
Packit Service 82fcde
			    for (size_t j = len; j > 0; j--)
Packit Service 82fcde
			      dest[needed + i - j] =
Packit Service 82fcde
				l_data->weights[weight_idx++];
Packit Service 82fcde
Packit Service 82fcde
			  i -= len;
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
		      needed += backw_len;
Packit Service 82fcde
		      backw_start = NULL;
Packit Service 82fcde
		      backw_len = 0;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  /* Now handle the forward element.  */
Packit Service 82fcde
		  if (needed + len < n)
Packit Service 82fcde
		    while (len-- > 0)
Packit Service 82fcde
		      dest[needed++] = l_data->weights[weight_idx++];
Packit Service 82fcde
		  else
Packit Service 82fcde
		    /* No more characters fit into the buffer.  */
Packit Service 82fcde
		    needed += len;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Remember start of the backward sequence & track length.  */
Packit Service 82fcde
		  if (backw_start == NULL)
Packit Service 82fcde
		    backw_start = pos;
Packit Service 82fcde
		  backw_len += len;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
	  /* Handle the pushed backward sequence.  */
Packit Service 82fcde
	  if (backw_start != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      for (size_t i = backw_len; i > 0; )
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len = find_idx (&backw_start, &weight_idx, &rule_idx,
Packit Service 82fcde
					 l_data, pass);
Packit Service 82fcde
		  if (needed + i < n)
Packit Service 82fcde
		    for (size_t j = len; j > 0; j--)
Packit Service 82fcde
		      dest[needed + i - j] =
Packit Service 82fcde
			l_data->weights[weight_idx++];
Packit Service 82fcde
Packit Service 82fcde
		  i -= len;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      needed += backw_len;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  int val = 1;
Packit Service 82fcde
#ifndef WIDE_CHAR_VERSION
Packit Service 82fcde
	  char buf[7];
Packit Service 82fcde
	  size_t buflen;
Packit Service 82fcde
#endif
Packit Service 82fcde
	  size_t i;
Packit Service 82fcde
Packit Service 82fcde
	  while (*cur != L('\0'))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      const USTRING_TYPE *pos = cur;
Packit Service 82fcde
	      size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data,
Packit Service 82fcde
				     pass);
Packit Service 82fcde
	      int rule = l_data->rulesets[rule_idx * l_data->nrules + pass];
Packit Service 82fcde
Packit Service 82fcde
	      if ((rule & sort_forward) != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Handle the pushed backward sequence.  */
Packit Service 82fcde
		  if (backw_start != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      for (size_t p = backw_len; p > 0; p--)
Packit Service 82fcde
			{
Packit Service 82fcde
			  size_t len;
Packit Service 82fcde
			  int32_t weight_idx;
Packit Service 82fcde
			  unsigned char rule_idx;
Packit Service 82fcde
			  const USTRING_TYPE *backw_cur = backw_start;
Packit Service 82fcde
Packit Service 82fcde
			  /* To prevent a warning init the used vars.  */
Packit Service 82fcde
			  len = find_idx (&backw_cur, &weight_idx,
Packit Service 82fcde
					  &rule_idx, l_data, pass);
Packit Service 82fcde
Packit Service 82fcde
			  for (i = 1; i < p; i++)
Packit Service 82fcde
			    len = find_idx (&backw_cur, &weight_idx,
Packit Service 82fcde
					    &rule_idx, l_data, pass);
Packit Service 82fcde
Packit Service 82fcde
			  if (len != 0)
Packit Service 82fcde
			    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
			      if (needed + 1 + len < n)
Packit Service 82fcde
				{
Packit Service 82fcde
				  dest[needed] = val;
Packit Service 82fcde
				  for (i = 0; i < len; ++i)
Packit Service 82fcde
				    dest[needed + 1 + i] =
Packit Service 82fcde
				      l_data->weights[weight_idx + i];
Packit Service 82fcde
				}
Packit Service 82fcde
			      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
			      buflen = utf8_encode (buf, val);
Packit Service 82fcde
			      if (needed + buflen + len < n)
Packit Service 82fcde
				{
Packit Service 82fcde
				  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
				    dest[needed + i] = buf[i];
Packit Service 82fcde
				  for (i = 0; i < len; ++i)
Packit Service 82fcde
				    dest[needed + buflen + i] =
Packit Service 82fcde
				      l_data->weights[weight_idx + i];
Packit Service 82fcde
				}
Packit Service 82fcde
			      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
			      val = 1;
Packit Service 82fcde
			    }
Packit Service 82fcde
			  else
Packit Service 82fcde
			    ++val;
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
		      backw_start = NULL;
Packit Service 82fcde
		      backw_len = 0;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  /* Now handle the forward element.  */
Packit Service 82fcde
		  if (len != 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
		      if (needed + 1 + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  dest[needed] = val;
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + 1 + i] =
Packit Service 82fcde
			      l_data->weights[weight_idx + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
		      buflen = utf8_encode (buf, val);
Packit Service 82fcde
		      if (needed + buflen + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
			    dest[needed + i] = buf[i];
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + buflen + i] =
Packit Service 82fcde
			      l_data->weights[weight_idx + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
		      val = 1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    ++val;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Remember start of the backward sequence & track length.  */
Packit Service 82fcde
		  if (backw_start == NULL)
Packit Service 82fcde
		    backw_start = pos;
Packit Service 82fcde
		  backw_len++;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Handle the pushed backward sequence.  */
Packit Service 82fcde
	  if (backw_start != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      for (size_t p = backw_len; p > 0; p--)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len;
Packit Service 82fcde
		  int32_t weight_idx;
Packit Service 82fcde
		  unsigned char rule_idx;
Packit Service 82fcde
		  const USTRING_TYPE *backw_cur = backw_start;
Packit Service 82fcde
Packit Service 82fcde
		  /* To prevent a warning init the used vars.  */
Packit Service 82fcde
		  len = find_idx (&backw_cur, &weight_idx,
Packit Service 82fcde
				  &rule_idx, l_data, pass);
Packit Service 82fcde
Packit Service 82fcde
		  for (i = 1; i < p; i++)
Packit Service 82fcde
		    len = find_idx (&backw_cur, &weight_idx,
Packit Service 82fcde
				    &rule_idx, l_data, pass);
Packit Service 82fcde
Packit Service 82fcde
		  if (len != 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
		      if (needed + 1 + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  dest[needed] = val;
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + 1 + i] =
Packit Service 82fcde
			      l_data->weights[weight_idx + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
		      buflen = utf8_encode (buf, val);
Packit Service 82fcde
		      if (needed + buflen + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
			    dest[needed + i] = buf[i];
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + buflen + i] =
Packit Service 82fcde
			      l_data->weights[weight_idx + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
		      val = 1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    ++val;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Finally store the byte to separate the passes or terminate
Packit Service 82fcde
	 the string.  */
Packit Service 82fcde
      if (needed < n)
Packit Service 82fcde
	dest[needed] = pass + 1 < l_data->nrules ? L('\1') : L('\0');
Packit Service 82fcde
      ++needed;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* This is a little optimization: many collation specifications have
Packit Service 82fcde
     a `position' rule at the end and if no non-ignored character
Packit Service 82fcde
     is found the last \1 byte is immediately followed by a \0 byte
Packit Service 82fcde
     signalling this.  We can avoid the \1 byte(s).  */
Packit Service 82fcde
  if (needed > 2 && needed == last_needed + 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Remove the \1 byte.  */
Packit Service 82fcde
      if (--needed <= n)
Packit Service 82fcde
	dest[needed - 1] = L('\0');
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Return the number of bytes/words we need, but don't count the NUL
Packit Service 82fcde
     byte/word at the end.  */
Packit Service 82fcde
  return needed - 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Do the transformation using weight-index and rule cache.  */
Packit Service 82fcde
static size_t
Packit Service 82fcde
do_xfrm_cached (STRING_TYPE *dest, size_t n, const locale_data_t *l_data,
Packit Service 82fcde
		size_t idxmax, int32_t *idxarr, const unsigned char *rulearr)
Packit Service 82fcde
{
Packit Service 82fcde
  uint_fast32_t nrules = l_data->nrules;
Packit Service 82fcde
  unsigned char *rulesets = l_data->rulesets;
Packit Service 82fcde
  USTRING_TYPE *weights = l_data->weights;
Packit Service 82fcde
  uint_fast32_t pass;
Packit Service 82fcde
  size_t needed = 0;
Packit Service 82fcde
  size_t last_needed;
Packit Service 82fcde
  size_t idxcnt;
Packit Service 82fcde
Packit Service 82fcde
  /* Now the passes over the weights.  */
Packit Service 82fcde
  for (pass = 0; pass < nrules; ++pass)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t backw_stop = ~0ul;
Packit Service 82fcde
      int rule = rulesets[rulearr[0] * nrules + pass];
Packit Service 82fcde
      /* We assume that if a rule has defined `position' in one section
Packit Service 82fcde
	 this is true for all of them.  */
Packit Service 82fcde
      int position = rule & sort_position;
Packit Service 82fcde
Packit Service 82fcde
      last_needed = needed;
Packit Service 82fcde
      if (position == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if ((rule & sort_forward) != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len;
Packit Service 82fcde
Packit Service 82fcde
		  if (backw_stop != ~0ul)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Handle the pushed elements now.  */
Packit Service 82fcde
		      size_t backw;
Packit Service 82fcde
Packit Service 82fcde
		      for (backw = idxcnt; backw > backw_stop; )
Packit Service 82fcde
			{
Packit Service 82fcde
			  --backw;
Packit Service 82fcde
			  len = weights[idxarr[backw]++];
Packit Service 82fcde
Packit Service 82fcde
			  if (needed + len < n)
Packit Service 82fcde
			    while (len-- > 0)
Packit Service 82fcde
			      dest[needed++] = weights[idxarr[backw]++];
Packit Service 82fcde
			  else
Packit Service 82fcde
			    {
Packit Service 82fcde
				/* No more characters fit into the buffer.  */
Packit Service 82fcde
			      needed += len;
Packit Service 82fcde
			      idxarr[backw] += len;
Packit Service 82fcde
			    }
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
		      backw_stop = ~0ul;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  /* Now handle the forward element.  */
Packit Service 82fcde
		  len = weights[idxarr[idxcnt]++];
Packit Service 82fcde
		  if (needed + len < n)
Packit Service 82fcde
		    while (len-- > 0)
Packit Service 82fcde
		      dest[needed++] = weights[idxarr[idxcnt]++];
Packit Service 82fcde
		  else
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* No more characters fit into the buffer.  */
Packit Service 82fcde
		      needed += len;
Packit Service 82fcde
		      idxarr[idxcnt] += len;
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Remember where the backwards series started.  */
Packit Service 82fcde
		  if (backw_stop == ~0ul)
Packit Service 82fcde
		    backw_stop = idxcnt;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
	  if (backw_stop != ~0ul)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Handle the pushed elements now.  */
Packit Service 82fcde
	      size_t backw;
Packit Service 82fcde
Packit Service 82fcde
	      backw = idxcnt;
Packit Service 82fcde
	      while (backw > backw_stop)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len = weights[idxarr[--backw]++];
Packit Service 82fcde
Packit Service 82fcde
		  if (needed + len < n)
Packit Service 82fcde
		    while (len-- > 0)
Packit Service 82fcde
		      dest[needed++] = weights[idxarr[backw]++];
Packit Service 82fcde
		  else
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* No more characters fit into the buffer.  */
Packit Service 82fcde
		      needed += len;
Packit Service 82fcde
		      idxarr[backw] += len;
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  int val = 1;
Packit Service 82fcde
#ifndef WIDE_CHAR_VERSION
Packit Service 82fcde
	  char buf[7];
Packit Service 82fcde
	  size_t buflen;
Packit Service 82fcde
#endif
Packit Service 82fcde
	  size_t i;
Packit Service 82fcde
Packit Service 82fcde
	  for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if ((rule & sort_forward) != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len;
Packit Service 82fcde
Packit Service 82fcde
		  if (backw_stop != ~0ul)
Packit Service 82fcde
		    {
Packit Service 82fcde
		     /* Handle the pushed elements now.  */
Packit Service 82fcde
		      size_t backw;
Packit Service 82fcde
Packit Service 82fcde
		      for (backw = idxcnt; backw > backw_stop; )
Packit Service 82fcde
			{
Packit Service 82fcde
			  --backw;
Packit Service 82fcde
			  len = weights[idxarr[backw]++];
Packit Service 82fcde
			  if (len != 0)
Packit Service 82fcde
			    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
			      if (needed + 1 + len < n)
Packit Service 82fcde
				{
Packit Service 82fcde
				  dest[needed] = val;
Packit Service 82fcde
				  for (i = 0; i < len; ++i)
Packit Service 82fcde
				    dest[needed + 1 + i] =
Packit Service 82fcde
				      weights[idxarr[backw] + i];
Packit Service 82fcde
				}
Packit Service 82fcde
			      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
			      buflen = utf8_encode (buf, val);
Packit Service 82fcde
			      if (needed + buflen + len < n)
Packit Service 82fcde
				{
Packit Service 82fcde
				  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
				    dest[needed + i] = buf[i];
Packit Service 82fcde
				  for (i = 0; i < len; ++i)
Packit Service 82fcde
				    dest[needed + buflen + i] =
Packit Service 82fcde
				      weights[idxarr[backw] + i];
Packit Service 82fcde
				}
Packit Service 82fcde
			      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
			      idxarr[backw] += len;
Packit Service 82fcde
			      val = 1;
Packit Service 82fcde
			    }
Packit Service 82fcde
			  else
Packit Service 82fcde
			    ++val;
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
		      backw_stop = ~0ul;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  /* Now handle the forward element.  */
Packit Service 82fcde
		  len = weights[idxarr[idxcnt]++];
Packit Service 82fcde
		  if (len != 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
		      if (needed + 1+ len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  dest[needed] = val;
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + 1 + i] =
Packit Service 82fcde
			      weights[idxarr[idxcnt] + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
		      buflen = utf8_encode (buf, val);
Packit Service 82fcde
		      if (needed + buflen + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
			    dest[needed + i] = buf[i];
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + buflen + i] =
Packit Service 82fcde
			      weights[idxarr[idxcnt] + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
		      idxarr[idxcnt] += len;
Packit Service 82fcde
		      val = 1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    /* Note that we don't have to increment `idxarr[idxcnt]'
Packit Service 82fcde
		       since the length is zero.  */
Packit Service 82fcde
		    ++val;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Remember where the backwards series started.  */
Packit Service 82fcde
		  if (backw_stop == ~0ul)
Packit Service 82fcde
		    backw_stop = idxcnt;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  if (backw_stop != ~0ul)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Handle the pushed elements now.  */
Packit Service 82fcde
	      size_t backw;
Packit Service 82fcde
Packit Service 82fcde
	      backw = idxmax - 1;
Packit Service 82fcde
	      while (backw > backw_stop)
Packit Service 82fcde
		{
Packit Service 82fcde
		  size_t len = weights[idxarr[--backw]++];
Packit Service 82fcde
		  if (len != 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
#ifdef WIDE_CHAR_VERSION
Packit Service 82fcde
		      if (needed + 1 + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  dest[needed] = val;
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + 1 + i] =
Packit Service 82fcde
			      weights[idxarr[backw] + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += 1 + len;
Packit Service 82fcde
#else
Packit Service 82fcde
		      buflen = utf8_encode (buf, val);
Packit Service 82fcde
		      if (needed + buflen + len < n)
Packit Service 82fcde
			{
Packit Service 82fcde
			  for (i = 0; i < buflen; ++i)
Packit Service 82fcde
			    dest[needed + i] = buf[i];
Packit Service 82fcde
			  for (i = 0; i < len; ++i)
Packit Service 82fcde
			    dest[needed + buflen + i] =
Packit Service 82fcde
			      weights[idxarr[backw] + i];
Packit Service 82fcde
			}
Packit Service 82fcde
		      needed += buflen + len;
Packit Service 82fcde
#endif
Packit Service 82fcde
		      idxarr[backw] += len;
Packit Service 82fcde
		      val = 1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    ++val;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Finally store the byte to separate the passes or terminate
Packit Service 82fcde
	 the string.  */
Packit Service 82fcde
      if (needed < n)
Packit Service 82fcde
	dest[needed] = pass + 1 < nrules ? L('\1') : L('\0');
Packit Service 82fcde
      ++needed;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* This is a little optimization: many collation specifications have
Packit Service 82fcde
     a `position' rule at the end and if no non-ignored character
Packit Service 82fcde
     is found the last \1 byte is immediately followed by a \0 byte
Packit Service 82fcde
     signalling this.  We can avoid the \1 byte(s).  */
Packit Service 82fcde
  if (needed > 2 && needed == last_needed + 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Remove the \1 byte.  */
Packit Service 82fcde
      if (--needed <= n)
Packit Service 82fcde
	dest[needed - 1] = L('\0');
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Return the number of bytes/words we need, but don't count the NUL
Packit Service 82fcde
     byte/word at the end.  */
Packit Service 82fcde
  return needed - 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
size_t
Packit Service 82fcde
STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, locale_t l)
Packit Service 82fcde
{
Packit Service 82fcde
  locale_data_t l_data;
Packit Service 82fcde
  struct __locale_data *current = l->__locales[LC_COLLATE];
Packit Service 82fcde
  l_data.nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
Packit Service 82fcde
Packit Service 82fcde
  /* Handle byte comparison case.  */
Packit Service 82fcde
  if (l_data.nrules == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t srclen = STRLEN (src);
Packit Service 82fcde
Packit Service 82fcde
      if (n != 0)
Packit Service 82fcde
	STPNCPY (dest, src, MIN (srclen + 1, n));
Packit Service 82fcde
Packit Service 82fcde
      return srclen;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Handle an empty string, code hereafter relies on strlen (src) > 0.  */
Packit Service 82fcde
  if (*src == L('\0'))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (n != 0)
Packit Service 82fcde
	*dest = L('\0');
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Get the locale data.  */
Packit Service 82fcde
  l_data.rulesets = (unsigned char *)
Packit Service 82fcde
    current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
Packit Service 82fcde
  l_data.table = (int32_t *)
Packit Service 82fcde
    current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
Packit Service 82fcde
  l_data.weights = (USTRING_TYPE *)
Packit Service 82fcde
    current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
Packit Service 82fcde
  l_data.extra = (USTRING_TYPE *)
Packit Service 82fcde
    current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
Packit Service 82fcde
  l_data.indirect = (int32_t *)
Packit Service 82fcde
    current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
Packit Service 82fcde
Packit Service 82fcde
  assert (((uintptr_t) l_data.table) % __alignof__ (l_data.table[0]) == 0);
Packit Service 82fcde
  assert (((uintptr_t) l_data.weights) % __alignof__ (l_data.weights[0]) == 0);
Packit Service 82fcde
  assert (((uintptr_t) l_data.extra) % __alignof__ (l_data.extra[0]) == 0);
Packit Service 82fcde
  assert (((uintptr_t) l_data.indirect) % __alignof__ (l_data.indirect[0]) == 0);
Packit Service 82fcde
Packit Service 82fcde
  /* We need the elements of the string as unsigned values since they
Packit Service 82fcde
     are used as indeces.  */
Packit Service 82fcde
  const USTRING_TYPE *usrc = (const USTRING_TYPE *) src;
Packit Service 82fcde
Packit Service 82fcde
  /* Allocate cache for small strings on the stack and fill it with weight and
Packit Service 82fcde
     rule indices.  If the cache size is not sufficient, continue with the
Packit Service 82fcde
     uncached xfrm version.  */
Packit Service 82fcde
  size_t idxmax = 0;
Packit Service 82fcde
  const USTRING_TYPE *cur = usrc;
Packit Service 82fcde
  int32_t *idxarr = alloca (SMALL_STR_SIZE * sizeof (int32_t));
Packit Service 82fcde
  unsigned char *rulearr = alloca (SMALL_STR_SIZE + 1);
Packit Service 82fcde
Packit Service 82fcde
  do
Packit Service 82fcde
    {
Packit Service 82fcde
      int32_t tmp = findidx (l_data.table, l_data.indirect, l_data.extra, &cur,
Packit Service 82fcde
			     -1);
Packit Service 82fcde
      rulearr[idxmax] = tmp >> 24;
Packit Service 82fcde
      idxarr[idxmax] = tmp & 0xffffff;
Packit Service 82fcde
Packit Service 82fcde
      ++idxmax;
Packit Service 82fcde
    }
Packit Service 82fcde
  while (*cur != L('\0') && idxmax < SMALL_STR_SIZE);
Packit Service 82fcde
Packit Service 82fcde
  /* This element is only read, the value never used but to determine
Packit Service 82fcde
     another value which then is ignored.  */
Packit Service 82fcde
  rulearr[idxmax] = '\0';
Packit Service 82fcde
Packit Service 82fcde
  /* Do the transformation.  */
Packit Service 82fcde
  if (*cur == L('\0'))
Packit Service 82fcde
    return do_xfrm_cached (dest, n, &l_data, idxmax, idxarr, rulearr);
Packit Service 82fcde
  else
Packit Service 82fcde
    return do_xfrm (usrc, dest, n, &l_data);
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (STRXFRM)
Packit Service 82fcde
Packit Service 82fcde
#ifndef WIDE_CHAR_VERSION
Packit Service 82fcde
weak_alias (__strxfrm_l, strxfrm_l)
Packit Service 82fcde
#endif