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/fnmatch.c
          +++ new/usr/src/lib/libc/port/locale/fnmatch.c
↓ open down ↓ 23 lines elided ↑ open up ↑
  24   24   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25   25   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26   26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   */
  32   32  
  33   33  /*
       34 + * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  34   35   * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  35   36   * Use is subject to license terms.
  36   37   */
  37   38  
  38   39  /*
  39   40   * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
  40   41   * Compares a filename or pathname to a pattern.
  41   42   */
  42   43  
  43   44  /*
↓ open down ↓ 5 lines elided ↑ open up ↑
  49   50   * 3. Multibyte conversion state objects (mbstate_t) are passed around and
  50   51   *    used for most, but not all, conversions. Further work will be required
  51   52   *    to support state-dependent encodings.
  52   53   */
  53   54  
  54   55  #include "lint.h"
  55   56  #include <fnmatch.h>
  56   57  #include <limits.h>
  57   58  #include <string.h>
  58   59  #include <wchar.h>
       60 +#include <xlocale.h>
  59   61  #include <wctype.h>
  60      -
       62 +#include "localeimpl.h"
  61   63  #include "collate.h"
  62   64  
  63   65  #define EOS     '\0'
  64   66  
  65   67  #define RANGE_MATCH     1
  66   68  #define RANGE_NOMATCH   0
  67   69  #define RANGE_ERROR     (-1)
  68   70  
  69      -static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
       71 +static int rangematch(const char *, wchar_t, int, char **, mbstate_t *,
       72 +    locale_t);
  70   73  static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
  71      -    mbstate_t);
       74 +    mbstate_t, locale_t);
  72   75  
  73   76  int
  74   77  fnmatch(pattern, string, flags)
  75   78          const char *pattern, *string;
  76   79          int flags;
  77   80  {
       81 +        locale_t loc = uselocale(NULL);
  78   82          static const mbstate_t initial = { 0 };
  79   83  
  80      -        return (fnmatch1(pattern, string, string, flags, initial, initial));
       84 +        return (fnmatch1(pattern, string, string, flags, initial, initial,
       85 +            loc));
  81   86  }
  82   87  
  83   88  static int
  84   89  fnmatch1(const char *pattern, const char *string, const char *stringstart,
  85      -    int flags, mbstate_t patmbs, mbstate_t strmbs)
       90 +    int flags, mbstate_t patmbs, mbstate_t strmbs, locale_t loc)
  86   91  {
  87   92          char *newp;
  88   93          char c;
  89   94          wchar_t pc, sc;
  90   95          size_t pclen, sclen;
  91   96  
  92   97          for (;;) {
  93      -                pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
       98 +                pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX, &patmbs, loc);
  94   99                  if (pclen == (size_t)-1 || pclen == (size_t)-2)
  95  100                          return (FNM_NOMATCH);
  96  101                  pattern += pclen;
  97      -                sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs);
      102 +                sclen = mbrtowc_l(&sc, string, MB_LEN_MAX, &strmbs, loc);
  98  103                  if (sclen == (size_t)-1 || sclen == (size_t)-2) {
  99  104                          sc = (unsigned char)*string;
 100  105                          sclen = 1;
 101  106                          (void) memset(&strmbs, 0, sizeof (strmbs));
 102  107                  }
 103  108                  switch (pc) {
 104  109                  case EOS:
 105  110                          /*
 106  111                           * Removed FNM_LEADING_DIR, as it is not present
 107  112                           * on Solaris.
↓ open down ↓ 30 lines elided ↑ open up ↑
 138  143                                          return (0);
 139  144                          else if (c == '/' && flags & FNM_PATHNAME) {
 140  145                                  if ((string = strchr(string, '/')) == NULL)
 141  146                                          return (FNM_NOMATCH);
 142  147                                  break;
 143  148                          }
 144  149  
 145  150                          /* General case, use recursion. */
 146  151                          while (sc != EOS) {
 147  152                                  if (!fnmatch1(pattern, string, stringstart,
 148      -                                    flags, patmbs, strmbs))
      153 +                                    flags, patmbs, strmbs, loc))
 149  154                                          return (0);
 150      -                                sclen = mbrtowc(&sc, string, MB_LEN_MAX,
 151      -                                    &strmbs);
      155 +                                sclen = mbrtowc_l(&sc, string, MB_LEN_MAX,
      156 +                                    &strmbs, loc);
 152  157                                  if (sclen == (size_t)-1 ||
 153  158                                      sclen == (size_t)-2) {
 154  159                                          sc = (unsigned char)*string;
 155  160                                          sclen = 1;
 156  161                                          (void) memset(&strmbs, 0,
 157  162                                              sizeof (strmbs));
 158  163                                  }
 159  164                                  if (sc == '/' && flags & FNM_PATHNAME)
 160  165                                          break;
 161  166                                  string += sclen;
