Print this page
2964 need POSIX 2008 locale object support
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Approved by: TBD

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libc/port/locale/collate.c
          +++ new/usr/src/lib/libc/port/locale/collate.c
   1    1  /*
   2      - * Copright 2010 Nexenta Systems, Inc.  All rights reserved.
        2 + * Copyright 2014 Garrett D'Amore <garrett@damore.org>
        3 + * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
   3    4   * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
   4    5   *              at Electronni Visti IA, Kiev, Ukraine.
   5    6   *                      All rights reserved.
   6    7   *
   7    8   * Redistribution and use in source and binary forms, with or without
   8    9   * modification, are permitted provided that the following conditions
   9   10   * are met:
  10   11   * 1. Redistributions of source code must retain the above copyright
  11   12   *    notice, this list of conditions and the following disclaimer.
  12   13   * 2. Redistributions in binary form must reproduce the above copyright
↓ open down ↓ 24 lines elided ↑ open up ↑
  37   38  #include <unistd.h>
  38   39  #include <ctype.h>
  39   40  #include <unistd.h>
  40   41  #include <fcntl.h>
  41   42  #include <assert.h>
  42   43  #include <sys/stat.h>
  43   44  #include <sys/mman.h>
  44   45  
  45   46  #include "collate.h"
  46   47  #include "setlocale.h"
  47      -#include "ldpart.h"
  48   48  
  49   49  /*
  50   50   * See the comments in usr/src/cmd/localedef/collate.c for further
  51   51   * information.  It would also be very helpful to have a copy of the
  52   52   * POSIX standard for collation (in the locale format manual page)
  53   53   * handy (www.opengroup.org).
  54   54   */
  55   55  
  56      -static collate_subst_t          *subst_table[COLL_WEIGHTS_MAX];
  57      -static collate_char_t           *char_pri_table;
  58      -static collate_large_t          *large_pri_table;
  59      -static collate_chain_t          *chain_pri_table;
  60      -static char                     *cache = NULL;
  61      -static size_t                   cachesz;
  62      -static char                     collate_encoding[ENCODING_LEN + 1];
       56 +/*
       57 + * POSIX uses empty tables and falls down to strcmp.
       58 + */
       59 +struct lc_collate lc_collate_posix = {
       60 +        .lc_is_posix = 1,
       61 +};
  63   62  
  64      -/* Exposed externally to other parts of libc. */
  65      -collate_info_t                  *_collate_info;
  66      -int _collate_load_error = 1;
       63 +struct locdata __posix_collate_locdata = {
       64 +        .l_lname = "C",
       65 +        .l_refcnt = (uint32_t)-1,
       66 +        .l_data = { &lc_collate_posix }
       67 +};
  67   68  
  68   69  
  69      -int
  70      -_collate_load_tables(const char *encoding)
       70 +struct locdata *
       71 +__lc_collate_load(const char *locname)
  71   72  {
  72   73          int i, chains, z;
  73   74          char buf[PATH_MAX];
  74   75          char *TMP;
  75   76          char *map;
  76   77          collate_info_t *info;
  77   78          struct stat sbuf;
  78   79          int fd;
       80 +        struct locdata *ldata;
       81 +        struct lc_collate *lcc;
  79   82  
  80      -        /* 'encoding' must be already checked. */
  81      -        if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
  82      -                _collate_load_error = 1;
  83      -                return (_LDP_CACHE);
  84      -        }
  85      -
  86   83          /*
  87      -         * If the locale name is the same as our cache, use the cache.
  88      -         */
  89      -        if (cache && (strncmp(encoding, collate_encoding, ENCODING_LEN) == 0)) {
  90      -                _collate_load_error = 0;
  91      -                return (_LDP_CACHE);
  92      -        }
  93      -
  94      -        /*
  95   84           * Slurp the locale file into the cache.
  96   85           */
  97   86  
  98   87          (void) snprintf(buf, sizeof (buf), "%s/%s/LC_COLLATE/LCL_DATA",
  99      -            _PathLocale, encoding);
       88 +            _PathLocale, locname);
 100   89  
 101      -        if ((fd = open(buf, O_RDONLY)) < 0)
 102      -                return (_LDP_ERROR);
       90 +        if ((fd = open(buf, O_RDONLY)) < 0) {
       91 +                errno = EINVAL;
       92 +                return (NULL);
       93 +        }
 103   94          if (fstat(fd, &sbuf) < 0) {
 104   95                  (void) close(fd);
 105      -                return (_LDP_ERROR);
       96 +                errno = EINVAL;
       97 +                return (NULL);
 106   98          }
 107   99          if (sbuf.st_size < (COLLATE_STR_LEN + sizeof (info))) {
 108  100                  (void) close(fd);
 109  101                  errno = EINVAL;
 110      -                return (_LDP_ERROR);
      102 +                return (NULL);
 111  103          }
 112  104          map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 113  105          (void) close(fd);
 114  106          if ((TMP = map) == NULL) {
 115      -                return (_LDP_ERROR);
      107 +                errno = EINVAL;
      108 +                return (NULL);
 116  109          }
 117  110  
 118  111          if (strncmp(TMP, COLLATE_VERSION, COLLATE_STR_LEN) != 0) {
 119  112                  (void) munmap(map, sbuf.st_size);
 120  113                  errno = EINVAL;
 121      -                return (_LDP_ERROR);
      114 +                return (NULL);
 122  115          }
 123  116          TMP += COLLATE_STR_LEN;
 124  117  
 125  118          info = (void *)TMP;
 126  119          TMP += sizeof (*info);
 127  120  
 128  121          if ((info->directive_count < 1) ||
 129  122              (info->directive_count >= COLL_WEIGHTS_MAX) ||
 130  123              ((chains = info->chain_count) < 0)) {
 131  124                  (void) munmap(map, sbuf.st_size);
 132  125                  errno = EINVAL;
 133      -                return (_LDP_ERROR);
      126 +                return (NULL);
 134  127          }
 135  128  
 136  129          i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
 137  130              (sizeof (collate_chain_t) * chains) +
 138  131              (sizeof (collate_large_t) * info->large_count);
 139      -        for (z = 0; z < (info->directive_count); z++) {
      132 +        for (z = 0; z < info->directive_count; z++) {
 140  133                  i += sizeof (collate_subst_t) * info->subst_count[z];
 141  134          }
 142  135          if (i != (sbuf.st_size - (TMP - map))) {
 143  136                  (void) munmap(map, sbuf.st_size);
 144  137                  errno = EINVAL;
 145      -                return (_LDP_ERROR);
      138 +                return (NULL);
 146  139          }
 147  140  
 148      -        char_pri_table = (void *)TMP;
      141 +
      142 +        if ((ldata = __locdata_alloc(locname, sizeof (*lcc))) == NULL) {
      143 +                (void) munmap(map, sbuf.st_size);
      144 +                return (NULL);
      145 +        }
      146 +        lcc = ldata->l_data[0];
      147 +        ldata->l_map = map;
      148 +        ldata->l_map_len = sbuf.st_size;
      149 +
      150 +        lcc->lc_info = info;
      151 +        lcc->lc_directive_count = info->directive_count;
      152 +        lcc->lc_large_count = info->large_count;
      153 +
      154 +        for (z = 0; z < COLL_WEIGHTS_MAX; z++) {
      155 +                lcc->lc_directive[z] = info->directive[z];
      156 +                lcc->lc_subst_count[z] = info->subst_count[z];
      157 +                lcc->lc_pri_count[z] = info->pri_count[z];
      158 +                lcc->lc_undef_pri[z] = info->undef_pri[z];
      159 +        }
      160 +
      161 +        lcc->lc_char_table = (void *)TMP;
 149  162          TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
 150  163  
 151      -        for (z = 0; z < info->directive_count; z++) {
 152      -                if (info->subst_count[z] > 0) {
 153      -                        subst_table[z] = (void *)TMP;
 154      -                        TMP += info->subst_count[z] * sizeof (collate_subst_t);
      164 +        for (z = 0; z < lcc->lc_directive_count; z++) {
      165 +                int count;
      166 +                if ((count = lcc->lc_subst_count[z]) > 0) {
      167 +                        lcc->lc_subst_table[z] = (void *)TMP;
      168 +                        TMP += count * sizeof (collate_subst_t);
 155  169                  } else {
 156      -                        subst_table[z] = NULL;
      170 +                        lcc->lc_subst_table[z] = NULL;
 157  171                  }
 158  172          }
 159  173  
 160  174          if (chains > 0) {
 161      -                chain_pri_table = (void *)TMP;
      175 +                lcc->lc_chain_table = (void *)TMP;
 162  176                  TMP += chains * sizeof (collate_chain_t);
 163  177          } else
 164      -                chain_pri_table = NULL;
 165      -        if (info->large_count > 0)
 166      -                large_pri_table = (void *)TMP;
      178 +                lcc->lc_chain_table = NULL;
      179 +        lcc->lc_chain_count = chains;
      180 +        if (lcc->lc_large_count > 0)
      181 +                lcc->lc_large_table = (void *)TMP;
 167  182          else
 168      -                large_pri_table = NULL;
      183 +                lcc->lc_large_table = NULL;
 169  184  
 170      -        (void) strlcpy(collate_encoding, encoding, ENCODING_LEN);
 171      -        _collate_info = info;
 172      -
 173      -        if (cache)
 174      -                (void) munmap(cache, cachesz);
 175      -
 176      -        cache = map;
 177      -        cachesz = sbuf.st_size;
 178      -        _collate_load_error = 0;
 179      -
 180      -        return (_LDP_LOADED);
      185 +        return (ldata);
 181  186  }
 182  187  
 183      -static int32_t *
 184      -substsearch(const wchar_t key, int pass)
      188 +static const int32_t *
      189 +substsearch(const struct lc_collate *lcc, const wchar_t key, int pass)
 185  190  {
 186      -        collate_subst_t *p;
 187      -        int n = _collate_info->subst_count[pass];
      191 +        const collate_subst_t *p;
      192 +        int n = lcc->lc_subst_count[pass];
 188  193  
 189  194          if (n == 0)
 190  195                  return (NULL);
 191  196  
 192      -        if (pass >= _collate_info->directive_count)
      197 +        if (pass >= lcc->lc_directive_count)
 193  198                  return (NULL);
 194  199  
 195  200          if (!(key & COLLATE_SUBST_PRIORITY))
 196  201                  return (NULL);
 197  202  
 198      -        p = subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
      203 +        p = lcc->lc_subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
 199  204          assert(p->key == key);
 200  205          return (p->pri);
 201  206  }
 202  207  
 203  208  /*
 204  209   * Note: for performance reasons, we have expanded bsearch here.  This avoids
 205  210   * function call overhead with each comparison.
 206  211   */
 207  212  
 208  213  static collate_chain_t *
 209      -chainsearch(const wchar_t *key, int *len)
      214 +chainsearch(const struct lc_collate *lcc, const wchar_t *key, int *len)
 210  215  {
 211  216          int low;
 212  217          int high;
 213  218          int next, compar, l;
 214  219          collate_chain_t *p;
 215  220          collate_chain_t *tab;
 216  221  
 217      -        if (_collate_info->chain_count == 0)
      222 +        if (lcc->lc_info->chain_count == 0)
 218  223                  return (NULL);
 219  224  
 220  225          low = 0;
 221      -        high = _collate_info->chain_count - 1;
 222      -        tab = chain_pri_table;
      226 +        high = lcc->lc_info->chain_count - 1;
      227 +        tab = lcc->lc_chain_table;
 223  228  
 224  229          while (low <= high) {
 225  230                  next = (low + high) / 2;
 226  231                  p = tab + next;
 227  232                  compar = *key - *p->str;
 228  233                  if (compar == 0) {
 229  234                          l = wcsnlen(p->str, COLLATE_STR_LEN);
 230  235                          compar = wcsncmp(key, p->str, l);
 231  236                          if (compar == 0) {
 232  237                                  *len = l;
↓ open down ↓ 2 lines elided ↑ open up ↑
 235  240                  }
 236  241                  if (compar > 0)
 237  242                          low = next + 1;
 238  243                  else
 239  244                          high = next - 1;
 240  245          }
 241  246          return (NULL);
 242  247  }
 243  248  
 244  249  static collate_large_t *
 245      -largesearch(const wchar_t key)
      250 +largesearch(const struct lc_collate *lcc, const wchar_t key)
 246  251  {
 247  252          int low = 0;
 248      -        int high = _collate_info->large_count - 1;
      253 +        int high = lcc->lc_info->large_count - 1;
 249  254          int next, compar;
 250  255          collate_large_t *p;
 251      -        collate_large_t *tab = large_pri_table;
      256 +        collate_large_t *tab = lcc->lc_large_table;
 252  257  
 253      -        if (_collate_info->large_count == 0)
      258 +        if (lcc->lc_info->large_count == 0)
 254  259                  return (NULL);
 255  260  
 256  261          while (low <= high) {
 257  262                  next = (low + high) / 2;
 258  263                  p = tab + next;
 259  264                  compar = key - p->val;
 260  265                  if (compar == 0)
 261  266                          return (p);
 262  267                  if (compar > 0)
 263  268                          low = next + 1;
 264  269                  else
 265  270                          high = next - 1;
 266  271          }
 267  272          return (NULL);
 268  273  }
 269  274  
 270  275  void
 271      -_collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
      276 +_collate_lookup(const struct lc_collate *lcc, const wchar_t *t,
      277 +    int *len, int *pri, int which, const int **state)
 272  278  {
 273  279          collate_chain_t *p2;
 274  280          collate_large_t *match;
 275      -        collate_info_t *info = _collate_info;
 276  281          int p, l;
 277      -        int *sptr;
      282 +        const int *sptr;
 278  283  
 279  284          /*
 280  285           * If this is the "last" pass for the UNDEFINED, then
 281  286           * we just return the priority itself.
 282  287           */
 283      -        if (which >= info->directive_count) {
      288 +        if (which >= lcc->lc_directive_count) {
 284  289                  *pri = *t;
 285  290                  *len = 1;
 286  291                  *state = NULL;
 287  292                  return;
 288  293          }
 289  294  
 290  295          /*
 291  296           * If we have remaining substitution data from a previous
 292  297           * call, consume it first.
 293  298           */
↓ open down ↓ 5 lines elided ↑ open up ↑
 299  304                  return;
 300  305          }
 301  306  
 302  307          /* No active substitutions */
 303  308          *len = 1;
 304  309  
 305  310          /*
 306  311           * Check for composites such as dipthongs that collate as a
 307  312           * single element (aka chains or collating-elements).
 308  313           */
 309      -        if (((p2 = chainsearch(t, &l)) != NULL) &&
      314 +        if (((p2 = chainsearch(lcc, t, &l)) != NULL) &&
 310  315              ((p = p2->pri[which]) >= 0)) {
 311  316  
 312  317                  *len = l;
 313  318                  *pri = p;
 314  319  
 315  320          } else if (*t <= UCHAR_MAX) {
 316  321  
 317  322                  /*
 318  323                   * Character is a small (8-bit) character.
 319  324                   * We just look these up directly for speed.
 320  325                   */
 321      -                *pri = char_pri_table[*t].pri[which];
      326 +                *pri = lcc->lc_char_table[*t].pri[which];
 322  327  
 323      -        } else if ((info->large_count > 0) &&
 324      -            ((match = largesearch(*t)) != NULL)) {
      328 +        } else if ((lcc->lc_info->large_count > 0) &&
      329 +            ((match = largesearch(lcc, *t)) != NULL)) {
 325  330  
 326  331                  /*
 327  332                   * Character was found in the extended table.
 328  333                   */
 329  334                  *pri = match->pri.pri[which];
 330  335  
 331  336          } else {
 332  337                  /*
 333  338                   * Character lacks a specific definition.
 334  339                   */
 335      -                if (info->directive[which] & DIRECTIVE_UNDEFINED) {
      340 +                if (lcc->lc_directive[which] & DIRECTIVE_UNDEFINED) {
 336  341                          /* Mask off sign bit to prevent ordering confusion. */
 337  342                          *pri = (*t & COLLATE_MAX_PRIORITY);
 338  343                  } else {
 339      -                        *pri = info->undef_pri[which];
      344 +                        *pri = lcc->lc_undef_pri[which];
 340  345                  }
 341  346                  /* No substitutions for undefined characters! */
 342  347                  return;
 343  348          }
 344  349  
 345  350          /*
 346  351           * Try substituting (expanding) the character.  We are
 347  352           * currently doing this *after* the chain compression.  I
 348  353           * think it should not matter, but this way might be slightly
 349  354           * faster.
 350  355           *
 351  356           * We do this after the priority search, as this will help us
 352  357           * to identify a single key value.  In order for this to work,
 353  358           * its important that the priority assigned to a given element
 354  359           * to be substituted be unique for that level.  The localedef
 355  360           * code ensures this for us.
 356  361           */
 357      -        if ((sptr = substsearch(*pri, which)) != NULL) {
      362 +        if ((sptr = substsearch(lcc, *pri, which)) != NULL) {
 358  363                  if ((*pri = *sptr) != 0) {
 359  364                          sptr++;
 360  365                          *state = *sptr ? sptr : NULL;
 361  366                  }
 362  367          }
 363  368  
 364  369  }
 365  370  
 366  371  /*
 367  372   * This is the meaty part of wcsxfrm & strxfrm.  Note that it does
 368  373   * NOT NULL terminate.  That is left to the caller.
 369  374   */
 370  375  size_t
 371      -_collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
      376 +_collate_wxfrm(const struct lc_collate *lcc, const wchar_t *src, wchar_t *xf,
      377 +    size_t room)
 372  378  {
 373  379          int             pri;
 374  380          int             len;
 375  381          const wchar_t   *t;
 376  382          wchar_t         *tr = NULL;
 377  383          int             direc;
 378  384          int             pass;
 379      -        int32_t         *state;
      385 +        const int32_t   *state;
 380  386          size_t          want = 0;
 381  387          size_t          need = 0;
      388 +        int             ndir = lcc->lc_directive_count;
 382  389  
 383  390          assert(src);
 384  391  
 385      -        for (pass = 0; pass <= _collate_info->directive_count; pass++) {
      392 +        for (pass = 0; pass <= ndir; pass++) {
 386  393  
 387  394                  state = NULL;
 388  395  
 389  396                  if (pass != 0) {
 390  397                          /* insert level separator from the previous pass */
 391  398                          if (room) {
 392  399                                  *xf++ = 1;
 393  400                                  room--;
 394  401                          }
 395  402                          want++;
 396  403                  }
 397  404  
 398  405                  /* special pass for undefined */
 399      -                if (pass == _collate_info->directive_count) {
      406 +                if (pass == ndir) {
 400  407                          direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
 401  408                  } else {
 402      -                        direc = _collate_info->directive[pass];
      409 +                        direc = lcc->lc_directive[pass];
 403  410                  }
 404  411  
 405  412                  t = src;
 406  413  
 407  414                  if (direc & DIRECTIVE_BACKWARD) {
 408  415                          wchar_t *bp, *fp, c;
 409  416                          if (tr)
 410  417                                  free(tr);
 411  418                          if ((tr = wcsdup(t)) == NULL) {
 412  419                                  errno = ENOMEM;
↓ open down ↓ 4 lines elided ↑ open up ↑
 417  424                          while (bp < fp) {
 418  425                                  c = *bp;
 419  426                                  *bp++ = *fp;
 420  427                                  *fp-- = c;
 421  428                          }
 422  429                          t = (const wchar_t *)tr;
 423  430                  }
 424  431  
 425  432                  if (direc & DIRECTIVE_POSITION) {
 426  433                          while (*t || state) {
 427      -                                _collate_lookup(t, &len, &pri, pass, &state);
      434 +                                _collate_lookup(lcc, t, &len, &pri, pass,
      435 +                                    &state);
 428  436                                  t += len;
 429  437                                  if (pri <= 0) {
 430  438                                          if (pri < 0) {
 431  439                                                  errno = EINVAL;
 432  440                                                  goto fail;
 433  441                                          }
 434  442                                          pri = COLLATE_MAX_PRIORITY;
 435  443                                  }
 436  444                                  if (room) {
 437  445                                          *xf++ = pri;
 438  446                                          room--;
 439  447                                  }
 440  448                                  want++;
 441  449                                  need = want;
 442  450                          }
 443  451                  } else {
 444  452                          while (*t || state) {
 445      -                                _collate_lookup(t, &len, &pri, pass, &state);
      453 +                                _collate_lookup(lcc, t, &len, &pri, pass,
      454 +                                    &state);
 446  455                                  t += len;
 447  456                                  if (pri <= 0) {
 448  457                                          if (pri < 0) {
 449  458                                                  errno = EINVAL;
 450  459                                                  goto fail;
 451  460                                          }
 452  461                                          continue;
 453  462                                  }
 454  463                                  if (room) {
 455  464                                          *xf++ = pri;
↓ open down ↓ 34 lines elided ↑ open up ↑
 490  499   * priority for us, and ideally also give us a mask, and then we could
 491  500   * severely limit what we expand to.
 492  501   */
 493  502  #define XFRM_BYTES      6
 494  503  #define XFRM_OFFSET     ('0')   /* make all printable characters */
 495  504  #define XFRM_SHIFT      6
 496  505  #define XFRM_MASK       ((1 << XFRM_SHIFT) - 1)
 497  506  #define XFRM_SEP        ('.')   /* chosen to be less than XFRM_OFFSET */
 498  507  
 499  508  static int
 500      -xfrm(unsigned char *p, int pri, int pass)
      509 +xfrm(locale_t loc, unsigned char *p, int pri, int pass)
 501  510  {
 502  511          /* we use unsigned to ensure zero fill on right shift */
 503      -        uint32_t val = (uint32_t)_collate_info->pri_count[pass];
      512 +        uint32_t val = (uint32_t)loc->collate->lc_pri_count[pass];
 504  513          int nc = 0;
 505  514  
 506  515          while (val) {
 507  516                  *p = (pri & XFRM_MASK) + XFRM_OFFSET;
 508  517                  pri >>= XFRM_SHIFT;
 509  518                  val >>= XFRM_SHIFT;
 510  519                  p++;
 511  520                  nc++;
 512  521          }
 513  522          return (nc);
 514  523  }
 515  524  
 516  525  size_t
 517      -_collate_sxfrm(const wchar_t *src, char *xf, size_t room)
      526 +_collate_sxfrm(const wchar_t *src, char *xf, size_t room, locale_t loc)
 518  527  {
 519  528          int             pri;
 520  529          int             len;
 521  530          const wchar_t   *t;
 522  531          wchar_t         *tr = NULL;
 523  532          int             direc;
 524  533          int             pass;
 525      -        int32_t         *state;
      534 +        const int32_t   *state;
 526  535          size_t          want = 0;
 527  536          size_t          need = 0;
 528  537          int             b;
 529  538          uint8_t         buf[XFRM_BYTES];
      539 +        const struct lc_collate *lcc = loc->collate;
      540 +        int             ndir = lcc->lc_directive_count;
 530  541  
 531  542          assert(src);
 532  543  
 533      -        for (pass = 0; pass <= _collate_info->directive_count; pass++) {
      544 +        for (pass = 0; pass <= ndir; pass++) {
 534  545  
 535  546                  state = NULL;
 536  547  
 537  548                  if (pass != 0) {
 538  549                          /* insert level separator from the previous pass */
 539  550                          if (room) {
 540  551                                  *xf++ = XFRM_SEP;
 541  552                                  room--;
 542  553                          }
 543  554                          want++;
 544  555                  }
 545  556  
 546  557                  /* special pass for undefined */
 547      -                if (pass == _collate_info->directive_count) {
      558 +                if (pass == ndir) {
 548  559                          direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
 549  560                  } else {
 550      -                        direc = _collate_info->directive[pass];
      561 +                        direc = lcc->lc_directive[pass];
 551  562                  }
 552  563  
 553  564                  t = src;
 554  565  
 555  566                  if (direc & DIRECTIVE_BACKWARD) {
 556  567                          wchar_t *bp, *fp, c;
 557  568                          if (tr)
 558  569                                  free(tr);
 559  570                          if ((tr = wcsdup(t)) == NULL) {
 560  571                                  errno = ENOMEM;
↓ open down ↓ 5 lines elided ↑ open up ↑
 566  577                                  c = *bp;
 567  578                                  *bp++ = *fp;
 568  579                                  *fp-- = c;
 569  580                          }
 570  581                          t = (const wchar_t *)tr;
 571  582                  }
 572  583  
 573  584                  if (direc & DIRECTIVE_POSITION) {
 574  585                          while (*t || state) {
 575  586  
 576      -                                _collate_lookup(t, &len, &pri, pass, &state);
      587 +                                _collate_lookup(lcc, t, &len, &pri, pass,
      588 +                                    &state);
 577  589                                  t += len;
 578  590                                  if (pri <= 0) {
 579  591                                          if (pri < 0) {
 580  592                                                  errno = EINVAL;
 581  593                                                  goto fail;
 582  594                                          }
 583  595                                          pri = COLLATE_MAX_PRIORITY;
 584  596                                  }
 585  597  
 586      -                                b = xfrm(buf, pri, pass);
      598 +                                b = xfrm(loc, buf, pri, pass);
 587  599                                  want += b;
 588  600                                  if (room) {
 589  601                                          while (b) {
 590  602                                                  b--;
 591  603                                                  if (room) {
 592  604                                                          *xf++ = buf[b];
 593  605                                                          room--;
 594  606                                                  }
 595  607                                          }
 596  608                                  }
 597  609                                  need = want;
 598  610                          }
 599  611                  } else {
 600  612                          while (*t || state) {
 601      -                                _collate_lookup(t, &len, &pri, pass, &state);
      613 +                                _collate_lookup(lcc, t, &len, &pri, pass,
      614 +                                    &state);
 602  615                                  t += len;
 603  616                                  if (pri <= 0) {
 604  617                                          if (pri < 0) {
 605  618                                                  errno = EINVAL;
 606  619                                                  goto fail;
 607  620                                          }
 608  621                                          continue;
 609  622                                  }
 610  623  
 611      -                                b = xfrm(buf, pri, pass);
      624 +                                b = xfrm(loc, buf, pri, pass);
 612  625                                  want += b;
 613  626                                  if (room) {
 614  627  
 615  628                                          while (b) {
 616  629                                                  b--;
 617  630                                                  if (room) {
 618  631                                                          *xf++ = buf[b];
 619  632                                                          room--;
 620  633                                                  }
 621  634                                          }
↓ open down ↓ 16 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX