Blame string/strxfrm_l.c

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