↓ open down ↓ 3 lines elided ↑ open up ↑
 165  170                          if (sc == EOS)
 166  171                                  return (FNM_NOMATCH);
 167  172                          if (sc == '/' && (flags & FNM_PATHNAME))
 168  173                                  return (FNM_NOMATCH);
 169  174                          if (sc == '.' && (flags & FNM_PERIOD) &&
 170  175                              (string == stringstart ||
 171  176                              ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
 172  177                                  return (FNM_NOMATCH);
 173  178  
 174  179                          switch (rangematch(pattern, sc, flags, &newp,
 175      -                            &patmbs)) {
      180 +                            &patmbs, loc)) {
 176  181                          case RANGE_ERROR:
 177  182                                  goto norm;
 178  183                          case RANGE_MATCH:
 179  184                                  pattern = newp;
 180  185                                  break;
 181  186                          case RANGE_NOMATCH:
 182  187                                  return (FNM_NOMATCH);
 183  188                          }
 184  189                          string += sclen;
 185  190                          break;
 186  191                  case '\\':
 187  192                          if (!(flags & FNM_NOESCAPE)) {
 188      -                                pclen = mbrtowc(&pc, pattern, MB_LEN_MAX,
 189      -                                    &patmbs);
      193 +                                pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX,
      194 +                                    &patmbs, loc);
 190  195                                  if (pclen == (size_t)-1 || pclen == (size_t)-2)
 191  196                                          return (FNM_NOMATCH);
 192  197                                  if (pclen == 0)
 193  198                                          pc = '\\';
 194  199                                  pattern += pclen;
 195  200                          }
 196  201                          /* FALLTHROUGH */
 197  202                  default:
 198  203                  norm:
 199  204                          if (pc == sc)
 200  205                                  string += sclen;
 201  206  
 202  207                          else if ((flags & FNM_IGNORECASE) &&
 203      -                            (towlower(pc) == towlower(sc)))
      208 +                            (towlower_l(pc, loc) == towlower_l(sc, loc)))
 204  209                                  string += sclen;
 205  210                          else
 206  211                                  return (FNM_NOMATCH);
 207  212  
 208  213                          break;
 209  214                  }
 210  215          }
 211  216          /* NOTREACHED */
 212  217  }
 213  218  
 214  219  static int
 215      -rangematch(pattern, test, flags, newp, patmbs)
 216      -        const char *pattern;
 217      -        wchar_t test;
 218      -        int flags;
 219      -        char **newp;
 220      -        mbstate_t *patmbs;
      220 +rangematch(const char *pattern, wchar_t test, int flags, char **newp,
      221 +    mbstate_t *patmbs, locale_t loc)
 221  222  {
 222  223          int negate, ok;
 223  224          wchar_t c, c2;
 224  225          size_t pclen;
 225  226          const char *origpat;
 226  227  
 227  228          /*
 228  229           * A bracket expression starting with an unquoted circumflex
 229  230           * character produces unspecified results (IEEE 1003.2-1992,
 230  231           * 3.13.2).  This implementation treats it like '!', for
 231  232           * consistency with the regular expression syntax.
 232  233           * J.T. Conklin (conklin@ngai.kaleida.com)
 233  234           */
 234  235          if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
 235  236                  ++pattern;
 236  237  
 237  238          if (flags & FNM_IGNORECASE)
 238      -                test = towlower(test);
      239 +                test = towlower_l(test, loc);
 239  240  
 240  241          /*
 241  242           * A right bracket shall lose its special meaning and represent
 242  243           * itself in a bracket expression if it occurs first in the list.
 243  244           * -- POSIX.2 2.8.3.2
 244  245           */
 245  246          ok = 0;
 246  247          origpat = pattern;
 247  248          for (;;) {
 248  249                  if (*pattern == ']' && pattern > origpat) {
 249  250                          pattern++;
 250  251                          break;
 251  252                  } else if (*pattern == '\0') {
 252  253                          return (RANGE_ERROR);
 253  254                  } else if (*pattern == '/' && (flags & FNM_PATHNAME)) {
 254  255                          return (RANGE_NOMATCH);
 255  256                  } else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
 256  257                          pattern++;
 257      -                pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
      258 +                pclen = mbrtowc_l(&c, pattern, MB_LEN_MAX, patmbs, loc);
 258  259                  if (pclen == (size_t)-1 || pclen == (size_t)-2)
 259  260                          return (RANGE_NOMATCH);
 260  261                  pattern += pclen;
 261  262  
 262  263                  if (flags & FNM_IGNORECASE)
 263      -                        c = towlower(c);
      264 +                        c = towlower_l(c, loc);
 264  265  
 265  266                  if (*pattern == '-' && *(pattern + 1) != EOS &&
 266  267                      *(pattern + 1) != ']') {
 267  268                          if (*++pattern == '\\' && !(flags & FNM_NOESCAPE))
 268  269                                  if (*pattern != EOS)
 269  270                                          pattern++;
 270      -                        pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs);
      271 +                        pclen = mbrtowc_l(&c2, pattern, MB_LEN_MAX, patmbs,
      272 +                            loc);
 271  273                          if (pclen == (size_t)-1 || pclen == (size_t)-2)
 272  274                                  return (RANGE_NOMATCH);
 273  275                          pattern += pclen;
 274  276                          if (c2 == EOS)
 275  277                                  return (RANGE_ERROR);
 276  278  
 277  279                          if (flags & FNM_IGNORECASE)
 278      -                                c2 = towlower(c2);
      280 +                                c2 = towlower_l(c2, loc);
 279  281  
 280      -                        if (_collate_load_error ?
      282 +                        if (loc->collate->lc_is_posix ?
 281  283                              c <= test && test <= c2 :
 282      -                            _collate_range_cmp(c, test) <= 0 &&
 283      -                            _collate_range_cmp(test, c2) <= 0)
      284 +                            _collate_range_cmp(c, test, loc) <= 0 &&
      285 +                            _collate_range_cmp(test, c2, loc) <= 0)
 284  286                                  ok = 1;
 285  287                  } else if (c == test)
 286  288                          ok = 1;
 287  289          }
 288  290  
 289  291          *newp = (char *)pattern;
 290  292          return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
 291  293  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX