198038Sache/* Locale-specific memory comparison.
2133543Stjr   Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc.
398038Sache
498038Sache   This program is free software; you can redistribute it and/or modify
598038Sache   it under the terms of the GNU General Public License as published by
698038Sache   the Free Software Foundation; either version 2, or (at your option)
798038Sache   any later version.
898038Sache
998038Sache   This program is distributed in the hope that it will be useful,
1098038Sache   but WITHOUT ANY WARRANTY; without even the implied warranty of
1198038Sache   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1298038Sache   GNU General Public License for more details.
1398038Sache
1498038Sache   You should have received a copy of the GNU General Public License
1598038Sache   along with this program; if not, write to the Free Software Foundation,
1698038Sache   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1798038Sache
1898038Sache/* Contributed by Paul Eggert <eggert@twinsun.com>.  */
1998038Sache
2098038Sache#if HAVE_CONFIG_H
2198038Sache# include <config.h>
2298038Sache#endif
2398038Sache
24131447Stjr#include "memcoll.h"
25131447Stjr
2698038Sache#include <errno.h>
27131447Stjr#include <string.h>
2898038Sache
2998038Sache/* Compare S1 (with length S1LEN) and S2 (with length S2LEN) according
3098038Sache   to the LC_COLLATE locale.  S1 and S2 do not overlap, and are not
31131447Stjr   adjacent.  Perhaps temporarily modify the bytes after S1 and S2,
32131447Stjr   but restore their original contents before returning.  Set errno to an
3398038Sache   error number if there is an error, and to zero otherwise.  */
3498038Sacheint
3598038Sachememcoll (char *s1, size_t s1len, char *s2, size_t s2len)
3698038Sache{
3798038Sache  int diff;
38131447Stjr
39131447Stjr#if HAVE_STRCOLL
40131447Stjr
4198038Sache  char n1 = s1[s1len];
4298038Sache  char n2 = s2[s2len];
4398038Sache
4498038Sache  s1[s1len++] = '\0';
4598038Sache  s2[s2len++] = '\0';
4698038Sache
4798038Sache  while (! (errno = 0, (diff = strcoll (s1, s2)) || errno))
4898038Sache    {
4998038Sache      /* strcoll found no difference, but perhaps it was fooled by NUL
5098038Sache	 characters in the data.  Work around this problem by advancing
5198038Sache	 past the NUL chars.  */
5298038Sache      size_t size1 = strlen (s1) + 1;
5398038Sache      size_t size2 = strlen (s2) + 1;
5498038Sache      s1 += size1;
5598038Sache      s2 += size2;
5698038Sache      s1len -= size1;
5798038Sache      s2len -= size2;
5898038Sache
5998038Sache      if (s1len == 0)
6098038Sache	{
6198038Sache	  if (s2len != 0)
6298038Sache	    diff = -1;
6398038Sache	  break;
6498038Sache	}
6598038Sache      else if (s2len == 0)
6698038Sache	{
6798038Sache	  diff = 1;
6898038Sache	  break;
6998038Sache	}
7098038Sache    }
7198038Sache
7298038Sache  s1[s1len - 1] = n1;
7398038Sache  s2[s2len - 1] = n2;
7498038Sache
75131447Stjr#else
76131447Stjr
77131447Stjr  diff = memcmp (s1, s2, s1len < s2len ? s1len : s2len);
78131447Stjr  if (! diff)
79131447Stjr    diff = s1len < s2len ? -1 : s1len != s2len;
80131447Stjr  errno = 0;
81131447Stjr
82131447Stjr#endif
83131447Stjr
8498038Sache  return diff;
8598038Sache}
86