116dce513Schristos /* File name comparison routine.
216dce513Schristos
3*e992f068Schristos Copyright (C) 2007-2022 Free Software Foundation, Inc.
416dce513Schristos
516dce513Schristos This program is free software; you can redistribute it and/or modify
616dce513Schristos it under the terms of the GNU General Public License as published by
716dce513Schristos the Free Software Foundation; either version 2, or (at your option)
816dce513Schristos any later version.
916dce513Schristos
1016dce513Schristos This program is distributed in the hope that it will be useful,
1116dce513Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1216dce513Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1316dce513Schristos GNU General Public License for more details.
1416dce513Schristos
1516dce513Schristos You should have received a copy of the GNU General Public License
1616dce513Schristos along with this program; if not, write to the Free Software Foundation,
1716dce513Schristos Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
1816dce513Schristos
1916dce513Schristos #ifdef HAVE_CONFIG_H
2016dce513Schristos #include "config.h"
2116dce513Schristos #endif
2216dce513Schristos
2316dce513Schristos #ifdef HAVE_STRING_H
2416dce513Schristos #include <string.h>
2516dce513Schristos #endif
2616dce513Schristos
2716dce513Schristos #ifdef HAVE_STDLIB_H
2816dce513Schristos #include <stdlib.h>
2916dce513Schristos #endif
3016dce513Schristos
3116dce513Schristos #include "filenames.h"
3216dce513Schristos #include "safe-ctype.h"
3316dce513Schristos #include "libiberty.h"
3416dce513Schristos
3516dce513Schristos /*
3616dce513Schristos
3716dce513Schristos @deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2})
3816dce513Schristos
3916dce513Schristos Return zero if the two file names @var{s1} and @var{s2} are equivalent.
4016dce513Schristos If not equivalent, the returned value is similar to what @code{strcmp}
4116dce513Schristos would return. In other words, it returns a negative value if @var{s1}
4216dce513Schristos is less than @var{s2}, or a positive value if @var{s2} is greater than
4316dce513Schristos @var{s2}.
4416dce513Schristos
4516dce513Schristos This function does not normalize file names. As a result, this function
4616dce513Schristos will treat filenames that are spelled differently as different even in
4716dce513Schristos the case when the two filenames point to the same underlying file.
4816dce513Schristos However, it does handle the fact that on DOS-like file systems, forward
4916dce513Schristos and backward slashes are equal.
5016dce513Schristos
5116dce513Schristos @end deftypefn
5216dce513Schristos
5316dce513Schristos */
5416dce513Schristos
5516dce513Schristos int
filename_cmp(const char * s1,const char * s2)5616dce513Schristos filename_cmp (const char *s1, const char *s2)
5716dce513Schristos {
5816dce513Schristos #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
5916dce513Schristos && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
6016dce513Schristos return strcmp(s1, s2);
6116dce513Schristos #else
6216dce513Schristos for (;;)
6316dce513Schristos {
6416dce513Schristos int c1 = *s1;
6516dce513Schristos int c2 = *s2;
6616dce513Schristos
6716dce513Schristos #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
6816dce513Schristos c1 = TOLOWER (c1);
6916dce513Schristos c2 = TOLOWER (c2);
7016dce513Schristos #endif
7116dce513Schristos
7216dce513Schristos #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
7316dce513Schristos /* On DOS-based file systems, the '/' and the '\' are equivalent. */
7416dce513Schristos if (c1 == '/')
7516dce513Schristos c1 = '\\';
7616dce513Schristos if (c2 == '/')
7716dce513Schristos c2 = '\\';
7816dce513Schristos #endif
7916dce513Schristos
8016dce513Schristos if (c1 != c2)
8116dce513Schristos return (c1 - c2);
8216dce513Schristos
8316dce513Schristos if (c1 == '\0')
8416dce513Schristos return 0;
8516dce513Schristos
8616dce513Schristos s1++;
8716dce513Schristos s2++;
8816dce513Schristos }
8916dce513Schristos #endif
9016dce513Schristos }
9116dce513Schristos
9216dce513Schristos /*
9316dce513Schristos
9416dce513Schristos @deftypefn Extension int filename_ncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n})
9516dce513Schristos
9616dce513Schristos Return zero if the two file names @var{s1} and @var{s2} are equivalent
9716dce513Schristos in range @var{n}.
9816dce513Schristos If not equivalent, the returned value is similar to what @code{strncmp}
9916dce513Schristos would return. In other words, it returns a negative value if @var{s1}
10016dce513Schristos is less than @var{s2}, or a positive value if @var{s2} is greater than
10116dce513Schristos @var{s2}.
10216dce513Schristos
10316dce513Schristos This function does not normalize file names. As a result, this function
10416dce513Schristos will treat filenames that are spelled differently as different even in
10516dce513Schristos the case when the two filenames point to the same underlying file.
10616dce513Schristos However, it does handle the fact that on DOS-like file systems, forward
10716dce513Schristos and backward slashes are equal.
10816dce513Schristos
10916dce513Schristos @end deftypefn
11016dce513Schristos
11116dce513Schristos */
11216dce513Schristos
11316dce513Schristos int
filename_ncmp(const char * s1,const char * s2,size_t n)11416dce513Schristos filename_ncmp (const char *s1, const char *s2, size_t n)
11516dce513Schristos {
11616dce513Schristos #if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \
11716dce513Schristos && !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
11816dce513Schristos return strncmp(s1, s2, n);
11916dce513Schristos #else
12016dce513Schristos if (!n)
12116dce513Schristos return 0;
12216dce513Schristos for (; n > 0; --n)
12316dce513Schristos {
12416dce513Schristos int c1 = *s1;
12516dce513Schristos int c2 = *s2;
12616dce513Schristos
12716dce513Schristos #if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM)
12816dce513Schristos c1 = TOLOWER (c1);
12916dce513Schristos c2 = TOLOWER (c2);
13016dce513Schristos #endif
13116dce513Schristos
13216dce513Schristos #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
13316dce513Schristos /* On DOS-based file systems, the '/' and the '\' are equivalent. */
13416dce513Schristos if (c1 == '/')
13516dce513Schristos c1 = '\\';
13616dce513Schristos if (c2 == '/')
13716dce513Schristos c2 = '\\';
13816dce513Schristos #endif
13916dce513Schristos
14016dce513Schristos if (c1 == '\0' || c1 != c2)
14116dce513Schristos return (c1 - c2);
14216dce513Schristos
14316dce513Schristos s1++;
14416dce513Schristos s2++;
14516dce513Schristos }
14616dce513Schristos return 0;
14716dce513Schristos #endif
14816dce513Schristos }
14916dce513Schristos
15016dce513Schristos /*
15116dce513Schristos
15216dce513Schristos @deftypefn Extension hashval_t filename_hash (const void *@var{s})
15316dce513Schristos
15416dce513Schristos Return the hash value for file name @var{s} that will be compared
15516dce513Schristos using filename_cmp.
15616dce513Schristos This function is for use with hashtab.c hash tables.
15716dce513Schristos
15816dce513Schristos @end deftypefn
15916dce513Schristos
16016dce513Schristos */
16116dce513Schristos
16216dce513Schristos hashval_t
filename_hash(const void * s)16316dce513Schristos filename_hash (const void *s)
16416dce513Schristos {
16516dce513Schristos /* The cast is for -Wc++-compat. */
16616dce513Schristos const unsigned char *str = (const unsigned char *) s;
16716dce513Schristos hashval_t r = 0;
16816dce513Schristos unsigned char c;
16916dce513Schristos
17016dce513Schristos while ((c = *str++) != 0)
17116dce513Schristos {
17216dce513Schristos if (c == '\\')
17316dce513Schristos c = '/';
17416dce513Schristos c = TOLOWER (c);
17516dce513Schristos r = r * 67 + c - 113;
17616dce513Schristos }
17716dce513Schristos
17816dce513Schristos return r;
17916dce513Schristos }
18016dce513Schristos
18116dce513Schristos /*
18216dce513Schristos
18316dce513Schristos @deftypefn Extension int filename_eq (const void *@var{s1}, const void *@var{s2})
18416dce513Schristos
18516dce513Schristos Return non-zero if file names @var{s1} and @var{s2} are equivalent.
18616dce513Schristos This function is for use with hashtab.c hash tables.
18716dce513Schristos
18816dce513Schristos @end deftypefn
18916dce513Schristos
19016dce513Schristos */
19116dce513Schristos
19216dce513Schristos int
filename_eq(const void * s1,const void * s2)19316dce513Schristos filename_eq (const void *s1, const void *s2)
19416dce513Schristos {
19516dce513Schristos /* The casts are for -Wc++-compat. */
19616dce513Schristos return filename_cmp ((const char *) s1, (const char *) s2) == 0;
19716dce513Schristos }
19816dce513Schristos
19916dce513Schristos /*
20016dce513Schristos
20116dce513Schristos @deftypefn Extension int canonical_filename_eq (const char *@var{a}, const char *@var{b})
20216dce513Schristos
20316dce513Schristos Return non-zero if file names @var{a} and @var{b} are equivalent.
20416dce513Schristos This function compares the canonical versions of the filenames as returned by
20516dce513Schristos @code{lrealpath()}, so that so that different file names pointing to the same
20616dce513Schristos underlying file are treated as being identical.
20716dce513Schristos
20816dce513Schristos @end deftypefn
20916dce513Schristos
21016dce513Schristos */
21116dce513Schristos
21216dce513Schristos int
canonical_filename_eq(const char * a,const char * b)21316dce513Schristos canonical_filename_eq (const char * a, const char * b)
21416dce513Schristos {
21516dce513Schristos char * ca = lrealpath(a);
21616dce513Schristos char * cb = lrealpath(b);
21716dce513Schristos int res = filename_eq (ca, cb);
21816dce513Schristos free (ca);
21916dce513Schristos free (cb);
22016dce513Schristos return res;
22116dce513Schristos }
222